@authon/react 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -21,13 +21,29 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  AuthonProvider: () => AuthonProvider,
24
+ Button: () => Button,
25
+ Divider: () => Divider,
26
+ Input: () => Input,
24
27
  Protect: () => Protect,
28
+ ProviderIcon: () => ProviderIcon,
25
29
  SignIn: () => SignIn,
26
30
  SignUp: () => SignUp,
27
31
  SignedIn: () => SignedIn,
28
32
  SignedOut: () => SignedOut,
33
+ SocialButton: () => SocialButton,
34
+ SocialButtons: () => SocialButtons,
35
+ ThemeProvider: () => ThemeProvider,
29
36
  UserButton: () => UserButton,
37
+ UserProfile: () => UserProfile,
30
38
  useAuthon: () => useAuthon,
39
+ useAuthonMfa: () => useAuthonMfa,
40
+ useAuthonPasskeys: () => useAuthonPasskeys,
41
+ useAuthonPasswordless: () => useAuthonPasswordless,
42
+ useAuthonSessions: () => useAuthonSessions,
43
+ useAuthonWeb3: () => useAuthonWeb3,
44
+ useBranding: () => useBranding,
45
+ useOrganization: () => useOrganization,
46
+ useOrganizationList: () => useOrganizationList,
31
47
  useUser: () => useUser
32
48
  });
33
49
  module.exports = __toCommonJS(index_exports);
@@ -40,6 +56,7 @@ var AuthonContext = (0, import_react.createContext)(null);
40
56
  function AuthonProvider({ publishableKey, children, config }) {
41
57
  const [user, setUser] = (0, import_react.useState)(null);
42
58
  const [isLoading, setIsLoading] = (0, import_react.useState)(true);
59
+ const [activeOrganization, setActiveOrganization] = (0, import_react.useState)(null);
43
60
  const clientRef = (0, import_react.useRef)(null);
44
61
  (0, import_react.useEffect)(() => {
45
62
  const client = new import_js.Authon(publishableKey, config);
@@ -67,6 +84,7 @@ function AuthonProvider({ publishableKey, children, config }) {
67
84
  const signOut = (0, import_react.useCallback)(async () => {
68
85
  await clientRef.current?.signOut();
69
86
  setUser(null);
87
+ setActiveOrganization(null);
70
88
  }, []);
71
89
  const openSignIn = (0, import_react.useCallback)(async () => {
72
90
  await clientRef.current?.openSignIn();
@@ -82,13 +100,15 @@ function AuthonProvider({ publishableKey, children, config }) {
82
100
  isSignedIn: !!user,
83
101
  isLoading,
84
102
  user,
103
+ activeOrganization,
104
+ setActiveOrganization,
85
105
  signOut,
86
106
  openSignIn,
87
107
  openSignUp,
88
108
  getToken,
89
109
  client: clientRef.current
90
110
  }),
91
- [user, isLoading, signOut, openSignIn, openSignUp, getToken]
111
+ [user, isLoading, activeOrganization, signOut, openSignIn, openSignUp, getToken]
92
112
  );
93
113
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthonContext.Provider, { value, children });
94
114
  }
@@ -109,206 +129,2223 @@ function useUser() {
109
129
  return { user, isLoading };
110
130
  }
111
131
 
112
- // src/SignIn.tsx
132
+ // src/components/SignIn.tsx
133
+ var import_react7 = require("react");
134
+ var import_shared3 = require("@authon/shared");
135
+ var import_js2 = require("@authon/js");
136
+
137
+ // src/hooks/useBranding.ts
113
138
  var import_react3 = require("react");
114
- var import_jsx_runtime2 = require("react/jsx-runtime");
115
- function SignIn({ mode = "popup" }) {
139
+ var import_shared = require("@authon/shared");
140
+ var cache = /* @__PURE__ */ new Map();
141
+ function useBranding() {
116
142
  const { client } = useAuthon();
117
- const containerRef = (0, import_react3.useRef)(null);
118
- (0, import_react3.useEffect)(() => {
119
- if (mode === "popup") {
120
- client?.openSignIn();
143
+ const [state, setState] = (0, import_react3.useState)(() => {
144
+ const key = client?.publishableKey;
145
+ return cache.get(key ?? "") ?? { branding: import_shared.DEFAULT_BRANDING, providers: [], isLoaded: false };
146
+ });
147
+ const fetchedRef = (0, import_react3.useRef)(false);
148
+ const fetchBranding = (0, import_react3.useCallback)(async () => {
149
+ if (!client || fetchedRef.current) return;
150
+ const key = client.publishableKey;
151
+ const cached = cache.get(key);
152
+ if (cached) {
153
+ setState(cached);
154
+ return;
121
155
  }
122
- }, [client, mode]);
123
- if (mode === "embedded") {
124
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref: containerRef, id: "authon-signin-container" });
125
- }
126
- return null;
156
+ fetchedRef.current = true;
157
+ try {
158
+ const providers = await client.getProviders();
159
+ const apiUrl = client.config?.apiUrl ?? "https://api.authon.dev";
160
+ const res = await fetch(`${apiUrl}/v1/auth/branding`, {
161
+ headers: { "x-api-key": key },
162
+ credentials: "include"
163
+ });
164
+ let branding = import_shared.DEFAULT_BRANDING;
165
+ if (res.ok) {
166
+ const data = await res.json();
167
+ branding = { ...import_shared.DEFAULT_BRANDING, ...data };
168
+ }
169
+ const next = { branding, providers, isLoaded: true };
170
+ cache.set(key, next);
171
+ setState(next);
172
+ } catch {
173
+ const fallback = { branding: import_shared.DEFAULT_BRANDING, providers: [], isLoaded: true };
174
+ setState(fallback);
175
+ }
176
+ }, [client]);
177
+ (0, import_react3.useEffect)(() => {
178
+ fetchBranding();
179
+ }, [fetchBranding]);
180
+ return state;
127
181
  }
128
182
 
129
- // src/SignUp.tsx
183
+ // src/components/shared/ThemeProvider.tsx
130
184
  var import_react4 = require("react");
185
+ var import_shared2 = require("@authon/shared");
186
+ var import_jsx_runtime2 = require("react/jsx-runtime");
187
+ var ThemeContext = (0, import_react4.createContext)(null);
188
+ function useTheme() {
189
+ const ctx = (0, import_react4.useContext)(ThemeContext);
190
+ if (!ctx) {
191
+ return resolveTheme(import_shared2.DEFAULT_BRANDING, false);
192
+ }
193
+ return ctx;
194
+ }
195
+ function resolveTheme(branding, _dark) {
196
+ const radius = branding.borderRadius ?? import_shared2.DEFAULT_BRANDING.borderRadius ?? 12;
197
+ return {
198
+ primaryStart: branding.primaryColorStart ?? import_shared2.DEFAULT_BRANDING.primaryColorStart ?? "#7c3aed",
199
+ primaryEnd: branding.primaryColorEnd ?? import_shared2.DEFAULT_BRANDING.primaryColorEnd ?? "#4f46e5",
200
+ bg: branding.lightBg ?? import_shared2.DEFAULT_BRANDING.lightBg ?? "#ffffff",
201
+ text: branding.lightText ?? import_shared2.DEFAULT_BRANDING.lightText ?? "#111827",
202
+ textMuted: "#6b7280",
203
+ border: "#e5e7eb",
204
+ borderRadius: `${radius}px`,
205
+ fontFamily: 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
206
+ inputStyle: "outline"
207
+ };
208
+ }
209
+ function ThemeProvider({ branding, children, overrides, style, className }) {
210
+ const merged = (0, import_react4.useMemo)(() => ({ ...branding, ...overrides }), [branding, overrides]);
211
+ const theme = (0, import_react4.useMemo)(() => resolveTheme(merged, false), [merged]);
212
+ const cssVars = {
213
+ "--authon-primary-start": theme.primaryStart,
214
+ "--authon-primary-end": theme.primaryEnd,
215
+ "--authon-bg": theme.bg,
216
+ "--authon-text": theme.text,
217
+ "--authon-text-muted": theme.textMuted,
218
+ "--authon-border": theme.border,
219
+ "--authon-radius": theme.borderRadius,
220
+ "--authon-font": theme.fontFamily
221
+ };
222
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ThemeContext.Provider, { value: theme, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
223
+ "div",
224
+ {
225
+ className,
226
+ style: {
227
+ fontFamily: theme.fontFamily,
228
+ color: theme.text,
229
+ ...cssVars,
230
+ ...style
231
+ },
232
+ children
233
+ }
234
+ ) });
235
+ }
236
+
237
+ // src/components/shared/Input.tsx
238
+ var import_react5 = require("react");
131
239
  var import_jsx_runtime3 = require("react/jsx-runtime");
