@kendevelops/auth-flow-kit 1.2.8 → 1.2.9

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
@@ -34,9 +34,7 @@ var import_react = require("react");
34
34
 
35
35
  // src/http.ts
36
36
  function makeURL(baseURL, path) {
37
- const base = baseURL.replace(/\/$/, "");
38
- const suffix = path.startsWith("/") ? path : `/${path}`;
39
- return `${base}${suffix}`;
37
+ return `${baseURL.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`;
40
38
  }
41
39
  function getStoredAccessToken() {
42
40
  try {
@@ -47,11 +45,8 @@ function getStoredAccessToken() {
47
45
  }
48
46
  function setStoredAccessToken(token) {
49
47
  try {
50
- if (token) {
51
- localStorage.setItem("afk_access_token", token);
52
- return;
53
- }
54
- localStorage.removeItem("afk_access_token");
48
+ if (token) localStorage.setItem("afk_access_token", token);
49
+ else localStorage.removeItem("afk_access_token");
55
50
  } catch {
56
51
  }
57
52
  }
@@ -60,27 +55,20 @@ async function httpJSON(url, opts = {}, withAuth = false) {
60
55
  "Content-Type": "application/json"
61
56
  };
62
57
  if (withAuth) {
63
- const storedToken = getStoredAccessToken();
64
- if (storedToken) {
65
- headers["Authorization"] = `Bearer ${storedToken}`;
66
- }
58
+ const tok = getStoredAccessToken();
59
+ if (tok) headers["Authorization"] = `Bearer ${tok}`;
67
60
  }
68
61
  const res = await fetch(url, {
69
62
  ...opts,
70
- headers: {
71
- ...headers,
72
- ...opts.headers || {}
73
- }
63
+ headers: { ...headers, ...opts.headers || {} }
74
64
  });
75
65
  if (!res.ok) {
76
66
  let message = `Request failed (${res.status})`;
77
67
  const contentType = res.headers.get("content-type") || "";
78
68
  if (contentType.includes("application/json")) {
79
69
  try {
80
- const body = await res.json();
81
- if (body?.message) {
82
- message = body.message;
83
- }
70
+ const data = await res.json();
71
+ if (data?.message) message = data.message;
84
72
  } catch {
85
73
  }
86
74
  }
@@ -200,29 +188,18 @@ function PasswordResetScreen() {
200
188
  const [email, setEmail] = (0, import_react3.useState)("");
201
189
  const [sent, setSent] = (0, import_react3.useState)(false);
202
190
  const [error, setError] = (0, import_react3.useState)(null);
203
- const isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
204
191
  const requestReset = async (e) => {
205
192
  e.preventDefault();
206
193
  setError(null);
207
- const trimmedEmail = email.trim();
208
- if (!trimmedEmail) {
209
- setError("Email is required.");
210
- return;
211
- }
212
- if (!isValidEmail(trimmedEmail)) {
213
- setError("Enter a valid email address.");
214
- return;
215
- }
216
194
  try {
217
195
  const url = makeURL(config.baseURL, config.endpoints.forgot);
218
196
  await httpJSON(url, {
219
197
  method: "POST",
220
- body: JSON.stringify({ email: trimmedEmail })
198
+ body: JSON.stringify({ email })
221
199
  });
222
200
  setSent(true);
223
201
  } catch (err) {
224
- const message = err instanceof Error ? err.message : "Failed to request reset";
225
- setError(message);
202
+ setError(err?.message || "Failed to request reset");
226
203
  }
227
204
  };
228
205
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
@@ -262,7 +239,6 @@ function PasswordResetScreen() {
262
239
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
263
240
  "label",
264
241
  {
265
- htmlFor: "afk-reset-email",
266
242
  style: {
267
243
  position: "absolute",
268
244
  top: sent ? "-18px" : "-10px",
@@ -279,7 +255,6 @@ function PasswordResetScreen() {
279
255
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
280
256
  "input",
281
257
  {
282
- id: "afk-reset-email",
283
258
  value: email,
284
259
  onChange: (e) => setEmail(e.target.value),
285
260
  type: "email",
@@ -342,8 +317,6 @@ function PasswordResetScreen() {
342
317
  error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
343
318
  "p",
344
319
  {
345
- role: "alert",
346
- "aria-live": "polite",
347
320
  style: {
348
321
  marginTop: 20,
349
322
  color: "crimson",
@@ -394,26 +367,15 @@ function LoginScreen() {
394
367
  setError(null);
395
368
  const trimmedEmail = email.trim();
396
369
  const trimmedPassword = password.trim();
397
- if (!trimmedEmail) {
398
- setError("Email is required.");
399
- setSubmitting(false);
400
- return;
401
- }
402
- if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmedEmail)) {
403
- setError("Enter a valid email address.");
404
- setSubmitting(false);
405
- return;
406
- }
407
- if (!trimmedPassword) {
408
- setError("Password is required.");
370
+ if (!trimmedEmail || !trimmedPassword) {
371
+ setError("Email and password cannot be empty.");
409
372
  setSubmitting(false);
410
373
  return;
411
374
  }
412
375
  try {
413
376
  await login(trimmedEmail, trimmedPassword);
414
377
  } catch (err) {
415
- const message = err instanceof Error ? err.message : "Login failed";
416
- setError(message);
378
+ setError(err?.message || "Login failed");
417
379
  } finally {
418
380
  setSubmitting(false);
419
381
  }
@@ -454,7 +416,6 @@ function LoginScreen() {
454
416
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
455
417
  "label",
456
418
  {
457
- htmlFor: "afk-login-email",
458
419
  style: {
459
420
  position: "absolute",
460
421
  top: "-10px",
@@ -471,7 +432,6 @@ function LoginScreen() {
471
432
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
472
433
  "input",
473
434
  {
474
- id: "afk-login-email",
475
435
  value: email,
476
436
  onChange: (e) => setEmail(e.target.value),
477
437
  type: "email",
@@ -501,7 +461,6 @@ function LoginScreen() {
501
461
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
502
462
  "label",
503
463
  {
504
- htmlFor: "afk-login-password",
505
464
  style: {
506
465
  position: "absolute",
507
466
  top: "-10px",
@@ -518,7 +477,6 @@ function LoginScreen() {
518
477
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
519
478
  "input",
520
479
  {
521
- id: "afk-login-password",
522
480
  value: password,
523
481
  onChange: (e) => setPassword(e.target.value),
524
482
  type: "password",
@@ -583,8 +541,6 @@ function LoginScreen() {
583
541
  error && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
584
542
  "p",
585
543
  {
586
- role: "alert",
587
- "aria-live": "polite",
588
544
  style: {
589
545
  marginTop: 18,
590
546
  color: "crimson",
@@ -608,21 +564,8 @@ function SignupScreen() {
608
564
  const [name, setName] = (0, import_react5.useState)("");
609
565
  const [email, setEmail] = (0, import_react5.useState)("");
610
566
  const [password, setPassword] = (0, import_react5.useState)("");
611
- const [confirmPassword, setConfirmPassword] = (0, import_react5.useState)("");
612
567
  const [submitting, setSubmitting] = (0, import_react5.useState)(false);
613
568
  const [error, setError] = (0, import_react5.useState)(null);
614
- const isValidEmail = (value) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
615
- const getPasswordStrength = (value) => {
616
- let score = 0;
617
- if (value.length >= 8) score++;
618
- if (/[A-Z]/.test(value)) score++;
619
- if (/[0-9]/.test(value)) score++;
620
- if (/[^A-Za-z0-9]/.test(value)) score++;
621
- if (!value) return { label: "", color: "" };
622
- if (score <= 1) return { label: "Weak", color: "crimson" };
623
- if (score === 2) return { label: "Medium", color: "#f39c12" };
624
- return { label: "Strong", color: "#2ecc71" };
625
- };
626
569
  const onSubmit = async (e) => {
627
570
  e.preventDefault();
628
571
  setSubmitting(true);
@@ -630,47 +573,15 @@ function SignupScreen() {
630
573
  const trimmedEmail = email.trim();
631
574
  const trimmedPassword = password.trim();
632
575
  const trimmedName = name.trim();
633
- const trimmedConfirm = confirmPassword.trim();
634
- if (!trimmedName) {
635
- setError("Name is required.");
636
- setSubmitting(false);
637
- return;
638
- }
639
- if (!trimmedEmail) {
640
- setError("Email is required.");
641
- setSubmitting(false);
642
- return;
643
- }
644
- if (!isValidEmail(trimmedEmail)) {
645
- setError("Enter a valid email address.");
646
- setSubmitting(false);
647
- return;
648
- }
649
- if (!trimmedPassword) {
650
- setError("Password is required.");
651
- setSubmitting(false);
652
- return;
653
- }
654
- if (trimmedPassword.length < 8) {
655
- setError("Password must be at least 8 characters long.");
656
- setSubmitting(false);
657
- return;
658
- }
659
- if (!trimmedConfirm) {
660
- setError("Please confirm your password.");
661
- setSubmitting(false);
662
- return;
663
- }
664
- if (trimmedPassword !== trimmedConfirm) {
665
- setError("Passwords do not match.");
576
+ if (!trimmedEmail || !trimmedPassword || !trimmedName) {
577
+ setError("Email and password cannot be empty.");
666
578
  setSubmitting(false);
667
579
  return;
668
580
  }
669
581
  try {
670
- await signup({ name: trimmedName, email: trimmedEmail, password: trimmedPassword });
582
+ await signup({ name, email, password });
671
583
  } catch (err) {
672
- const message = err instanceof Error ? err.message : "Signup failed";
673
- setError(message);
584
+ setError(err?.message || "Signup failed");
674
585
  } finally {
675
586
  setSubmitting(false);
676
587
  }
@@ -712,7 +623,6 @@ function SignupScreen() {
712
623
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
713
624
  "label",
714
625
  {
715
- htmlFor: "afk-signup-name",
716
626
  style: {
717
627
  position: "absolute",
718
628
  top: "-10px",
@@ -729,7 +639,6 @@ function SignupScreen() {
729
639
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
730
640
  "input",
731
641
  {
732
- id: "afk-signup-name",
733
642
  value: name,
734
643
  onChange: (e) => setName(e.target.value),
735
644
  placeholder: "Your name",
@@ -758,7 +667,6 @@ function SignupScreen() {
758
667
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
759
668
  "label",
760
669
  {
761
- htmlFor: "afk-signup-email",
762
670
  style: {
763
671
  position: "absolute",
764
672
  top: "-10px",
@@ -775,7 +683,6 @@ function SignupScreen() {
775
683
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
776
684
  "input",
777
685
  {
778
- id: "afk-signup-email",
779
686
  value: email,
780
687
  onChange: (e) => setEmail(e.target.value),
781
688
  type: "email",
@@ -805,7 +712,6 @@ function SignupScreen() {
805
712
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
806
713
  "label",
807
714
  {
808
- htmlFor: "afk-signup-password",
809
715
  style: {
810
716
  position: "absolute",
811
717
  top: "-10px",
@@ -822,7 +728,6 @@ function SignupScreen() {
822
728
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
823
729
  "input",
824
730
  {
825
- id: "afk-signup-password",
826
731
  value: password,
827
732
  onChange: (e) => setPassword(e.target.value),
828
733
  type: "password",
@@ -848,95 +753,6 @@ function SignupScreen() {
848
753
  }
849
754
  )
850
755
  ] }),
851
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { position: "relative", marginBottom: 18 }, children: [
852
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
853
- "label",
854
- {
855
- htmlFor: "afk-signup-confirm-password",
856
- style: {
857
- position: "absolute",
858
- top: "-10px",
859
- left: "14px",
860
- background: "rgba(255,255,255,0.85)",
861
- padding: "0 6px",
862
- fontSize: 13,
863
- color: "#444",
864
- borderRadius: 6
865
- },
866
- children: "Confirm password"
867
- }
868
- ),
869
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
870
- "input",
871
- {
872
- id: "afk-signup-confirm-password",
873
- value: confirmPassword,
874
- onChange: (e) => setConfirmPassword(e.target.value),
875
- type: "password",
876
- placeholder: "Repeat your password",
877
- style: {
878
- width: "80%",
879
- padding: "14px 16px",
880
- borderRadius: 12,
881
- border: "1px solid #d2d2d2",
882
- fontSize: 15,
883
- outline: "none",
884
- transition: "0.25s",
885
- background: "rgba(255,255,255,0.85)"
886
- },
887
- onFocus: (e) => {
888
- e.currentTarget.style.border = "1px solid #4b4bff";
889
- e.currentTarget.style.boxShadow = "0 0 0 3px rgba(75,75,255,0.25)";
890
- },
891
- onBlur: (e) => {
892
- e.currentTarget.style.border = "1px solid #d2d2d2";
893
- e.currentTarget.style.boxShadow = "0 0 0 transparent";
894
- }
895
- }
896
- )
897
- ] }),
898
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
899
- "div",
900
- {
901
- style: {
902
- marginBottom: 20,
903
- fontSize: 12,
904
- color: "#555"
905
- },
906
- children: [
907
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { style: { marginBottom: 6 }, children: "Use at least 8 characters, including letters, numbers, and symbols." }),
908
- password && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
909
- "p",
910
- {
911
- style: {
912
- fontWeight: 600,
913
- color: getPasswordStrength(password).color
914
- },
915
- children: [
916
- "Password strength: ",
917
- getPasswordStrength(password).label
918
- ]
919
- }
920
- )
921
- ]
922
- }
923
- ),
924
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
925
- "p",
926
- {
927
- style: {
928
- textAlign: "center",
929
- fontSize: 13,
930
- color: "#4b4bff",
931
- cursor: "pointer",
932
- marginBottom: 24
933
- },
934
- onClick: () => {
935
- window.dispatchEvent(new CustomEvent("auth-flow-kit:navigate-to-login"));
936
- },
937
- children: "Already have an account? Sign in"
938
- }
939
- ),
940
756
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
941
757
  "button",
942
758
  {
@@ -962,8 +778,6 @@ function SignupScreen() {
962
778
  error && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
963
779
  "p",
964
780
  {
965
- role: "alert",
966
- "aria-live": "polite",
967
781
  style: {
968
782
  marginTop: 18,
969
783
  color: "crimson",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/AuthContext.tsx","../src/http.ts","../src/Protected.tsx","../src/screens/LoginScreen.tsx","../src/screens/PasswordResetScreen.tsx","../src/screens/SignupScreen.tsx"],"sourcesContent":["export { AuthProvider, useAuth } from \"./AuthContext\";\r\nexport { default as Protected } from \"./Protected\";\r\n\r\n// Screens\r\nexport { default as LoginScreen } from \"./screens/LoginScreen\";\r\nexport { default as SignupScreen } from \"./screens/SignupScreen\";\r\nexport { default as PasswordResetScreen } from \"./screens/PasswordResetScreen\";\r\n\r\n// Types\r\nexport * from \"./types\";\r\n","/* \r\nDevelopers using this library should wrap their app with:\r\n <AuthProvider config={...}>\r\n <App />\r\n </AuthProvider>\r\n \r\n When they do this, then can be able to access auth anywhere with:\r\n const { user, login, logout, getToken } = useAuth();\r\n*/\r\n\r\nimport React, {\r\n createContext,\r\n useContext,\r\n useEffect,\r\n useMemo,\r\n useState,\r\n} from \"react\";\r\n\r\nimport {\r\n AuthContextType,\r\n AuthProviderConfig,\r\n StandardAuthResponse,\r\n User,\r\n} from \"./types\";\r\n\r\nimport {\r\n httpJSON,\r\n makeURL,\r\n setStoredAccessToken,\r\n getStoredAccessToken,\r\n} from \"./http\";\r\n\r\nconst AuthContext = createContext<AuthContextType | undefined>(undefined);\r\n\r\nexport function useAuth(): AuthContextType {\r\n const ctx = useContext(AuthContext);\r\n if (!ctx) throw new Error(\"useAuth must be used inside AuthProvider\");\r\n return ctx;\r\n}\r\n\r\nexport function AuthProvider({\r\n config,\r\n children,\r\n}: React.PropsWithChildren<{ config: AuthProviderConfig }>) {\r\n const { baseURL, endpoints, onLoginSuccess, onLogout } = config;\r\n\r\n const [user, setUser] = useState<User | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n\r\n const getToken = () => getStoredAccessToken();\r\n\r\n // Restore user from localStorage on app load\r\n useEffect(() => {\r\n const savedUser = localStorage.getItem(\"afk_user\");\r\n if (savedUser) {\r\n setUser(JSON.parse(savedUser));\r\n }\r\n setLoading(false);\r\n }, []);\r\n\r\n // LOGIN\r\n const login: AuthContextType[\"login\"] = async (email, password) => {\r\n const url = makeURL(baseURL, endpoints.login);\r\n\r\n const res = await httpJSON<StandardAuthResponse>(url, {\r\n method: \"POST\",\r\n body: JSON.stringify({ email, password }),\r\n });\r\n\r\n // store token + user\r\n setStoredAccessToken(res.accessToken);\r\n localStorage.setItem(\"afk_user\", JSON.stringify(res.user));\r\n\r\n setUser(res.user);\r\n\r\n if (onLoginSuccess) onLoginSuccess();\r\n };\r\n\r\n // SIGNUP\r\n const signup: AuthContextType[\"signup\"] = async (payload) => {\r\n const url = makeURL(baseURL, endpoints.signup);\r\n\r\n const res = await httpJSON<StandardAuthResponse>(url, {\r\n method: \"POST\",\r\n body: JSON.stringify(payload),\r\n });\r\n\r\n setStoredAccessToken(res.accessToken);\r\n localStorage.setItem(\"afk_user\", JSON.stringify(res.user));\r\n\r\n setUser(res.user);\r\n\r\n if (onLoginSuccess) onLoginSuccess();\r\n };\r\n\r\n // LOGOUT\r\n const logout = () => {\r\n setStoredAccessToken(null);\r\n localStorage.removeItem(\"afk_user\");\r\n setUser(null);\r\n\r\n if (onLogout) onLogout();\r\n };\r\n\r\n const value = useMemo<AuthContextType>(\r\n () => ({\r\n user,\r\n loading,\r\n login,\r\n signup,\r\n logout,\r\n getToken,\r\n config,\r\n }),\r\n [user, loading, config],\r\n );\r\n\r\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\r\n}\r\n","/*\r\n This file contains the low-level HTTP utilities used internally by\r\n auth-flow-kit to communicate with the backend.\r\n\r\n It provides:\r\n - makeURL: safely joins baseURL + endpoint path\r\n - getStoredAccessToken: reads the JWT from localStorage\r\n - setStoredAccessToken: stores/removes the JWT\r\n - httpJSON: wrapper around fetch with JSON + optional auth header\r\n\r\n NOTES FOR DEVELOPERS USING THE LIBRARY:\r\n You do NOT need to import or modify anything in this file.\r\n It is an internal helper used by the AuthProvider and auth screens.\r\n\r\n This keeps the library lightweight, predictable,\r\n and familiar to developers used to Redux Toolkit-style authentication.\r\n*/\r\n\r\nexport function makeURL(baseURL: string, path: string) {\r\n const base = baseURL.replace(/\\/$/, \"\");\r\n const suffix = path.startsWith(\"/\") ? path : `/${path}`;\r\n\r\n return `${base}${suffix}`;\r\n}\r\n\r\nexport function getStoredAccessToken(): string | null {\r\n try {\r\n return localStorage.getItem(\"afk_access_token\");\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function setStoredAccessToken(token: string | null) {\r\n try {\r\n if (token) {\r\n localStorage.setItem(\"afk_access_token\", token);\r\n return;\r\n }\r\n\r\n localStorage.removeItem(\"afk_access_token\");\r\n } catch {\r\n // Storage may be unavailable (private mode, browser restrictions, etc.)\r\n }\r\n}\r\n\r\nexport async function httpJSON<T>(\r\n url: string,\r\n opts: RequestInit = {},\r\n withAuth = false,\r\n): Promise<T> {\r\n const headers: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n };\r\n\r\n if (withAuth) {\r\n const storedToken = getStoredAccessToken();\r\n if (storedToken) {\r\n headers[\"Authorization\"] = `Bearer ${storedToken}`;\r\n }\r\n }\r\n\r\n const res = await fetch(url, {\r\n ...opts,\r\n headers: {\r\n ...headers,\r\n ...(opts.headers || {}),\r\n },\r\n });\r\n\r\n if (!res.ok) {\r\n let message = `Request failed (${res.status})`;\r\n const contentType = res.headers.get(\"content-type\") || \"\";\r\n\r\n if (contentType.includes(\"application/json\")) {\r\n try {\r\n const body = await res.json();\r\n if (body?.message) {\r\n message = body.message;\r\n }\r\n } catch {\r\n // ignore malformed JSON responses\r\n }\r\n }\r\n\r\n if (contentType.includes(\"text/html\")) {\r\n if (res.status === 404 && url.includes(\"forgot\")) {\r\n message =\r\n \"The forgot password endpoint you added in config.endpoints.forgot does not exist in your server. Please check and update your config.endpoints.forgot\";\r\n } else {\r\n message = \"Unexpected server error\";\r\n }\r\n }\r\n\r\n if (res.status === 404 && url.includes(\"forgot\")) {\r\n console.error(\r\n `[auth-flow-kit] Password reset endpoint not found.\r\n\r\n Expected a POST route matching:\r\n ${url}\r\n\r\n Fix this by either:\r\n - Adding the route on your backend, or\r\n - Updating config.endpoints.forgot`,\r\n );\r\n }\r\n\r\n throw new Error(message);\r\n }\r\n\r\n return res.json() as Promise<T>;\r\n}\r\n","\"use client\";\r\n\r\n/*\r\nProtected component\r\n\r\nWraps authenticated content and prevents rendering when unauthenticated.\r\n\r\nIMPORTANT:\r\nThis component does NOT hard-redirect by default.\r\nNavigation should be handled by the host application (router or state).\r\n\r\nIf redirectTo is provided AND the host app supports routing,\r\na redirect will occur.\r\n*/\r\n\r\nimport React, { useEffect } from \"react\";\r\nimport { useAuth } from \"./AuthContext\";\r\n\r\ntype ProtectedProps = {\r\n children: React.ReactNode;\r\n redirectTo?: string;\r\n};\r\n\r\nexport default function Protected({ children, redirectTo }: ProtectedProps) {\r\n const { user, loading } = useAuth();\r\n\r\n useEffect(() => {\r\n if (!loading && !user && redirectTo) {\r\n window.location.href = redirectTo;\r\n }\r\n }, [loading, user, redirectTo]);\r\n\r\n if (loading) return <div>Loading...</div>;\r\n if (!user) return null;\r\n\r\n return <>{children}</>;\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\nimport PasswordResetScreen from \"./PasswordResetScreen\";\r\n\r\nexport default function LoginScreen() {\r\n const { login } = useAuth();\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [submitting, setSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [showReset, setShowReset] = useState(false);\r\n\r\n if (showReset) {\r\n return (\r\n <div style={{ animation: \"fade .2s\" }}>\r\n <PasswordResetScreen />\r\n <p\r\n onClick={() => setShowReset(false)}\r\n style={{\r\n marginTop: 16,\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n textDecoration: \"underline\",\r\n }}\r\n >\r\n Back to login\r\n </p>\r\n </div>\r\n );\r\n }\r\n\r\n // Submit\r\n const onSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setSubmitting(true);\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n const trimmedPassword = password.trim();\r\n\r\n if (!trimmedEmail) {\r\n setError(\"Email is required.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(trimmedEmail)) {\r\n setError(\"Enter a valid email address.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n if (!trimmedPassword) {\r\n setError(\"Password is required.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await login(trimmedEmail, trimmedPassword);\r\n } catch (err: unknown) {\r\n const message = err instanceof Error ? err.message : \"Login failed\";\r\n setError(message);\r\n } finally {\r\n setSubmitting(false);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={onSubmit}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.3s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Welcome Back 👋\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n htmlFor=\"afk-login-email\"\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.8)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n id=\"afk-login-email\"\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 10 }}>\r\n <label\r\n htmlFor=\"afk-login-password\"\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.8)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Password\r\n </label>\r\n\r\n <input\r\n id=\"afk-login-password\"\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"••••••••\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <p\r\n onClick={() => setShowReset(true)}\r\n style={{\r\n textAlign: \"right\",\r\n fontSize: 13,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n marginBottom: 24,\r\n }}\r\n >\r\n Forgot password?\r\n </p>\r\n\r\n <button\r\n disabled={submitting}\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n\r\n background: submitting\r\n ? \"linear-gradient(90deg, #b2bdfd, #8da0ff)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.25s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {submitting ? \"Signing in...\" : \"Sign in\"}\r\n </button>\r\n\r\n {error && (\r\n <p\r\n role=\"alert\"\r\n aria-live=\"polite\"\r\n style={{\r\n marginTop: 18,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\nimport { httpJSON, makeURL } from \"../http\";\r\n\r\nexport default function PasswordResetScreen() {\r\n const { config } = useAuth();\r\n\r\n const [email, setEmail] = useState(\"\");\r\n const [sent, setSent] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const isValidEmail = (value: string) =>\r\n /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value);\r\n\r\n const requestReset = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n\r\n if (!trimmedEmail) {\r\n setError(\"Email is required.\");\r\n return;\r\n }\r\n\r\n if (!isValidEmail(trimmedEmail)) {\r\n setError(\"Enter a valid email address.\");\r\n return;\r\n }\r\n\r\n try {\r\n const url = makeURL(config.baseURL, config.endpoints.forgot);\r\n\r\n await httpJSON(url, {\r\n method: \"POST\",\r\n body: JSON.stringify({ email: trimmedEmail }),\r\n });\r\n\r\n setSent(true);\r\n } catch (err: unknown) {\r\n const message =\r\n err instanceof Error ? err.message : \"Failed to request reset\";\r\n setError(message);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={requestReset}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n // GLASS EFFECT\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.25s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Reset Password 🔑\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n htmlFor=\"afk-reset-email\"\r\n style={{\r\n position: \"absolute\",\r\n top: sent ? \"-18px\" : \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n id=\"afk-reset-email\"\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"90%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <button\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n\r\n background: sent\r\n ? \"linear-gradient(90deg, #7aff9d, #34c759)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.3s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {sent ? \"Link Sent ✔\" : \"Send reset link\"}\r\n </button>\r\n\r\n {sent && (\r\n <p\r\n style={{\r\n marginTop: 20,\r\n color: \"#2ecc71\",\r\n textAlign: \"center\",\r\n fontSize: 15,\r\n fontWeight: 600,\r\n }}\r\n >\r\n Check your email for reset instructions.\r\n </p>\r\n )}\r\n\r\n {error && (\r\n <p\r\n role=\"alert\"\r\n aria-live=\"polite\"\r\n style={{\r\n marginTop: 20,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\n\r\nexport default function SignupScreen() {\r\n const { signup } = useAuth();\r\n const [name, setName] = useState(\"\");\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [confirmPassword, setConfirmPassword] = useState(\"\");\r\n const [submitting, setSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const isValidEmail = (value: string) =>\r\n /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value);\r\n\r\n const getPasswordStrength = (value: string) => {\r\n let score = 0;\r\n if (value.length >= 8) score++;\r\n if (/[A-Z]/.test(value)) score++;\r\n if (/[0-9]/.test(value)) score++;\r\n if (/[^A-Za-z0-9]/.test(value)) score++;\r\n\r\n if (!value) return { label: \"\", color: \"\" };\r\n if (score <= 1) return { label: \"Weak\", color: \"crimson\" };\r\n if (score === 2) return { label: \"Medium\", color: \"#f39c12\" };\r\n return { label: \"Strong\", color: \"#2ecc71\" };\r\n };\r\n\r\n const onSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setSubmitting(true);\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n const trimmedPassword = password.trim();\r\n const trimmedName = name.trim();\r\n const trimmedConfirm = confirmPassword.trim();\r\n\r\n if (!trimmedName) {\r\n setError(\"Name is required.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n if (!trimmedEmail) {\r\n setError(\"Email is required.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n if (!isValidEmail(trimmedEmail)) {\r\n setError(\"Enter a valid email address.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n if (!trimmedPassword) {\r\n setError(\"Password is required.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n if (trimmedPassword.length < 8) {\r\n setError(\"Password must be at least 8 characters long.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n if (!trimmedConfirm) {\r\n setError(\"Please confirm your password.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n if (trimmedPassword !== trimmedConfirm) {\r\n setError(\"Passwords do not match.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await signup({ name: trimmedName, email: trimmedEmail, password: trimmedPassword });\r\n } catch (err: unknown) {\r\n const message = err instanceof Error ? err.message : \"Signup failed\";\r\n setError(message);\r\n } finally {\r\n setSubmitting(false);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={onSubmit}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n // GLASS EFFECT\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.3s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Create Account ✨\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n htmlFor=\"afk-signup-name\"\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Name\r\n </label>\r\n\r\n <input\r\n id=\"afk-signup-name\"\r\n value={name}\r\n onChange={(e) => setName(e.target.value)}\r\n placeholder=\"Your name\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n htmlFor=\"afk-signup-email\"\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n id=\"afk-signup-email\"\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n htmlFor=\"afk-signup-password\"\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Password\r\n </label>\r\n\r\n <input\r\n id=\"afk-signup-password\"\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"••••••••\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 18 }}>\r\n <label\r\n htmlFor=\"afk-signup-confirm-password\"\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Confirm password\r\n </label>\r\n\r\n <input\r\n id=\"afk-signup-confirm-password\"\r\n value={confirmPassword}\r\n onChange={(e) => setConfirmPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"Repeat your password\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div\r\n style={{\r\n marginBottom: 20,\r\n fontSize: 12,\r\n color: \"#555\",\r\n }}\r\n >\r\n <p style={{ marginBottom: 6 }}>\r\n Use at least 8 characters, including letters, numbers, and symbols.\r\n </p>\r\n {password && (\r\n <p\r\n style={{\r\n fontWeight: 600,\r\n color: getPasswordStrength(password).color,\r\n }}\r\n >\r\n Password strength: {getPasswordStrength(password).label}\r\n </p>\r\n )}\r\n </div>\r\n\r\n <p\r\n style={{\r\n textAlign: \"center\",\r\n fontSize: 13,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n marginBottom: 24,\r\n }}\r\n onClick={() => {\r\n // This allows parent components to handle navigation\r\n // Developers can override this behavior in their app\r\n window.dispatchEvent(new CustomEvent(\"auth-flow-kit:navigate-to-login\"));\r\n }}\r\n >\r\n Already have an account? Sign in\r\n </p>\r\n\r\n <button\r\n disabled={submitting}\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n background: submitting\r\n ? \"linear-gradient(90deg, #b2bdfd, #8da0ff)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.25s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {submitting ? \"Creating...\" : \"Create account\"}\r\n </button>\r\n\r\n {error && (\r\n <p\r\n role=\"alert\"\r\n aria-live=\"polite\"\r\n style={{\r\n marginTop: 18,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACUA,mBAMO;;;ACEA,SAAS,QAAQ,SAAiB,MAAc;AACrD,QAAM,OAAO,QAAQ,QAAQ,OAAO,EAAE;AACtC,QAAM,SAAS,KAAK,WAAW,GAAG,IAAI,OAAO,IAAI,IAAI;AAErD,SAAO,GAAG,IAAI,GAAG,MAAM;AACzB;AAEO,SAAS,uBAAsC;AACpD,MAAI;AACF,WAAO,aAAa,QAAQ,kBAAkB;AAAA,EAChD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,qBAAqB,OAAsB;AACzD,MAAI;AACF,QAAI,OAAO;AACT,mBAAa,QAAQ,oBAAoB,KAAK;AAC9C;AAAA,IACF;AAEA,iBAAa,WAAW,kBAAkB;AAAA,EAC5C,QAAQ;AAAA,EAER;AACF;AAEA,eAAsB,SACpB,KACA,OAAoB,CAAC,GACrB,WAAW,OACC;AACZ,QAAM,UAAkC;AAAA,IACtC,gBAAgB;AAAA,EAClB;AAEA,MAAI,UAAU;AACZ,UAAM,cAAc,qBAAqB;AACzC,QAAI,aAAa;AACf,cAAQ,eAAe,IAAI,UAAU,WAAW;AAAA,IAClD;AAAA,EACF;AAEA,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,GAAG;AAAA,IACH,SAAS;AAAA,MACP,GAAG;AAAA,MACH,GAAI,KAAK,WAAW,CAAC;AAAA,IACvB;AAAA,EACF,CAAC;AAED,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,UAAU,mBAAmB,IAAI,MAAM;AAC3C,UAAM,cAAc,IAAI,QAAQ,IAAI,cAAc,KAAK;AAEvD,QAAI,YAAY,SAAS,kBAAkB,GAAG;AAC5C,UAAI;AACF,cAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,YAAI,MAAM,SAAS;AACjB,oBAAU,KAAK;AAAA,QACjB;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,QAAI,YAAY,SAAS,WAAW,GAAG;AACrC,UAAI,IAAI,WAAW,OAAO,IAAI,SAAS,QAAQ,GAAG;AAChD,kBACE;AAAA,MACJ,OAAO;AACL,kBAAU;AAAA,MACZ;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,OAAO,IAAI,SAAS,QAAQ,GAAG;AAChD,cAAQ;AAAA,QACN;AAAA;AAAA;AAAA,YAGI,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA,MAKT;AAAA,IACF;AAEA,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AAEA,SAAO,IAAI,KAAK;AAClB;;;ADMS;AArFT,IAAM,kBAAc,4BAA2C,MAAS;AAEjE,SAAS,UAA2B;AACzC,QAAM,UAAM,yBAAW,WAAW;AAClC,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,0CAA0C;AACpE,SAAO;AACT;AAEO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AACF,GAA4D;AAC1D,QAAM,EAAE,SAAS,WAAW,gBAAgB,SAAS,IAAI;AAEzD,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAsB,IAAI;AAClD,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,IAAI;AAE3C,QAAM,WAAW,MAAM,qBAAqB;AAG5C,8BAAU,MAAM;AACd,UAAM,YAAY,aAAa,QAAQ,UAAU;AACjD,QAAI,WAAW;AACb,cAAQ,KAAK,MAAM,SAAS,CAAC;AAAA,IAC/B;AACA,eAAW,KAAK;AAAA,EAClB,GAAG,CAAC,CAAC;AAGL,QAAM,QAAkC,OAAO,OAAO,aAAa;AACjE,UAAM,MAAM,QAAQ,SAAS,UAAU,KAAK;AAE5C,UAAM,MAAM,MAAM,SAA+B,KAAK;AAAA,MACpD,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,CAAC;AAAA,IAC1C,CAAC;AAGD,yBAAqB,IAAI,WAAW;AACpC,iBAAa,QAAQ,YAAY,KAAK,UAAU,IAAI,IAAI,CAAC;AAEzD,YAAQ,IAAI,IAAI;AAEhB,QAAI,eAAgB,gBAAe;AAAA,EACrC;AAGA,QAAM,SAAoC,OAAO,YAAY;AAC3D,UAAM,MAAM,QAAQ,SAAS,UAAU,MAAM;AAE7C,UAAM,MAAM,MAAM,SAA+B,KAAK;AAAA,MACpD,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,OAAO;AAAA,IAC9B,CAAC;AAED,yBAAqB,IAAI,WAAW;AACpC,iBAAa,QAAQ,YAAY,KAAK,UAAU,IAAI,IAAI,CAAC;AAEzD,YAAQ,IAAI,IAAI;AAEhB,QAAI,eAAgB,gBAAe;AAAA,EACrC;AAGA,QAAM,SAAS,MAAM;AACnB,yBAAqB,IAAI;AACzB,iBAAa,WAAW,UAAU;AAClC,YAAQ,IAAI;AAEZ,QAAI,SAAU,UAAS;AAAA,EACzB;AAEA,QAAM,YAAQ;AAAA,IACZ,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,CAAC,MAAM,SAAS,MAAM;AAAA,EACxB;AAEA,SAAO,4CAAC,YAAY,UAAZ,EAAqB,OAAe,UAAS;AACvD;;;AEvGA,IAAAA,gBAAiC;AAiBX,IAAAC,sBAAA;AATP,SAAR,UAA2B,EAAE,UAAU,WAAW,GAAmB;AAC1E,QAAM,EAAE,MAAM,QAAQ,IAAI,QAAQ;AAElC,+BAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,QAAQ,YAAY;AACnC,aAAO,SAAS,OAAO;AAAA,IACzB;AAAA,EACF,GAAG,CAAC,SAAS,MAAM,UAAU,CAAC;AAE9B,MAAI,QAAS,QAAO,6CAAC,SAAI,wBAAU;AACnC,MAAI,CAAC,KAAM,QAAO;AAElB,SAAO,6EAAG,UAAS;AACrB;;;ACnCA,IAAAC,gBAAgC;;;ACAhC,IAAAC,gBAAgC;AAkE1B,IAAAC,sBAAA;AA9DS,SAAR,sBAAuC;AAC5C,QAAM,EAAE,OAAO,IAAI,QAAQ;AAE3B,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAS,KAAK;AACtC,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AAEtD,QAAM,eAAe,CAAC,UACpB,6BAA6B,KAAK,KAAK;AAEzC,QAAM,eAAe,OAAO,MAAuB;AACjD,MAAE,eAAe;AACjB,aAAS,IAAI;AAEb,UAAM,eAAe,MAAM,KAAK;AAEhC,QAAI,CAAC,cAAc;AACjB,eAAS,oBAAoB;AAC7B;AAAA,IACF;AAEA,QAAI,CAAC,aAAa,YAAY,GAAG;AAC/B,eAAS,8BAA8B;AACvC;AAAA,IACF;AAEA,QAAI;AACF,YAAM,MAAM,QAAQ,OAAO,SAAS,OAAO,UAAU,MAAM;AAE3D,YAAM,SAAS,KAAK;AAAA,QAClB,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU,EAAE,OAAO,aAAa,CAAC;AAAA,MAC9C,CAAC;AAED,cAAQ,IAAI;AAAA,IACd,SAAS,KAAc;AACrB,YAAM,UACJ,eAAe,QAAQ,IAAI,UAAU;AACvC,eAAS,OAAO;AAAA,IAClB;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,UAAU;AAAA,MACV,OAAO;AAAA,QACL,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd,YAAY;AAAA;AAAA,QAGZ,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,sBAAsB;AAAA,QAEtB,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,WAAW;AAAA,MACb;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,cAAc;AAAA,cACd,OAAO;AAAA,cACP,YAAY;AAAA,cACZ,UAAU;AAAA,cACV,WAAW;AAAA,cACX,eAAe;AAAA,YACjB;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK,OAAO,UAAU;AAAA,gBACtB,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,cACxC,MAAK;AAAA,cACL,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAO;AAAA,cACL,OAAO;AAAA,cACP,SAAS;AAAA,cACT,cAAc;AAAA,cAEd,YAAY,OACR,6CACA;AAAA,cAEJ,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,eAAe;AAAA,cACf,QAAQ;AAAA,cACR,YAAY;AAAA,cACZ,WAAW;AAAA,YACb;AAAA,YAEC,iBAAO,qBAAgB;AAAA;AAAA,QAC1B;AAAA,QAEC,QACC;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,WAAW;AAAA,cACX,OAAO;AAAA,cACP,WAAW;AAAA,cACX,UAAU;AAAA,cACV,YAAY;AAAA,YACd;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QAGD,SACC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,aAAU;AAAA,YACV,OAAO;AAAA,cACL,WAAW;AAAA,cACX,OAAO;AAAA,cACP,WAAW;AAAA,cACX,UAAU;AAAA,cACV,YAAY;AAAA,YACd;AAAA,YAEC;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;ADpKM,IAAAC,sBAAA;AAVS,SAAR,cAA+B;AACpC,QAAM,EAAE,MAAM,IAAI,QAAQ;AAC1B,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAS,EAAE;AAC3C,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,KAAK;AAClD,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AACtD,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,KAAK;AAEhD,MAAI,WAAW;AACb,WACE,8CAAC,SAAI,OAAO,EAAE,WAAW,WAAW,GAClC;AAAA,mDAAC,uBAAoB;AAAA,MACrB;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,MAAM,aAAa,KAAK;AAAA,UACjC,OAAO;AAAA,YACL,WAAW;AAAA,YACX,WAAW;AAAA,YACX,UAAU;AAAA,YACV,OAAO;AAAA,YACP,QAAQ;AAAA,YACR,gBAAgB;AAAA,UAClB;AAAA,UACD;AAAA;AAAA,MAED;AAAA,OACF;AAAA,EAEJ;AAGA,QAAM,WAAW,OAAO,MAAuB;AAC7C,MAAE,eAAe;AACjB,kBAAc,IAAI;AAClB,aAAS,IAAI;AAEb,UAAM,eAAe,MAAM,KAAK;AAChC,UAAM,kBAAkB,SAAS,KAAK;AAEtC,QAAI,CAAC,cAAc;AACjB,eAAS,oBAAoB;AAC7B,oBAAc,KAAK;AACnB;AAAA,IACF;AAEA,QAAI,CAAC,6BAA6B,KAAK,YAAY,GAAG;AACpD,eAAS,8BAA8B;AACvC,oBAAc,KAAK;AACnB;AAAA,IACF;AAEA,QAAI,CAAC,iBAAiB;AACpB,eAAS,uBAAuB;AAChC,oBAAc,KAAK;AACnB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,MAAM,cAAc,eAAe;AAAA,IAC3C,SAAS,KAAc;AACrB,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,eAAS,OAAO;AAAA,IAClB,UAAE;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd,YAAY;AAAA,QAEZ,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,sBAAsB;AAAA,QAEtB,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,WAAW;AAAA,MACb;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,cAAc;AAAA,cACd,OAAO;AAAA,cACP,YAAY;AAAA,cACZ,UAAU;AAAA,cACV,WAAW;AAAA,cACX,eAAe;AAAA,YACjB;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,cACxC,MAAK;AAAA,cACL,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA,cAC3C,MAAK;AAAA,cACL,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,MAAM,aAAa,IAAI;AAAA,YAChC,OAAO;AAAA,cACL,WAAW;AAAA,cACX,UAAU;AAAA,cACV,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,cAAc;AAAA,YAChB;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,UAAU;AAAA,YACV,MAAK;AAAA,YACL,OAAO;AAAA,cACL,OAAO;AAAA,cACP,SAAS;AAAA,cACT,cAAc;AAAA,cAEd,YAAY,aACR,6CACA;AAAA,cAEJ,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,eAAe;AAAA,cACf,QAAQ;AAAA,cACR,YAAY;AAAA,cACZ,WAAW;AAAA,YACb;AAAA,YAEC,uBAAa,kBAAkB;AAAA;AAAA,QAClC;AAAA,QAEC,SACC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,aAAU;AAAA,YACV,OAAO;AAAA,cACL,WAAW;AAAA,cACX,OAAO;AAAA,cACP,WAAW;AAAA,cACX,UAAU;AAAA,cACV,YAAY;AAAA,YACd;AAAA,YAEC;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AErPA,IAAAC,gBAAgC;AA8G1B,IAAAC,sBAAA;AA3GS,SAAR,eAAgC;AACrC,QAAM,EAAE,OAAO,IAAI,QAAQ;AAC3B,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAS,EAAE;AACnC,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,QAAM,CAAC,UAAU,WAAW,QAAI,wBAAS,EAAE;AAC3C,QAAM,CAAC,iBAAiB,kBAAkB,QAAI,wBAAS,EAAE;AACzD,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,KAAK;AAClD,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AAEtD,QAAM,eAAe,CAAC,UACpB,6BAA6B,KAAK,KAAK;AAEzC,QAAM,sBAAsB,CAAC,UAAkB;AAC7C,QAAI,QAAQ;AACZ,QAAI,MAAM,UAAU,EAAG;AACvB,QAAI,QAAQ,KAAK,KAAK,EAAG;AACzB,QAAI,QAAQ,KAAK,KAAK,EAAG;AACzB,QAAI,eAAe,KAAK,KAAK,EAAG;AAEhC,QAAI,CAAC,MAAO,QAAO,EAAE,OAAO,IAAI,OAAO,GAAG;AAC1C,QAAI,SAAS,EAAG,QAAO,EAAE,OAAO,QAAQ,OAAO,UAAU;AACzD,QAAI,UAAU,EAAG,QAAO,EAAE,OAAO,UAAU,OAAO,UAAU;AAC5D,WAAO,EAAE,OAAO,UAAU,OAAO,UAAU;AAAA,EAC7C;AAEA,QAAM,WAAW,OAAO,MAAuB;AAC7C,MAAE,eAAe;AACjB,kBAAc,IAAI;AAClB,aAAS,IAAI;AAEb,UAAM,eAAe,MAAM,KAAK;AAChC,UAAM,kBAAkB,SAAS,KAAK;AACtC,UAAM,cAAc,KAAK,KAAK;AAC9B,UAAM,iBAAiB,gBAAgB,KAAK;AAE5C,QAAI,CAAC,aAAa;AAChB,eAAS,mBAAmB;AAC5B,oBAAc,KAAK;AACnB;AAAA,IACF;AAEA,QAAI,CAAC,cAAc;AACjB,eAAS,oBAAoB;AAC7B,oBAAc,KAAK;AACnB;AAAA,IACF;AAEA,QAAI,CAAC,aAAa,YAAY,GAAG;AAC/B,eAAS,8BAA8B;AACvC,oBAAc,KAAK;AACnB;AAAA,IACF;AAEA,QAAI,CAAC,iBAAiB;AACpB,eAAS,uBAAuB;AAChC,oBAAc,KAAK;AACnB;AAAA,IACF;AAEA,QAAI,gBAAgB,SAAS,GAAG;AAC9B,eAAS,8CAA8C;AACvD,oBAAc,KAAK;AACnB;AAAA,IACF;AAEA,QAAI,CAAC,gBAAgB;AACnB,eAAS,+BAA+B;AACxC,oBAAc,KAAK;AACnB;AAAA,IACF;AAEA,QAAI,oBAAoB,gBAAgB;AACtC,eAAS,yBAAyB;AAClC,oBAAc,KAAK;AACnB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,OAAO,EAAE,MAAM,aAAa,OAAO,cAAc,UAAU,gBAAgB,CAAC;AAAA,IACpF,SAAS,KAAc;AACrB,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,eAAS,OAAO;AAAA,IAClB,UAAE;AACA,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,OAAO;AAAA,QACL,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,cAAc;AAAA,QACd,YAAY;AAAA;AAAA,QAGZ,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,sBAAsB;AAAA,QAEtB,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,WAAW;AAAA,MACb;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,cAAc;AAAA,cACd,OAAO;AAAA,cACP,YAAY;AAAA,cACZ,UAAU;AAAA,cACV,WAAW;AAAA,cACX,eAAe;AAAA,YACjB;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,cACvC,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,cACxC,MAAK;AAAA,cACL,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA,cAC3C,MAAK;AAAA,cACL,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA,8CAAC,SAAI,OAAO,EAAE,UAAU,YAAY,cAAc,GAAG,GACnD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,KAAK;AAAA,gBACL,MAAM;AAAA,gBACN,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,cACD;AAAA;AAAA,UAED;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,IAAG;AAAA,cACH,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,mBAAmB,EAAE,OAAO,KAAK;AAAA,cAClD,MAAK;AAAA,cACL,aAAY;AAAA,cACZ,OAAO;AAAA,gBACL,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc;AAAA,gBACd,QAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,YAAY;AAAA,cACd;AAAA,cACA,SAAS,CAAC,MAAM;AACd,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA,cACA,QAAQ,CAAC,MAAM;AACb,kBAAE,cAAc,MAAM,SAAS;AAC/B,kBAAE,cAAc,MAAM,YAAY;AAAA,cACpC;AAAA;AAAA,UACF;AAAA,WACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,cAAc;AAAA,cACd,UAAU;AAAA,cACV,OAAO;AAAA,YACT;AAAA,YAEA;AAAA,2DAAC,OAAE,OAAO,EAAE,cAAc,EAAE,GAAG,iFAE/B;AAAA,cACC,YACC;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO;AAAA,oBACL,YAAY;AAAA,oBACZ,OAAO,oBAAoB,QAAQ,EAAE;AAAA,kBACvC;AAAA,kBACD;AAAA;AAAA,oBACqB,oBAAoB,QAAQ,EAAE;AAAA;AAAA;AAAA,cACpD;AAAA;AAAA;AAAA,QAEJ;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,WAAW;AAAA,cACX,UAAU;AAAA,cACV,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,cAAc;AAAA,YAChB;AAAA,YACA,SAAS,MAAM;AAGb,qBAAO,cAAc,IAAI,YAAY,iCAAiC,CAAC;AAAA,YACzE;AAAA,YACD;AAAA;AAAA,QAED;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,UAAU;AAAA,YACV,MAAK;AAAA,YACL,OAAO;AAAA,cACL,OAAO;AAAA,cACP,SAAS;AAAA,cACT,cAAc;AAAA,cACd,YAAY,aACR,6CACA;AAAA,cAEJ,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,eAAe;AAAA,cACf,QAAQ;AAAA,cACR,YAAY;AAAA,cACZ,WAAW;AAAA,YACb;AAAA,YAEC,uBAAa,gBAAgB;AAAA;AAAA,QAChC;AAAA,QAEC,SACC;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,aAAU;AAAA,YACV,OAAO;AAAA,cACL,WAAW;AAAA,cACX,OAAO;AAAA,cACP,WAAW;AAAA,cACX,UAAU;AAAA,cACV,YAAY;AAAA,YACd;AAAA,YAEC;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;","names":["import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/AuthContext.tsx","../src/http.ts","../src/Protected.tsx","../src/screens/LoginScreen.tsx","../src/screens/PasswordResetScreen.tsx","../src/screens/SignupScreen.tsx"],"sourcesContent":["export { AuthProvider, useAuth } from \"./AuthContext\";\r\nexport { default as Protected } from \"./Protected\";\r\n\r\n// Screens\r\nexport { default as LoginScreen } from \"./screens/LoginScreen\";\r\nexport { default as SignupScreen } from \"./screens/SignupScreen\";\r\nexport { default as PasswordResetScreen } from \"./screens/PasswordResetScreen\";\r\n\r\n// Types\r\nexport * from \"./types\";\r\n","/* \r\nDevelopers using this library should wrap their app with:\r\n <AuthProvider config={...}>\r\n <App />\r\n </AuthProvider>\r\n \r\n Then they can access auth anywhere with:\r\n const { user, login, logout, getToken } = useAuth();\r\n*/\r\n\r\nimport React, {\r\n createContext,\r\n useContext,\r\n useEffect,\r\n useMemo,\r\n useState,\r\n} from \"react\";\r\n\r\nimport {\r\n AuthContextType,\r\n AuthProviderConfig,\r\n StandardAuthResponse,\r\n User,\r\n} from \"./types\";\r\n\r\nimport {\r\n httpJSON,\r\n makeURL,\r\n setStoredAccessToken,\r\n getStoredAccessToken,\r\n} from \"./http\";\r\n\r\nconst AuthContext = createContext<AuthContextType | undefined>(undefined);\r\n\r\nexport function useAuth(): AuthContextType {\r\n const ctx = useContext(AuthContext);\r\n if (!ctx) throw new Error(\"useAuth must be used inside AuthProvider\");\r\n return ctx;\r\n}\r\n\r\nexport function AuthProvider({\r\n config,\r\n children,\r\n}: React.PropsWithChildren<{ config: AuthProviderConfig }>) {\r\n const { baseURL, endpoints, onLoginSuccess, onLogout } = config;\r\n\r\n const [user, setUser] = useState<User | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n\r\n const getToken = () => getStoredAccessToken();\r\n\r\n // Restore user from localStorage on app load\r\n useEffect(() => {\r\n const savedUser = localStorage.getItem(\"afk_user\");\r\n if (savedUser) {\r\n setUser(JSON.parse(savedUser));\r\n }\r\n setLoading(false);\r\n }, []);\r\n\r\n // LOGIN\r\n const login: AuthContextType[\"login\"] = async (email, password) => {\r\n const url = makeURL(baseURL, endpoints.login);\r\n\r\n const res = await httpJSON<StandardAuthResponse>(url, {\r\n method: \"POST\",\r\n body: JSON.stringify({ email, password }),\r\n });\r\n\r\n // store token + user\r\n setStoredAccessToken(res.accessToken);\r\n localStorage.setItem(\"afk_user\", JSON.stringify(res.user));\r\n\r\n setUser(res.user);\r\n\r\n if (onLoginSuccess) onLoginSuccess();\r\n };\r\n\r\n // SIGNUP\r\n const signup: AuthContextType[\"signup\"] = async (payload) => {\r\n const url = makeURL(baseURL, endpoints.signup);\r\n\r\n const res = await httpJSON<StandardAuthResponse>(url, {\r\n method: \"POST\",\r\n body: JSON.stringify(payload),\r\n });\r\n\r\n setStoredAccessToken(res.accessToken);\r\n localStorage.setItem(\"afk_user\", JSON.stringify(res.user));\r\n\r\n setUser(res.user);\r\n\r\n if (onLoginSuccess) onLoginSuccess();\r\n };\r\n\r\n // LOGOUT\r\n const logout = () => {\r\n setStoredAccessToken(null);\r\n localStorage.removeItem(\"afk_user\");\r\n setUser(null);\r\n\r\n if (onLogout) onLogout();\r\n };\r\n\r\n const value = useMemo<AuthContextType>(\r\n () => ({\r\n user,\r\n loading,\r\n login,\r\n signup,\r\n logout,\r\n getToken,\r\n config,\r\n }),\r\n [user, loading, config]\r\n );\r\n\r\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\r\n}\r\n","/*\r\n This file contains the low-level HTTP utilities used internally by\r\n auth-flow-kit to communicate with the backend.\r\n\r\n It provides:\r\n - makeURL: safely joins baseURL + endpoint path\r\n - getStoredAccessToken: reads the JWT from localStorage\r\n - setStoredAccessToken: stores/removes the JWT\r\n - httpJSON: wrapper around fetch with JSON + optional auth header\r\n\r\n NOTES FOR DEVELOPERS USING THE LIBRARY:\r\n You do NOT need to import or modify anything in this file.\r\n It is an internal helper used by the AuthProvider and auth screens.\r\n\r\n This keeps the library lightweight, predictable,\r\n and familiar to developers used to Redux Toolkit-style authentication.\r\n*/\r\n\r\nexport function makeURL(baseURL: string, path: string) {\r\n return `${baseURL.replace(/\\/$/, \"\")}${\r\n path.startsWith(\"/\") ? path : `/${path}`\r\n }`;\r\n}\r\n\r\nexport function getStoredAccessToken(): string | null {\r\n try {\r\n return localStorage.getItem(\"afk_access_token\");\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function setStoredAccessToken(token: string | null) {\r\n try {\r\n if (token) localStorage.setItem(\"afk_access_token\", token);\r\n else localStorage.removeItem(\"afk_access_token\");\r\n } catch {\r\n // Gonna ignore storage errors (Safari private mode, etc.) for now, not exactly needed.\r\n }\r\n}\r\n\r\nexport async function httpJSON<T>(\r\n url: string,\r\n opts: RequestInit = {},\r\n withAuth = false,\r\n): Promise<T> {\r\n const headers: Record<string, string> = {\r\n \"Content-Type\": \"application/json\",\r\n };\r\n\r\n if (withAuth) {\r\n const tok = getStoredAccessToken();\r\n if (tok) headers[\"Authorization\"] = `Bearer ${tok}`;\r\n }\r\n\r\n const res = await fetch(url, {\r\n ...opts,\r\n headers: { ...headers, ...(opts.headers || {}) },\r\n });\r\n\r\n if (!res.ok) {\r\n let message = `Request failed (${res.status})`;\r\n const contentType = res.headers.get(\"content-type\") || \"\";\r\n\r\n // Backend returned JSON error\r\n if (contentType.includes(\"application/json\")) {\r\n try {\r\n const data = await res.json();\r\n if (data?.message) message = data.message;\r\n } catch {\r\n // ignore JSON parse errors, cos not important to me now\r\n }\r\n }\r\n\r\n // Backend returned HTML (Express default error pages)\r\n if (contentType.includes(\"text/html\")) {\r\n if (res.status === 404 && url.includes(\"forgot\")) {\r\n message =\r\n \"The forgot password endpoint you added in config.endpoints.forgot does not exist in your server. Please check and update your config.endpoints.forgot\";\r\n } else {\r\n message = \"Unexpected server error\";\r\n }\r\n }\r\n\r\n // Developer-only guidance\r\n if (res.status === 404 && url.includes(\"forgot\")) {\r\n console.error(\r\n `[auth-flow-kit] Password reset endpoint not found.\r\n\r\n Expected a POST route matching:\r\n ${url}\r\n\r\n Fix this by either:\r\n - Adding the route on your backend, or\r\n - Updating config.endpoints.forgot`,\r\n );\r\n }\r\n\r\n throw new Error(message);\r\n }\r\n\r\n return res.json() as Promise<T>;\r\n}\r\n","\"use client\";\r\n\r\n/*\r\nProtected component\r\n\r\nWraps authenticated content and prevents rendering when unauthenticated.\r\n\r\nIMPORTANT:\r\nThis component does NOT hard-redirect by default.\r\nNavigation should be handled by the host application (router or state).\r\n\r\nIf redirectTo is provided AND the host app supports routing,\r\na redirect will occur.\r\n*/\r\n\r\nimport React, { useEffect } from \"react\";\r\nimport { useAuth } from \"./AuthContext\";\r\n\r\ntype ProtectedProps = {\r\n children: React.ReactNode;\r\n redirectTo?: string;\r\n};\r\n\r\nexport default function Protected({ children, redirectTo }: ProtectedProps) {\r\n const { user, loading } = useAuth();\r\n\r\n useEffect(() => {\r\n if (!loading && !user && redirectTo) {\r\n window.location.href = redirectTo;\r\n }\r\n }, [loading, user, redirectTo]);\r\n\r\n if (loading) return <div>Loading...</div>;\r\n if (!user) return null;\r\n\r\n return <>{children}</>;\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\nimport PasswordResetScreen from \"./PasswordResetScreen\";\r\n\r\nexport default function LoginScreen() {\r\n const { login } = useAuth();\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [submitting, setSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [showReset, setShowReset] = useState(false);\r\n\r\n if (showReset) {\r\n return (\r\n <div style={{ animation: \"fade .2s\" }}>\r\n <PasswordResetScreen />\r\n <p\r\n onClick={() => setShowReset(false)}\r\n style={{\r\n marginTop: 16,\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n textDecoration: \"underline\",\r\n }}\r\n >\r\n Back to login\r\n </p>\r\n </div>\r\n );\r\n }\r\n\r\n // Submit\r\n const onSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setSubmitting(true);\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n const trimmedPassword = password.trim();\r\n\r\n if (!trimmedEmail || !trimmedPassword) {\r\n setError(\"Email and password cannot be empty.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await login(trimmedEmail, trimmedPassword);\r\n } catch (err: any) {\r\n setError(err?.message || \"Login failed\");\r\n } finally {\r\n setSubmitting(false);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={onSubmit}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.3s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Welcome Back 👋\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.8)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 10 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.8)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Password\r\n </label>\r\n\r\n <input\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"••••••••\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <p\r\n onClick={() => setShowReset(true)}\r\n style={{\r\n textAlign: \"right\",\r\n fontSize: 13,\r\n color: \"#4b4bff\",\r\n cursor: \"pointer\",\r\n marginBottom: 24,\r\n }}\r\n >\r\n Forgot password?\r\n </p>\r\n\r\n <button\r\n disabled={submitting}\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n\r\n background: submitting\r\n ? \"linear-gradient(90deg, #b2bdfd, #8da0ff)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.25s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {submitting ? \"Signing in...\" : \"Sign in\"}\r\n </button>\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 18,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\nimport { httpJSON, makeURL } from \"../http\";\r\n\r\nexport default function PasswordResetScreen() {\r\n const { config } = useAuth();\r\n\r\n const [email, setEmail] = useState(\"\");\r\n const [sent, setSent] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const requestReset = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n\r\n try {\r\n const url = makeURL(config.baseURL, config.endpoints.forgot);\r\n\r\n await httpJSON(url, {\r\n method: \"POST\",\r\n body: JSON.stringify({ email }),\r\n });\r\n\r\n setSent(true);\r\n } catch (err: any) {\r\n setError(err?.message || \"Failed to request reset\");\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={requestReset}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n // GLASS EFFECT\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.25s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Reset Password 🔑\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: sent ? \"-18px\" : \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"90%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <button\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n\r\n background: sent\r\n ? \"linear-gradient(90deg, #7aff9d, #34c759)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.3s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {sent ? \"Link Sent ✔\" : \"Send reset link\"}\r\n </button>\r\n\r\n {sent && (\r\n <p\r\n style={{\r\n marginTop: 20,\r\n color: \"#2ecc71\",\r\n textAlign: \"center\",\r\n fontSize: 15,\r\n fontWeight: 600,\r\n }}\r\n >\r\n Check your email for reset instructions.\r\n </p>\r\n )}\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 20,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n","\"use client\";\r\nimport React, { useState } from \"react\";\r\nimport { useAuth } from \"../AuthContext\";\r\n\r\nexport default function SignupScreen() {\r\n const { signup } = useAuth();\r\n const [name, setName] = useState(\"\");\r\n const [email, setEmail] = useState(\"\");\r\n const [password, setPassword] = useState(\"\");\r\n const [submitting, setSubmitting] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const onSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setSubmitting(true);\r\n setError(null);\r\n\r\n const trimmedEmail = email.trim();\r\n const trimmedPassword = password.trim();\r\n const trimmedName = name.trim();\r\n\r\n if (!trimmedEmail || !trimmedPassword || !trimmedName) {\r\n setError(\"Email and password cannot be empty.\");\r\n setSubmitting(false);\r\n return;\r\n }\r\n\r\n try {\r\n await signup({ name, email, password });\r\n } catch (err: any) {\r\n setError(err?.message || \"Signup failed\");\r\n } finally {\r\n setSubmitting(false);\r\n }\r\n };\r\n\r\n return (\r\n <form\r\n onSubmit={onSubmit}\r\n style={{\r\n maxWidth: 400,\r\n margin: \"60px auto\",\r\n padding: 32,\r\n borderRadius: 20,\r\n fontFamily: \"Inter, sans-serif\",\r\n\r\n // GLASS EFFECT\r\n background: \"rgba(255, 255, 255, 0.25)\",\r\n backdropFilter: \"blur(14px)\",\r\n WebkitBackdropFilter: \"blur(14px)\",\r\n\r\n boxShadow: \"0 20px 40px rgba(0,0,0,0.15)\",\r\n border: \"1px solid rgba(255,255,255,0.4)\",\r\n animation: \"fadeIn 0.3s ease\",\r\n }}\r\n >\r\n <h2\r\n style={{\r\n marginBottom: 30,\r\n color: \"#060f22\",\r\n fontWeight: 700,\r\n fontSize: 30,\r\n textAlign: \"center\",\r\n letterSpacing: \"-0.5px\",\r\n }}\r\n >\r\n Create Account ✨\r\n </h2>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Name\r\n </label>\r\n\r\n <input\r\n value={name}\r\n onChange={(e) => setName(e.target.value)}\r\n placeholder=\"Your name\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Email\r\n </label>\r\n\r\n <input\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n type=\"email\"\r\n placeholder=\"you@example.com\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <div style={{ position: \"relative\", marginBottom: 26 }}>\r\n <label\r\n style={{\r\n position: \"absolute\",\r\n top: \"-10px\",\r\n left: \"14px\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n padding: \"0 6px\",\r\n fontSize: 13,\r\n color: \"#444\",\r\n borderRadius: 6,\r\n }}\r\n >\r\n Password\r\n </label>\r\n\r\n <input\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n type=\"password\"\r\n placeholder=\"••••••••\"\r\n style={{\r\n width: \"80%\",\r\n padding: \"14px 16px\",\r\n borderRadius: 12,\r\n border: \"1px solid #d2d2d2\",\r\n fontSize: 15,\r\n outline: \"none\",\r\n transition: \"0.25s\",\r\n background: \"rgba(255,255,255,0.85)\",\r\n }}\r\n onFocus={(e) => {\r\n e.currentTarget.style.border = \"1px solid #4b4bff\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 3px rgba(75,75,255,0.25)\";\r\n }}\r\n onBlur={(e) => {\r\n e.currentTarget.style.border = \"1px solid #d2d2d2\";\r\n e.currentTarget.style.boxShadow = \"0 0 0 transparent\";\r\n }}\r\n />\r\n </div>\r\n\r\n <button\r\n disabled={submitting}\r\n type=\"submit\"\r\n style={{\r\n width: \"100%\",\r\n padding: \"14px 20px\",\r\n borderRadius: 12,\r\n background: submitting\r\n ? \"linear-gradient(90deg, #b2bdfd, #8da0ff)\"\r\n : \"linear-gradient(90deg, #5353aaff, #060f22ff)\",\r\n\r\n color: \"white\",\r\n border: \"none\",\r\n fontSize: 16,\r\n fontWeight: 700,\r\n letterSpacing: \"0.3px\",\r\n cursor: \"pointer\",\r\n transition: \"0.25s\",\r\n boxShadow: \"0 8px 20px rgba(75,75,255,0.25)\",\r\n }}\r\n >\r\n {submitting ? \"Creating...\" : \"Create account\"}\r\n </button>\r\n\r\n {error && (\r\n <p\r\n style={{\r\n marginTop: 18,\r\n color: \"crimson\",\r\n textAlign: \"center\",\r\n fontSize: 14,\r\n fontWeight: 500,\r\n }}\r\n >\r\n {error}\r\n </p>\r\n )}\r\n </form>\r\n );\r\n}\r\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime"]}