authvital-sdk 0.1.1-dev.3.cefb119.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.mjs ADDED
@@ -0,0 +1,1299 @@
1
+ import {
2
+ AppAccessEventHandler,
3
+ AuthVitalEventHandler,
4
+ AuthVitalWebhooks,
5
+ InviteEventHandler,
6
+ LicenseEventHandler,
7
+ MemberEventHandler,
8
+ SYNC_EVENT_TYPES,
9
+ SubjectEventHandler,
10
+ WebhookRouter,
11
+ isAppAccessEvent,
12
+ isInviteEvent,
13
+ isLicenseEvent,
14
+ isMemberEvent,
15
+ isSubjectEvent
16
+ } from "./chunk-ETJ5ICJ7.mjs";
17
+ import {
18
+ checkAuthStatus,
19
+ decodeJwt,
20
+ decodeState,
21
+ encodeState,
22
+ exchangeCodeForTokens,
23
+ extractCallbackParams,
24
+ generateCodeChallenge,
25
+ generateCodeVerifier,
26
+ handleCallback,
27
+ loginToAuthVital,
28
+ logout,
29
+ signupAtAuthVital,
30
+ startAuthorizationFlow,
31
+ startLogin,
32
+ startSignup
33
+ } from "./chunk-JNEJMHGA.mjs";
34
+ import {
35
+ captureInviteTokenFromUrl,
36
+ clearStoredInviteToken,
37
+ consumeInvitation,
38
+ createInvitation,
39
+ getInvitation,
40
+ getStoredInviteToken,
41
+ listTenantInvitations,
42
+ revokeInvitation,
43
+ storeInviteToken
44
+ } from "./chunk-JPODZIZT.mjs";
45
+
46
+ // src/client/provider.tsx
47
+ import { createContext, useContext, useState, useCallback } from "react";
48
+ import { jsx } from "react/jsx-runtime";
49
+ var AuthContext = createContext(null);
50
+ var ConfigContext = createContext(null);
51
+ function AuthVitalProvider({
52
+ clientId,
53
+ authVitalHost,
54
+ initialUser = null,
55
+ initialTenants = [],
56
+ children
57
+ }) {
58
+ const [isLoading, setIsLoading] = useState(false);
59
+ const [isSigningIn, setIsSigningIn] = useState(false);
60
+ const [isSigningUp, setIsSigningUp] = useState(false);
61
+ const [user, setUser] = useState(initialUser);
62
+ const [tenants, setTenants] = useState(initialTenants);
63
+ const [currentTenant, setCurrentTenant] = useState(initialTenants[0] || null);
64
+ const [error, setError] = useState(null);
65
+ const setAuthState = useCallback((newUser, newTenants = []) => {
66
+ setUser(newUser);
67
+ setTenants(newTenants);
68
+ setCurrentTenant(newTenants[0] || null);
69
+ setError(null);
70
+ }, []);
71
+ const clearAuthState = useCallback(() => {
72
+ setUser(null);
73
+ setTenants([]);
74
+ setCurrentTenant(null);
75
+ }, []);
76
+ const login = useCallback(
77
+ async (_email, _password) => {
78
+ setIsSigningIn(true);
79
+ setError(null);
80
+ try {
81
+ const { startAuthorizationFlow: startAuthorizationFlow2 } = await import("./oauth-UAFXEKZ7.mjs");
82
+ const redirectUri = typeof window !== "undefined" ? window.location.origin + "/api/auth/callback" : "";
83
+ await startAuthorizationFlow2({
84
+ authVitalHost,
85
+ clientId,
86
+ redirectUri
87
+ });
88
+ return { user: null, tenants: [] };
89
+ } catch (err) {
90
+ const message = err instanceof Error ? err.message : "Login failed";
91
+ setError(message);
92
+ throw err;
93
+ } finally {
94
+ setIsSigningIn(false);
95
+ }
96
+ },
97
+ [authVitalHost, clientId]
98
+ );
99
+ const signUp = useCallback(
100
+ async (_data) => {
101
+ setIsSigningUp(true);
102
+ setError(null);
103
+ try {
104
+ const { startAuthorizationFlow: startAuthorizationFlow2 } = await import("./oauth-UAFXEKZ7.mjs");
105
+ const redirectUri = typeof window !== "undefined" ? window.location.origin + "/api/auth/callback" : "";
106
+ await startAuthorizationFlow2({
107
+ authVitalHost,
108
+ clientId,
109
+ redirectUri
110
+ }, { screen: "signup" });
111
+ return { user: null };
112
+ } catch (err) {
113
+ const message = err instanceof Error ? err.message : "Sign up failed";
114
+ setError(message);
115
+ throw err;
116
+ } finally {
117
+ setIsSigningUp(false);
118
+ }
119
+ },
120
+ [authVitalHost, clientId]
121
+ );
122
+ const signOut = useCallback(async () => {
123
+ clearAuthState();
124
+ const { logout: authVitalLogout } = await import("./oauth-UAFXEKZ7.mjs");
125
+ await authVitalLogout(authVitalHost, {
126
+ postLogoutRedirectUri: typeof window !== "undefined" ? window.location.origin : void 0
127
+ });
128
+ }, [authVitalHost, clearAuthState]);
129
+ const setActiveTenant = useCallback(
130
+ (tenantId) => {
131
+ const tenant = tenants.find((t) => t.id === tenantId);
132
+ if (tenant) setCurrentTenant(tenant);
133
+ },
134
+ [tenants]
135
+ );
136
+ const refreshToken = useCallback(async () => {
137
+ }, []);
138
+ const checkAuth = useCallback(async () => {
139
+ return !!user;
140
+ }, [user]);
141
+ const value = {
142
+ isAuthenticated: !!user,
143
+ isLoading,
144
+ isSigningIn,
145
+ isSigningUp,
146
+ user,
147
+ tenants,
148
+ currentTenant,
149
+ error,
150
+ // Auth methods (redirect to OAuth)
151
+ login,
152
+ signIn: login,
153
+ signUp,
154
+ signOut,
155
+ logout: signOut,
156
+ // Tenant methods
157
+ setActiveTenant,
158
+ switchTenant: setActiveTenant,
159
+ // Session methods (no-ops, server handles this)
160
+ refreshToken,
161
+ checkAuth,
162
+ // State setters (new!)
163
+ setAuthState,
164
+ clearAuthState
165
+ };
166
+ const configValue = { authVitalHost, clientId };
167
+ return /* @__PURE__ */ jsx(ConfigContext.Provider, { value: configValue, children: /* @__PURE__ */ jsx(AuthContext.Provider, { value, children }) });
168
+ }
169
+ function useAuth() {
170
+ const context = useContext(AuthContext);
171
+ if (!context) {
172
+ throw new Error("useAuth must be used within an AuthVitalProvider");
173
+ }
174
+ return context;
175
+ }
176
+ function useUser() {
177
+ const { user } = useAuth();
178
+ return user;
179
+ }
180
+ function useTenant() {
181
+ const { currentTenant } = useAuth();
182
+ return currentTenant;
183
+ }
184
+ function useTenants() {
185
+ const { tenants } = useAuth();
186
+ return tenants;
187
+ }
188
+ function useAuthVitalConfig() {
189
+ const context = useContext(ConfigContext);
190
+ if (!context) {
191
+ throw new Error("useAuthVitalConfig must be used within an AuthVitalProvider");
192
+ }
193
+ return context;
194
+ }
195
+ function useOAuth(options) {
196
+ const config = useAuthVitalConfig();
197
+ const { isAuthenticated } = useAuth();
198
+ const [isLoading, setIsLoading] = useState(false);
199
+ const redirectUri = options?.redirectUri || (typeof window !== "undefined" ? window.location.origin + "/api/auth/callback" : "");
200
+ const startLogin2 = useCallback(async (opts) => {
201
+ setIsLoading(true);
202
+ try {
203
+ const { startAuthorizationFlow: startAuthorizationFlow2 } = await import("./oauth-UAFXEKZ7.mjs");
204
+ await startAuthorizationFlow2({
205
+ authVitalHost: config.authVitalHost,
206
+ clientId: config.clientId,
207
+ redirectUri,
208
+ scope: opts?.scope
209
+ }, { state: opts?.state });
210
+ } finally {
211
+ setIsLoading(false);
212
+ }
213
+ }, [config, redirectUri]);
214
+ const startSignup2 = useCallback(async (opts) => {
215
+ setIsLoading(true);
216
+ try {
217
+ const { startAuthorizationFlow: startAuthorizationFlow2 } = await import("./oauth-UAFXEKZ7.mjs");
218
+ await startAuthorizationFlow2({
219
+ authVitalHost: config.authVitalHost,
220
+ clientId: config.clientId,
221
+ redirectUri,
222
+ scope: opts?.scope
223
+ }, { state: opts?.state, screen: "signup" });
224
+ } finally {
225
+ setIsLoading(false);
226
+ }
227
+ }, [config, redirectUri]);
228
+ const logoutFn = useCallback(async (logoutOptions) => {
229
+ const { logout: authVitalLogout } = await import("./oauth-UAFXEKZ7.mjs");
230
+ await authVitalLogout(config.authVitalHost, logoutOptions);
231
+ }, [config.authVitalHost]);
232
+ return {
233
+ isAuthenticated,
234
+ isLoading,
235
+ startLogin: startLogin2,
236
+ startSignup: startSignup2,
237
+ logout: logoutFn
238
+ };
239
+ }
240
+ function useInvitation(options = {}) {
241
+ const { onConsumed, onError } = options;
242
+ const config = useAuthVitalConfig();
243
+ const [invitation, setInvitation] = useState(null);
244
+ const [isLoading, setIsLoading] = useState(false);
245
+ const [error, setError] = useState(null);
246
+ const [consumed, setConsumed] = useState(false);
247
+ const fetchInvitation = useCallback(async (token) => {
248
+ setIsLoading(true);
249
+ setError(null);
250
+ try {
251
+ const { getInvitation: getInvitation2 } = await import("./invitations-EFJA5C6L.mjs");
252
+ const invite = await getInvitation2(config.authVitalHost, token);
253
+ setInvitation(invite);
254
+ return invite;
255
+ } catch (err) {
256
+ const error2 = err instanceof Error ? err : new Error("Failed to fetch invitation");
257
+ setError(error2);
258
+ throw error2;
259
+ } finally {
260
+ setIsLoading(false);
261
+ }
262
+ }, [config.authVitalHost]);
263
+ const acceptAndLogin = useCallback(async (token, loginOptions) => {
264
+ const { storeInviteToken: storeInviteToken2 } = await import("./invitations-EFJA5C6L.mjs");
265
+ const { startAuthorizationFlow: startAuthorizationFlow2 } = await import("./oauth-UAFXEKZ7.mjs");
266
+ storeInviteToken2(token);
267
+ await startAuthorizationFlow2({
268
+ authVitalHost: config.authVitalHost,
269
+ clientId: config.clientId,
270
+ redirectUri: typeof window !== "undefined" ? window.location.origin + "/api/auth/callback" : ""
271
+ }, { state: loginOptions?.state });
272
+ }, [config]);
273
+ const consumeInvite = useCallback(async (token) => {
274
+ setIsLoading(true);
275
+ setError(null);
276
+ try {
277
+ const { consumeInvitation: consumeInvitation2, clearStoredInviteToken: clearStoredInviteToken2 } = await import("./invitations-EFJA5C6L.mjs");
278
+ const result = await consumeInvitation2(config.authVitalHost, "", token);
279
+ clearStoredInviteToken2();
280
+ setConsumed(true);
281
+ onConsumed?.(result);
282
+ return result;
283
+ } catch (err) {
284
+ const error2 = err instanceof Error ? err : new Error("Failed to consume invitation");
285
+ setError(error2);
286
+ onError?.(error2);
287
+ throw error2;
288
+ } finally {
289
+ setIsLoading(false);
290
+ }
291
+ }, [config.authVitalHost, onConsumed, onError]);
292
+ return {
293
+ invitation,
294
+ isLoading,
295
+ error,
296
+ consumed,
297
+ hasPendingInvite: typeof window !== "undefined" ? !!sessionStorage.getItem("authvital_invite_token") : false,
298
+ fetchInvitation,
299
+ acceptAndLogin,
300
+ consumeInvite
301
+ };
302
+ }
303
+
304
+ // src/client/components/ProtectedRoute.tsx
305
+ import { useEffect as useEffect2 } from "react";
306
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
307
+ function ProtectedRoute({
308
+ children,
309
+ redirectTo = "/login",
310
+ showLoading = true,
311
+ loadingComponent
312
+ }) {
313
+ const { isAuthenticated, isLoading } = useAuth();
314
+ useEffect2(() => {
315
+ if (!isLoading && !isAuthenticated) {
316
+ window.location.href = redirectTo;
317
+ }
318
+ }, [isLoading, isAuthenticated, redirectTo]);
319
+ if (isLoading) {
320
+ if (loadingComponent) {
321
+ return /* @__PURE__ */ jsx2(Fragment, { children: loadingComponent });
322
+ }
323
+ if (showLoading) {
324
+ return /* @__PURE__ */ jsx2("div", { style: {
325
+ display: "flex",
326
+ alignItems: "center",
327
+ justifyContent: "center",
328
+ minHeight: "200px"
329
+ }, children: /* @__PURE__ */ jsx2(LoadingSpinner, {}) });
330
+ }
331
+ return null;
332
+ }
333
+ if (!isAuthenticated) {
334
+ return null;
335
+ }
336
+ return /* @__PURE__ */ jsx2(Fragment, { children });
337
+ }
338
+ function LoadingSpinner() {
339
+ return /* @__PURE__ */ jsxs(
340
+ "svg",
341
+ {
342
+ width: "24",
343
+ height: "24",
344
+ viewBox: "0 0 24 24",
345
+ fill: "none",
346
+ style: { animation: "spin 1s linear infinite" },
347
+ children: [
348
+ /* @__PURE__ */ jsx2("style", { children: `
349
+ @keyframes spin {
350
+ from { transform: rotate(0deg); }
351
+ to { transform: rotate(360deg); }
352
+ }
353
+ ` }),
354
+ /* @__PURE__ */ jsx2(
355
+ "circle",
356
+ {
357
+ cx: "12",
358
+ cy: "12",
359
+ r: "10",
360
+ stroke: "currentColor",
361
+ strokeWidth: "3",
362
+ strokeLinecap: "round",
363
+ strokeDasharray: "60 40",
364
+ opacity: "0.25"
365
+ }
366
+ ),
367
+ /* @__PURE__ */ jsx2(
368
+ "circle",
369
+ {
370
+ cx: "12",
371
+ cy: "12",
372
+ r: "10",
373
+ stroke: "#7c3aed",
374
+ strokeWidth: "3",
375
+ strokeLinecap: "round",
376
+ strokeDasharray: "60 40"
377
+ }
378
+ )
379
+ ]
380
+ }
381
+ );
382
+ }
383
+
384
+ // src/client/components/SignUpForm.tsx
385
+ import { useState as useState2 } from "react";
386
+
387
+ // src/client/components/styles.ts
388
+ function getStyles(appearance = {}) {
389
+ const theme = appearance.theme || "light";
390
+ const vars = appearance.variables || {};
391
+ const elements = appearance.elements || {};
392
+ const isDark = theme === "dark";
393
+ const colors = {
394
+ primary: vars.colorPrimary || "#7c3aed",
395
+ background: vars.colorBackground || (isDark ? "#1e1e2e" : "#ffffff"),
396
+ text: vars.colorText || (isDark ? "#ffffff" : "#1a1a1a"),
397
+ textSecondary: vars.colorTextSecondary || (isDark ? "#a1a1aa" : "#6b7280"),
398
+ danger: vars.colorDanger || "#dc2626",
399
+ success: vars.colorSuccess || "#16a34a",
400
+ border: isDark ? "rgba(255,255,255,0.1)" : "#e5e7eb",
401
+ inputBg: isDark ? "rgba(255,255,255,0.05)" : "#ffffff"
402
+ };
403
+ const borderRadius = vars.borderRadius || "0.5rem";
404
+ const fontFamily = vars.fontFamily || "system-ui, -apple-system, sans-serif";
405
+ return {
406
+ card: {
407
+ maxWidth: "400px",
408
+ width: "100%",
409
+ padding: "2rem",
410
+ backgroundColor: colors.background,
411
+ borderRadius: "1rem",
412
+ boxShadow: isDark ? "0 25px 50px -12px rgba(0, 0, 0, 0.5)" : "0 25px 50px -12px rgba(0, 0, 0, 0.25)",
413
+ fontFamily,
414
+ ...elements.card
415
+ },
416
+ header: {
417
+ textAlign: "center",
418
+ marginBottom: "1.5rem",
419
+ ...elements.header
420
+ },
421
+ title: {
422
+ fontSize: "1.5rem",
423
+ fontWeight: 600,
424
+ color: colors.text,
425
+ margin: "0 0 0.25rem 0"
426
+ },
427
+ subtitle: {
428
+ fontSize: "0.875rem",
429
+ color: colors.textSecondary,
430
+ margin: 0
431
+ },
432
+ form: {
433
+ display: "flex",
434
+ flexDirection: "column",
435
+ gap: "1rem",
436
+ ...elements.form
437
+ },
438
+ inputGroup: {
439
+ display: "flex",
440
+ flexDirection: "column",
441
+ gap: "0.375rem"
442
+ },
443
+ label: {
444
+ fontSize: "0.875rem",
445
+ fontWeight: 500,
446
+ color: colors.text
447
+ },
448
+ input: {
449
+ padding: "0.75rem",
450
+ border: `1px solid ${colors.border}`,
451
+ borderRadius,
452
+ fontSize: "1rem",
453
+ backgroundColor: colors.inputBg,
454
+ color: colors.text,
455
+ outline: "none",
456
+ transition: "border-color 0.2s, box-shadow 0.2s",
457
+ ...elements.input
458
+ },
459
+ primaryButton: {
460
+ padding: "0.75rem 1.5rem",
461
+ backgroundColor: colors.primary,
462
+ color: "#ffffff",
463
+ border: "none",
464
+ borderRadius,
465
+ fontSize: "1rem",
466
+ fontWeight: 500,
467
+ cursor: "pointer",
468
+ transition: "opacity 0.2s",
469
+ ...elements.primaryButton
470
+ },
471
+ buttonDisabled: {
472
+ opacity: 0.6,
473
+ cursor: "not-allowed"
474
+ },
475
+ secondaryButton: {
476
+ padding: "0.75rem 1.5rem",
477
+ backgroundColor: "transparent",
478
+ color: colors.text,
479
+ border: `1px solid ${colors.border}`,
480
+ borderRadius,
481
+ fontSize: "1rem",
482
+ fontWeight: 500,
483
+ cursor: "pointer",
484
+ transition: "background-color 0.2s",
485
+ ...elements.secondaryButton
486
+ },
487
+ socialButtons: {
488
+ display: "flex",
489
+ flexDirection: "column",
490
+ gap: "0.75rem",
491
+ marginBottom: "1rem"
492
+ },
493
+ socialButton: {
494
+ display: "flex",
495
+ alignItems: "center",
496
+ justifyContent: "center",
497
+ padding: "0.75rem",
498
+ border: `1px solid ${colors.border}`,
499
+ borderRadius,
500
+ backgroundColor: "transparent",
501
+ color: colors.text,
502
+ fontSize: "0.875rem",
503
+ fontWeight: 500,
504
+ cursor: "pointer",
505
+ transition: "background-color 0.2s",
506
+ ...elements.socialButton
507
+ },
508
+ divider: {
509
+ display: "flex",
510
+ alignItems: "center",
511
+ gap: "1rem",
512
+ color: colors.textSecondary,
513
+ fontSize: "0.75rem",
514
+ margin: "0.5rem 0"
515
+ },
516
+ link: {
517
+ color: colors.primary,
518
+ textDecoration: "none",
519
+ cursor: "pointer",
520
+ fontWeight: 500,
521
+ ...elements.link
522
+ },
523
+ forgotPassword: {
524
+ textAlign: "right",
525
+ marginTop: "-0.5rem"
526
+ },
527
+ footer: {
528
+ textAlign: "center",
529
+ marginTop: "1.5rem",
530
+ fontSize: "0.875rem",
531
+ color: colors.textSecondary,
532
+ ...elements.footer
533
+ },
534
+ error: {
535
+ padding: "0.75rem",
536
+ backgroundColor: isDark ? "rgba(220, 38, 38, 0.1)" : "#fef2f2",
537
+ border: `1px solid ${isDark ? "rgba(220, 38, 38, 0.2)" : "#fecaca"}`,
538
+ borderRadius,
539
+ color: colors.danger,
540
+ fontSize: "0.875rem",
541
+ marginBottom: "1rem",
542
+ ...elements.error
543
+ },
544
+ success: {
545
+ padding: "0.75rem",
546
+ backgroundColor: isDark ? "rgba(22, 163, 74, 0.1)" : "#f0fdf4",
547
+ border: `1px solid ${isDark ? "rgba(22, 163, 74, 0.2)" : "#bbf7d0"}`,
548
+ borderRadius,
549
+ color: colors.success,
550
+ fontSize: "0.875rem",
551
+ marginBottom: "1rem"
552
+ },
553
+ userButton: {
554
+ display: "flex",
555
+ alignItems: "center",
556
+ gap: "0.5rem",
557
+ padding: "0.5rem",
558
+ border: "none",
559
+ borderRadius,
560
+ backgroundColor: "transparent",
561
+ cursor: "pointer",
562
+ transition: "background-color 0.2s"
563
+ },
564
+ avatar: {
565
+ width: "32px",
566
+ height: "32px",
567
+ borderRadius: "50%",
568
+ backgroundColor: colors.primary,
569
+ color: "#ffffff",
570
+ display: "flex",
571
+ alignItems: "center",
572
+ justifyContent: "center",
573
+ fontSize: "0.875rem",
574
+ fontWeight: 500
575
+ },
576
+ dropdown: {
577
+ position: "absolute",
578
+ top: "100%",
579
+ right: 0,
580
+ marginTop: "0.5rem",
581
+ minWidth: "200px",
582
+ backgroundColor: colors.background,
583
+ border: `1px solid ${colors.border}`,
584
+ borderRadius,
585
+ boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1)",
586
+ overflow: "hidden",
587
+ zIndex: 50
588
+ },
589
+ dropdownItem: {
590
+ display: "block",
591
+ width: "100%",
592
+ padding: "0.75rem 1rem",
593
+ textAlign: "left",
594
+ border: "none",
595
+ backgroundColor: "transparent",
596
+ color: colors.text,
597
+ fontSize: "0.875rem",
598
+ cursor: "pointer",
599
+ transition: "background-color 0.2s"
600
+ }
601
+ };
602
+ }
603
+
604
+ // src/client/components/SignUpForm.tsx
605
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
606
+ function SignUpForm({
607
+ onSuccess,
608
+ onError,
609
+ showSignInLink = true,
610
+ onSignInClick,
611
+ redirectUri,
612
+ appearance
613
+ }) {
614
+ const config = useAuthVitalConfig();
615
+ const styles = getStyles(appearance);
616
+ const [email, setEmail] = useState2("");
617
+ const [givenName, setGivenName] = useState2("");
618
+ const [familyName, setFamilyName] = useState2("");
619
+ const [isLoading, setIsLoading] = useState2(false);
620
+ const [error, setError] = useState2(null);
621
+ const [emailSent, setEmailSent] = useState2(false);
622
+ const handleSubmit = async (e) => {
623
+ e.preventDefault();
624
+ setIsLoading(true);
625
+ setError(null);
626
+ try {
627
+ const response = await fetch(`${config.authVitalHost}/api/signup/initiate`, {
628
+ method: "POST",
629
+ headers: { "Content-Type": "application/json" },
630
+ credentials: "include",
631
+ body: JSON.stringify({
632
+ email,
633
+ givenName: givenName || void 0,
634
+ familyName: familyName || void 0,
635
+ redirectUri,
636
+ clientId: config.clientId
637
+ })
638
+ });
639
+ const result = await response.json();
640
+ if (!response.ok) {
641
+ throw new Error(result.message || "Failed to send verification email");
642
+ }
643
+ if (result.success) {
644
+ setEmailSent(true);
645
+ onSuccess?.({ email, message: result.message || "Verification email sent" });
646
+ } else {
647
+ throw new Error(result.message || "Failed to send verification email");
648
+ }
649
+ } catch (err) {
650
+ const error2 = err instanceof Error ? err : new Error("Failed to send verification email");
651
+ setError(error2.message);
652
+ onError?.(error2);
653
+ } finally {
654
+ setIsLoading(false);
655
+ }
656
+ };
657
+ const handleResend = async () => {
658
+ setIsLoading(true);
659
+ try {
660
+ const response = await fetch(`${config.authVitalHost}/api/signup/resend`, {
661
+ method: "POST",
662
+ headers: { "Content-Type": "application/json" },
663
+ credentials: "include",
664
+ body: JSON.stringify({ email, redirectUri })
665
+ });
666
+ if (!response.ok) {
667
+ const result = await response.json();
668
+ throw new Error(result.message || "Failed to resend email");
669
+ }
670
+ setError(null);
671
+ } catch (err) {
672
+ const error2 = err instanceof Error ? err : new Error("Failed to resend email");
673
+ setError(error2.message);
674
+ } finally {
675
+ setIsLoading(false);
676
+ }
677
+ };
678
+ if (emailSent) {
679
+ return /* @__PURE__ */ jsxs2("div", { style: styles.card, children: [
680
+ /* @__PURE__ */ jsxs2("div", { style: styles.header, children: [
681
+ /* @__PURE__ */ jsx3("div", { style: { ...styles.avatar, width: "64px", height: "64px", margin: "0 auto 1rem", fontSize: "1.5rem" }, children: "\u2709\uFE0F" }),
682
+ /* @__PURE__ */ jsx3("h1", { style: styles.title, children: "Check your email" }),
683
+ /* @__PURE__ */ jsx3("p", { style: styles.subtitle, children: "We sent a verification link to" }),
684
+ /* @__PURE__ */ jsx3("p", { style: { color: "#7c3aed", fontWeight: 500, marginTop: "0.5rem" }, children: email })
685
+ ] }),
686
+ /* @__PURE__ */ jsx3("p", { style: { ...styles.subtitle, marginBottom: "1.5rem" }, children: "Click the link in the email to verify your address and complete your signup." }),
687
+ /* @__PURE__ */ jsx3(
688
+ "button",
689
+ {
690
+ onClick: handleResend,
691
+ disabled: isLoading,
692
+ style: {
693
+ ...styles.secondaryButton,
694
+ width: "100%",
695
+ ...isLoading ? styles.buttonDisabled : {}
696
+ },
697
+ children: isLoading ? "Sending..." : "Resend verification email"
698
+ }
699
+ ),
700
+ /* @__PURE__ */ jsx3(
701
+ "button",
702
+ {
703
+ onClick: () => setEmailSent(false),
704
+ style: { ...styles.link, display: "block", marginTop: "1rem", textAlign: "center", width: "100%", background: "none", border: "none", cursor: "pointer" },
705
+ children: "Use a different email"
706
+ }
707
+ ),
708
+ error && /* @__PURE__ */ jsx3("div", { style: styles.error, children: error })
709
+ ] });
710
+ }
711
+ return /* @__PURE__ */ jsxs2("div", { style: styles.card, children: [
712
+ /* @__PURE__ */ jsxs2("div", { style: styles.header, children: [
713
+ /* @__PURE__ */ jsx3("h1", { style: styles.title, children: "Create an account" }),
714
+ /* @__PURE__ */ jsx3("p", { style: styles.subtitle, children: "Start your free trial today" })
715
+ ] }),
716
+ error && /* @__PURE__ */ jsx3("div", { style: styles.error, children: error }),
717
+ /* @__PURE__ */ jsxs2("form", { onSubmit: handleSubmit, style: styles.form, children: [
718
+ /* @__PURE__ */ jsxs2("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "1rem" }, children: [
719
+ /* @__PURE__ */ jsxs2("div", { style: styles.inputGroup, children: [
720
+ /* @__PURE__ */ jsx3("label", { style: styles.label, children: "First name" }),
721
+ /* @__PURE__ */ jsx3(
722
+ "input",
723
+ {
724
+ type: "text",
725
+ value: givenName,
726
+ onChange: (e) => setGivenName(e.target.value),
727
+ placeholder: "John",
728
+ style: styles.input
729
+ }
730
+ )
731
+ ] }),
732
+ /* @__PURE__ */ jsxs2("div", { style: styles.inputGroup, children: [
733
+ /* @__PURE__ */ jsx3("label", { style: styles.label, children: "Last name" }),
734
+ /* @__PURE__ */ jsx3(
735
+ "input",
736
+ {
737
+ type: "text",
738
+ value: familyName,
739
+ onChange: (e) => setFamilyName(e.target.value),
740
+ placeholder: "Doe",
741
+ style: styles.input
742
+ }
743
+ )
744
+ ] })
745
+ ] }),
746
+ /* @__PURE__ */ jsxs2("div", { style: styles.inputGroup, children: [
747
+ /* @__PURE__ */ jsx3("label", { style: styles.label, children: "Work email" }),
748
+ /* @__PURE__ */ jsx3(
749
+ "input",
750
+ {
751
+ type: "email",
752
+ value: email,
753
+ onChange: (e) => setEmail(e.target.value),
754
+ placeholder: "you@company.com",
755
+ required: true,
756
+ style: styles.input
757
+ }
758
+ )
759
+ ] }),
760
+ /* @__PURE__ */ jsx3(
761
+ "button",
762
+ {
763
+ type: "submit",
764
+ disabled: isLoading,
765
+ style: {
766
+ ...styles.primaryButton,
767
+ width: "100%",
768
+ ...isLoading ? styles.buttonDisabled : {}
769
+ },
770
+ children: isLoading ? "Sending verification..." : "Continue with email"
771
+ }
772
+ )
773
+ ] }),
774
+ showSignInLink && /* @__PURE__ */ jsxs2("div", { style: styles.footer, children: [
775
+ "Already have an account?",
776
+ " ",
777
+ /* @__PURE__ */ jsx3(
778
+ "button",
779
+ {
780
+ type: "button",
781
+ onClick: onSignInClick,
782
+ style: { ...styles.link, background: "none", border: "none", cursor: "pointer", padding: 0 },
783
+ children: "Sign in"
784
+ }
785
+ )
786
+ ] })
787
+ ] });
788
+ }
789
+
790
+ // src/client/components/VerifyEmail.tsx
791
+ import { useState as useState3, useEffect as useEffect3, useRef as useRef2 } from "react";
792
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
793
+ function VerifyEmail({
794
+ token,
795
+ onSuccess,
796
+ onError,
797
+ onContinueSignup,
798
+ onLogin,
799
+ onStartOver,
800
+ appearance
801
+ }) {
802
+ const config = useAuthVitalConfig();
803
+ const styles = getStyles(appearance);
804
+ const [status, setStatus] = useState3("loading");
805
+ const [message, setMessage] = useState3("");
806
+ const [verifiedData, setVerifiedData] = useState3(null);
807
+ const hasVerified = useRef2(false);
808
+ useEffect3(() => {
809
+ if (hasVerified.current) return;
810
+ hasVerified.current = true;
811
+ const verifyToken = async () => {
812
+ if (!token) {
813
+ setStatus("error");
814
+ setMessage("Invalid verification link. No token provided.");
815
+ onError?.(new Error("No token provided"), "error");
816
+ return;
817
+ }
818
+ try {
819
+ const response = await fetch(`${config.authVitalHost}/api/signup/verify`, {
820
+ method: "POST",
821
+ headers: { "Content-Type": "application/json" },
822
+ credentials: "include",
823
+ body: JSON.stringify({ token })
824
+ });
825
+ const result = await response.json();
826
+ if (result.success) {
827
+ const data = {
828
+ token,
829
+ email: result.email,
830
+ givenName: result.givenName,
831
+ familyName: result.familyName,
832
+ tenantName: result.tenantName
833
+ };
834
+ setStatus("success");
835
+ setMessage(result.message || "Email verified successfully!");
836
+ setVerifiedData(data);
837
+ onSuccess?.(data);
838
+ } else {
839
+ let newStatus = "error";
840
+ switch (result.error) {
841
+ case "EXPIRED":
842
+ newStatus = "expired";
843
+ break;
844
+ case "ALREADY_COMPLETED":
845
+ newStatus = "already_completed";
846
+ break;
847
+ }
848
+ setStatus(newStatus);
849
+ setMessage(result.message || "Verification failed.");
850
+ onError?.(new Error(result.message || "Verification failed"), newStatus);
851
+ }
852
+ } catch (err) {
853
+ setStatus("error");
854
+ const error = err instanceof Error ? err : new Error("Verification failed");
855
+ setMessage(error.message);
856
+ onError?.(error, "error");
857
+ }
858
+ };
859
+ verifyToken();
860
+ }, [token, config.authVitalHost, onSuccess, onError]);
861
+ const handleContinueSignup = () => {
862
+ if (verifiedData) {
863
+ onContinueSignup?.(verifiedData);
864
+ }
865
+ };
866
+ const iconStyle = {
867
+ width: "64px",
868
+ height: "64px",
869
+ borderRadius: "50%",
870
+ display: "flex",
871
+ alignItems: "center",
872
+ justifyContent: "center",
873
+ margin: "0 auto 1rem",
874
+ fontSize: "2rem"
875
+ };
876
+ return /* @__PURE__ */ jsxs3("div", { style: styles.card, children: [
877
+ status === "loading" && /* @__PURE__ */ jsxs3("div", { style: { textAlign: "center" }, children: [
878
+ /* @__PURE__ */ jsx4("div", { style: { ...iconStyle, background: "rgba(124, 58, 237, 0.2)" }, children: "\u23F3" }),
879
+ /* @__PURE__ */ jsx4("h1", { style: styles.title, children: "Verifying your email..." }),
880
+ /* @__PURE__ */ jsx4("p", { style: styles.subtitle, children: "Please wait while we verify your email address." })
881
+ ] }),
882
+ status === "success" && /* @__PURE__ */ jsxs3("div", { style: { textAlign: "center" }, children: [
883
+ /* @__PURE__ */ jsx4("div", { style: { ...iconStyle, background: "rgba(22, 163, 74, 0.2)" }, children: "\u2713" }),
884
+ /* @__PURE__ */ jsx4("h1", { style: styles.title, children: "Email Verified!" }),
885
+ /* @__PURE__ */ jsx4("p", { style: styles.subtitle, children: message }),
886
+ verifiedData?.email && /* @__PURE__ */ jsx4("p", { style: { color: "#7c3aed", marginBottom: "1.5rem" }, children: verifiedData.email }),
887
+ /* @__PURE__ */ jsx4(
888
+ "button",
889
+ {
890
+ onClick: handleContinueSignup,
891
+ style: { ...styles.primaryButton, width: "100%" },
892
+ children: "Continue to Complete Signup"
893
+ }
894
+ )
895
+ ] }),
896
+ status === "expired" && /* @__PURE__ */ jsxs3("div", { style: { textAlign: "center" }, children: [
897
+ /* @__PURE__ */ jsx4("div", { style: { ...iconStyle, background: "rgba(234, 179, 8, 0.2)" }, children: "\u26A0\uFE0F" }),
898
+ /* @__PURE__ */ jsx4("h1", { style: styles.title, children: "Link Expired" }),
899
+ /* @__PURE__ */ jsx4("p", { style: { ...styles.subtitle, marginBottom: "1.5rem" }, children: message }),
900
+ /* @__PURE__ */ jsx4(
901
+ "button",
902
+ {
903
+ onClick: onStartOver,
904
+ style: { ...styles.primaryButton, width: "100%" },
905
+ children: "Sign Up Again"
906
+ }
907
+ )
908
+ ] }),
909
+ status === "already_completed" && /* @__PURE__ */ jsxs3("div", { style: { textAlign: "center" }, children: [
910
+ /* @__PURE__ */ jsx4("div", { style: { ...iconStyle, background: "rgba(59, 130, 246, 0.2)" }, children: "\u2713" }),
911
+ /* @__PURE__ */ jsx4("h1", { style: styles.title, children: "Already Verified" }),
912
+ /* @__PURE__ */ jsx4("p", { style: { ...styles.subtitle, marginBottom: "1.5rem" }, children: message }),
913
+ /* @__PURE__ */ jsx4(
914
+ "button",
915
+ {
916
+ onClick: onLogin,
917
+ style: { ...styles.primaryButton, width: "100%" },
918
+ children: "Sign In"
919
+ }
920
+ )
921
+ ] }),
922
+ status === "error" && /* @__PURE__ */ jsxs3("div", { style: { textAlign: "center" }, children: [
923
+ /* @__PURE__ */ jsx4("div", { style: { ...iconStyle, background: "rgba(220, 38, 38, 0.2)" }, children: "\u2717" }),
924
+ /* @__PURE__ */ jsx4("h1", { style: styles.title, children: "Verification Failed" }),
925
+ /* @__PURE__ */ jsx4("p", { style: { ...styles.subtitle, marginBottom: "1.5rem" }, children: message }),
926
+ /* @__PURE__ */ jsx4(
927
+ "button",
928
+ {
929
+ onClick: onStartOver,
930
+ style: { ...styles.primaryButton, width: "100%" },
931
+ children: "Try Again"
932
+ }
933
+ )
934
+ ] })
935
+ ] });
936
+ }
937
+
938
+ // src/client/components/CompleteSignupForm.tsx
939
+ import { useState as useState4, useEffect as useEffect4 } from "react";
940
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
941
+ var GENERIC_DOMAINS = [
942
+ "gmail.com",
943
+ "yahoo.com",
944
+ "hotmail.com",
945
+ "outlook.com",
946
+ "live.com",
947
+ "icloud.com",
948
+ "me.com",
949
+ "mac.com",
950
+ "aol.com",
951
+ "protonmail.com",
952
+ "zoho.com",
953
+ "yandex.com",
954
+ "mail.com",
955
+ "gmx.com",
956
+ "fastmail.com"
957
+ ];
958
+ function isGenericDomain(email) {
959
+ const domain = email.split("@")[1]?.toLowerCase();
960
+ return GENERIC_DOMAINS.includes(domain);
961
+ }
962
+ function extractDomain(email) {
963
+ return email.split("@")[1]?.toLowerCase() || "";
964
+ }
965
+ function suggestOrgName(email) {
966
+ const domain = extractDomain(email);
967
+ const name = domain.split(".")[0];
968
+ return name.charAt(0).toUpperCase() + name.slice(1);
969
+ }
970
+ function suggestSlug(email) {
971
+ const domain = extractDomain(email);
972
+ return domain.split(".")[0].toLowerCase().replace(/[^a-z0-9]/g, "");
973
+ }
974
+ function CompleteSignupForm({
975
+ token,
976
+ email,
977
+ givenName: initialGivenName = "",
978
+ familyName: initialFamilyName = "",
979
+ tenantName: initialOrgName = "",
980
+ redirectUri,
981
+ onSuccess,
982
+ onError,
983
+ appearance
984
+ }) {
985
+ const config = useAuthVitalConfig();
986
+ const styles = getStyles(appearance);
987
+ const [givenName, setGivenName] = useState4(initialGivenName);
988
+ const [familyName, setFamilyName] = useState4(initialFamilyName);
989
+ const [password, setPassword] = useState4("");
990
+ const [confirmPassword, setConfirmPassword] = useState4("");
991
+ const [tenantName, setTenantName] = useState4(initialOrgName || suggestOrgName(email));
992
+ const [slug, setSlug] = useState4(suggestSlug(email));
993
+ const [isLoading, setIsLoading] = useState4(false);
994
+ const [error, setError] = useState4(null);
995
+ const [success, setSuccess] = useState4(false);
996
+ const [slugAvailable, setSlugAvailable] = useState4(null);
997
+ const [checkingSlug, setCheckingSlug] = useState4(false);
998
+ const isGeneric = isGenericDomain(email);
999
+ const domain = extractDomain(email);
1000
+ useEffect4(() => {
1001
+ if (!slug || isGeneric) {
1002
+ setSlugAvailable(null);
1003
+ return;
1004
+ }
1005
+ const timer = setTimeout(async () => {
1006
+ setCheckingSlug(true);
1007
+ try {
1008
+ const response = await fetch(`${config.authVitalHost}/api/tenants/check-slug/${slug}`, {
1009
+ credentials: "include"
1010
+ });
1011
+ if (response.ok) {
1012
+ const result = await response.json();
1013
+ setSlugAvailable(result.available);
1014
+ } else {
1015
+ setSlugAvailable(true);
1016
+ }
1017
+ } catch {
1018
+ setSlugAvailable(true);
1019
+ } finally {
1020
+ setCheckingSlug(false);
1021
+ }
1022
+ }, 500);
1023
+ return () => clearTimeout(timer);
1024
+ }, [slug, isGeneric, config.authVitalHost]);
1025
+ const handleSubmit = async (e) => {
1026
+ e.preventDefault();
1027
+ if (password !== confirmPassword) {
1028
+ setError("Passwords do not match");
1029
+ return;
1030
+ }
1031
+ if (password.length < 8) {
1032
+ setError("Password must be at least 8 characters");
1033
+ return;
1034
+ }
1035
+ if (!isGeneric && !tenantName.trim()) {
1036
+ setError("Organization name is required");
1037
+ return;
1038
+ }
1039
+ setIsLoading(true);
1040
+ setError(null);
1041
+ try {
1042
+ const response = await fetch(`${config.authVitalHost}/api/signup/complete`, {
1043
+ method: "POST",
1044
+ headers: { "Content-Type": "application/json" },
1045
+ credentials: "include",
1046
+ body: JSON.stringify({
1047
+ email,
1048
+ password,
1049
+ token,
1050
+ givenName: givenName || void 0,
1051
+ familyName: familyName || void 0,
1052
+ ...isGeneric ? {} : {
1053
+ tenantName: tenantName.trim(),
1054
+ slug: slug.trim()
1055
+ }
1056
+ })
1057
+ });
1058
+ const result = await response.json();
1059
+ if (!response.ok) {
1060
+ throw new Error(result.message || "Failed to complete signup");
1061
+ }
1062
+ setSuccess(true);
1063
+ onSuccess?.(result);
1064
+ setTimeout(() => {
1065
+ if (result.tenant?.slug && result.initiateLoginUri) {
1066
+ const redirectUrl = result.initiateLoginUri.replace("{tenant}", result.tenant.slug);
1067
+ window.location.href = redirectUrl;
1068
+ } else if (redirectUri) {
1069
+ window.location.href = redirectUri;
1070
+ }
1071
+ }, 2e3);
1072
+ } catch (err) {
1073
+ const error2 = err instanceof Error ? err : new Error("Failed to complete signup");
1074
+ setError(error2.message);
1075
+ onError?.(error2);
1076
+ } finally {
1077
+ setIsLoading(false);
1078
+ }
1079
+ };
1080
+ if (success) {
1081
+ return /* @__PURE__ */ jsx5("div", { style: styles.card, children: /* @__PURE__ */ jsxs4("div", { style: { textAlign: "center" }, children: [
1082
+ /* @__PURE__ */ jsx5("div", { style: {
1083
+ width: "64px",
1084
+ height: "64px",
1085
+ borderRadius: "50%",
1086
+ background: "rgba(22, 163, 74, 0.2)",
1087
+ display: "flex",
1088
+ alignItems: "center",
1089
+ justifyContent: "center",
1090
+ margin: "0 auto 1rem",
1091
+ fontSize: "2rem"
1092
+ }, children: "\u2713" }),
1093
+ /* @__PURE__ */ jsx5("h1", { style: styles.title, children: "Account Created!" }),
1094
+ /* @__PURE__ */ jsx5("p", { style: styles.subtitle, children: "Your account has been created successfully. Redirecting..." }),
1095
+ /* @__PURE__ */ jsx5("div", { style: { marginTop: "1rem" }, children: "\u23F3" })
1096
+ ] }) });
1097
+ }
1098
+ return /* @__PURE__ */ jsxs4("div", { style: styles.card, children: [
1099
+ /* @__PURE__ */ jsxs4("div", { style: styles.header, children: [
1100
+ /* @__PURE__ */ jsx5("h1", { style: styles.title, children: "Complete Your Account" }),
1101
+ /* @__PURE__ */ jsx5("p", { style: { color: "#7c3aed" }, children: email })
1102
+ ] }),
1103
+ /* @__PURE__ */ jsxs4("div", { style: {
1104
+ display: "flex",
1105
+ alignItems: "center",
1106
+ gap: "0.5rem",
1107
+ padding: "0.75rem",
1108
+ marginBottom: "1.5rem",
1109
+ borderRadius: "0.5rem",
1110
+ background: isGeneric ? "rgba(59, 130, 246, 0.1)" : "rgba(124, 58, 237, 0.1)",
1111
+ border: `1px solid ${isGeneric ? "rgba(59, 130, 246, 0.2)" : "rgba(124, 58, 237, 0.2)"}`,
1112
+ color: isGeneric ? "#3b82f6" : "#7c3aed",
1113
+ fontSize: "0.875rem"
1114
+ }, children: [
1115
+ /* @__PURE__ */ jsx5("span", { children: isGeneric ? "\u{1F464}" : "\u{1F3E2}" }),
1116
+ /* @__PURE__ */ jsx5("span", { children: isGeneric ? "Personal account" : `Business account for ${domain}` })
1117
+ ] }),
1118
+ error && /* @__PURE__ */ jsx5("div", { style: styles.error, children: error }),
1119
+ /* @__PURE__ */ jsxs4("form", { onSubmit: handleSubmit, style: styles.form, children: [
1120
+ /* @__PURE__ */ jsxs4("div", { style: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: "1rem" }, children: [
1121
+ /* @__PURE__ */ jsxs4("div", { style: styles.inputGroup, children: [
1122
+ /* @__PURE__ */ jsx5("label", { style: styles.label, children: "First name" }),
1123
+ /* @__PURE__ */ jsx5(
1124
+ "input",
1125
+ {
1126
+ type: "text",
1127
+ value: givenName,
1128
+ onChange: (e) => setGivenName(e.target.value),
1129
+ placeholder: "John",
1130
+ style: styles.input
1131
+ }
1132
+ )
1133
+ ] }),
1134
+ /* @__PURE__ */ jsxs4("div", { style: styles.inputGroup, children: [
1135
+ /* @__PURE__ */ jsx5("label", { style: styles.label, children: "Last name" }),
1136
+ /* @__PURE__ */ jsx5(
1137
+ "input",
1138
+ {
1139
+ type: "text",
1140
+ value: familyName,
1141
+ onChange: (e) => setFamilyName(e.target.value),
1142
+ placeholder: "Doe",
1143
+ style: styles.input
1144
+ }
1145
+ )
1146
+ ] })
1147
+ ] }),
1148
+ !isGeneric && /* @__PURE__ */ jsxs4(Fragment2, { children: [
1149
+ /* @__PURE__ */ jsxs4("div", { style: styles.inputGroup, children: [
1150
+ /* @__PURE__ */ jsx5("label", { style: styles.label, children: "Tenant name" }),
1151
+ /* @__PURE__ */ jsx5(
1152
+ "input",
1153
+ {
1154
+ type: "text",
1155
+ value: tenantName,
1156
+ onChange: (e) => {
1157
+ setTenantName(e.target.value);
1158
+ setSlug(e.target.value.toLowerCase().replace(/[^a-z0-9]/g, ""));
1159
+ },
1160
+ placeholder: "Acme Inc.",
1161
+ required: true,
1162
+ style: styles.input
1163
+ }
1164
+ )
1165
+ ] }),
1166
+ /* @__PURE__ */ jsxs4("div", { style: styles.inputGroup, children: [
1167
+ /* @__PURE__ */ jsx5("label", { style: styles.label, children: "URL slug" }),
1168
+ /* @__PURE__ */ jsxs4("div", { style: { display: "flex", alignItems: "stretch" }, children: [
1169
+ /* @__PURE__ */ jsx5("span", { style: {
1170
+ padding: "0.5rem 0.75rem",
1171
+ background: "rgba(255,255,255,0.05)",
1172
+ border: "1px solid rgba(255,255,255,0.1)",
1173
+ borderRight: "none",
1174
+ borderRadius: "0.5rem 0 0 0.5rem",
1175
+ color: "#9ca3af",
1176
+ fontSize: "0.875rem",
1177
+ display: "flex",
1178
+ alignItems: "center"
1179
+ }, children: "app.example.com/" }),
1180
+ /* @__PURE__ */ jsx5(
1181
+ "input",
1182
+ {
1183
+ type: "text",
1184
+ value: slug,
1185
+ onChange: (e) => setSlug(e.target.value.toLowerCase().replace(/[^a-z0-9-]/g, "")),
1186
+ placeholder: "acme",
1187
+ required: true,
1188
+ style: {
1189
+ ...styles.input,
1190
+ borderRadius: "0 0.5rem 0.5rem 0",
1191
+ flex: 1
1192
+ }
1193
+ }
1194
+ )
1195
+ ] }),
1196
+ checkingSlug && /* @__PURE__ */ jsx5("p", { style: { fontSize: "0.75rem", color: "#9ca3af", marginTop: "0.25rem" }, children: "Checking availability..." }),
1197
+ !checkingSlug && slugAvailable === true && /* @__PURE__ */ jsx5("p", { style: { fontSize: "0.75rem", color: "#16a34a", marginTop: "0.25rem" }, children: "\u2713 Available" }),
1198
+ !checkingSlug && slugAvailable === false && /* @__PURE__ */ jsx5("p", { style: { fontSize: "0.75rem", color: "#dc2626", marginTop: "0.25rem" }, children: "\u2717 Already taken" })
1199
+ ] })
1200
+ ] }),
1201
+ /* @__PURE__ */ jsxs4("div", { style: styles.inputGroup, children: [
1202
+ /* @__PURE__ */ jsx5("label", { style: styles.label, children: "Password" }),
1203
+ /* @__PURE__ */ jsx5(
1204
+ "input",
1205
+ {
1206
+ type: "password",
1207
+ value: password,
1208
+ onChange: (e) => setPassword(e.target.value),
1209
+ placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
1210
+ required: true,
1211
+ minLength: 8,
1212
+ style: styles.input
1213
+ }
1214
+ ),
1215
+ /* @__PURE__ */ jsx5("p", { style: { fontSize: "0.75rem", color: "#9ca3af", marginTop: "0.25rem" }, children: "At least 8 characters" })
1216
+ ] }),
1217
+ /* @__PURE__ */ jsxs4("div", { style: styles.inputGroup, children: [
1218
+ /* @__PURE__ */ jsx5("label", { style: styles.label, children: "Confirm password" }),
1219
+ /* @__PURE__ */ jsx5(
1220
+ "input",
1221
+ {
1222
+ type: "password",
1223
+ value: confirmPassword,
1224
+ onChange: (e) => setConfirmPassword(e.target.value),
1225
+ placeholder: "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022",
1226
+ required: true,
1227
+ style: styles.input
1228
+ }
1229
+ )
1230
+ ] }),
1231
+ /* @__PURE__ */ jsx5(
1232
+ "button",
1233
+ {
1234
+ type: "submit",
1235
+ disabled: isLoading || !isGeneric && slugAvailable === false,
1236
+ style: {
1237
+ ...styles.primaryButton,
1238
+ width: "100%",
1239
+ ...isLoading || !isGeneric && slugAvailable === false ? styles.buttonDisabled : {}
1240
+ },
1241
+ children: isLoading ? "Creating account..." : isGeneric ? "Create Personal Account" : "Create Organization"
1242
+ }
1243
+ )
1244
+ ] })
1245
+ ] });
1246
+ }
1247
+ export {
1248
+ AppAccessEventHandler,
1249
+ AuthVitalEventHandler,
1250
+ AuthVitalProvider,
1251
+ CompleteSignupForm,
1252
+ InviteEventHandler,
1253
+ LicenseEventHandler,
1254
+ MemberEventHandler,
1255
+ ProtectedRoute,
1256
+ SYNC_EVENT_TYPES,
1257
+ SignUpForm,
1258
+ SubjectEventHandler,
1259
+ VerifyEmail,
1260
+ WebhookRouter,
1261
+ AuthVitalWebhooks as WebhookVerifier,
1262
+ captureInviteTokenFromUrl,
1263
+ checkAuthStatus,
1264
+ clearStoredInviteToken,
1265
+ consumeInvitation,
1266
+ createInvitation,
1267
+ decodeJwt,
1268
+ decodeState,
1269
+ encodeState,
1270
+ exchangeCodeForTokens,
1271
+ extractCallbackParams,
1272
+ generateCodeChallenge,
1273
+ generateCodeVerifier,
1274
+ getInvitation,
1275
+ getStoredInviteToken,
1276
+ getStyles,
1277
+ handleCallback,
1278
+ isAppAccessEvent,
1279
+ isInviteEvent,
1280
+ isLicenseEvent,
1281
+ isMemberEvent,
1282
+ isSubjectEvent,
1283
+ listTenantInvitations,
1284
+ loginToAuthVital,
1285
+ logout,
1286
+ revokeInvitation,
1287
+ signupAtAuthVital,
1288
+ startAuthorizationFlow,
1289
+ startLogin,
1290
+ startSignup,
1291
+ storeInviteToken,
1292
+ useAuth,
1293
+ useAuthVitalConfig,
1294
+ useInvitation,
1295
+ useOAuth,
1296
+ useTenant,
1297
+ useTenants,
1298
+ useUser
1299
+ };