132
- function SignUp({ mode = "popup" }) {
240
+ function Input({
241
+ label,
242
+ error,
243
+ hint,
244
+ inputStyle,
245
+ onChange,
246
+ rightElement,
247
+ style: userStyle,
248
+ ...rest
249
+ }) {
250
+ const theme = useTheme();
251
+ const [focused, setFocused] = (0, import_react5.useState)(false);
252
+ const resolvedStyle = inputStyle ?? theme.inputStyle;
253
+ const wrapperStyle = {
254
+ display: "flex",
255
+ flexDirection: "column",
256
+ gap: 6,
257
+ width: "100%"
258
+ };
259
+ const labelStyle = {
260
+ fontSize: 13,
261
+ fontWeight: 500,
262
+ color: error ? "#ef4444" : theme.text
263
+ };
264
+ const inputContainerStyle = {
265
+ position: "relative",
266
+ display: "flex",
267
+ alignItems: "center"
268
+ };
269
+ const baseInputStyle = {
270
+ width: "100%",
271
+ height: 44,
272
+ paddingLeft: 14,
273
+ paddingRight: rightElement ? 44 : 14,
274
+ borderRadius: theme.borderRadius,
275
+ fontFamily: theme.fontFamily,
276
+ fontSize: 15,
277
+ color: theme.text,
278
+ outline: "none",
279
+ transition: "border-color 0.15s, box-shadow 0.15s, background 0.15s",
280
+ boxSizing: "border-box",
281
+ ...userStyle
282
+ };
283
+ let inputVariantStyle = {};
284
+ if (resolvedStyle === "filled") {
285
+ inputVariantStyle = {
286
+ background: focused ? `${theme.primaryStart}0d` : "#f3f4f6",
287
+ border: `1.5px solid ${error ? "#ef4444" : focused ? theme.primaryStart : "transparent"}`,
288
+ boxShadow: focused && !error ? `0 0 0 3px ${theme.primaryStart}22` : "none"
289
+ };
290
+ } else {
291
+ inputVariantStyle = {
292
+ background: theme.bg,
293
+ border: `1.5px solid ${error ? "#ef4444" : focused ? theme.primaryStart : theme.border}`,
294
+ boxShadow: focused && !error ? `0 0 0 3px ${theme.primaryStart}22` : "none"
295
+ };
296
+ }
297
+ const rightStyle = {
298
+ position: "absolute",
299
+ right: 12,
300
+ display: "flex",
301
+ alignItems: "center",
302
+ color: theme.textMuted
303
+ };
304
+ const hintStyle = {
305
+ fontSize: 12,
306
+ color: error ? "#ef4444" : theme.textMuted
307
+ };
308
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: wrapperStyle, children: [
309
+ label && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { style: labelStyle, children: label }),
310
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: inputContainerStyle, children: [
311
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
312
+ "input",
313
+ {
314
+ ...rest,
315
+ style: { ...baseInputStyle, ...inputVariantStyle },
316
+ onFocus: (e) => {
317
+ setFocused(true);
318
+ rest.onFocus?.(e);
319
+ },
320
+ onBlur: (e) => {
321
+ setFocused(false);
322
+ rest.onBlur?.(e);
323
+ },
324
+ onChange: (e) => onChange?.(e.target.value)
325
+ }
326
+ ),
327
+ rightElement && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: rightStyle, children: rightElement })
328
+ ] }),
329
+ (error || hint) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: hintStyle, children: error ?? hint })
330
+ ] });
331
+ }
332
+
333
+ // src/components/shared/Button.tsx
334
+ var import_react6 = require("react");
335
+ var import_jsx_runtime4 = require("react/jsx-runtime");
336
+ var SPINNER_STYLE = {
337
+ display: "inline-block",
338
+ width: 16,
339
+ height: 16,
340
+ border: "2px solid currentColor",
341
+ borderTopColor: "transparent",
342
+ borderRadius: "50%",
343
+ animation: "authon-spin 0.6s linear infinite",
344
+ flexShrink: 0
345
+ };
346
+ function Button({
347
+ variant = "primary",
348
+ size = "md",
349
+ fullWidth = false,
350
+ loading = false,
351
+ disabled = false,
352
+ children,
353
+ onClick,
354
+ type = "button",
355
+ style: userStyle
356
+ }) {
357
+ const theme = useTheme();
358
+ const [hovered, setHovered] = (0, import_react6.useState)(false);
359
+ const sizeMap = {
360
+ sm: { height: 36, paddingLeft: 12, paddingRight: 12, fontSize: 13 },
361
+ md: { height: 44, paddingLeft: 16, paddingRight: 16, fontSize: 15 },
362
+ lg: { height: 52, paddingLeft: 20, paddingRight: 20, fontSize: 16 }
363
+ };
364
+ const base = {
365
+ display: "inline-flex",
366
+ alignItems: "center",
367
+ justifyContent: "center",
368
+ gap: 8,
369
+ borderRadius: theme.borderRadius,
370
+ fontFamily: theme.fontFamily,
371
+ fontWeight: 600,
372
+ border: "none",
373
+ cursor: disabled || loading ? "not-allowed" : "pointer",
374
+ transition: "opacity 0.15s, transform 0.1s",
375
+ width: fullWidth ? "100%" : void 0,
376
+ opacity: disabled ? 0.55 : hovered && !disabled && !loading ? 0.88 : 1,
377
+ transform: hovered && !disabled && !loading ? "translateY(-1px)" : void 0,
378
+ userSelect: "none",
379
+ ...sizeMap[size]
380
+ };
381
+ let variantStyle = {};
382
+ switch (variant) {
383
+ case "primary":
384
+ variantStyle = {
385
+ background: `linear-gradient(135deg, ${theme.primaryStart}, ${theme.primaryEnd})`,
386
+ color: "#ffffff",
387
+ boxShadow: hovered ? `0 4px 16px ${theme.primaryStart}55` : "0 2px 8px rgba(0,0,0,0.1)"
388
+ };
389
+ break;
390
+ case "secondary":
391
+ variantStyle = {
392
+ background: `${theme.primaryStart}18`,
393
+ color: theme.primaryStart
394
+ };
395
+ break;
396
+ case "outline":
397
+ variantStyle = {
398
+ background: "transparent",
399
+ color: theme.text,
400
+ border: `1.5px solid ${theme.border}`
401
+ };
402
+ break;
403
+ case "ghost":
404
+ variantStyle = {
405
+ background: "transparent",
406
+ color: theme.textMuted
407
+ };
408
+ break;
409
+ case "social":
410
+ variantStyle = {
411
+ background: theme.bg,
412
+ color: theme.text,
413
+ border: `1.5px solid ${theme.border}`
414
+ };
415
+ break;
416
+ }
417
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
418
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `@keyframes authon-spin { to { transform: rotate(360deg); } }` }),
419
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
420
+ "button",
421
+ {
422
+ type,
423
+ disabled: disabled || loading,
424
+ onClick,
425
+ onMouseEnter: () => setHovered(true),
426
+ onMouseLeave: () => setHovered(false),
427
+ style: { ...base, ...variantStyle, ...userStyle },
428
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: SPINNER_STYLE }) : children
429
+ }
430
+ )
431
+ ] });
432
+ }
433
+
434
+ // src/components/shared/Divider.tsx
435
+ var import_jsx_runtime5 = require("react/jsx-runtime");
436
+ function Divider({ label = "Or continue with" }) {
437
+ const theme = useTheme();
438
+ const containerStyle = {
439
+ display: "flex",
440
+ alignItems: "center",
441
+ gap: 12,
442
+ margin: "4px 0"
443
+ };
444
+ const lineStyle = {
445
+ flex: 1,
446
+ height: 1,
447
+ background: theme.border
448
+ };
449
+ const textStyle = {
450
+ fontSize: 13,
451
+ color: theme.textMuted,
452
+ whiteSpace: "nowrap",
453
+ fontWeight: 400
454
+ };
455
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: containerStyle, children: [
456
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: lineStyle }),
457
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: textStyle, children: label }),
458
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: lineStyle })
459
+ ] });
460
+ }
461
+
462
+ // src/components/SignIn.tsx
463
+ var import_jsx_runtime6 = require("react/jsx-runtime");
464
+ function SignInCard({ afterSignInUrl, onSignIn, onNavigateSignUp }) {
465
+ const theme = useTheme();
466
+ const { client } = useAuthon();
467
+ const { branding, providers, isLoaded } = useBranding();
468
+ const [email, setEmail] = (0, import_react7.useState)("");
469
+ const [password, setPassword] = (0, import_react7.useState)("");
470
+ const [showPassword, setShowPassword] = (0, import_react7.useState)(false);
471
+ const [loading, setLoading] = (0, import_react7.useState)(false);
472
+ const [oauthLoading, setOauthLoading] = (0, import_react7.useState)(null);
473
+ const [error, setError] = (0, import_react7.useState)("");
474
+ const [fieldErrors, setFieldErrors] = (0, import_react7.useState)({});
475
+ const validate = () => {
476
+ const errs = {};
477
+ if (!email.trim()) errs.email = "Email is required";
478
+ else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) errs.email = "Invalid email address";
479
+ if (!password) errs.password = "Password is required";
480
+ setFieldErrors(errs);
481
+ return Object.keys(errs).length === 0;
482
+ };
483
+ const handleSubmit = async () => {
484
+ if (!validate() || !client) return;
485
+ setLoading(true);
486
+ setError("");
487
+ try {
488
+ await client.signInWithEmail(email, password);
489
+ if (afterSignInUrl) window.location.assign(afterSignInUrl);
490
+ onSignIn?.();
491
+ } catch (e) {
492
+ setError(e?.message ?? "Sign in failed");
493
+ } finally {
494
+ setLoading(false);
495
+ }
496
+ };
497
+ const handleOAuth = async (provider) => {
498
+ if (!client) return;
499
+ setOauthLoading(provider);
500
+ setError("");
501
+ try {
502
+ await client.signInWithOAuth(provider);
503
+ } catch (e) {
504
+ setError(e?.message ?? "OAuth sign in failed");
505
+ } finally {
506
+ setOauthLoading(null);
507
+ }
508
+ };
509
+ const cardStyle = {
510
+ width: "100%",
511
+ maxWidth: 440,
512
+ background: theme.bg,
513
+ borderRadius: `calc(${theme.borderRadius} + 4px)`,
514
+ boxShadow: "0 4px 32px rgba(0,0,0,0.10)",
515
+ padding: "40px 36px 32px",
516
+ boxSizing: "border-box",
517
+ display: "flex",
518
+ flexDirection: "column",
519
+ gap: 20,
520
+ fontFamily: theme.fontFamily
521
+ };
522
+ const logoStyle = {
523
+ display: "flex",
524
+ flexDirection: "column",
525
+ alignItems: "center",
526
+ gap: 10
527
+ };
528
+ const titleStyle = {
529
+ fontSize: 24,
530
+ fontWeight: 700,
531
+ color: theme.text,
532
+ textAlign: "center",
533
+ letterSpacing: "-0.3px"
534
+ };
535
+ const subtitleStyle = {
536
+ fontSize: 14,
537
+ color: theme.textMuted,
538
+ textAlign: "center",
539
+ marginTop: -12
540
+ };
541
+ const errorBoxStyle = {
542
+ padding: "10px 14px",
543
+ borderRadius: theme.borderRadius,
544
+ background: "#fef2f2",
545
+ border: "1px solid #fecaca",
546
+ color: "#dc2626",
547
+ fontSize: 13
548
+ };
549
+ const forgotStyle = {
550
+ textAlign: "right",
551
+ marginTop: -12
552
+ };
553
+ const linkStyle = {
554
+ fontSize: 13,
555
+ color: theme.primaryStart,
556
+ background: "none",
557
+ border: "none",
558
+ cursor: "pointer",
559
+ padding: 0,
560
+ fontFamily: theme.fontFamily,
561
+ textDecoration: "none"
562
+ };
563
+ const footerStyle = {
564
+ textAlign: "center",
565
+ fontSize: 14,
566
+ color: theme.textMuted,
567
+ paddingTop: 4
568
+ };
569
+ const eyeIconPath = showPassword ? "M17.94 17.94A10.07 10.07 0 0112 20c-7 0-11-8-11-8a18.45 18.45 0 015.06-5.94M9.9 4.24A9.12 9.12 0 0112 4c7 0 11 8 11 8a18.5 18.5 0 01-2.16 3.19m-6.72-1.07a3 3 0 11-4.24-4.24 M1 1l22 22" : "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z M12 9a3 3 0 100 6 3 3 0 000-6z";
570
+ const showEmailPw = branding.showEmailPassword !== false;
571
+ const showDivider = branding.showDivider !== false && providers.length > 0 && showEmailPw;
572
+ const providersToShow = providers.filter(
573
+ (p) => !(branding.hiddenProviders ?? []).includes(p)
574
+ );
575
+ if (!isLoaded) {
576
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { ...cardStyle, alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
577
+ "span",
578
+ {
579
+ style: {
580
+ width: 28,
581
+ height: 28,
582
+ border: `3px solid ${theme.primaryStart}33`,
583
+ borderTopColor: theme.primaryStart,
584
+ borderRadius: "50%",
585
+ display: "inline-block",
586
+ animation: "authon-spin 0.7s linear infinite"
587
+ }
588
+ }
589
+ ) });
590
+ }
591
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: cardStyle, children: [
592
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: logoStyle, children: [
593
+ branding.logoDataUrl && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("img", { src: branding.logoDataUrl, alt: branding.brandName ?? "Logo", style: { height: 40, objectFit: "contain" } }),
594
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { style: titleStyle, children: "Sign in" }),
595
+ branding.brandName && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { style: subtitleStyle, children: [
596
+ "to ",
597
+ branding.brandName
598
+ ] })
599
+ ] }),
600
+ error && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: errorBoxStyle, children: error }),
601
+ providersToShow.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: providersToShow.length <= 3 ? providersToShow.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
602
+ OAuthButton,
603
+ {
604
+ provider,
605
+ loading: oauthLoading === provider,
606
+ disabled: !!oauthLoading || loading,
607
+ onClick: () => handleOAuth(provider),
608
+ borderRadius: theme.borderRadius
609
+ },
610
+ provider
611
+ )) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 10, justifyContent: "center" }, children: providersToShow.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
612
+ CompactOAuthButton,
613
+ {
614
+ provider,
615
+ loading: oauthLoading === provider,
616
+ disabled: !!oauthLoading || loading,
617
+ onClick: () => handleOAuth(provider),
618
+ borderRadius: theme.borderRadius
619
+ },
620
+ provider
621
+ )) }) }),
622
+ showDivider && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Divider, {}),
623
+ showEmailPw && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
624
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
625
+ Input,
626
+ {
627
+ label: "Email",
628
+ type: "email",
629
+ placeholder: "you@example.com",
630
+ value: email,
631
+ onChange: setEmail,
632
+ error: fieldErrors.email,
633
+ autoComplete: "email"
634
+ }
635
+ ),
636
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
637
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
638
+ Input,
639
+ {
640
+ label: "Password",
641
+ type: showPassword ? "text" : "password",
642
+ placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
643
+ value: password,
644
+ onChange: setPassword,
645
+ error: fieldErrors.password,
646
+ autoComplete: "current-password",
647
+ rightElement: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
648
+ "button",
649
+ {
650
+ type: "button",
651
+ onClick: () => setShowPassword((v) => !v),
652
+ style: { background: "none", border: "none", cursor: "pointer", padding: 0, display: "flex", color: theme.textMuted },
653
+ "aria-label": showPassword ? "Hide password" : "Show password",
654
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: eyeIconPath }) })
655
+ }
656
+ )
657
+ }
658
+ ),
659
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: forgotStyle, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", style: linkStyle, children: "Forgot password?" }) })
660
+ ] }),
661
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
662
+ Button,
663
+ {
664
+ variant: "primary",
665
+ fullWidth: true,
666
+ loading,
667
+ disabled: !!oauthLoading,
668
+ onClick: handleSubmit,
669
+ children: "Sign in"
670
+ }
671
+ )
672
+ ] }),
673
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: footerStyle, children: [
674
+ "Don't have an account?",
675
+ " ",
676
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
677
+ "button",
678
+ {
679
+ type: "button",
680
+ style: linkStyle,
681
+ onClick: onNavigateSignUp,
682
+ children: "Sign up"
683
+ }
684
+ )
685
+ ] }),
686
+ branding.showSecuredBy !== false && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SecuredByAuthon, { primaryStart: theme.primaryStart, textMuted: theme.textMuted }),
687
+ branding.termsUrl || branding.privacyUrl ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { textAlign: "center", fontSize: 11, color: theme.textMuted, marginTop: -8 }, children: [
688
+ branding.termsUrl && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("a", { href: branding.termsUrl, target: "_blank", rel: "noopener noreferrer", style: { color: theme.textMuted }, children: "Terms" }),
689
+ branding.termsUrl && branding.privacyUrl && " \xB7 ",
690
+ branding.privacyUrl && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("a", { href: branding.privacyUrl, target: "_blank", rel: "noopener noreferrer", style: { color: theme.textMuted }, children: "Privacy" })
691
+ ] }) : null
692
+ ] });
693
+ }
694
+ function OAuthButton({ provider, loading, disabled, onClick, borderRadius }) {
695
+ const [hovered, setHovered] = (0, import_react7.useState)(false);
696
+ const colors = import_shared3.PROVIDER_COLORS[provider] ?? { bg: "#333", text: "#fff" };
697
+ const name = import_shared3.PROVIDER_DISPLAY_NAMES[provider] ?? provider;
698
+ const config = (0, import_js2.getProviderButtonConfig)(provider);
699
+ const needsBorder = colors.bg.toLowerCase() === "#ffffff";
700
+ const style = {
701
+ display: "flex",
702
+ alignItems: "center",
703
+ gap: 10,
704
+ width: "100%",
705
+ height: 44,
706
+ paddingLeft: 16,
707
+ paddingRight: 16,
708
+ borderRadius,
709
+ background: colors.bg,
710
+ color: colors.text,
711
+ border: needsBorder ? "1.5px solid #dadce0" : "none",
712
+ cursor: disabled ? "not-allowed" : "pointer",
713
+ fontSize: 15,
714
+ fontWeight: 600,
715
+ fontFamily: "system-ui, -apple-system, sans-serif",
716
+ justifyContent: "center",
717
+ opacity: disabled ? 0.6 : hovered ? 0.88 : 1,
718
+ transition: "opacity 0.15s",
719
+ boxSizing: "border-box"
720
+ };
721
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
722
+ "button",
723
+ {
724
+ type: "button",
725
+ style,
726
+ onClick,
727
+ disabled,
728
+ onMouseEnter: () => setHovered(true),
729
+ onMouseLeave: () => setHovered(false),
730
+ "aria-label": `Continue with ${name}`,
731
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { width: 18, height: 18, border: `2px solid ${colors.text}`, borderTopColor: "transparent", borderRadius: "50%", display: "inline-block", animation: "authon-spin 0.6s linear infinite" } }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
732
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { display: "flex", alignItems: "center" }, dangerouslySetInnerHTML: { __html: config.iconSvg } }),
733
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
734
+ "Continue with ",
735
+ name
736
+ ] })
737
+ ] })
738
+ }
739
+ );
740
+ }
741
+ function CompactOAuthButton({ provider, loading, disabled, onClick, borderRadius }) {
742
+ const [hovered, setHovered] = (0, import_react7.useState)(false);
743
+ const colors = import_shared3.PROVIDER_COLORS[provider] ?? { bg: "#333", text: "#fff" };
744
+ const name = import_shared3.PROVIDER_DISPLAY_NAMES[provider] ?? provider;
745
+ const config = (0, import_js2.getProviderButtonConfig)(provider);
746
+ const needsBorder = colors.bg.toLowerCase() === "#ffffff";
747
+ const style = {
748
+ display: "flex",
749
+ alignItems: "center",
750
+ justifyContent: "center",
751
+ width: 48,
752
+ height: 48,
753
+ borderRadius,
754
+ background: colors.bg,
755
+ border: needsBorder ? "1.5px solid #dadce0" : "none",
756
+ cursor: disabled ? "not-allowed" : "pointer",
757
+ opacity: disabled ? 0.6 : hovered ? 0.85 : 1,
758
+ transition: "opacity 0.15s",
759
+ padding: 0
760
+ };
761
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
762
+ "button",
763
+ {
764
+ type: "button",
765
+ style,
766
+ onClick,
767
+ disabled,
768
+ onMouseEnter: () => setHovered(true),
769
+ onMouseLeave: () => setHovered(false),
770
+ "aria-label": `Continue with ${name}`,
771
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { width: 18, height: 18, border: `2px solid ${colors.text}`, borderTopColor: "transparent", borderRadius: "50%", display: "inline-block", animation: "authon-spin 0.6s linear infinite" } }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { display: "flex" }, dangerouslySetInnerHTML: { __html: config.iconSvg } })
772
+ }
773
+ );
774
+ }
775
+ function SecuredByAuthon({ primaryStart, textMuted }) {
776
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: 5, marginTop: -8 }, children: [
777
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("svg", { width: "12", height: "14", viewBox: "0 0 12 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
778
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M6 0L0.5 2.5V6.5C0.5 9.7 2.9 12.7 6 13.5C9.1 12.7 11.5 9.7 11.5 6.5V2.5L6 0Z", fill: primaryStart, opacity: "0.85" }),
779
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M4 7L5.5 8.5L8.5 5.5", stroke: "white", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" })
780
+ ] }),
781
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: { fontSize: 11, color: textMuted }, children: [
782
+ "Secured by",
783
+ " ",
784
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("a", { href: "https://authon.dev", target: "_blank", rel: "noopener noreferrer", style: { color: primaryStart, textDecoration: "none", fontWeight: 600 }, children: "Authon" })
785
+ ] })
786
+ ] });
787
+ }
788
+ function SignIn({ appearance, afterSignInUrl, onSignIn, onNavigateSignUp }) {
789
+ const { branding, isLoaded } = useBranding();
790
+ const effectiveBranding = isLoaded ? { ...branding, ...appearance?.variables ?? {} } : branding;
791
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(ThemeProvider, { branding: effectiveBranding, overrides: appearance?.variables, style: { display: "flex", justifyContent: "center" }, children: [
792
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("style", { children: `@keyframes authon-spin { to { transform: rotate(360deg); } }` }),
793
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
794
+ SignInCard,
795
+ {
796
+ afterSignInUrl,
797
+ onSignIn,
798
+ onNavigateSignUp
799
+ }
800
+ )
801
+ ] });
802
+ }
803
+
804
+ // src/components/SignUp.tsx
805
+ var import_react8 = require("react");
806
+ var import_shared4 = require("@authon/shared");
807
+ var import_js3 = require("@authon/js");
808
+ var import_jsx_runtime7 = require("react/jsx-runtime");
809
+ function SignUpCard({ afterSignUpUrl, onSignUp, onNavigateSignIn }) {
810
+ const theme = useTheme();
133
811
  const { client } = useAuthon();
134
- (0, import_react4.useEffect)(() => {
135
- if (mode === "popup") {
136
- client?.openSignUp();
812
+ const { branding, providers, isLoaded } = useBranding();
813
+ const [displayName, setDisplayName] = (0, import_react8.useState)("");
814
+ const [email, setEmail] = (0, import_react8.useState)("");
815
+ const [password, setPassword] = (0, import_react8.useState)("");
816
+ const [confirmPassword, setConfirmPassword] = (0, import_react8.useState)("");
817
+ const [showPassword, setShowPassword] = (0, import_react8.useState)(false);
818
+ const [loading, setLoading] = (0, import_react8.useState)(false);
819
+ const [oauthLoading, setOauthLoading] = (0, import_react8.useState)(null);
820
+ const [error, setError] = (0, import_react8.useState)("");
821
+ const [fieldErrors, setFieldErrors] = (0, import_react8.useState)({});
822
+ const validate = () => {
823
+ const errs = {};
824
+ if (!email.trim()) errs.email = "Email is required";
825
+ else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) errs.email = "Invalid email address";
826
+ if (!password) errs.password = "Password is required";
827
+ else if (password.length < 8) errs.password = "Password must be at least 8 characters";
828
+ if (confirmPassword !== password) errs.confirmPassword = "Passwords do not match";
829
+ setFieldErrors(errs);
830
+ return Object.keys(errs).length === 0;
831
+ };
832
+ const handleSubmit = async () => {
833
+ if (!validate() || !client) return;
834
+ setLoading(true);
835
+ setError("");
836
+ try {
837
+ await client.signUpWithEmail(email, password, displayName ? { displayName } : void 0);
838
+ if (afterSignUpUrl) window.location.assign(afterSignUpUrl);
839
+ onSignUp?.();
840
+ } catch (e) {
841
+ setError(e?.message ?? "Sign up failed");
842
+ } finally {
843
+ setLoading(false);
137
844
  }
138
- }, [client, mode]);
139
- if (mode === "embedded") {
140
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { id: "authon-signup-container" });
845
+ };
846
+ const handleOAuth = async (provider) => {
847
+ if (!client) return;
848
+ setOauthLoading(provider);
849
+ setError("");
850
+ try {
851
+ await client.signInWithOAuth(provider);
852
+ } catch (e) {
853
+ setError(e?.message ?? "OAuth sign in failed");
854
+ } finally {
855
+ setOauthLoading(null);
856
+ }
857
+ };
858
+ const cardStyle = {
859
+ width: "100%",
860
+ maxWidth: 440,
861
+ background: theme.bg,
862
+ borderRadius: `calc(${theme.borderRadius} + 4px)`,
863
+ boxShadow: "0 4px 32px rgba(0,0,0,0.10)",
864
+ padding: "40px 36px 32px",
865
+ boxSizing: "border-box",
866
+ display: "flex",
867
+ flexDirection: "column",
868
+ gap: 20,
869
+ fontFamily: theme.fontFamily
870
+ };
871
+ const logoStyle = {
872
+ display: "flex",
873
+ flexDirection: "column",
874
+ alignItems: "center",
875
+ gap: 10
876
+ };
877
+ const titleStyle = {
878
+ fontSize: 24,
879
+ fontWeight: 700,
880
+ color: theme.text,
881
+ textAlign: "center",
882
+ letterSpacing: "-0.3px"
883
+ };
884
+ const subtitleStyle = {
885
+ fontSize: 14,
886
+ color: theme.textMuted,
887
+ textAlign: "center",
888
+ marginTop: -12
889
+ };
890
+ const errorBoxStyle = {
891
+ padding: "10px 14px",
892
+ borderRadius: theme.borderRadius,
893
+ background: "#fef2f2",
894
+ border: "1px solid #fecaca",
895
+ color: "#dc2626",
896
+ fontSize: 13
897
+ };
898
+ const linkStyle = {
899
+ fontSize: 13,
900
+ color: theme.primaryStart,
901
+ background: "none",
902
+ border: "none",
903
+ cursor: "pointer",
904
+ padding: 0,
905
+ fontFamily: theme.fontFamily,
906
+ textDecoration: "none"
907
+ };
908
+ const footerStyle = {
909
+ textAlign: "center",
910
+ fontSize: 14,
911
+ color: theme.textMuted,
912
+ paddingTop: 4
913
+ };
914
+ const showEmailPw = branding.showEmailPassword !== false;
915
+ const showDivider = branding.showDivider !== false && providers.length > 0 && showEmailPw;
916
+ const providersToShow = providers.filter(
917
+ (p) => !(branding.hiddenProviders ?? []).includes(p)
918
+ );
919
+ if (!isLoaded) {
920
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { ...cardStyle, alignItems: "center", justifyContent: "center", minHeight: 200 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
921
+ "span",
922
+ {
923
+ style: {
924
+ width: 28,
925
+ height: 28,
926
+ border: `3px solid ${theme.primaryStart}33`,
927
+ borderTopColor: theme.primaryStart,
928
+ borderRadius: "50%",
929
+ display: "inline-block",
930
+ animation: "authon-spin 0.7s linear infinite"
931
+ }
932
+ }
933
+ ) });
141
934
  }
142
- return null;
935
+ const eyeIconPath = showPassword ? "M17.94 17.94A10.07 10.07 0 0112 20c-7 0-11-8-11-8a18.45 18.45 0 015.06-5.94M9.9 4.24A9.12 9.12 0 0112 4c7 0 11 8 11 8a18.5 18.5 0 01-2.16 3.19m-6.72-1.07a3 3 0 11-4.24-4.24 M1 1l22 22" : "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z M12 9a3 3 0 100 6 3 3 0 000-6z";
936
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: cardStyle, children: [
937
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: logoStyle, children: [
938
+ branding.logoDataUrl && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("img", { src: branding.logoDataUrl, alt: branding.brandName ?? "Logo", style: { height: 40, objectFit: "contain" } }),
939
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { style: titleStyle, children: "Create account" }),
940
+ branding.brandName && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { style: subtitleStyle, children: [
941
+ "Join ",
942
+ branding.brandName
943
+ ] })
944
+ ] }),
945
+ error && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: errorBoxStyle, children: error }),
946
+ providersToShow.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: providersToShow.length <= 3 ? providersToShow.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
947
+ OAuthButtonFull,
948
+ {
949
+ provider,
950
+ loading: oauthLoading === provider,
951
+ disabled: !!oauthLoading || loading,
952
+ onClick: () => handleOAuth(provider),
953
+ borderRadius: theme.borderRadius
954
+ },
955
+ provider
956
+ )) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 10, justifyContent: "center" }, children: providersToShow.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
957
+ CompactOAuthBtn,
958
+ {
959
+ provider,
960
+ loading: oauthLoading === provider,
961
+ disabled: !!oauthLoading || loading,
962
+ onClick: () => handleOAuth(provider),
963
+ borderRadius: theme.borderRadius
964
+ },
965
+ provider
966
+ )) }) }),
967
+ showDivider && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Divider, {}),
968
+ showEmailPw && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
969
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
970
+ Input,
971
+ {
972
+ label: "Display name",
973
+ type: "text",
974
+ placeholder: "Your name",
975
+ value: displayName,
976
+ onChange: setDisplayName,
977
+ error: fieldErrors.displayName,
978
+ autoComplete: "name"
979
+ }
980
+ ),
981
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
982
+ Input,
983
+ {
984
+ label: "Email",
985
+ type: "email",
986
+ placeholder: "you@example.com",
987
+ value: email,
988
+ onChange: setEmail,
989
+ error: fieldErrors.email,
990
+ autoComplete: "email"
991
+ }
992
+ ),
993
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
994
+ Input,
995
+ {
996
+ label: "Password",
997
+ type: showPassword ? "text" : "password",
998
+ placeholder: "Minimum 8 characters",
999
+ value: password,
1000
+ onChange: setPassword,
1001
+ error: fieldErrors.password,
1002
+ autoComplete: "new-password",
1003
+ rightElement: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1004
+ "button",
1005
+ {
1006
+ type: "button",
1007
+ onClick: () => setShowPassword((v) => !v),
1008
+ style: { background: "none", border: "none", cursor: "pointer", padding: 0, display: "flex", color: theme.textMuted },
1009
+ "aria-label": showPassword ? "Hide password" : "Show password",
1010
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: eyeIconPath }) })
1011
+ }
1012
+ )
1013
+ }
1014
+ ),
1015
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1016
+ Input,
1017
+ {
1018
+ label: "Confirm password",
1019
+ type: showPassword ? "text" : "password",
1020
+ placeholder: "Repeat password",
1021
+ value: confirmPassword,
1022
+ onChange: setConfirmPassword,
1023
+ error: fieldErrors.confirmPassword,
1024
+ autoComplete: "new-password"
1025
+ }
1026
+ ),
1027
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1028
+ Button,
1029
+ {
1030
+ variant: "primary",
1031
+ fullWidth: true,
1032
+ loading,
1033
+ disabled: !!oauthLoading,
1034
+ onClick: handleSubmit,
1035
+ children: "Create account"
1036
+ }
1037
+ )
1038
+ ] }),
1039
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: footerStyle, children: [
1040
+ "Already have an account?",
1041
+ " ",
1042
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", style: linkStyle, onClick: onNavigateSignIn, children: "Sign in" })
1043
+ ] }),
1044
+ branding.showSecuredBy !== false && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SecuredByAuthon2, { primaryStart: theme.primaryStart, textMuted: theme.textMuted }),
1045
+ branding.termsUrl || branding.privacyUrl ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { textAlign: "center", fontSize: 11, color: theme.textMuted, marginTop: -8 }, children: [
1046
+ "By creating an account you agree to our",
1047
+ " ",
1048
+ branding.termsUrl && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("a", { href: branding.termsUrl, target: "_blank", rel: "noopener noreferrer", style: { color: theme.primaryStart }, children: "Terms" }),
1049
+ branding.termsUrl && branding.privacyUrl && " and ",
1050
+ branding.privacyUrl && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("a", { href: branding.privacyUrl, target: "_blank", rel: "noopener noreferrer", style: { color: theme.primaryStart }, children: "Privacy Policy" })
1051
+ ] }) : null
1052
+ ] });
1053
+ }
1054
+ function OAuthButtonFull({ provider, loading, disabled, onClick, borderRadius }) {
1055
+ const [hovered, setHovered] = (0, import_react8.useState)(false);
1056
+ const colors = import_shared4.PROVIDER_COLORS[provider] ?? { bg: "#333", text: "#fff" };
1057
+ const name = import_shared4.PROVIDER_DISPLAY_NAMES[provider] ?? provider;
1058
+ const config = (0, import_js3.getProviderButtonConfig)(provider);
1059
+ const needsBorder = colors.bg.toLowerCase() === "#ffffff";
1060
+ const style = {
1061
+ display: "flex",
1062
+ alignItems: "center",
1063
+ gap: 10,
1064
+ width: "100%",
1065
+ height: 44,
1066
+ paddingLeft: 16,
1067
+ paddingRight: 16,
1068
+ borderRadius,
1069
+ background: colors.bg,
1070
+ color: colors.text,
1071
+ border: needsBorder ? "1.5px solid #dadce0" : "none",
1072
+ cursor: disabled ? "not-allowed" : "pointer",
1073
+ fontSize: 15,
1074
+ fontWeight: 600,
1075
+ fontFamily: "system-ui, -apple-system, sans-serif",
1076
+ justifyContent: "center",
1077
+ opacity: disabled ? 0.6 : hovered ? 0.88 : 1,
1078
+ transition: "opacity 0.15s",
1079
+ boxSizing: "border-box"
1080
+ };
1081
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1082
+ "button",
1083
+ {
1084
+ type: "button",
1085
+ style,
1086
+ onClick,
1087
+ disabled,
1088
+ onMouseEnter: () => setHovered(true),
1089
+ onMouseLeave: () => setHovered(false),
1090
+ "aria-label": `Continue with ${name}`,
1091
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { width: 18, height: 18, border: `2px solid ${colors.text}`, borderTopColor: "transparent", borderRadius: "50%", display: "inline-block", animation: "authon-spin 0.6s linear infinite" } }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
1092
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { display: "flex", alignItems: "center" }, dangerouslySetInnerHTML: { __html: config.iconSvg } }),
1093
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
1094
+ "Continue with ",
1095
+ name
1096
+ ] })
1097
+ ] })
1098
+ }
1099
+ );
1100
+ }
1101
+ function CompactOAuthBtn({ provider, loading, disabled, onClick, borderRadius }) {
1102
+ const [hovered, setHovered] = (0, import_react8.useState)(false);
1103
+ const colors = import_shared4.PROVIDER_COLORS[provider] ?? { bg: "#333", text: "#fff" };
1104
+ const name = import_shared4.PROVIDER_DISPLAY_NAMES[provider] ?? provider;
1105
+ const config = (0, import_js3.getProviderButtonConfig)(provider);
1106
+ const needsBorder = colors.bg.toLowerCase() === "#ffffff";
1107
+ const style = {
1108
+ display: "flex",
1109
+ alignItems: "center",
1110
+ justifyContent: "center",
1111
+ width: 48,
1112
+ height: 48,
1113
+ borderRadius,
1114
+ background: colors.bg,
1115
+ border: needsBorder ? "1.5px solid #dadce0" : "none",
1116
+ cursor: disabled ? "not-allowed" : "pointer",
1117
+ opacity: disabled ? 0.6 : hovered ? 0.85 : 1,
1118
+ transition: "opacity 0.15s",
1119
+ padding: 0
1120
+ };
1121
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1122
+ "button",
1123
+ {
1124
+ type: "button",
1125
+ style,
1126
+ onClick,
1127
+ disabled,
1128
+ onMouseEnter: () => setHovered(true),
1129
+ onMouseLeave: () => setHovered(false),
1130
+ "aria-label": `Continue with ${name}`,
1131
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { width: 18, height: 18, border: `2px solid ${colors.text}`, borderTopColor: "transparent", borderRadius: "50%", display: "inline-block", animation: "authon-spin 0.6s linear infinite" } }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { display: "flex" }, dangerouslySetInnerHTML: { __html: config.iconSvg } })
1132
+ }
1133
+ );
1134
+ }
1135
+ function SecuredByAuthon2({ primaryStart, textMuted }) {
1136
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: 5, marginTop: -8 }, children: [
1137
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("svg", { width: "12", height: "14", viewBox: "0 0 12 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
1138
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M6 0L0.5 2.5V6.5C0.5 9.7 2.9 12.7 6 13.5C9.1 12.7 11.5 9.7 11.5 6.5V2.5L6 0Z", fill: primaryStart, opacity: "0.85" }),
1139
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M4 7L5.5 8.5L8.5 5.5", stroke: "white", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" })
1140
+ ] }),
1141
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { style: { fontSize: 11, color: textMuted }, children: [
1142
+ "Secured by",
1143
+ " ",
1144
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("a", { href: "https://authon.dev", target: "_blank", rel: "noopener noreferrer", style: { color: primaryStart, textDecoration: "none", fontWeight: 600 }, children: "Authon" })
1145
+ ] })
1146
+ ] });
1147
+ }
1148
+ function SignUp({ appearance, afterSignUpUrl, onSignUp, onNavigateSignIn }) {
1149
+ const { branding, isLoaded } = useBranding();
1150
+ const effectiveBranding = isLoaded ? { ...branding, ...appearance?.variables ?? {} } : branding;
1151
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(ThemeProvider, { branding: effectiveBranding, overrides: appearance?.variables, style: { display: "flex", justifyContent: "center" }, children: [
1152
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `@keyframes authon-spin { to { transform: rotate(360deg); } }` }),
1153
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1154
+ SignUpCard,
1155
+ {
1156
+ afterSignUpUrl,
1157
+ onSignUp,
1158
+ onNavigateSignIn
1159
+ }
1160
+ )
1161
+ ] });
143
1162
  }
144
1163
 
145
- // src/UserButton.tsx
146
- var import_react5 = require("react");
147
- var import_jsx_runtime4 = require("react/jsx-runtime");
148
- function UserButton() {
149
- const { user, signOut, openSignIn, isSignedIn } = useAuthon();
150
- const [open, setOpen] = (0, import_react5.useState)(false);
151
- const dropdownRef = (0, import_react5.useRef)(null);
152
- const handleClickOutside = (0, import_react5.useCallback)((e) => {
1164
+ // src/components/UserButton.tsx
1165
+ var import_react9 = require("react");
1166
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1167
+ function UserAvatar({
1168
+ avatarUrl,
1169
+ displayName,
1170
+ email,
1171
+ size,
1172
+ primaryStart,
1173
+ primaryEnd
1174
+ }) {
1175
+ const initials = displayName ? displayName.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2) : (email?.[0] ?? "?").toUpperCase();
1176
+ const avatarStyle = {
1177
+ width: size,
1178
+ height: size,
1179
+ borderRadius: "50%",
1180
+ overflow: "hidden",
1181
+ display: "flex",
1182
+ alignItems: "center",
1183
+ justifyContent: "center",
1184
+ background: avatarUrl ? "transparent" : `linear-gradient(135deg, ${primaryStart}, ${primaryEnd})`,
1185
+ color: "#fff",
1186
+ fontSize: size * 0.38,
1187
+ fontWeight: 700,
1188
+ userSelect: "none"
1189
+ };
1190
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: avatarStyle, children: avatarUrl ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("img", { src: avatarUrl, alt: displayName ?? "avatar", style: { width: "100%", height: "100%", objectFit: "cover" } }) : initials });
1191
+ }
1192
+ function UserButtonInner({ afterSignOutUrl, userProfileUrl }) {
1193
+ const theme = useTheme();
1194
+ const { user, signOut, openSignIn, isSignedIn, activeOrganization, client } = useAuthon();
1195
+ const [open, setOpen] = (0, import_react9.useState)(false);
1196
+ const dropdownRef = (0, import_react9.useRef)(null);
1197
+ const handleClickOutside = (0, import_react9.useCallback)((e) => {
153
1198
  if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
154
1199
  setOpen(false);
155
1200
  }
156
1201
  }, []);
157
- (0, import_react5.useEffect)(() => {
158
- if (open) {
159
- document.addEventListener("mousedown", handleClickOutside);
160
- }
1202
+ (0, import_react9.useEffect)(() => {
1203
+ if (open) document.addEventListener("mousedown", handleClickOutside);
161
1204
  return () => document.removeEventListener("mousedown", handleClickOutside);
162
1205
  }, [open, handleClickOutside]);
163
1206
  if (!isSignedIn) {
164
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1207
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
165
1208
  "button",
166
1209
  {
1210
+ type: "button",
167
1211
  onClick: () => openSignIn(),
168
1212
  style: {
169
- padding: "8px 16px",
170
- borderRadius: "8px",
1213
+ padding: "8px 18px",
1214
+ borderRadius: theme.borderRadius,
171
1215
  border: "none",
172
- background: "linear-gradient(135deg, #7c3aed, #4f46e5)",
1216
+ background: `linear-gradient(135deg, ${theme.primaryStart}, ${theme.primaryEnd})`,
173
1217
  color: "#fff",
174
1218
  cursor: "pointer",
175
- fontSize: "14px",
176
- fontWeight: 600
1219
+ fontSize: 14,
1220
+ fontWeight: 600,
1221
+ fontFamily: theme.fontFamily
177
1222
  },
178
1223
  children: "Sign In"
179
1224
  }
180
1225
  );
181
1226
  }
182
- const initials = user?.displayName ? user.displayName.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2) : (user?.email?.[0] ?? "?").toUpperCase();
183
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { ref: dropdownRef, style: { position: "relative", display: "inline-block" }, children: [
184
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
185
- "button",
1227
+ const triggerStyle = {
1228
+ width: 38,
1229
+ height: 38,
1230
+ borderRadius: "50%",
1231
+ border: `2px solid ${theme.primaryStart}`,
1232
+ background: "none",
1233
+ cursor: "pointer",
1234
+ padding: 1,
1235
+ overflow: "hidden",
1236
+ display: "flex",
1237
+ alignItems: "center",
1238
+ justifyContent: "center"
1239
+ };
1240
+ const dropdownStyle = {
1241
+ position: "absolute",
1242
+ right: 0,
1243
+ top: 46,
1244
+ minWidth: 240,
1245
+ background: theme.bg,
1246
+ border: `1px solid ${theme.border}`,
1247
+ borderRadius: theme.borderRadius,
1248
+ boxShadow: "0 8px 32px rgba(0,0,0,0.13)",
1249
+ zIndex: 9999,
1250
+ overflow: "hidden",
1251
+ fontFamily: theme.fontFamily
1252
+ };
1253
+ const headerStyle = {
1254
+ padding: "14px 16px",
1255
+ borderBottom: `1px solid ${theme.border}`,
1256
+ display: "flex",
1257
+ alignItems: "center",
1258
+ gap: 12
1259
+ };
1260
+ const menuItemStyle = (danger) => ({
1261
+ display: "flex",
1262
+ alignItems: "center",
1263
+ gap: 10,
1264
+ width: "100%",
1265
+ padding: "10px 16px",
1266
+ textAlign: "left",
1267
+ background: "none",
1268
+ border: "none",
1269
+ cursor: "pointer",
1270
+ fontSize: 14,
1271
+ color: danger ? "#ef4444" : theme.text,
1272
+ fontWeight: 500,
1273
+ fontFamily: theme.fontFamily,
1274
+ boxSizing: "border-box"
1275
+ });
1276
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { ref: dropdownRef, style: { position: "relative", display: "inline-block" }, children: [
1277
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", style: triggerStyle, onClick: () => setOpen((v) => !v), "aria-label": "User menu", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1278
+ UserAvatar,
186
1279
  {
187
- onClick: () => setOpen((v) => !v),
188
- style: {
189
- width: "36px",
190
- height: "36px",
191
- borderRadius: "50%",
192
- border: "2px solid #7c3aed",
193
- background: user?.avatarUrl ? "transparent" : "linear-gradient(135deg, #7c3aed, #4f46e5)",
194
- cursor: "pointer",
195
- padding: 0,
196
- overflow: "hidden",
197
- display: "flex",
198
- alignItems: "center",
199
- justifyContent: "center",
200
- color: "#fff",
201
- fontSize: "13px",
202
- fontWeight: 700
203
- },
204
- children: user?.avatarUrl ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
205
- "img",
1280
+ avatarUrl: user?.avatarUrl,
1281
+ displayName: user?.displayName,
1282
+ email: user?.email,
1283
+ size: 32,
1284
+ primaryStart: theme.primaryStart,
1285
+ primaryEnd: theme.primaryEnd
1286
+ }
1287
+ ) }),
1288
+ open && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: dropdownStyle, children: [
1289
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: headerStyle, children: [
1290
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1291
+ UserAvatar,
206
1292
  {
207
- src: user.avatarUrl,
208
- alt: user.displayName ?? "avatar",
209
- style: { width: "100%", height: "100%", objectFit: "cover" }
1293
+ avatarUrl: user?.avatarUrl,
1294
+ displayName: user?.displayName,
1295
+ email: user?.email,
1296
+ size: 40,
1297
+ primaryStart: theme.primaryStart,
1298
+ primaryEnd: theme.primaryEnd
210
1299
  }
211
- ) : initials
212
- }
213
- ),
214
- open && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
215
- "div",
216
- {
217
- style: {
218
- position: "absolute",
219
- right: 0,
220
- top: "44px",
221
- minWidth: "200px",
222
- background: "#fff",
223
- border: "1px solid #e5e7eb",
224
- borderRadius: "12px",
225
- boxShadow: "0 8px 24px rgba(0,0,0,0.12)",
226
- zIndex: 9999,
227
- overflow: "hidden"
228
- },
229
- children: [
230
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
231
- "div",
232
- {
233
- style: {
234
- padding: "12px 16px",
235
- borderBottom: "1px solid #f3f4f6"
236
- },
237
- children: [
238
- user?.displayName && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "14px", fontWeight: 600, color: "#111827" }, children: user.displayName }),
239
- user?.email && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { fontSize: "12px", color: "#6b7280", marginTop: "2px" }, children: user.email })
240
- ]
241
- }
242
- ),
243
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
244
- "button",
245
- {
246
- onClick: async () => {
247
- setOpen(false);
248
- await signOut();
249
- },
250
- style: {
251
- display: "block",
252
- width: "100%",
253
- padding: "10px 16px",
254
- textAlign: "left",
255
- background: "none",
256
- border: "none",
257
- cursor: "pointer",
258
- fontSize: "14px",
259
- color: "#ef4444",
260
- fontWeight: 500
261
- },
262
- onMouseEnter: (e) => {
263
- e.currentTarget.style.background = "#fef2f2";
264
- },
265
- onMouseLeave: (e) => {
266
- e.currentTarget.style.background = "none";
267
- },
268
- children: "Sign out"
269
- }
270
- )
271
- ]
272
- }
273
- )
1300
+ ),
1301
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
1302
+ user?.displayName && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: 14, fontWeight: 600, color: theme.text, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: user.displayName }),
1303
+ user?.email && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: 12, color: theme.textMuted, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", marginTop: 1 }, children: user.email })
1304
+ ] })
1305
+ ] }),
1306
+ activeOrganization && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1307
+ OrgSwitcherRow,
1308
+ {
1309
+ org: activeOrganization,
1310
+ primaryStart: theme.primaryStart,
1311
+ theme,
1312
+ client
1313
+ }
1314
+ ),
1315
+ userProfileUrl && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1316
+ MenuButton,
1317
+ {
1318
+ style: menuItemStyle(),
1319
+ onClick: () => {
1320
+ setOpen(false);
1321
+ window.location.assign(userProfileUrl);
1322
+ },
1323
+ icon: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1324
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2" }),
1325
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("circle", { cx: "12", cy: "7", r: "4" })
1326
+ ] }),
1327
+ children: "Manage account"
1328
+ }
1329
+ ),
1330
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { borderTop: `1px solid ${theme.border}` }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1331
+ MenuButton,
1332
+ {
1333
+ style: menuItemStyle(true),
1334
+ onClick: async () => {
1335
+ setOpen(false);
1336
+ await signOut();
1337
+ if (afterSignOutUrl) window.location.assign(afterSignOutUrl);
1338
+ },
1339
+ icon: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1340
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("path", { d: "M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4" }),
1341
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("polyline", { points: "16 17 21 12 16 7" }),
1342
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("line", { x1: "21", y1: "12", x2: "9", y2: "12" })
1343
+ ] }),
1344
+ children: "Sign out"
1345
+ }
1346
+ ) })
1347
+ ] })
274
1348
  ] });
275
1349
  }
1350
+ function MenuButton({
1351
+ style: baseStyle2,
1352
+ onClick,
1353
+ icon,
1354
+ children
1355
+ }) {
1356
+ const [hovered, setHovered] = (0, import_react9.useState)(false);
1357
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1358
+ "button",
1359
+ {
1360
+ type: "button",
1361
+ style: {
1362
+ ...baseStyle2,
1363
+ background: hovered ? baseStyle2.color === "#ef4444" ? "#fef2f2" : "#f9fafb" : "none"
1364
+ },
1365
+ onClick,
1366
+ onMouseEnter: () => setHovered(true),
1367
+ onMouseLeave: () => setHovered(false),
1368
+ children: [
1369
+ icon,
1370
+ children
1371
+ ]
1372
+ }
1373
+ );
1374
+ }
1375
+ function OrgSwitcherRow({
1376
+ org,
1377
+ primaryStart,
1378
+ theme,
1379
+ client
1380
+ }) {
1381
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1382
+ "div",
1383
+ {
1384
+ style: {
1385
+ padding: "8px 16px",
1386
+ borderBottom: `1px solid ${theme.border}`,
1387
+ display: "flex",
1388
+ alignItems: "center",
1389
+ gap: 10
1390
+ },
1391
+ children: [
1392
+ org.logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("img", { src: org.logoUrl, alt: org.name, style: { width: 24, height: 24, borderRadius: 6, objectFit: "cover" } }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1393
+ "div",
1394
+ {
1395
+ style: {
1396
+ width: 24,
1397
+ height: 24,
1398
+ borderRadius: 6,
1399
+ background: `${primaryStart}22`,
1400
+ color: primaryStart,
1401
+ display: "flex",
1402
+ alignItems: "center",
1403
+ justifyContent: "center",
1404
+ fontSize: 11,
1405
+ fontWeight: 700
1406
+ },
1407
+ children: org.name[0]?.toUpperCase()
1408
+ }
1409
+ ),
1410
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
1411
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: 12, color: theme.textMuted }, children: "Organization" }),
1412
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { style: { fontSize: 13, fontWeight: 600, color: theme.text, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: org.name })
1413
+ ] })
1414
+ ]
1415
+ }
1416
+ );
1417
+ }
1418
+ function UserButton({ appearance, afterSignOutUrl, userProfileUrl }) {
1419
+ const { branding } = useBranding();
1420
+ const effectiveBranding = { ...branding, ...appearance?.variables ?? {} };
1421
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ThemeProvider, { branding: effectiveBranding, style: { display: "inline-block" }, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(UserButtonInner, { afterSignOutUrl, userProfileUrl }) });
1422
+ }
276
1423
 
277
1424
  // src/SignedIn.tsx
278
- var import_jsx_runtime5 = require("react/jsx-runtime");
1425
+ var import_jsx_runtime9 = require("react/jsx-runtime");
279
1426
  function SignedIn({ children }) {
280
1427
  const { isSignedIn, isLoading } = useAuthon();
281
1428
  if (isLoading || !isSignedIn) return null;
282
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, { children });
1429
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children });
283
1430
  }
284
1431
 
285
1432
  // src/SignedOut.tsx
286
- var import_jsx_runtime6 = require("react/jsx-runtime");
1433
+ var import_jsx_runtime10 = require("react/jsx-runtime");
287
1434
  function SignedOut({ children }) {
288
1435
  const { isSignedIn, isLoading } = useAuthon();
289
1436
  if (isLoading || isSignedIn) return null;
290
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children });
1437
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_jsx_runtime10.Fragment, { children });
291
1438
  }
292
1439
 
293
1440
  // src/Protect.tsx
294
- var import_jsx_runtime7 = require("react/jsx-runtime");
1441
+ var import_jsx_runtime11 = require("react/jsx-runtime");
295
1442
  function Protect({ children, fallback = null, condition }) {
296
1443
  const { isSignedIn, isLoading, user } = useAuthon();
297
1444
  if (isLoading) return null;
298
- if (!isSignedIn || !user) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: fallback });
299
- if (condition && !condition(user)) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: fallback });
300
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children });
1445
+ if (!isSignedIn || !user) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: fallback });
1446
+ if (condition && !condition(user)) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: fallback });
1447
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children });
1448
+ }
1449
+
1450
+ // src/SocialButton.tsx
1451
+ var import_shared5 = require("@authon/shared");
1452
+ var import_js4 = require("@authon/js");
1453
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1454
+ var baseStyle = {
1455
+ display: "flex",
1456
+ alignItems: "center",
1457
+ justifyContent: "center",
1458
+ gap: 10,
1459
+ paddingLeft: 16,
1460
+ paddingRight: 16,
1461
+ border: "none",
1462
+ cursor: "pointer",
1463
+ fontFamily: "inherit",
1464
+ transition: "opacity 0.15s",
1465
+ width: "100%"
1466
+ };
1467
+ var compactBaseStyle = {
1468
+ display: "flex",
1469
+ alignItems: "center",
1470
+ justifyContent: "center",
1471
+ border: "none",
1472
+ cursor: "pointer",
1473
+ transition: "opacity 0.15s",
1474
+ padding: 0
1475
+ };
1476
+ function SocialButton({
1477
+ provider,
1478
+ onClick,
1479
+ loading = false,
1480
+ disabled = false,
1481
+ label,
1482
+ compact = false,
1483
+ className,
1484
+ style: userStyle,
1485
+ iconSize,
1486
+ borderRadius = 10,
1487
+ height = 48,
1488
+ size = 48
1489
+ }) {
1490
+ const colors = import_shared5.PROVIDER_COLORS[provider] || { bg: "#333", text: "#fff" };
1491
+ const displayName = import_shared5.PROVIDER_DISPLAY_NAMES[provider] || provider;
1492
+ const buttonLabel = label ?? `Continue with ${displayName}`;
1493
+ const needsBorder = colors.bg.toLowerCase() === "#ffffff";
1494
+ const resolvedIconSize = iconSize ?? (compact ? 24 : 20);
1495
+ const config = (0, import_js4.getProviderButtonConfig)(provider);
1496
+ const iconSvg = config.iconSvg.replace(/width="\d+"/, `width="${resolvedIconSize}"`).replace(/height="\d+"/, `height="${resolvedIconSize}"`);
1497
+ const borderProps = needsBorder ? { border: "1px solid #dadce0" } : {};
1498
+ if (compact) {
1499
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1500
+ "button",
1501
+ {
1502
+ className,
1503
+ style: {
1504
+ ...compactBaseStyle,
1505
+ backgroundColor: colors.bg,
1506
+ borderRadius,
1507
+ width: size,
1508
+ height: size,
1509
+ ...borderProps,
1510
+ ...userStyle
1511
+ },
1512
+ onClick: () => onClick(provider),
1513
+ disabled: disabled || loading,
1514
+ "aria-label": `Sign in with ${displayName}`,
1515
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1516
+ "span",
1517
+ {
1518
+ style: {
1519
+ display: "inline-block",
1520
+ width: 16,
1521
+ height: 16,
1522
+ border: `2px solid ${colors.text}`,
1523
+ borderTopColor: "transparent",
1524
+ borderRadius: "50%",
1525
+ animation: "authon-spin 0.6s linear infinite"
1526
+ }
1527
+ }
1528
+ ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1529
+ "span",
1530
+ {
1531
+ style: { display: "flex", alignItems: "center", flexShrink: 0 },
1532
+ dangerouslySetInnerHTML: { __html: iconSvg }
1533
+ }
1534
+ )
1535
+ }
1536
+ );
1537
+ }
1538
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1539
+ "button",
1540
+ {
1541
+ className,
1542
+ style: {
1543
+ ...baseStyle,
1544
+ backgroundColor: colors.bg,
1545
+ color: colors.text,
1546
+ borderRadius,
1547
+ height,
1548
+ ...borderProps,
1549
+ ...userStyle
1550
+ },
1551
+ onClick: () => onClick(provider),
1552
+ disabled: disabled || loading,
1553
+ "aria-label": `Sign in with ${displayName}`,
1554
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1555
+ "span",
1556
+ {
1557
+ style: {
1558
+ display: "inline-block",
1559
+ width: 16,
1560
+ height: 16,
1561
+ border: `2px solid ${colors.text}`,
1562
+ borderTopColor: "transparent",
1563
+ borderRadius: "50%",
1564
+ animation: "authon-spin 0.6s linear infinite"
1565
+ }
1566
+ }
1567
+ ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
1568
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1569
+ "span",
1570
+ {
1571
+ style: { display: "flex", alignItems: "center", flexShrink: 0 },
1572
+ dangerouslySetInnerHTML: { __html: iconSvg }
1573
+ }
1574
+ ),
1575
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { style: { fontSize: 15, fontWeight: 600, whiteSpace: "nowrap" }, children: buttonLabel })
1576
+ ] })
1577
+ }
1578
+ );
1579
+ }
1580
+
1581
+ // src/SocialButtons.tsx
1582
+ var import_react10 = require("react");
1583
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1584
+ function SocialButtons({
1585
+ onSuccess,
1586
+ onError,
1587
+ className,
1588
+ style: userStyle,
1589
+ gap,
1590
+ compact = false,
1591
+ labels,
1592
+ buttonProps
1593
+ }) {
1594
+ const { client } = useAuthon();
1595
+ const [providers, setProviders] = (0, import_react10.useState)([]);
1596
+ const [loadingProvider, setLoadingProvider] = (0, import_react10.useState)(null);
1597
+ (0, import_react10.useEffect)(() => {
1598
+ if (!client) return;
1599
+ client.getProviders().then((p) => setProviders(p));
1600
+ }, [client]);
1601
+ if (providers.length === 0) return null;
1602
+ const resolvedGap = gap ?? (compact ? 12 : 10);
1603
+ const handleClick = async (provider) => {
1604
+ if (!client) return;
1605
+ setLoadingProvider(provider);
1606
+ try {
1607
+ await client.signInWithOAuth(provider);
1608
+ onSuccess?.();
1609
+ } catch (e) {
1610
+ const error = e instanceof Error ? e : new Error(String(e));
1611
+ onError?.(error);
1612
+ } finally {
1613
+ setLoadingProvider(null);
1614
+ }
1615
+ };
1616
+ const containerStyle = compact ? { display: "flex", flexDirection: "row", flexWrap: "wrap", justifyContent: "center", gap: resolvedGap, ...userStyle } : { display: "flex", flexDirection: "column", gap: resolvedGap, ...userStyle };
1617
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className, style: containerStyle, children: providers.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1618
+ SocialButton,
1619
+ {
1620
+ provider,
1621
+ onClick: handleClick,
1622
+ loading: loadingProvider === provider,
1623
+ disabled: !!loadingProvider,
1624
+ compact,
1625
+ label: labels?.[provider],
1626
+ ...buttonProps
1627
+ },
1628
+ provider
1629
+ )) });
1630
+ }
1631
+
1632
+ // src/useAuthonMfa.ts
1633
+ var import_react11 = require("react");
1634
+ function useAuthonMfa() {
1635
+ const ctx = (0, import_react11.useContext)(AuthonContext);
1636
+ if (!ctx) throw new Error("useAuthonMfa must be used within <AuthonProvider>");
1637
+ const [isLoading, setIsLoading] = (0, import_react11.useState)(false);
1638
+ const [error, setError] = (0, import_react11.useState)(null);
1639
+ const wrap = (0, import_react11.useCallback)(
1640
+ async (fn) => {
1641
+ setIsLoading(true);
1642
+ setError(null);
1643
+ try {
1644
+ const result = await fn();
1645
+ return result;
1646
+ } catch (err) {
1647
+ setError(err instanceof Error ? err : new Error(String(err)));
1648
+ return null;
1649
+ } finally {
1650
+ setIsLoading(false);
1651
+ }
1652
+ },
1653
+ []
1654
+ );
1655
+ const setupMfa = (0, import_react11.useCallback)(async () => {
1656
+ return wrap(() => ctx.client.setupMfa());
1657
+ }, [ctx.client, wrap]);
1658
+ const verifyMfaSetup = (0, import_react11.useCallback)(
1659
+ async (code) => {
1660
+ const result = await wrap(() => ctx.client.verifyMfaSetup(code));
1661
+ return result !== null;
1662
+ },
1663
+ [ctx.client, wrap]
1664
+ );
1665
+ const verifyMfa = (0, import_react11.useCallback)(
1666
+ async (mfaToken, code) => {
1667
+ const result = await wrap(() => ctx.client.verifyMfa(mfaToken, code));
1668
+ return result !== null;
1669
+ },
1670
+ [ctx.client, wrap]
1671
+ );
1672
+ const disableMfa = (0, import_react11.useCallback)(
1673
+ async (code) => {
1674
+ const result = await wrap(() => ctx.client.disableMfa(code));
1675
+ return result !== null;
1676
+ },
1677
+ [ctx.client, wrap]
1678
+ );
1679
+ const getMfaStatus = (0, import_react11.useCallback)(async () => {
1680
+ return wrap(() => ctx.client.getMfaStatus());
1681
+ }, [ctx.client, wrap]);
1682
+ const regenerateBackupCodes = (0, import_react11.useCallback)(
1683
+ async (code) => {
1684
+ return wrap(() => ctx.client.regenerateBackupCodes(code));
1685
+ },
1686
+ [ctx.client, wrap]
1687
+ );
1688
+ return {
1689
+ setupMfa,
1690
+ verifyMfaSetup,
1691
+ verifyMfa,
1692
+ disableMfa,
1693
+ getMfaStatus,
1694
+ regenerateBackupCodes,
1695
+ isLoading,
1696
+ error
1697
+ };
1698
+ }
1699
+
1700
+ // src/useAuthonPasskeys.ts
1701
+ var import_react12 = require("react");
1702
+ function useAuthonPasskeys() {
1703
+ const ctx = (0, import_react12.useContext)(AuthonContext);
1704
+ if (!ctx) throw new Error("useAuthonPasskeys must be used within <AuthonProvider>");
1705
+ const [isLoading, setIsLoading] = (0, import_react12.useState)(false);
1706
+ const [error, setError] = (0, import_react12.useState)(null);
1707
+ const wrap = (0, import_react12.useCallback)(
1708
+ async (fn) => {
1709
+ setIsLoading(true);
1710
+ setError(null);
1711
+ try {
1712
+ return await fn();
1713
+ } catch (err) {
1714
+ setError(err instanceof Error ? err : new Error(String(err)));
1715
+ return null;
1716
+ } finally {
1717
+ setIsLoading(false);
1718
+ }
1719
+ },
1720
+ []
1721
+ );
1722
+ const registerPasskey = (0, import_react12.useCallback)(
1723
+ (name) => wrap(() => ctx.client.registerPasskey(name)),
1724
+ [ctx.client, wrap]
1725
+ );
1726
+ const authenticateWithPasskey = (0, import_react12.useCallback)(
1727
+ async (email) => {
1728
+ const result = await wrap(() => ctx.client.authenticateWithPasskey(email));
1729
+ return result !== null;
1730
+ },
1731
+ [ctx.client, wrap]
1732
+ );
1733
+ const listPasskeys = (0, import_react12.useCallback)(
1734
+ () => wrap(() => ctx.client.listPasskeys()),
1735
+ [ctx.client, wrap]
1736
+ );
1737
+ const renamePasskey = (0, import_react12.useCallback)(
1738
+ (id, name) => wrap(() => ctx.client.renamePasskey(id, name)),
1739
+ [ctx.client, wrap]
1740
+ );
1741
+ const revokePasskey = (0, import_react12.useCallback)(
1742
+ async (id) => {
1743
+ const result = await wrap(() => ctx.client.revokePasskey(id));
1744
+ return result !== null;
1745
+ },
1746
+ [ctx.client, wrap]
1747
+ );
1748
+ return {
1749
+ registerPasskey,
1750
+ authenticateWithPasskey,
1751
+ listPasskeys,
1752
+ renamePasskey,
1753
+ revokePasskey,
1754
+ isLoading,
1755
+ error
1756
+ };
1757
+ }
1758
+
1759
+ // src/useAuthonPasswordless.ts
1760
+ var import_react13 = require("react");
1761
+ function useAuthonPasswordless() {
1762
+ const ctx = (0, import_react13.useContext)(AuthonContext);
1763
+ if (!ctx) throw new Error("useAuthonPasswordless must be used within <AuthonProvider>");
1764
+ const [isLoading, setIsLoading] = (0, import_react13.useState)(false);
1765
+ const [error, setError] = (0, import_react13.useState)(null);
1766
+ const wrap = (0, import_react13.useCallback)(
1767
+ async (fn) => {
1768
+ setIsLoading(true);
1769
+ setError(null);
1770
+ try {
1771
+ return await fn();
1772
+ } catch (err) {
1773
+ setError(err instanceof Error ? err : new Error(String(err)));
1774
+ return null;
1775
+ } finally {
1776
+ setIsLoading(false);
1777
+ }
1778
+ },
1779
+ []
1780
+ );
1781
+ const sendMagicLink = (0, import_react13.useCallback)(
1782
+ async (email) => {
1783
+ const result = await wrap(() => ctx.client.sendMagicLink(email));
1784
+ return result !== null;
1785
+ },
1786
+ [ctx.client, wrap]
1787
+ );
1788
+ const sendEmailOtp = (0, import_react13.useCallback)(
1789
+ async (email) => {
1790
+ const result = await wrap(() => ctx.client.sendEmailOtp(email));
1791
+ return result !== null;
1792
+ },
1793
+ [ctx.client, wrap]
1794
+ );
1795
+ const verifyPasswordless = (0, import_react13.useCallback)(
1796
+ async (opts) => {
1797
+ const result = await wrap(() => ctx.client.verifyPasswordless(opts));
1798
+ return result !== null;
1799
+ },
1800
+ [ctx.client, wrap]
1801
+ );
1802
+ return {
1803
+ sendMagicLink,
1804
+ sendEmailOtp,
1805
+ verifyPasswordless,
1806
+ isLoading,
1807
+ error
1808
+ };
1809
+ }
1810
+
1811
+ // src/useAuthonWeb3.ts
1812
+ var import_react14 = require("react");
1813
+ function useAuthonWeb3() {
1814
+ const ctx = (0, import_react14.useContext)(AuthonContext);
1815
+ if (!ctx) throw new Error("useAuthonWeb3 must be used within <AuthonProvider>");
1816
+ const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
1817
+ const [error, setError] = (0, import_react14.useState)(null);
1818
+ const wrap = (0, import_react14.useCallback)(
1819
+ async (fn) => {
1820
+ setIsLoading(true);
1821
+ setError(null);
1822
+ try {
1823
+ return await fn();
1824
+ } catch (err) {
1825
+ setError(err instanceof Error ? err : new Error(String(err)));
1826
+ return null;
1827
+ } finally {
1828
+ setIsLoading(false);
1829
+ }
1830
+ },
1831
+ []
1832
+ );
1833
+ const getNonce = (0, import_react14.useCallback)(
1834
+ (address, chain, walletType, chainId) => wrap(() => ctx.client.web3GetNonce(address, chain, walletType, chainId)),
1835
+ [ctx.client, wrap]
1836
+ );
1837
+ const verify = (0, import_react14.useCallback)(
1838
+ async (message, signature, address, chain, walletType) => {
1839
+ const result = await wrap(
1840
+ () => ctx.client.web3Verify(message, signature, address, chain, walletType)
1841
+ );
1842
+ return result !== null;
1843
+ },
1844
+ [ctx.client, wrap]
1845
+ );
1846
+ const listWallets = (0, import_react14.useCallback)(
1847
+ () => wrap(() => ctx.client.listWallets()),
1848
+ [ctx.client, wrap]
1849
+ );
1850
+ const linkWallet = (0, import_react14.useCallback)(
1851
+ (params) => wrap(() => ctx.client.linkWallet(params)),
1852
+ [ctx.client, wrap]
1853
+ );
1854
+ const unlinkWallet = (0, import_react14.useCallback)(
1855
+ async (walletId) => {
1856
+ const result = await wrap(() => ctx.client.unlinkWallet(walletId));
1857
+ return result !== null;
1858
+ },
1859
+ [ctx.client, wrap]
1860
+ );
1861
+ return {
1862
+ getNonce,
1863
+ verify,
1864
+ listWallets,
1865
+ linkWallet,
1866
+ unlinkWallet,
1867
+ isLoading,
1868
+ error
1869
+ };
1870
+ }
1871
+
1872
+ // src/useAuthonSessions.ts
1873
+ var import_react15 = require("react");
1874
+ function useAuthonSessions() {
1875
+ const ctx = (0, import_react15.useContext)(AuthonContext);
1876
+ if (!ctx) throw new Error("useAuthonSessions must be used within <AuthonProvider>");
1877
+ const [isLoading, setIsLoading] = (0, import_react15.useState)(false);
1878
+ const [error, setError] = (0, import_react15.useState)(null);
1879
+ const wrap = (0, import_react15.useCallback)(
1880
+ async (fn) => {
1881
+ setIsLoading(true);
1882
+ setError(null);
1883
+ try {
1884
+ return await fn();
1885
+ } catch (err) {
1886
+ setError(err instanceof Error ? err : new Error(String(err)));
1887
+ return null;
1888
+ } finally {
1889
+ setIsLoading(false);
1890
+ }
1891
+ },
1892
+ []
1893
+ );
1894
+ const listSessions = (0, import_react15.useCallback)(
1895
+ () => wrap(() => ctx.client.listSessions()),
1896
+ [ctx.client, wrap]
1897
+ );
1898
+ const revokeSession = (0, import_react15.useCallback)(
1899
+ async (sessionId) => {
1900
+ const result = await wrap(() => ctx.client.revokeSession(sessionId));
1901
+ return result !== null;
1902
+ },
1903
+ [ctx.client, wrap]
1904
+ );
1905
+ return {
1906
+ listSessions,
1907
+ revokeSession,
1908
+ isLoading,
1909
+ error
1910
+ };
1911
+ }
1912
+
1913
+ // src/useOrganization.ts
1914
+ var import_react16 = require("react");
1915
+ function useOrganization() {
1916
+ const ctx = (0, import_react16.useContext)(AuthonContext);
1917
+ if (!ctx) throw new Error("useOrganization must be used within <AuthonProvider>");
1918
+ const [members, setMembers] = (0, import_react16.useState)([]);
1919
+ const [isLoaded, setIsLoaded] = (0, import_react16.useState)(false);
1920
+ const organization = ctx.activeOrganization;
1921
+ (0, import_react16.useEffect)(() => {
1922
+ if (!organization || !ctx.client) {
1923
+ setMembers([]);
1924
+ setIsLoaded(!organization);
1925
+ return;
1926
+ }
1927
+ setIsLoaded(false);
1928
+ ctx.client.organizations.getMembers(organization.id).then((m) => {
1929
+ setMembers(m);
1930
+ setIsLoaded(true);
1931
+ }).catch(() => {
1932
+ setMembers([]);
1933
+ setIsLoaded(true);
1934
+ });
1935
+ }, [organization?.id, ctx.client]);
1936
+ return {
1937
+ organization,
1938
+ members,
1939
+ isLoaded
1940
+ };
1941
+ }
1942
+
1943
+ // src/useOrganizationList.ts
1944
+ var import_react17 = require("react");
1945
+ function useOrganizationList() {
1946
+ const ctx = (0, import_react17.useContext)(AuthonContext);
1947
+ if (!ctx) throw new Error("useOrganizationList must be used within <AuthonProvider>");
1948
+ const [organizations, setOrganizations] = (0, import_react17.useState)([]);
1949
+ const [isLoaded, setIsLoaded] = (0, import_react17.useState)(false);
1950
+ (0, import_react17.useEffect)(() => {
1951
+ if (!ctx.client || !ctx.isSignedIn) {
1952
+ setOrganizations([]);
1953
+ setIsLoaded(!ctx.isSignedIn);
1954
+ return;
1955
+ }
1956
+ setIsLoaded(false);
1957
+ ctx.client.organizations.list().then((res) => {
1958
+ setOrganizations(res.data);
1959
+ setIsLoaded(true);
1960
+ }).catch(() => {
1961
+ setOrganizations([]);
1962
+ setIsLoaded(true);
1963
+ });
1964
+ }, [ctx.client, ctx.isSignedIn]);
1965
+ const createOrganization = (0, import_react17.useCallback)(
1966
+ async (params) => {
1967
+ if (!ctx.client) return null;
1968
+ try {
1969
+ const org = await ctx.client.organizations.create(params);
1970
+ setOrganizations((prev) => [...prev, org]);
1971
+ return org;
1972
+ } catch {
1973
+ return null;
1974
+ }
1975
+ },
1976
+ [ctx.client]
1977
+ );
1978
+ const setActive = (0, import_react17.useCallback)(
1979
+ (org) => {
1980
+ ctx.setActiveOrganization(org);
1981
+ },
1982
+ [ctx.setActiveOrganization]
1983
+ );
1984
+ return {
1985
+ organizations,
1986
+ isLoaded,
1987
+ createOrganization,
1988
+ setActive
1989
+ };
1990
+ }
1991
+
1992
+ // src/components/UserProfile.tsx
1993
+ var import_react18 = require("react");
1994
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1995
+ function ProfileTab() {
1996
+ const theme = useTheme();
1997
+ const { user, client } = useAuthon();
1998
+ const [displayName, setDisplayName] = (0, import_react18.useState)(user?.displayName ?? "");
1999
+ const [phone, setPhone] = (0, import_react18.useState)(user?.phone ?? "");
2000
+ const [loading, setLoading] = (0, import_react18.useState)(false);
2001
+ const [success, setSuccess] = (0, import_react18.useState)("");
2002
+ const [error, setError] = (0, import_react18.useState)("");
2003
+ const handleSave = async () => {
2004
+ if (!client) return;
2005
+ setLoading(true);
2006
+ setError("");
2007
+ setSuccess("");
2008
+ try {
2009
+ await client.updateProfile({ displayName: displayName || void 0, phone: phone || void 0 });
2010
+ setSuccess("Profile updated");
2011
+ } catch (e) {
2012
+ setError(e?.message ?? "Failed to update profile");
2013
+ } finally {
2014
+ setLoading(false);
2015
+ }
2016
+ };
2017
+ const initials = user?.displayName ? user.displayName.split(" ").map((n) => n[0]).join("").toUpperCase().slice(0, 2) : (user?.email?.[0] ?? "?").toUpperCase();
2018
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 24 }, children: [
2019
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 16 }, children: [
2020
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2021
+ "div",
2022
+ {
2023
+ style: {
2024
+ width: 64,
2025
+ height: 64,
2026
+ borderRadius: "50%",
2027
+ background: user?.avatarUrl ? "transparent" : `linear-gradient(135deg, ${theme.primaryStart}, ${theme.primaryEnd})`,
2028
+ color: "#fff",
2029
+ display: "flex",
2030
+ alignItems: "center",
2031
+ justifyContent: "center",
2032
+ fontSize: 22,
2033
+ fontWeight: 700,
2034
+ overflow: "hidden",
2035
+ flexShrink: 0
2036
+ },
2037
+ children: user?.avatarUrl ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("img", { src: user.avatarUrl, alt: "avatar", style: { width: "100%", height: "100%", objectFit: "cover" } }) : initials
2038
+ }
2039
+ ),
2040
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
2041
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 16, fontWeight: 600, color: theme.text }, children: user?.displayName ?? "User" }),
2042
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 13, color: theme.textMuted }, children: user?.email }),
2043
+ !user?.emailVerified && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: { fontSize: 11, color: "#d97706", background: "#fef3c7", padding: "2px 8px", borderRadius: 99, fontWeight: 500, marginTop: 4, display: "inline-block" }, children: "Email not verified" })
2044
+ ] })
2045
+ ] }),
2046
+ success && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { padding: "10px 14px", borderRadius: theme.borderRadius, background: "#f0fdf4", border: "1px solid #bbf7d0", color: "#166534", fontSize: 13 }, children: success }),
2047
+ error && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { padding: "10px 14px", borderRadius: theme.borderRadius, background: "#fef2f2", border: "1px solid #fecaca", color: "#dc2626", fontSize: 13 }, children: error }),
2048
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
2049
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Input, { label: "Display name", value: displayName, onChange: setDisplayName, placeholder: "Your name" }),
2050
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Input, { label: "Email", type: "email", value: user?.email ?? "", disabled: true, placeholder: "Email" }),
2051
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Input, { label: "Phone", type: "tel", value: phone, onChange: setPhone, placeholder: "+1 (555) 000-0000" })
2052
+ ] }),
2053
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Button, { variant: "primary", onClick: handleSave, loading, style: { alignSelf: "flex-start", minWidth: 120 }, children: "Save changes" })
2054
+ ] });
2055
+ }
2056
+ function SecurityTab() {
2057
+ const theme = useTheme();
2058
+ const { client } = useAuthon();
2059
+ const [currentPw, setCurrentPw] = (0, import_react18.useState)("");
2060
+ const [newPw, setNewPw] = (0, import_react18.useState)("");
2061
+ const [confirmPw, setConfirmPw] = (0, import_react18.useState)("");
2062
+ const [pwLoading, setPwLoading] = (0, import_react18.useState)(false);
2063
+ const [pwError, setPwError] = (0, import_react18.useState)("");
2064
+ const [pwSuccess, setPwSuccess] = (0, import_react18.useState)("");
2065
+ const [mfaStatus, setMfaStatus] = (0, import_react18.useState)(null);
2066
+ const [mfaLoading, setMfaLoading] = (0, import_react18.useState)(false);
2067
+ (0, import_react18.useEffect)(() => {
2068
+ if (!client) return;
2069
+ client.getMfaStatus().then(setMfaStatus).catch(() => null);
2070
+ }, [client]);
2071
+ const handlePasswordChange = async () => {
2072
+ if (!client) return;
2073
+ if (newPw !== confirmPw) {
2074
+ setPwError("Passwords do not match");
2075
+ return;
2076
+ }
2077
+ if (newPw.length < 8) {
2078
+ setPwError("Password must be at least 8 characters");
2079
+ return;
2080
+ }
2081
+ setPwLoading(true);
2082
+ setPwError("");
2083
+ setPwSuccess("");
2084
+ try {
2085
+ await client.updateProfile({ displayName: void 0 });
2086
+ setPwSuccess("Password updated");
2087
+ setCurrentPw("");
2088
+ setNewPw("");
2089
+ setConfirmPw("");
2090
+ } catch (e) {
2091
+ setPwError(e?.message ?? "Failed to update password");
2092
+ } finally {
2093
+ setPwLoading(false);
2094
+ }
2095
+ };
2096
+ const sectionTitle = {
2097
+ fontSize: 15,
2098
+ fontWeight: 600,
2099
+ color: theme.text,
2100
+ marginBottom: 16,
2101
+ paddingBottom: 10,
2102
+ borderBottom: `1px solid ${theme.border}`
2103
+ };
2104
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 32 }, children: [
2105
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
2106
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: sectionTitle, children: "Change password" }),
2107
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 16 }, children: [
2108
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Input, { label: "Current password", type: "password", value: currentPw, onChange: setCurrentPw, placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022", autoComplete: "current-password" }),
2109
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Input, { label: "New password", type: "password", value: newPw, onChange: setNewPw, placeholder: "Minimum 8 characters", autoComplete: "new-password" }),
2110
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Input, { label: "Confirm new password", type: "password", value: confirmPw, onChange: setConfirmPw, placeholder: "Repeat new password", autoComplete: "new-password" }),
2111
+ pwError && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "#dc2626", fontSize: 13 }, children: pwError }),
2112
+ pwSuccess && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "#166534", fontSize: 13 }, children: pwSuccess }),
2113
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Button, { variant: "primary", onClick: handlePasswordChange, loading: pwLoading, style: { alignSelf: "flex-start", minWidth: 160 }, children: "Update password" })
2114
+ ] })
2115
+ ] }),
2116
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
2117
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: sectionTitle, children: "Two-factor authentication" }),
2118
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", padding: "14px 0" }, children: [
2119
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
2120
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 14, fontWeight: 500, color: theme.text }, children: "Authenticator app" }),
2121
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 13, color: theme.textMuted, marginTop: 2 }, children: mfaStatus?.enabled ? `Enabled \xB7 ${mfaStatus.backupCodesRemaining} backup codes remaining` : "Add extra security to your account" })
2122
+ ] }),
2123
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2124
+ "span",
2125
+ {
2126
+ style: {
2127
+ display: "inline-flex",
2128
+ alignItems: "center",
2129
+ gap: 4,
2130
+ padding: "3px 10px",
2131
+ borderRadius: 99,
2132
+ fontSize: 12,
2133
+ fontWeight: 600,
2134
+ background: mfaStatus?.enabled ? "#f0fdf4" : "#f3f4f6",
2135
+ color: mfaStatus?.enabled ? "#166534" : theme.textMuted
2136
+ },
2137
+ children: [
2138
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: { width: 6, height: 6, borderRadius: "50%", background: mfaStatus?.enabled ? "#22c55e" : "#9ca3af", display: "inline-block" } }),
2139
+ mfaStatus?.enabled ? "Enabled" : "Disabled"
2140
+ ]
2141
+ }
2142
+ ) })
2143
+ ] })
2144
+ ] })
2145
+ ] });
2146
+ }
2147
+ function SessionsTab() {
2148
+ const theme = useTheme();
2149
+ const { client } = useAuthon();
2150
+ const [sessions, setSessions] = (0, import_react18.useState)([]);
2151
+ const [loading, setLoading] = (0, import_react18.useState)(true);
2152
+ const [revoking, setRevoking] = (0, import_react18.useState)(null);
2153
+ const loadSessions = (0, import_react18.useCallback)(async () => {
2154
+ if (!client) return;
2155
+ setLoading(true);
2156
+ try {
2157
+ const data = await client.listSessions();
2158
+ setSessions(data);
2159
+ } catch {
2160
+ } finally {
2161
+ setLoading(false);
2162
+ }
2163
+ }, [client]);
2164
+ (0, import_react18.useEffect)(() => {
2165
+ loadSessions();
2166
+ }, [loadSessions]);
2167
+ const handleRevoke = async (sessionId) => {
2168
+ if (!client) return;
2169
+ setRevoking(sessionId);
2170
+ try {
2171
+ await client.revokeSession(sessionId);
2172
+ setSessions((prev) => prev.filter((s) => s.id !== sessionId));
2173
+ } catch {
2174
+ } finally {
2175
+ setRevoking(null);
2176
+ }
2177
+ };
2178
+ const sectionTitle = {
2179
+ fontSize: 15,
2180
+ fontWeight: 600,
2181
+ color: theme.text,
2182
+ marginBottom: 16,
2183
+ paddingBottom: 10,
2184
+ borderBottom: `1px solid ${theme.border}`
2185
+ };
2186
+ if (loading) {
2187
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { display: "flex", justifyContent: "center", padding: 40 }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: { width: 24, height: 24, border: `3px solid ${theme.primaryStart}33`, borderTopColor: theme.primaryStart, borderRadius: "50%", display: "inline-block", animation: "authon-spin 0.7s linear infinite" } }) });
2188
+ }
2189
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { children: [
2190
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: sectionTitle, children: "Active sessions" }),
2191
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 10 }, children: sessions.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: theme.textMuted, fontSize: 14, textAlign: "center", padding: "24px 0" }, children: "No active sessions" }) : sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
2192
+ "div",
2193
+ {
2194
+ style: {
2195
+ display: "flex",
2196
+ alignItems: "center",
2197
+ justifyContent: "space-between",
2198
+ padding: "12px 14px",
2199
+ borderRadius: theme.borderRadius,
2200
+ border: `1px solid ${theme.border}`,
2201
+ gap: 12
2202
+ },
2203
+ children: [
2204
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 12, flex: 1, minWidth: 0 }, children: [
2205
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { width: 36, height: 36, borderRadius: "50%", background: `${theme.primaryStart}18`, color: theme.primaryStart, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
2206
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("rect", { x: "2", y: "3", width: "20", height: "14", rx: "2", ry: "2" }),
2207
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("line", { x1: "8", y1: "21", x2: "16", y2: "21" }),
2208
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("line", { x1: "12", y1: "17", x2: "12", y2: "21" })
2209
+ ] }) }),
2210
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { minWidth: 0 }, children: [
2211
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { fontSize: 13, fontWeight: 500, color: theme.text, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: session.userAgent ? session.userAgent.length > 50 ? session.userAgent.slice(0, 50) + "\u2026" : session.userAgent : "Unknown device" }),
2212
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { fontSize: 12, color: theme.textMuted, marginTop: 2 }, children: [
2213
+ session.ipAddress ?? "Unknown IP",
2214
+ session.lastActiveAt && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
2215
+ " \xB7 ",
2216
+ formatRelative(session.lastActiveAt)
2217
+ ] })
2218
+ ] })
2219
+ ] })
2220
+ ] }),
2221
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2222
+ Button,
2223
+ {
2224
+ variant: "outline",
2225
+ size: "sm",
2226
+ loading: revoking === session.id,
2227
+ onClick: () => handleRevoke(session.id),
2228
+ children: "Revoke"
2229
+ }
2230
+ )
2231
+ ]
2232
+ },
2233
+ session.id
2234
+ )) })
2235
+ ] });
2236
+ }
2237
+ function formatRelative(dateStr) {
2238
+ const diff = Date.now() - new Date(dateStr).getTime();
2239
+ const mins = Math.floor(diff / 6e4);
2240
+ if (mins < 1) return "Just now";
2241
+ if (mins < 60) return `${mins}m ago`;
2242
+ const hours = Math.floor(mins / 60);
2243
+ if (hours < 24) return `${hours}h ago`;
2244
+ const days = Math.floor(hours / 24);
2245
+ return `${days}d ago`;
2246
+ }
2247
+ function UserProfilePanel() {
2248
+ const theme = useTheme();
2249
+ const [tab, setTab] = (0, import_react18.useState)("profile");
2250
+ const panelStyle = {
2251
+ width: "100%",
2252
+ maxWidth: 640,
2253
+ background: theme.bg,
2254
+ borderRadius: `calc(${theme.borderRadius} + 4px)`,
2255
+ boxShadow: "0 4px 32px rgba(0,0,0,0.10)",
2256
+ overflow: "hidden",
2257
+ fontFamily: theme.fontFamily
2258
+ };
2259
+ const tabBarStyle = {
2260
+ display: "flex",
2261
+ borderBottom: `1px solid ${theme.border}`,
2262
+ padding: "0 24px"
2263
+ };
2264
+ const tabBtnStyle = (active) => ({
2265
+ padding: "14px 16px",
2266
+ background: "none",
2267
+ border: "none",
2268
+ borderBottom: active ? `2px solid ${theme.primaryStart}` : "2px solid transparent",
2269
+ color: active ? theme.primaryStart : theme.textMuted,
2270
+ fontWeight: active ? 600 : 400,
2271
+ fontSize: 14,
2272
+ cursor: "pointer",
2273
+ fontFamily: theme.fontFamily,
2274
+ marginBottom: -1
2275
+ });
2276
+ const contentStyle = {
2277
+ padding: "28px 28px"
2278
+ };
2279
+ const tabs = [
2280
+ { key: "profile", label: "Profile" },
2281
+ { key: "security", label: "Security" },
2282
+ { key: "sessions", label: "Sessions" }
2283
+ ];
2284
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: panelStyle, children: [
2285
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("style", { children: `@keyframes authon-spin { to { transform: rotate(360deg); } }` }),
2286
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: tabBarStyle, children: tabs.map(({ key, label }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
2287
+ "button",
2288
+ {
2289
+ type: "button",
2290
+ style: tabBtnStyle(tab === key),
2291
+ onClick: () => setTab(key),
2292
+ children: label
2293
+ },
2294
+ key
2295
+ )) }),
2296
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: contentStyle, children: [
2297
+ tab === "profile" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ProfileTab, {}),
2298
+ tab === "security" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SecurityTab, {}),
2299
+ tab === "sessions" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SessionsTab, {})
2300
+ ] })
2301
+ ] });
2302
+ }
2303
+ function UserProfile({ appearance }) {
2304
+ const { branding } = useBranding();
2305
+ const effectiveBranding = { ...branding, ...appearance?.variables ?? {} };
2306
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ThemeProvider, { branding: effectiveBranding, style: { display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(UserProfilePanel, {}) });
2307
+ }
2308
+
2309
+ // src/components/shared/ProviderIcon.tsx
2310
+ var import_js5 = require("@authon/js");
2311
+ var import_jsx_runtime15 = require("react/jsx-runtime");
2312
+ function ProviderIcon({ provider, size = 20 }) {
2313
+ const config = (0, import_js5.getProviderButtonConfig)(provider);
2314
+ const svg = config.iconSvg.replace(/width="\d+"/, `width="${size}"`).replace(/height="\d+"/, `height="${size}"`);
2315
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
2316
+ "span",
2317
+ {
2318
+ style: { display: "flex", alignItems: "center", flexShrink: 0 },
2319
+ dangerouslySetInnerHTML: { __html: svg }
2320
+ }
2321
+ );
301
2322
  }
302
2323
  // Annotate the CommonJS export names for ESM import in node:
303
2324
  0 && (module.exports = {
304
2325
  AuthonProvider,
2326
+ Button,
2327
+ Divider,
2328
+ Input,
305
2329
  Protect,
2330
+ ProviderIcon,
306
2331
  SignIn,
307
2332
  SignUp,
308
2333
  SignedIn,
309
2334
  SignedOut,
2335
+ SocialButton,
2336
+ SocialButtons,
2337
+ ThemeProvider,
310
2338
  UserButton,
2339
+ UserProfile,
311
2340
  useAuthon,
2341
+ useAuthonMfa,
2342
+ useAuthonPasskeys,
2343
+ useAuthonPasswordless,
2344
+ useAuthonSessions,
2345
+ useAuthonWeb3,
2346
+ useBranding,
2347
+ useOrganization,
2348
+ useOrganizationList,
312
2349
  useUser
313
2350
  });
314
2351
  //# sourceMappingURL=index.cjs.map