@tern-secure/nextjs 4.0.0 → 4.1.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.
Files changed (96) hide show
  1. package/dist/cjs/app-router/client/TernSecureProvider.js +17 -2
  2. package/dist/cjs/app-router/client/TernSecureProvider.js.map +1 -1
  3. package/dist/cjs/app-router/client/actions.js +49 -49
  4. package/dist/cjs/app-router/client/actions.js.map +1 -1
  5. package/dist/cjs/app-router/route-handler/internal-route.js +17 -2
  6. package/dist/cjs/app-router/route-handler/internal-route.js.map +1 -1
  7. package/dist/cjs/boundary/TernSecureClientProvider.js +163 -40
  8. package/dist/cjs/boundary/TernSecureClientProvider.js.map +1 -1
  9. package/dist/cjs/boundary/TernSecureCtx.js.map +1 -1
  10. package/dist/cjs/boundary/hooks/useAuth.js +7 -8
  11. package/dist/cjs/boundary/hooks/useAuth.js.map +1 -1
  12. package/dist/cjs/components/sign-in.js +136 -45
  13. package/dist/cjs/components/sign-in.js.map +1 -1
  14. package/dist/cjs/components/sign-out-button.js +10 -1
  15. package/dist/cjs/components/sign-out-button.js.map +1 -1
  16. package/dist/cjs/components/sign-out.js +12 -3
  17. package/dist/cjs/components/sign-out.js.map +1 -1
  18. package/dist/cjs/components/sign-up.js +10 -5
  19. package/dist/cjs/components/sign-up.js.map +1 -1
  20. package/dist/cjs/errors.js +232 -5
  21. package/dist/cjs/errors.js.map +1 -1
  22. package/dist/cjs/index.js +0 -3
  23. package/dist/cjs/index.js.map +1 -1
  24. package/dist/cjs/types.js +14 -0
  25. package/dist/cjs/types.js.map +1 -1
  26. package/dist/cjs/utils/construct.js +50 -18
  27. package/dist/cjs/utils/construct.js.map +1 -1
  28. package/dist/cjs/utils/redirect.js +57 -0
  29. package/dist/cjs/utils/redirect.js.map +1 -0
  30. package/dist/esm/app-router/client/TernSecureProvider.js +17 -2
  31. package/dist/esm/app-router/client/TernSecureProvider.js.map +1 -1
  32. package/dist/esm/app-router/client/actions.js +59 -51
  33. package/dist/esm/app-router/client/actions.js.map +1 -1
  34. package/dist/esm/app-router/route-handler/internal-route.js +13 -1
  35. package/dist/esm/app-router/route-handler/internal-route.js.map +1 -1
  36. package/dist/esm/boundary/TernSecureClientProvider.js +164 -41
  37. package/dist/esm/boundary/TernSecureClientProvider.js.map +1 -1
  38. package/dist/esm/boundary/TernSecureCtx.js.map +1 -1
  39. package/dist/esm/boundary/hooks/useAuth.js +7 -8
  40. package/dist/esm/boundary/hooks/useAuth.js.map +1 -1
  41. package/dist/esm/components/sign-in.js +137 -46
  42. package/dist/esm/components/sign-in.js.map +1 -1
  43. package/dist/esm/components/sign-out-button.js +11 -2
  44. package/dist/esm/components/sign-out-button.js.map +1 -1
  45. package/dist/esm/components/sign-out.js +13 -4
  46. package/dist/esm/components/sign-out.js.map +1 -1
  47. package/dist/esm/components/sign-up.js +10 -5
  48. package/dist/esm/components/sign-up.js.map +1 -1
  49. package/dist/esm/errors.js +228 -4
  50. package/dist/esm/errors.js.map +1 -1
  51. package/dist/esm/index.js +0 -2
  52. package/dist/esm/index.js.map +1 -1
  53. package/dist/esm/types.js +6 -0
  54. package/dist/esm/types.js.map +1 -1
  55. package/dist/esm/utils/construct.js +46 -17
  56. package/dist/esm/utils/construct.js.map +1 -1
  57. package/dist/esm/utils/redirect.js +32 -0
  58. package/dist/esm/utils/redirect.js.map +1 -0
  59. package/dist/types/app-router/client/TernSecureProvider.d.ts +14 -3
  60. package/dist/types/app-router/client/TernSecureProvider.d.ts.map +1 -1
  61. package/dist/types/app-router/client/actions.d.ts +23 -21
  62. package/dist/types/app-router/client/actions.d.ts.map +1 -1
  63. package/dist/types/app-router/route-handler/internal-route.d.ts +3 -0
  64. package/dist/types/app-router/route-handler/internal-route.d.ts.map +1 -1
  65. package/dist/types/boundary/TernSecureClientProvider.d.ts +17 -1
  66. package/dist/types/boundary/TernSecureClientProvider.d.ts.map +1 -1
  67. package/dist/types/boundary/TernSecureCtx.d.ts +3 -1
  68. package/dist/types/boundary/TernSecureCtx.d.ts.map +1 -1
  69. package/dist/types/boundary/hooks/useAuth.d.ts +4 -1
  70. package/dist/types/boundary/hooks/useAuth.d.ts.map +1 -1
  71. package/dist/types/components/sign-in.d.ts +1 -2
  72. package/dist/types/components/sign-in.d.ts.map +1 -1
  73. package/dist/types/components/sign-out-button.d.ts +2 -1
  74. package/dist/types/components/sign-out-button.d.ts.map +1 -1
  75. package/dist/types/components/sign-out.d.ts +2 -1
  76. package/dist/types/components/sign-out.d.ts.map +1 -1
  77. package/dist/types/components/sign-up.d.ts.map +1 -1
  78. package/dist/types/components/ui/alert.d.ts +1 -1
  79. package/dist/types/components/ui/button.d.ts +1 -1
  80. package/dist/types/errors.d.ts +36 -2
  81. package/dist/types/errors.d.ts.map +1 -1
  82. package/dist/types/index.d.ts +0 -1
  83. package/dist/types/index.d.ts.map +1 -1
  84. package/dist/types/types.d.ts +35 -0
  85. package/dist/types/types.d.ts.map +1 -1
  86. package/dist/types/utils/construct.d.ts +20 -4
  87. package/dist/types/utils/construct.d.ts.map +1 -1
  88. package/dist/types/utils/redirect.d.ts +9 -0
  89. package/dist/types/utils/redirect.d.ts.map +1 -0
  90. package/package.json +6 -6
  91. package/dist/cjs/boundary/hooks/useUser.js +0 -44
  92. package/dist/cjs/boundary/hooks/useUser.js.map +0 -1
  93. package/dist/esm/boundary/hooks/useUser.js +0 -20
  94. package/dist/esm/boundary/hooks/useUser.js.map +0 -1
  95. package/dist/types/boundary/hooks/useUser.d.ts +0 -7
  96. package/dist/types/boundary/hooks/useUser.d.ts.map +0 -1
@@ -15,6 +15,7 @@ import { Separator } from "./ui/separator";
15
15
  import { createUser, signInWithRedirectGoogle, signInWithMicrosoft } from "../app-router/client/actions";
16
16
  import { useSignUp } from "../boundary/hooks/useSignUp";
17
17
  import { handleInternalRoute } from "../app-router/route-handler/internal-route";
18
+ import { getErrorAlertVariant } from "../errors";
18
19
  function SignUp({
19
20
  redirectUrl,
20
21
  onError,
@@ -22,10 +23,10 @@ function SignUp({
22
23
  }) {
23
24
  const pathname = usePathname();
24
25
  const InternalComponent = handleInternalRoute(pathname);
26
+ const { setEmail: setContextEmail } = useSignUp();
25
27
  if (InternalComponent) {
26
28
  return /* @__PURE__ */ jsx(InternalComponent, {});
27
29
  }
28
- const { setEmail: setContextEmail } = useSignUp();
29
30
  const [formData, setFormData] = useState({
30
31
  email: "",
31
32
  password: "",
@@ -34,7 +35,7 @@ function SignUp({
34
35
  const [showPassword, setShowPassword] = useState(false);
35
36
  const [showConfirmPassword, setShowConfirmPassword] = useState(false);
36
37
  const [isLoading, setLoading] = useState(false);
37
- const [error, setError] = useState("");
38
+ const [error, setError] = useState(null);
38
39
  const [passwordFocused, setPasswordFocused] = useState(false);
39
40
  const router = useRouter();
40
41
  const passwordRequirements = [
@@ -69,6 +70,7 @@ function SignUp({
69
70
  ...prev,
70
71
  [name]: value
71
72
  }));
73
+ setError(null);
72
74
  };
73
75
  const isFormValid = () => {
74
76
  return formData.email.length > 0 && passwordRequirements.every((req) => req.satisfied);
@@ -77,15 +79,18 @@ function SignUp({
77
79
  e.preventDefault();
78
80
  if (!isFormValid()) return;
79
81
  setLoading(true);
82
+ setError(null);
80
83
  try {
81
84
  const result = await createUser(formData.email, formData.password);
82
85
  if (result.success) {
83
86
  setContextEmail(formData.email);
84
87
  onSuccess == null ? void 0 : onSuccess();
85
88
  router.push(`sign-up/verify`);
89
+ } else {
90
+ setError(result);
86
91
  }
87
92
  } catch (error2) {
88
- const errorMessage = error2 instanceof Error ? error2.message : "Failed to sign in";
93
+ const errorMessage = error2;
89
94
  setError(errorMessage);
90
95
  onError == null ? void 0 : onError(error2 instanceof Error ? error2 : new Error("Failed to create account"));
91
96
  } finally {
@@ -103,7 +108,7 @@ function SignUp({
103
108
  throw new Error(result.error);
104
109
  }
105
110
  } catch (err) {
106
- const errorMessage = err instanceof Error ? err.message : `Failed to sign in with ${provider}`;
111
+ const errorMessage = err;
107
112
  setError(errorMessage);
108
113
  const newUrl = new URL(window.location.href);
109
114
  newUrl.searchParams.delete("signInRedirect");
@@ -119,7 +124,7 @@ function SignUp({
119
124
  ] }),
120
125
  /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, children: [
121
126
  /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
122
- error && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: error }) }),
127
+ error && /* @__PURE__ */ jsx(Alert, { variant: getErrorAlertVariant(error), className: "animate-in fade-in-50", children: /* @__PURE__ */ jsx(AlertDescription, { children: error.message }) }),
123
128
  /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
124
129
  /* @__PURE__ */ jsx(Label, { htmlFor: "email", children: "Email" }),
125
130
  /* @__PURE__ */ jsx(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/sign-up.tsx"],"sourcesContent":["\"use client\"\n\nimport { useState } from \"react\"\nimport { useRouter, usePathname } from 'next/navigation'\nimport Link from \"next/link\"\nimport { Eye, EyeOff, Check, X, Loader2 } from \"lucide-react\"\nimport { Button } from \"./ui/button\"\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from \"./ui/card\"\nimport { Input } from \"./ui/input\"\nimport { Label } from \"./ui/label\"\nimport { Alert, AlertDescription } from \"./ui/alert\"\nimport { cn } from \"../lib/utils\"\nimport { AuthBackground } from \"./background\"\nimport { Separator } from \"./ui/separator\"\nimport { createUser, signInWithRedirectGoogle, signInWithMicrosoft } from '../app-router/client/actions'\nimport { useSignUp } from '../boundary/hooks/useSignUp'\nimport { handleInternalRoute } from '../app-router/route-handler/internal-route'\n\nexport interface SignUpProps {\n redirectUrl?: string\n onError?: (error: Error) => void\n onSuccess?: () => void\n}\n\nexport interface PasswordRequirement {\n text: string\n satisfied: boolean\n}\n\nexport function SignUp({\n redirectUrl, \n onError,\n onSuccess,\n }: SignUpProps) {\n const pathname = usePathname()\n const InternalComponent = handleInternalRoute(pathname)\n\n if (InternalComponent) {\n return <InternalComponent />\n }\n\n const { setEmail: setContextEmail } = useSignUp()\n const [formData, setFormData] = useState({\n email: \"\",\n password: \"\",\n confirmPassword: \"\",\n })\n const [showPassword, setShowPassword] = useState(false)\n const [showConfirmPassword, setShowConfirmPassword] = useState(false)\n const [isLoading, setLoading] = useState(false)\n const [error, setError] = useState(\"\")\n const [passwordFocused, setPasswordFocused] = useState(false)\n const router = useRouter()\n\n const passwordRequirements: PasswordRequirement[] = [\n {\n text: \"At least 8 characters long\",\n satisfied: formData.password.length >= 8,\n },\n {\n text: \"Contains at least one uppercase letter\",\n satisfied: /[A-Z]/.test(formData.password),\n },\n {\n text: \"Contains at least one lowercase letter\",\n satisfied: /[a-z]/.test(formData.password),\n },\n {\n text: \"Contains at least one number\",\n satisfied: /\\d/.test(formData.password),\n },\n {\n text: \"Contains at least one special character\",\n satisfied: /[!@#$%^&*(),.?\":{}|<>]/.test(formData.password),\n },\n {\n text: \"Passwords match\",\n satisfied: formData.password === formData.confirmPassword && formData.password !== \"\",\n },\n ]\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const { name, value } = e.target\n setFormData((prev) => ({\n ...prev,\n [name]: value,\n }))\n }\n\n const isFormValid = () => {\n return formData.email.length > 0 && passwordRequirements.every((req) => req.satisfied)\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!isFormValid()) return\n\n setLoading(true)\n try {\n const result = await createUser(formData.email, formData.password)\n if(result.success) {\n setContextEmail(formData.email)\n\n onSuccess?.()\n\n router.push(`sign-up/verify`)\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Failed to sign in'\n setError(errorMessage)\n onError?.(error instanceof Error ? error : new Error('Failed to create account'))\n } finally {\n setLoading(false)\n }\n }\n\n\n const handleSocialSignIn = async (provider: 'google' | 'microsoft') => {\n setLoading(true)\n try {\n const currentUrl = new URL(window.location.href)\n currentUrl.searchParams.set('signInRedirect', 'true')\n window.history.replaceState({}, '', currentUrl.toString())\n\n const result = provider === 'google' ? await signInWithRedirectGoogle() : await signInWithMicrosoft()\n if (!result.success) {\n throw new Error(result.error)\n }\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : `Failed to sign in with ${provider}`\n setError(errorMessage)\n const newUrl = new URL(window.location.href)\n newUrl.searchParams.delete('signInRedirect')\n window.history.replaceState({}, '', newUrl.toString())\n }\n }\n\n return (\n <div className=\"relative flex min-h-screen items-center justify-center\">\n <AuthBackground />\n <Card className=\"w-full max-w-md mx-auto mt-8\">\n <CardHeader className=\"space-y-1 text-center\">\n <CardTitle className=\"text-2xl font-bold\">Create an account</CardTitle>\n <CardDescription>Enter your information below to create your account</CardDescription>\n </CardHeader>\n <form onSubmit={handleSubmit}>\n <CardContent className=\"space-y-4\">\n {error && (\n <Alert variant=\"destructive\">\n <AlertDescription>{error}</AlertDescription>\n </Alert>\n )}\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"email\">Email</Label>\n <Input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n placeholder=\"name@example.com\"\n value={formData.email}\n onChange={handleInputChange}\n required\n disabled={isLoading}\n />\n </div>\n\n <div className=\"space-y-2 relative flex-1\">\n <Label htmlFor=\"password\">Password</Label>\n <div className=\"relative\">\n <Input\n id=\"password\"\n name=\"password\"\n type={showPassword ? \"text\" : \"password\"}\n value={formData.password}\n onChange={handleInputChange}\n onFocus={() => setPasswordFocused(true)}\n onBlur={() => setPasswordFocused(false)}\n required\n disabled={isLoading}\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"absolute right-2 top-1/2 -translate-y-1/2 h-8 w-8 hover:bg-transparent\"\n onClick={() => setShowPassword(!showPassword)}\n >\n {showPassword ? <EyeOff className=\"h-4 w-4 text-muted-foreground hover:text-foreground\" /> : <Eye className=\"h-4 w-4 text-muted-foreground hover:text-foreground\" />}\n <span className=\"sr-only\">{showPassword ? \"Hide password\" : \"Show password\"}</span>\n </Button>\n </div>\n </div>\n\n <div className=\"space-y-2 relative flex-1\">\n <Label htmlFor=\"confirmPassword\">Confirm Password</Label>\n <div className=\"relative\">\n <Input\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n type={showConfirmPassword ? \"text\" : \"password\"}\n value={formData.confirmPassword}\n onChange={handleInputChange}\n required\n disabled={isLoading}\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"absolute right-2 top-1/2 -translate-y-1/2 h-8 w-8 hover:bg-transparent\"\n onClick={() => setShowConfirmPassword(!showConfirmPassword)}\n >\n {showConfirmPassword ? <EyeOff className=\"h-4 w-4 text-muted-foreground hover:text-foreground\" /> : <Eye className=\"h-4 w-4 text-muted-foreground hover:text-foreground\" />}\n <span className=\"sr-only\">{showConfirmPassword ? \"Hide password\" : \"Show password\"}</span>\n </Button>\n </div>\n </div>\n\n {/* Password Requirements */}\n <div\n className={cn(\n \"rounded-lg border bg-card text-card-foreground shadow-sm\",\n \"p-4 transition-all duration-200\",\n passwordFocused ? \"opacity-100\" : \"opacity-70\",\n )}\n >\n <div className=\"grid gap-2 text-sm\">\n {passwordRequirements.map((requirement, index) => (\n <div\n key={index}\n className={cn(\n \"flex items-center gap-2\",\n requirement.satisfied ? \"text-green-500\" : \"text-muted-foreground\",\n )}\n >\n {requirement.satisfied ? (\n <Check className=\"h-4 w-4 shrink-0\" />\n ) : (\n <X className=\"h-4 w-4 shrink-0\" />\n )}\n <span className=\"text-sm\">{requirement.text}</span>\n </div>\n ))}\n </div>\n </div>\n </CardContent>\n\n <CardFooter className=\"flex flex-col space-y-4\">\n <Button type=\"submit\" className=\"w-full\" disabled={!isFormValid() || isLoading}>\n {isLoading ? (\n <>\n <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />\n Creating account...\n </>\n ) : (\n \"Create account\"\n )}\n </Button>\n <p className=\"text-sm text-muted-foreground text-center\">\n Already have an account?{\" \"}\n <Link href=\"/sign-in\" className=\"text-primary underline-offset-4 transition-colors hover:underline\">\n Sign in\n </Link> or sign up with email\n </p>\n </CardFooter>\n </form>\n <Separator className=\"my-4 px-6\" />\n <div className=\"px-6 pb-4\">\n <div className=\"relative\">\n <div className=\"absolute inset-0 flex items-center\">\n <Separator className=\"w-full\" />\n </div>\n <div className=\"relative flex justify-center text-xs uppercase\">\n <span className=\"bg-background px-2 text-muted-foreground\">\n Or continue with\n </span>\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4 mt-4\">\n <Button \n variant=\"outline\" \n disabled={isLoading}\n onClick={() => handleSocialSignIn('google')} \n className=\"flex items-center justify-center\"\n >\n <svg className=\"w-5 h-5 mr-2\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\" fill=\"#4285F4\"/>\n <path d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\" fill=\"#34A853\"/>\n <path d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\" fill=\"#FBBC05\"/>\n <path d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\" fill=\"#EA4335\"/>\n </svg>\n Google\n </Button>\n <Button \n variant=\"outline\" \n disabled={isLoading}\n onClick={() => handleSocialSignIn('microsoft')} \n className=\"flex items-center justify-center\"\n >\n <svg className=\"w-5 h-5 mr-2\" viewBox=\"0 0 23 23\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill=\"#f3f3f3\" d=\"M0 0h23v23H0z\"/>\n <path fill=\"#f35325\" d=\"M1 1h10v10H1z\"/>\n <path fill=\"#81bc06\" d=\"M12 1h10v10H12z\"/>\n <path fill=\"#05a6f0\" d=\"M1 12h10v10H1z\"/>\n <path fill=\"#ffba08\" d=\"M12 12h10v10H12z\"/>\n </svg>\n Microsoft\n </Button>\n </div>\n </div>\n </Card>\n </div>\n )\n}\n"],"mappings":"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","names":["error"]}
1
+ {"version":3,"sources":["../../../src/components/sign-up.tsx"],"sourcesContent":["\"use client\"\n\nimport { useState } from \"react\"\nimport { useRouter, usePathname } from 'next/navigation'\nimport Link from \"next/link\"\nimport { Eye, EyeOff, Check, X, Loader2 } from \"lucide-react\"\nimport { Button } from \"./ui/button\"\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from \"./ui/card\"\nimport { Input } from \"./ui/input\"\nimport { Label } from \"./ui/label\"\nimport { Alert, AlertDescription } from \"./ui/alert\"\nimport { cn } from \"../lib/utils\"\nimport { AuthBackground } from \"./background\"\nimport { Separator } from \"./ui/separator\"\nimport { createUser, signInWithRedirectGoogle, signInWithMicrosoft } from '../app-router/client/actions'\nimport { useSignUp } from '../boundary/hooks/useSignUp'\nimport { handleInternalRoute } from '../app-router/route-handler/internal-route'\nimport { SignInResponse } from \"../types\"\nimport { getErrorAlertVariant, ErrorCode} from \"../errors\"\n\nexport interface SignUpProps {\n redirectUrl?: string\n onError?: (error: Error) => void\n onSuccess?: () => void\n}\n\nexport interface PasswordRequirement {\n text: string\n satisfied: boolean\n}\n\n\nexport function SignUp({\n redirectUrl, \n onError,\n onSuccess,\n }: SignUpProps) {\n const pathname = usePathname()\n const InternalComponent = handleInternalRoute(pathname)\n const { setEmail: setContextEmail } = useSignUp()\n\n if (InternalComponent) {\n return <InternalComponent />\n }\n\n \n const [formData, setFormData] = useState({\n email: \"\",\n password: \"\",\n confirmPassword: \"\",\n })\n const [showPassword, setShowPassword] = useState(false)\n const [showConfirmPassword, setShowConfirmPassword] = useState(false)\n const [isLoading, setLoading] = useState(false)\n const [error, setError] = useState<SignInResponse | null>(null)\n const [passwordFocused, setPasswordFocused] = useState(false)\n const router = useRouter()\n\n const passwordRequirements: PasswordRequirement[] = [\n {\n text: \"At least 8 characters long\",\n satisfied: formData.password.length >= 8,\n },\n {\n text: \"Contains at least one uppercase letter\",\n satisfied: /[A-Z]/.test(formData.password),\n },\n {\n text: \"Contains at least one lowercase letter\",\n satisfied: /[a-z]/.test(formData.password),\n },\n {\n text: \"Contains at least one number\",\n satisfied: /\\d/.test(formData.password),\n },\n {\n text: \"Contains at least one special character\",\n satisfied: /[!@#$%^&*(),.?\":{}|<>]/.test(formData.password),\n },\n {\n text: \"Passwords match\",\n satisfied: formData.password === formData.confirmPassword && formData.password !== \"\",\n },\n ]\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const { name, value } = e.target\n setFormData((prev) => ({\n ...prev,\n [name]: value,\n }))\n setError(null)\n }\n\n const isFormValid = () => {\n return formData.email.length > 0 && passwordRequirements.every((req) => req.satisfied)\n }\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n if (!isFormValid()) return\n\n setLoading(true)\n setError(null)\n try {\n const result = await createUser(formData.email, formData.password)\n if(result.success) {\n setContextEmail(formData.email)\n\n onSuccess?.()\n\n router.push(`sign-up/verify`)\n } else {\n setError(result)\n }\n } catch (error) {\n const errorMessage = error as SignInResponse\n setError(errorMessage)\n onError?.(error instanceof Error ? error : new Error('Failed to create account'))\n } finally {\n setLoading(false)\n }\n }\n\n\n const handleSocialSignIn = async (provider: 'google' | 'microsoft') => {\n setLoading(true)\n try {\n const currentUrl = new URL(window.location.href)\n currentUrl.searchParams.set('signInRedirect', 'true')\n window.history.replaceState({}, '', currentUrl.toString())\n\n const result = provider === 'google' ? await signInWithRedirectGoogle() : await signInWithMicrosoft()\n if (!result.success) {\n throw new Error(result.error)\n }\n } catch (err) {\n const errorMessage = err as SignInResponse\n setError(errorMessage)\n const newUrl = new URL(window.location.href)\n newUrl.searchParams.delete('signInRedirect')\n window.history.replaceState({}, '', newUrl.toString())\n }\n }\n\n return (\n <div className=\"relative flex min-h-screen items-center justify-center\">\n <AuthBackground />\n <Card className=\"w-full max-w-md mx-auto mt-8\">\n <CardHeader className=\"space-y-1 text-center\">\n <CardTitle className=\"text-2xl font-bold\">Create an account</CardTitle>\n <CardDescription>Enter your information below to create your account</CardDescription>\n </CardHeader>\n <form onSubmit={handleSubmit}>\n <CardContent className=\"space-y-4\">\n {error && (\n <Alert variant={getErrorAlertVariant(error)} className=\"animate-in fade-in-50\">\n <AlertDescription>{error.message}</AlertDescription>\n </Alert>\n )}\n\n <div className=\"space-y-2\">\n <Label htmlFor=\"email\">Email</Label>\n <Input\n id=\"email\"\n name=\"email\"\n type=\"email\"\n placeholder=\"name@example.com\"\n value={formData.email}\n onChange={handleInputChange}\n required\n disabled={isLoading}\n />\n </div>\n\n <div className=\"space-y-2 relative flex-1\">\n <Label htmlFor=\"password\">Password</Label>\n <div className=\"relative\">\n <Input\n id=\"password\"\n name=\"password\"\n type={showPassword ? \"text\" : \"password\"}\n value={formData.password}\n onChange={handleInputChange}\n onFocus={() => setPasswordFocused(true)}\n onBlur={() => setPasswordFocused(false)}\n required\n disabled={isLoading}\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"absolute right-2 top-1/2 -translate-y-1/2 h-8 w-8 hover:bg-transparent\"\n onClick={() => setShowPassword(!showPassword)}\n >\n {showPassword ? <EyeOff className=\"h-4 w-4 text-muted-foreground hover:text-foreground\" /> : <Eye className=\"h-4 w-4 text-muted-foreground hover:text-foreground\" />}\n <span className=\"sr-only\">{showPassword ? \"Hide password\" : \"Show password\"}</span>\n </Button>\n </div>\n </div>\n\n <div className=\"space-y-2 relative flex-1\">\n <Label htmlFor=\"confirmPassword\">Confirm Password</Label>\n <div className=\"relative\">\n <Input\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n type={showConfirmPassword ? \"text\" : \"password\"}\n value={formData.confirmPassword}\n onChange={handleInputChange}\n required\n disabled={isLoading}\n />\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"absolute right-2 top-1/2 -translate-y-1/2 h-8 w-8 hover:bg-transparent\"\n onClick={() => setShowConfirmPassword(!showConfirmPassword)}\n >\n {showConfirmPassword ? <EyeOff className=\"h-4 w-4 text-muted-foreground hover:text-foreground\" /> : <Eye className=\"h-4 w-4 text-muted-foreground hover:text-foreground\" />}\n <span className=\"sr-only\">{showConfirmPassword ? \"Hide password\" : \"Show password\"}</span>\n </Button>\n </div>\n </div>\n\n {/* Password Requirements */}\n <div\n className={cn(\n \"rounded-lg border bg-card text-card-foreground shadow-sm\",\n \"p-4 transition-all duration-200\",\n passwordFocused ? \"opacity-100\" : \"opacity-70\",\n )}\n >\n <div className=\"grid gap-2 text-sm\">\n {passwordRequirements.map((requirement, index) => (\n <div\n key={index}\n className={cn(\n \"flex items-center gap-2\",\n requirement.satisfied ? \"text-green-500\" : \"text-muted-foreground\",\n )}\n >\n {requirement.satisfied ? (\n <Check className=\"h-4 w-4 shrink-0\" />\n ) : (\n <X className=\"h-4 w-4 shrink-0\" />\n )}\n <span className=\"text-sm\">{requirement.text}</span>\n </div>\n ))}\n </div>\n </div>\n </CardContent>\n\n <CardFooter className=\"flex flex-col space-y-4\">\n <Button type=\"submit\" className=\"w-full\" disabled={!isFormValid() || isLoading}>\n {isLoading ? (\n <>\n <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />\n Creating account...\n </>\n ) : (\n \"Create account\"\n )}\n </Button>\n <p className=\"text-sm text-muted-foreground text-center\">\n Already have an account?{\" \"}\n <Link href=\"/sign-in\" className=\"text-primary underline-offset-4 transition-colors hover:underline\">\n Sign in\n </Link> or sign up with email\n </p>\n </CardFooter>\n </form>\n <Separator className=\"my-4 px-6\" />\n <div className=\"px-6 pb-4\">\n <div className=\"relative\">\n <div className=\"absolute inset-0 flex items-center\">\n <Separator className=\"w-full\" />\n </div>\n <div className=\"relative flex justify-center text-xs uppercase\">\n <span className=\"bg-background px-2 text-muted-foreground\">\n Or continue with\n </span>\n </div>\n </div>\n <div className=\"grid grid-cols-2 gap-4 mt-4\">\n <Button \n variant=\"outline\" \n disabled={isLoading}\n onClick={() => handleSocialSignIn('google')} \n className=\"flex items-center justify-center\"\n >\n <svg className=\"w-5 h-5 mr-2\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\n <path d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z\" fill=\"#4285F4\"/>\n <path d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\" fill=\"#34A853\"/>\n <path d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\" fill=\"#FBBC05\"/>\n <path d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\" fill=\"#EA4335\"/>\n </svg>\n Google\n </Button>\n <Button \n variant=\"outline\" \n disabled={isLoading}\n onClick={() => handleSocialSignIn('microsoft')} \n className=\"flex items-center justify-center\"\n >\n <svg className=\"w-5 h-5 mr-2\" viewBox=\"0 0 23 23\" xmlns=\"http://www.w3.org/2000/svg\">\n <path fill=\"#f3f3f3\" d=\"M0 0h23v23H0z\"/>\n <path fill=\"#f35325\" d=\"M1 1h10v10H1z\"/>\n <path fill=\"#81bc06\" d=\"M12 1h10v10H12z\"/>\n <path fill=\"#05a6f0\" d=\"M1 12h10v10H1z\"/>\n <path fill=\"#ffba08\" d=\"M12 12h10v10H12z\"/>\n </svg>\n Microsoft\n </Button>\n </div>\n </div>\n </Card>\n </div>\n )\n}\n"],"mappings":"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","names":["error"]}
@@ -1,17 +1,241 @@
1
1
  const ERRORS = {
2
2
  SERVER_SIDE_INITIALIZATION: "TernSecure must be initialized on the client side",
3
3
  REQUIRES_VERIFICATION: "AUTH_REQUIRES_VERIFICATION",
4
+ AUTHENTICATED: "AUTHENTICATED",
5
+ UNAUTHENTICATED: "UNAUTHENTICATED",
6
+ UNVERIFIED: "UNVERIFIED",
4
7
  NOT_INITIALIZED: "TernSecure services are not initialized. Call initializeTernSecure() first",
5
- HOOK_CONTEXT: (hookName) => `${hookName} must be used within TernSecureProvider`
8
+ HOOK_CONTEXT: "Hook must be used within TernSecureProvider",
9
+ EMAIL_NOT_VERIFIED: "EMAIL_NOT_VERIFIED",
10
+ INVALID_CREDENTIALS: "INVALID_CREDENTIALS",
11
+ USER_DISABLED: "USER_DISABLED",
12
+ TOO_MANY_ATTEMPTS: "TOO_MANY_ATTEMPTS",
13
+ NETWORK_ERROR: "NETWORK_ERROR",
14
+ INVALID_EMAIL: "INVALID_EMAIL",
15
+ WEAK_PASSWORD: "WEAK_PASSWORD",
16
+ EMAIL_EXISTS: "EMAIL_EXISTS",
17
+ POPUP_BLOCKED: "POPUP_BLOCKED",
18
+ OPERATION_NOT_ALLOWED: "OPERATION_NOT_ALLOWED",
19
+ EXPIRED_TOKEN: "EXPIRED_TOKEN",
20
+ INVALID_TOKEN: "INVALID_TOKEN",
21
+ SESSION_EXPIRED: "SESSION_EXPIRED",
22
+ INTERNAL_ERROR: "INTERNAL_ERROR"
23
+ };
24
+ const ERROR_PATTERNS = {
25
+ INVALID_EMAIL: /auth.*invalid.*email|invalid.*email.*auth|Firebase:.*Error.*auth\/invalid-email/i,
26
+ INVALID_CREDENTIALS: /auth.*invalid.*credential|invalid.*password|wrong.*password|Firebase:.*Error.*auth\/(invalid-credential|wrong-password|user-not-found)/i,
27
+ USER_DISABLED: /user.*disabled|disabled.*user|Firebase:.*Error.*auth\/user-disabled/i,
28
+ TOO_MANY_ATTEMPTS: /too.*many.*attempts|too.*many.*requests|Firebase:.*Error.*auth\/too-many-requests/i,
29
+ NETWORK_ERROR: /network.*request.*failed|failed.*network|Firebase:.*Error.*auth\/network-request-failed/i,
30
+ OPERATION_NOT_ALLOWED: /operation.*not.*allowed|method.*not.*allowed|Firebase:.*Error.*auth\/operation-not-allowed/i,
31
+ POPUP_BLOCKED: /popup.*blocked|blocked.*popup|Firebase:.*Error.*auth\/popup-blocked/i,
32
+ EMAIL_EXISTS: /email.*exists|email.*already.*use|Firebase:.*Error.*auth\/email-already-in-use/i,
33
+ EXPIRED_TOKEN: /token.*expired|expired.*token|Firebase:.*Error.*auth\/expired-token/i,
34
+ INVALID_TOKEN: /invalid.*token|token.*invalid|Firebase:.*Error.*auth\/invalid-token/i,
35
+ SESSION_EXPIRED: /session.*expired|expired.*session|Firebase:.*Error.*auth\/session-expired/i,
36
+ WEAK_PASSWORD: /weak.*password|password.*weak|Firebase:.*Error.*auth\/weak-password/i
6
37
  };
7
38
  class TernSecureError extends Error {
8
- constructor(message) {
9
- super(message);
39
+ constructor(code, message) {
40
+ super(message || code);
10
41
  this.name = "TernSecureError";
42
+ this.code = code;
43
+ }
44
+ }
45
+ function isFirebaseErrorLike(error) {
46
+ if (!error || typeof error !== "object") return false;
47
+ const err = error;
48
+ if (typeof err.message === "string") {
49
+ const bundledErrorMatch = err.message.match(/Firebase:\s*Error\s*$$auth\/([^)]+)$$/);
50
+ if (bundledErrorMatch) {
51
+ err.code = `auth/${bundledErrorMatch[1]}`;
52
+ return true;
53
+ }
54
+ }
55
+ return typeof err.code === "string" && err.code.startsWith("auth/") || typeof err.name === "string" && err.name.includes("FirebaseError");
56
+ }
57
+ function extractFirebaseErrorCode(error) {
58
+ if (typeof error.message === "string") {
59
+ const bundledErrorMatch = error.message.match(/Firebase:\s*Error\s*$$auth\/([^)]+)$$/);
60
+ if (bundledErrorMatch) {
61
+ return bundledErrorMatch[1];
62
+ }
63
+ }
64
+ if (error.code) {
65
+ return error.code.replace("auth/", "");
66
+ }
67
+ if (typeof error.message === "string") {
68
+ const messageCodeMatch = error.message.match(/auth\/([a-z-]+)/);
69
+ if (messageCodeMatch) {
70
+ return messageCodeMatch[1];
71
+ }
72
+ }
73
+ return "";
74
+ }
75
+ function mapFirebaseErrorCode(code) {
76
+ const directMappings = {
77
+ "invalid-email": "INVALID_EMAIL",
78
+ "user-disabled": "USER_DISABLED",
79
+ "too-many-requests": "TOO_MANY_ATTEMPTS",
80
+ "network-request-failed": "NETWORK_ERROR",
81
+ "operation-not-allowed": "OPERATION_NOT_ALLOWED",
82
+ "popup-blocked": "POPUP_BLOCKED",
83
+ "email-already-in-use": "EMAIL_EXISTS",
84
+ "weak-password": "WEAK_PASSWORD",
85
+ "invalid-credential": "INVALID_CREDENTIALS",
86
+ "wrong-password": "INVALID_CREDENTIALS",
87
+ "user-not-found": "INVALID_CREDENTIALS",
88
+ "invalid-password": "INVALID_CREDENTIALS",
89
+ "user-token-expired": "EXPIRED_TOKEN",
90
+ "invalid-id-token": "INVALID_TOKEN"
91
+ };
92
+ return directMappings[code] || "INTERNAL_ERROR";
93
+ }
94
+ function determineErrorTypeFromMessage(message) {
95
+ const bundledErrorMatch = message.match(/Firebase:\s*Error\s*$$auth\/([^)]+)$$/);
96
+ if (bundledErrorMatch) {
97
+ const errorCode = bundledErrorMatch[1];
98
+ const mappedCode = mapFirebaseErrorCode(errorCode);
99
+ if (mappedCode) {
100
+ return mappedCode;
101
+ }
102
+ }
103
+ for (const [errorType, pattern] of Object.entries(ERROR_PATTERNS)) {
104
+ if (pattern.test(message)) {
105
+ return errorType;
106
+ }
107
+ }
108
+ return "INTERNAL_ERROR";
109
+ }
110
+ function createErrorResponse(code, message) {
111
+ const defaultMessages = {
112
+ INVALID_EMAIL: "Invalid email format",
113
+ INVALID_CREDENTIALS: "Invalid email or password",
114
+ USER_DISABLED: "This account has been disabled",
115
+ TOO_MANY_ATTEMPTS: "Too many attempts. Please try again later",
116
+ NETWORK_ERROR: "Network error. Please check your connection",
117
+ OPERATION_NOT_ALLOWED: "This login method is not enabled",
118
+ POPUP_BLOCKED: "Login popup was blocked. Please enable popups",
119
+ EMAIL_EXISTS: "This email is already in use",
120
+ EXPIRED_TOKEN: "Your session has expired. Please login again",
121
+ INVALID_TOKEN: "Invalid authentication token",
122
+ SESSION_EXPIRED: "Your session has expired",
123
+ WEAK_PASSWORD: "Password is too weak",
124
+ EMAIL_NOT_VERIFIED: "Email verification required",
125
+ INTERNAL_ERROR: "An internal error occurred. Please try again",
126
+ SERVER_SIDE_INITIALIZATION: "TernSecure must be initialized on the client side",
127
+ REQUIRES_VERIFICATION: "Email verification required",
128
+ AUTHENTICATED: "Already authenticated",
129
+ UNAUTHENTICATED: "Authentication required",
130
+ UNVERIFIED: "Email verification required",
131
+ NOT_INITIALIZED: "TernSecure services are not initialized",
132
+ HOOK_CONTEXT: "Hook must be used within TernSecureProvider"
133
+ };
134
+ return {
135
+ success: false,
136
+ message: message || defaultMessages[code],
137
+ code
138
+ };
139
+ }
140
+ function handleFirebaseAuthError(error) {
141
+ function extractErrorInfo(input) {
142
+ if (typeof input === "string") {
143
+ const match = input.match(/Firebase:\s*Error\s*\(auth\/([^)]+)\)/);
144
+ if (match) {
145
+ return { code: match[1], message: input };
146
+ }
147
+ }
148
+ if (input && typeof input === "object") {
149
+ const err = input;
150
+ if (err.message) {
151
+ const match = err.message.match(/Firebase:\s*Error\s*\(auth\/([^)]+)\)/);
152
+ if (match) {
153
+ return { code: match[1], message: err.message };
154
+ }
155
+ }
156
+ if (err.code) {
157
+ return {
158
+ code: err.code.replace("auth/", ""),
159
+ message: err.message || ""
160
+ };
161
+ }
162
+ }
163
+ return null;
164
+ }
165
+ const ERROR_MESSAGES = {
166
+ "invalid-email": { message: "Invalid email format", code: "INVALID_EMAIL" },
167
+ "invalid-credential": { message: "Invalid email or password", code: "INVALID_CREDENTIALS" },
168
+ "invalid-login-credentials": { message: "Invalid email or password", code: "INVALID_CREDENTIALS" },
169
+ "wrong-password": { message: "Invalid email or password", code: "INVALID_CREDENTIALS" },
170
+ "user-not-found": { message: "Invalid email or password", code: "INVALID_CREDENTIALS" },
171
+ "user-disabled": { message: "This account has been disabled", code: "USER_DISABLED" },
172
+ "too-many-requests": { message: "Too many attempts. Please try again later", code: "TOO_MANY_ATTEMPTS" },
173
+ "network-request-failed": { message: "Network error. Please check your connection", code: "NETWORK_ERROR" },
174
+ "email-already-in-use": { message: "This email is already in use", code: "EMAIL_EXISTS" },
175
+ "weak-password": { message: "Password is too weak", code: "WEAK_PASSWORD" },
176
+ "operation-not-allowed": { message: "This login method is not enabled", code: "OPERATION_NOT_ALLOWED" },
177
+ "popup-blocked": { message: "Login popup was blocked. Please enable popups", code: "POPUP_BLOCKED" },
178
+ "expired-action-code": { message: "Your session has expired. Please login again", code: "EXPIRED_TOKEN" },
179
+ "user-token-expired": { message: "Your session has expired. Please login again", code: "EXPIRED_TOKEN" }
180
+ };
181
+ try {
182
+ const errorInfo = extractErrorInfo(error);
183
+ if (errorInfo) {
184
+ const mappedError = ERROR_MESSAGES[errorInfo.code];
185
+ if (mappedError) {
186
+ return {
187
+ success: false,
188
+ message: mappedError.message,
189
+ code: mappedError.code
190
+ };
191
+ }
192
+ }
193
+ const errorString = String(error);
194
+ const lastMatch = errorString.match(/Firebase:\s*Error\s*\(auth\/([^)]+)\)/);
195
+ if (lastMatch && ERROR_MESSAGES[lastMatch[1]]) {
196
+ return {
197
+ success: false,
198
+ ...ERROR_MESSAGES[lastMatch[1]]
199
+ };
200
+ }
201
+ } catch (e) {
202
+ }
203
+ return {
204
+ success: false,
205
+ message: "An unexpected error occurred. Please try again later",
206
+ code: "INTERNAL_ERROR"
207
+ };
208
+ }
209
+ function isAuthErrorResponse(response) {
210
+ return typeof response === "object" && response !== null && "success" in response && response.success === false && "code" in response && "message" in response;
211
+ }
212
+ function getErrorAlertVariant(error) {
213
+ if (!error) return "destructive";
214
+ switch (error.error) {
215
+ case "AUTHENTICATED":
216
+ return "default";
217
+ case "EMAIL_EXISTS":
218
+ case "UNAUTHENTICATED":
219
+ case "UNVERIFIED":
220
+ case "REQUIRES_VERIFICATION":
221
+ case "INVALID_EMAIL":
222
+ case "INVALID_TOKEN":
223
+ case "INTERNAL_ERROR":
224
+ case "USER_DISABLED":
225
+ case "TOO_MANY_ATTEMPTS":
226
+ case "NETWORK_ERROR":
227
+ case "SESSION_EXPIRED":
228
+ case "EXPIRED_TOKEN":
229
+ case "INVALID_CREDENTIALS":
230
+ default:
231
+ return "destructive";
11
232
  }
12
233
  }
13
234
  export {
14
235
  ERRORS,
15
- TernSecureError
236
+ TernSecureError,
237
+ getErrorAlertVariant,
238
+ handleFirebaseAuthError,
239
+ isAuthErrorResponse
16
240
  };
17
241
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/errors.ts"],"sourcesContent":["export const ERRORS = {\n SERVER_SIDE_INITIALIZATION: 'TernSecure must be initialized on the client side',\n REQUIRES_VERIFICATION: 'AUTH_REQUIRES_VERIFICATION',\n NOT_INITIALIZED: 'TernSecure services are not initialized. Call initializeTernSecure() first',\n HOOK_CONTEXT: (hookName: string) => `${hookName} must be used within TernSecureProvider`,\n } as const;\n \n export class TernSecureError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'TernSecureError';\n }\n }"],"mappings":"AAAO,MAAM,SAAS;AAAA,EAClB,4BAA4B;AAAA,EAC5B,uBAAuB;AAAA,EACvB,iBAAiB;AAAA,EACjB,cAAc,CAAC,aAAqB,GAAG,QAAQ;AACjD;AAEO,MAAM,wBAAwB,MAAM;AAAA,EACzC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/errors.ts"],"sourcesContent":["import { SignInResponse } from \"./types\"\n\nexport type ErrorCode = keyof typeof ERRORS\n\nexport interface AuthErrorResponse {\n success: false\n message: string\n code: ErrorCode\n}\n\nexport const ERRORS = {\n SERVER_SIDE_INITIALIZATION: \"TernSecure must be initialized on the client side\",\n REQUIRES_VERIFICATION: \"AUTH_REQUIRES_VERIFICATION\",\n AUTHENTICATED: \"AUTHENTICATED\",\n UNAUTHENTICATED: \"UNAUTHENTICATED\",\n UNVERIFIED: \"UNVERIFIED\",\n NOT_INITIALIZED: \"TernSecure services are not initialized. Call initializeTernSecure() first\",\n HOOK_CONTEXT: \"Hook must be used within TernSecureProvider\",\n EMAIL_NOT_VERIFIED: \"EMAIL_NOT_VERIFIED\",\n INVALID_CREDENTIALS: \"INVALID_CREDENTIALS\",\n USER_DISABLED: \"USER_DISABLED\",\n TOO_MANY_ATTEMPTS: \"TOO_MANY_ATTEMPTS\",\n NETWORK_ERROR: \"NETWORK_ERROR\",\n INVALID_EMAIL: \"INVALID_EMAIL\",\n WEAK_PASSWORD: \"WEAK_PASSWORD\",\n EMAIL_EXISTS: \"EMAIL_EXISTS\",\n POPUP_BLOCKED: \"POPUP_BLOCKED\",\n OPERATION_NOT_ALLOWED: \"OPERATION_NOT_ALLOWED\",\n EXPIRED_TOKEN: \"EXPIRED_TOKEN\",\n INVALID_TOKEN: \"INVALID_TOKEN\",\n SESSION_EXPIRED: \"SESSION_EXPIRED\",\n INTERNAL_ERROR: \"INTERNAL_ERROR\",\n} as const\n\n// Firebase Auth Error Code patterns\nconst ERROR_PATTERNS = {\n INVALID_EMAIL: /auth.*invalid.*email|invalid.*email.*auth|Firebase:.*Error.*auth\\/invalid-email/i,\n INVALID_CREDENTIALS:\n /auth.*invalid.*credential|invalid.*password|wrong.*password|Firebase:.*Error.*auth\\/(invalid-credential|wrong-password|user-not-found)/i,\n USER_DISABLED: /user.*disabled|disabled.*user|Firebase:.*Error.*auth\\/user-disabled/i,\n TOO_MANY_ATTEMPTS: /too.*many.*attempts|too.*many.*requests|Firebase:.*Error.*auth\\/too-many-requests/i,\n NETWORK_ERROR: /network.*request.*failed|failed.*network|Firebase:.*Error.*auth\\/network-request-failed/i,\n OPERATION_NOT_ALLOWED: /operation.*not.*allowed|method.*not.*allowed|Firebase:.*Error.*auth\\/operation-not-allowed/i,\n POPUP_BLOCKED: /popup.*blocked|blocked.*popup|Firebase:.*Error.*auth\\/popup-blocked/i,\n EMAIL_EXISTS: /email.*exists|email.*already.*use|Firebase:.*Error.*auth\\/email-already-in-use/i,\n EXPIRED_TOKEN: /token.*expired|expired.*token|Firebase:.*Error.*auth\\/expired-token/i,\n INVALID_TOKEN: /invalid.*token|token.*invalid|Firebase:.*Error.*auth\\/invalid-token/i,\n SESSION_EXPIRED: /session.*expired|expired.*session|Firebase:.*Error.*auth\\/session-expired/i,\n WEAK_PASSWORD: /weak.*password|password.*weak|Firebase:.*Error.*auth\\/weak-password/i,\n} as const\n\nexport class TernSecureError extends Error {\n code: ErrorCode\n\n constructor(code: ErrorCode, message?: string) {\n super(message || code)\n this.name = \"TernSecureError\"\n this.code = code\n }\n}\n\ninterface SerializedFirebaseError {\n name?: string\n code?: string\n message?: string\n stack?: string\n}\n\n/**\n * Determines if an object matches the shape of a Firebase Error\n */\nfunction isFirebaseErrorLike(error: unknown): error is SerializedFirebaseError {\n if (!error || typeof error !== \"object\") return false\n\n const err = error as SerializedFirebaseError\n\n // Check for bundled Firebase error format: \"Firebase: Error (auth/error-code)\"\n if (typeof err.message === \"string\") {\n const bundledErrorMatch = err.message.match(/Firebase:\\s*Error\\s*$$auth\\/([^)]+)$$/)\n if (bundledErrorMatch) {\n // Add the extracted code to the error object\n err.code = `auth/${bundledErrorMatch[1]}`\n return true\n }\n }\n\n return (\n (typeof err.code === \"string\" && err.code.startsWith(\"auth/\")) ||\n (typeof err.name === \"string\" && err.name.includes(\"FirebaseError\"))\n )\n}\n\n/**\n * Extracts the error code from a Firebase-like error object\n */\nfunction extractFirebaseErrorCode(error: SerializedFirebaseError): string {\n // First try to extract from bundled error message format\n if (typeof error.message === \"string\") {\n const bundledErrorMatch = error.message.match(/Firebase:\\s*Error\\s*$$auth\\/([^)]+)$$/)\n if (bundledErrorMatch) {\n return bundledErrorMatch[1]\n }\n }\n\n // Then try the standard code property\n if (error.code) {\n return error.code.replace(\"auth/\", \"\")\n }\n\n // Finally try to extract from error message if it contains an error code\n if (typeof error.message === \"string\") {\n const messageCodeMatch = error.message.match(/auth\\/([a-z-]+)/)\n if (messageCodeMatch) {\n return messageCodeMatch[1]\n }\n }\n\n return \"\"\n}\n\n/**\n * Maps a Firebase error code to our internal error code\n */\nfunction mapFirebaseErrorCode(code: string): ErrorCode {\n // Direct mapping for known error codes\n const directMappings: Record<string, ErrorCode> = {\n \"invalid-email\": \"INVALID_EMAIL\",\n \"user-disabled\": \"USER_DISABLED\",\n \"too-many-requests\": \"TOO_MANY_ATTEMPTS\",\n \"network-request-failed\": \"NETWORK_ERROR\",\n \"operation-not-allowed\": \"OPERATION_NOT_ALLOWED\",\n \"popup-blocked\": \"POPUP_BLOCKED\",\n \"email-already-in-use\": \"EMAIL_EXISTS\",\n \"weak-password\": \"WEAK_PASSWORD\",\n \"invalid-credential\": \"INVALID_CREDENTIALS\",\n \"wrong-password\": \"INVALID_CREDENTIALS\",\n \"user-not-found\": \"INVALID_CREDENTIALS\",\n \"invalid-password\": \"INVALID_CREDENTIALS\",\n \"user-token-expired\": \"EXPIRED_TOKEN\",\n \"invalid-id-token\": \"INVALID_TOKEN\",\n }\n\n return directMappings[code] || \"INTERNAL_ERROR\"\n}\n\n/**\n * Determines error type based on error message pattern matching\n */\nfunction determineErrorTypeFromMessage(message: string): ErrorCode {\n // First check for bundled Firebase error format\n const bundledErrorMatch = message.match(/Firebase:\\s*Error\\s*$$auth\\/([^)]+)$$/)\n if (bundledErrorMatch) {\n const errorCode = bundledErrorMatch[1]\n const mappedCode = mapFirebaseErrorCode(errorCode)\n if (mappedCode) {\n return mappedCode\n }\n }\n\n // Then check standard patterns\n for (const [errorType, pattern] of Object.entries(ERROR_PATTERNS)) {\n if (pattern.test(message)) {\n return errorType as ErrorCode\n }\n }\n\n return \"INTERNAL_ERROR\"\n}\n\n/**\n * Creates a standardized error response\n */\nfunction createErrorResponse(code: ErrorCode, message: string): AuthErrorResponse {\n const defaultMessages: Record<ErrorCode, string> = {\n INVALID_EMAIL: \"Invalid email format\",\n INVALID_CREDENTIALS: \"Invalid email or password\",\n USER_DISABLED: \"This account has been disabled\",\n TOO_MANY_ATTEMPTS: \"Too many attempts. Please try again later\",\n NETWORK_ERROR: \"Network error. Please check your connection\",\n OPERATION_NOT_ALLOWED: \"This login method is not enabled\",\n POPUP_BLOCKED: \"Login popup was blocked. Please enable popups\",\n EMAIL_EXISTS: \"This email is already in use\",\n EXPIRED_TOKEN: \"Your session has expired. Please login again\",\n INVALID_TOKEN: \"Invalid authentication token\",\n SESSION_EXPIRED: \"Your session has expired\",\n WEAK_PASSWORD: \"Password is too weak\",\n EMAIL_NOT_VERIFIED: \"Email verification required\",\n INTERNAL_ERROR: \"An internal error occurred. Please try again\",\n SERVER_SIDE_INITIALIZATION: \"TernSecure must be initialized on the client side\",\n REQUIRES_VERIFICATION: \"Email verification required\",\n AUTHENTICATED: \"Already authenticated\",\n UNAUTHENTICATED: \"Authentication required\",\n UNVERIFIED: \"Email verification required\",\n NOT_INITIALIZED: \"TernSecure services are not initialized\",\n HOOK_CONTEXT: \"Hook must be used within TernSecureProvider\",\n }\n\n return {\n success: false,\n message: message || defaultMessages[code],\n code,\n }\n}\n\n/**\n * Handles Firebase authentication errors with multiple fallback mechanisms\n */\nexport function handleFirebaseAuthError(error: unknown): AuthErrorResponse {\n // Helper to extract clean error code from bundled format\n function extractErrorInfo(input: unknown): { code: string; message: string } | null {\n // Case 1: String input (direct Firebase error message)\n if (typeof input === 'string') {\n const match = input.match(/Firebase:\\s*Error\\s*\\(auth\\/([^)]+)\\)/);\n if (match) {\n return { code: match[1], message: input };\n }\n }\n\n // Case 2: Error object\n if (input && typeof input === 'object') {\n const err = input as { code?: string; message?: string };\n \n // Check for bundled message format first\n if (err.message) {\n const match = err.message.match(/Firebase:\\s*Error\\s*\\(auth\\/([^)]+)\\)/);\n if (match) {\n return { code: match[1], message: err.message };\n }\n }\n\n // Check for direct code\n if (err.code) {\n return {\n code: err.code.replace('auth/', ''),\n message: err.message || ''\n };\n }\n }\n\n return null;\n }\n\n // Map error codes to user-friendly messages\n const ERROR_MESSAGES: Record<string, { message: string; code: ErrorCode }> = {\n 'invalid-email': { message: 'Invalid email format', code: 'INVALID_EMAIL' },\n 'invalid-credential': { message: 'Invalid email or password', code: 'INVALID_CREDENTIALS' },\n 'invalid-login-credentials': { message: 'Invalid email or password', code: 'INVALID_CREDENTIALS' },\n 'wrong-password': { message: 'Invalid email or password', code: 'INVALID_CREDENTIALS' },\n 'user-not-found': { message: 'Invalid email or password', code: 'INVALID_CREDENTIALS' },\n 'user-disabled': { message: 'This account has been disabled', code: 'USER_DISABLED' },\n 'too-many-requests': { message: 'Too many attempts. Please try again later', code: 'TOO_MANY_ATTEMPTS' },\n 'network-request-failed': { message: 'Network error. Please check your connection', code: 'NETWORK_ERROR' },\n 'email-already-in-use': { message: 'This email is already in use', code: 'EMAIL_EXISTS' },\n 'weak-password': { message: 'Password is too weak', code: 'WEAK_PASSWORD' },\n 'operation-not-allowed': { message: 'This login method is not enabled', code: 'OPERATION_NOT_ALLOWED' },\n 'popup-blocked': { message: 'Login popup was blocked. Please enable popups', code: 'POPUP_BLOCKED' },\n 'expired-action-code': { message: 'Your session has expired. Please login again', code: 'EXPIRED_TOKEN' },\n 'user-token-expired': { message: 'Your session has expired. Please login again', code: 'EXPIRED_TOKEN' }\n };\n\n try {\n // Extract error information\n const errorInfo = extractErrorInfo(error);\n \n if (errorInfo) {\n const mappedError = ERROR_MESSAGES[errorInfo.code];\n if (mappedError) {\n return {\n success: false,\n message: mappedError.message,\n code: mappedError.code\n };\n }\n }\n\n // If we couldn't extract or map the error, try one last time with string conversion\n const errorString = String(error);\n const lastMatch = errorString.match(/Firebase:\\s*Error\\s*\\(auth\\/([^)]+)\\)/);\n if (lastMatch && ERROR_MESSAGES[lastMatch[1]]) {\n return {\n success: false,\n ...ERROR_MESSAGES[lastMatch[1]]\n };\n }\n\n } catch (e) {\n // Silent catch - we'll return the default error\n }\n\n // Default fallback\n return {\n success: false,\n message: 'An unexpected error occurred. Please try again later',\n code: 'INTERNAL_ERROR'\n };\n}\n\n/**\n * Type guard to check if a response is an AuthErrorResponse\n */\nexport function isAuthErrorResponse(response: unknown): response is AuthErrorResponse {\n return (\n typeof response === \"object\" &&\n response !== null &&\n \"success\" in response &&\n (response as { success: boolean }).success === false &&\n \"code\" in response &&\n \"message\" in response\n )\n}\n\n\n\nexport function getErrorAlertVariant(error: SignInResponse | undefined) {\n if (!error) return \"destructive\"\n\n switch (error.error) {\n case \"AUTHENTICATED\":\n return \"default\"\n case \"EMAIL_EXISTS\":\n case \"UNAUTHENTICATED\":\n case \"UNVERIFIED\":\n case \"REQUIRES_VERIFICATION\":\n case \"INVALID_EMAIL\":\n case \"INVALID_TOKEN\":\n case \"INTERNAL_ERROR\":\n case \"USER_DISABLED\":\n case \"TOO_MANY_ATTEMPTS\":\n case \"NETWORK_ERROR\":\n case \"SESSION_EXPIRED\":\n case \"EXPIRED_TOKEN\":\n case \"INVALID_CREDENTIALS\":\n default:\n return \"destructive\"\n }\n}"],"mappings":"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","names":[]}
package/dist/esm/index.js CHANGED
@@ -3,7 +3,6 @@ import { loadFireConfig, validateConfig } from "./utils/config";
3
3
  import { signInWithEmail } from "./app-router/client/actions";
4
4
  import { TernSecureProvider } from "./app-router/client/TernSecureProvider";
5
5
  import { useAuth } from "./boundary/hooks/useAuth";
6
- import { useUser } from "./boundary/hooks/useUser";
7
6
  import { SignIn } from "./components/sign-in";
8
7
  import { SignOutButton } from "./components/sign-out-button";
9
8
  import { SignOut } from "./components/sign-out";
@@ -20,7 +19,6 @@ export {
20
19
  signInWithEmail,
21
20
  ternSecureAuth,
22
21
  useAuth,
23
- useUser,
24
22
  validateConfig
25
23
  };
26
24
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["\n//import { TernSecureServerProvider } from './app-router/server/TernSecureServerProvider'\n//import type { TernSecureState } from './app-router/client/TernSecureProvider'\nexport { TernSecureAuth, TernSecureFirestore, ternSecureAuth } from './utils/client-init'\nexport { loadFireConfig, validateConfig } from './utils/config'\nexport { signInWithEmail } from './app-router/client/actions'\n//export { useInternalContext } from './boundary/TernSecureCtx'\n//export { TernSecureClientProvider } from './app-router/client/TernSecureProvider'\nexport { TernSecureProvider } from './app-router/client/TernSecureProvider'\nexport { useAuth } from './boundary/hooks/useAuth' \nexport { useUser } from './boundary/hooks/useUser'\nexport { SignIn } from './components/sign-in'\nexport { SignOutButton } from './components/sign-out-button'\nexport { SignOut } from './components/sign-out'\nexport { SignUp } from './components/sign-up'\n\n//export const TernSecureProvider = TernSecureServerProvider\n//export type { TernSecureState }"],"mappings":"AAGA,SAAS,gBAAgB,qBAAqB,sBAAsB;AACpE,SAAS,gBAAgB,sBAAsB;AAC/C,SAAS,uBAAuB;AAGhC,SAAS,0BAA0B;AACnC,SAAS,eAAe;AACxB,SAAS,eAAe;AACxB,SAAS,cAAc;AACvB,SAAS,qBAAqB;AAC9B,SAAS,eAAe;AACxB,SAAS,cAAc;","names":[]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["\n//import { TernSecureServerProvider } from './app-router/server/TernSecureServerProvider'\n//import type { TernSecureState } from './app-router/client/TernSecureProvider'\nexport { TernSecureAuth, TernSecureFirestore, ternSecureAuth } from './utils/client-init'\nexport { loadFireConfig, validateConfig } from './utils/config'\nexport { signInWithEmail } from './app-router/client/actions'\n//export { useInternalContext } from './boundary/TernSecureCtx'\n//export { TernSecureClientProvider } from './app-router/client/TernSecureProvider'\nexport { TernSecureProvider } from './app-router/client/TernSecureProvider'\nexport { useAuth } from './boundary/hooks/useAuth' \nexport { SignIn } from './components/sign-in'\nexport { SignOutButton } from './components/sign-out-button'\nexport { SignOut } from './components/sign-out'\nexport { SignUp } from './components/sign-up'\n\n//export const TernSecureProvider = TernSecureServerProvider\n//export type { TernSecureState }"],"mappings":"AAGA,SAAS,gBAAgB,qBAAqB,sBAAsB;AACpE,SAAS,gBAAgB,sBAAsB;AAC/C,SAAS,uBAAuB;AAGhC,SAAS,0BAA0B;AACnC,SAAS,eAAe;AACxB,SAAS,cAAc;AACvB,SAAS,qBAAqB;AAC9B,SAAS,eAAe;AACxB,SAAS,cAAc;","names":[]}
package/dist/esm/types.js CHANGED
@@ -1 +1,7 @@
1
+ function isSignInResponse(value) {
2
+ return typeof value === "object" && "success" in value && typeof value.success === "boolean";
3
+ }
4
+ export {
5
+ isSignInResponse
6
+ };
1
7
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":["../../src/types.ts"],"sourcesContent":["import { FirebaseOptions } from 'firebase/app'\nimport { ERRORS } from './errors'\n\n\n/**\n * TernSecure Firebase configuration interface\n * Extends Firebase's base configuration options\n */\nexport interface TernSecureConfig extends FirebaseOptions {\n apiKey: string\n authDomain: string\n projectId: string\n storageBucket: string\n messagingSenderId: string\n appId: string\n measurementId?: string // Optional for analytics\n}\n\n/**\n * TernSecure initialization options\n */\nexport interface TernSecureOptions {\n /** Environment setting for different configurations */\n environment?: 'development' | 'production'\n /** Geographic region for data storage */\n region?: string\n /** Custom error handler */\n onError?: (error: Error) => void\n /** Debug mode flag */\n debug?: boolean\n}\n\n/**\n * Firebase initialization state\n */\nexport interface FirebaseState {\n /** Whether Firebase has been initialized */\n initialized: boolean\n /** Any initialization errors */\n error: Error | null\n /** Timestamp of last initialization attempt */\n lastInitAttempt?: number\n}\n\n/**\n * Configuration validation result\n */\nexport interface ConfigValidationResult {\n isValid: boolean\n errors: string[]\n config: TernSecureConfig\n}\n\n/**\n * Firebase Admin configuration interface\n */\nexport interface TernSecureAdminConfig {\n projectId: string\n clientEmail: string\n privateKey: string\n}\n\n/**\n * Firebase Admin configuration validation result\n */\nexport interface AdminConfigValidationResult {\n isValid: boolean\n errors: string[]\n config: TernSecureAdminConfig\n}\n\n\nexport interface SignInResponse {\n success: boolean;\n message?: string;\n error?: keyof typeof ERRORS | undefined; \n user?: any;\n}\n\nexport interface AuthError extends Error {\n code?: string\n message: string\n response?: SignInResponse\n}\n\nexport function isSignInResponse(value: any): value is SignInResponse {\n return typeof value === \"object\" && \"success\" in value && typeof value.success === \"boolean\"\n}\n\n\nexport interface TernSecureState {\n userId: string | null\n isLoaded: boolean\n error: Error | null\n isValid: boolean\n isVerified: boolean\n isAuthenticated: boolean\n token: any | null\n email: string | null\n status: \"loading\" | \"authenticated\" | \"unauthenticated\" | \"unverified\"\n requiresVerification: boolean\n}\n\nexport interface RedirectConfig {\n // URL to redirect to after successful authentication\n redirectUrl?: string\n // Whether this is a return visit (e.g. after sign out)\n isReturn?: boolean\n // Priority of the redirect (higher number = higher priority)\n priority?: number\n}\n\n\nexport interface SignInProps extends RedirectConfig {\n onError?: (error: Error) => void\n onSuccess?: () => void\n className?: string\n customStyles?: {\n card?: string\n input?: string\n button?: string\n label?: string\n separator?: string\n title?: string\n description?: string\n socialButton?: string\n }\n}\n\n\n"],"mappings":"AAqFO,SAAS,iBAAiB,OAAqC;AACpE,SAAO,OAAO,UAAU,YAAY,aAAa,SAAS,OAAO,MAAM,YAAY;AACrF;","names":[]}
@@ -1,37 +1,66 @@
1
+ import { isInternalRoute, isAuthRoute } from "../app-router/route-handler/internal-route";
1
2
  const constructFullUrl = (path) => {
3
+ if (typeof window === "undefined") return path;
2
4
  const baseUrl = window.location.origin;
3
5
  if (path.startsWith("http")) {
4
6
  return path;
5
7
  }
6
8
  return `${baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
7
9
  };
8
- const constructUrlWithRedirect = (path, redirectUrl, loginPath) => {
9
- const url = new URL(path, window.location.origin);
10
- if (redirectUrl && !redirectUrl.startsWith(loginPath)) {
11
- const fullRedirectUrl = redirectUrl.startsWith("http") ? redirectUrl : constructFullUrl(redirectUrl);
12
- url.searchParams.set("redirect_url", fullRedirectUrl);
10
+ const hasRedirectLoop = (currentPath, redirectPath) => {
11
+ if (!currentPath || !redirectPath) return false;
12
+ const cleanCurrentPath = currentPath.split("?")[0];
13
+ const cleanRedirectPath = redirectPath.split("?")[0];
14
+ return cleanCurrentPath === cleanRedirectPath;
15
+ };
16
+ const constructUrlWithRedirect = (path, redirectUrl) => {
17
+ const url = new URL(path, typeof window !== "undefined" ? window.location.origin : void 0);
18
+ if (redirectUrl && !isAuthRoute(redirectUrl) && !isInternalRoute(redirectUrl)) {
19
+ url.searchParams.set("redirect", redirectUrl);
13
20
  }
14
21
  return url.toString();
15
22
  };
16
- const getValidRedirectUrl = (redirectUrl, searchParams) => {
17
- const redirect = redirectUrl || searchParams.get("redirect_url") || "/";
23
+ const storePreviousPath = (path) => {
24
+ if (typeof window !== "undefined" && !isAuthRoute(path)) {
25
+ sessionStorage.setItem("previousPath", path);
26
+ }
27
+ };
28
+ const getPreviousPath = () => {
29
+ if (typeof window !== "undefined") {
30
+ return sessionStorage.getItem("previousPath");
31
+ }
32
+ return null;
33
+ };
34
+ const getValidRedirectUrl = (searchParams, configuredRedirect) => {
35
+ const urlRedirect = searchParams.get("redirect");
36
+ if (urlRedirect) {
37
+ return validateUrl(urlRedirect);
38
+ }
39
+ if (configuredRedirect) {
40
+ return validateUrl(configuredRedirect);
41
+ }
42
+ return "/";
43
+ };
44
+ const validateUrl = (url) => {
18
45
  try {
19
- if (redirect.startsWith("http")) {
20
- const url = new URL(redirect);
21
- if (url.origin === window.location.origin) {
22
- return redirect;
46
+ if (url.startsWith("http")) {
47
+ const urlObj = new URL(url);
48
+ if (typeof window !== "undefined" && urlObj.origin !== window.location.origin) {
49
+ return "/";
23
50
  }
24
- return "/";
51
+ return !isAuthRoute(urlObj.pathname) && !isInternalRoute(urlObj.pathname) ? urlObj.pathname : "/";
25
52
  }
26
- return constructFullUrl(redirect);
27
- } catch (e) {
28
- console.error("Invalid redirect URL:", e);
29
- return constructFullUrl("/");
53
+ return !isAuthRoute(url) && !isInternalRoute(url) ? url : "/";
54
+ } catch {
55
+ return "/";
30
56
  }
31
57
  };
32
58
  export {
33
59
  constructFullUrl,
34
60
  constructUrlWithRedirect,
35
- getValidRedirectUrl
61
+ getPreviousPath,
62
+ getValidRedirectUrl,
63
+ hasRedirectLoop,
64
+ storePreviousPath
36
65
  };
37
66
  //# sourceMappingURL=construct.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/construct.ts"],"sourcesContent":["/**\n * Constructs a full URL with the current origin\n * @param path - The path to construct the URL for\n * @returns The full URL with origin\n */\nexport const constructFullUrl = (path: string) => {\n const baseUrl = window.location.origin\n if (path.startsWith('http')) {\n return path\n }\n return `${baseUrl}${path.startsWith('/') ? path : `/${path}`}`\n }\n \n /**\n * Constructs a URL with redirect parameters\n * @param path - The base path (usually login path)\n * @param redirectUrl - The URL to redirect to after action completes\n * @param loginPath - The login path to check against\n * @returns The full URL with redirect parameters\n */\n export const constructUrlWithRedirect = (path: string, redirectUrl: string, loginPath: string) => {\n // Create the URL with the full origin\n const url = new URL(path, window.location.origin)\n \n // Add redirect parameter if provided and not redirecting to login\n if (redirectUrl && !redirectUrl.startsWith(loginPath)) {\n // Ensure redirect URL is also absolute if it's not already\n const fullRedirectUrl = redirectUrl.startsWith('http') \n ? redirectUrl \n : constructFullUrl(redirectUrl)\n \n url.searchParams.set('redirect_url', fullRedirectUrl)\n }\n \n return url.toString()\n }\n \n /**\n * Gets a validated redirect URL ensuring it's from the same origin\n * @param redirectUrl - The URL to validate\n * @param searchParams - The search parameters to check for redirect_url\n * @returns A validated redirect URL\n */\n export const getValidRedirectUrl = (\n redirectUrl: string | undefined,\n searchParams: URLSearchParams\n ): string => {\n const redirect = redirectUrl || searchParams.get('redirect_url') || '/'\n \n try {\n if (redirect.startsWith('http')) {\n const url = new URL(redirect)\n if (url.origin === window.location.origin) {\n return redirect\n }\n return '/'\n }\n return constructFullUrl(redirect)\n } catch (e) {\n console.error('Invalid redirect URL:', e)\n return constructFullUrl('/')\n }\n }\n \n "],"mappings":"AAKO,MAAM,mBAAmB,CAAC,SAAiB;AAC9C,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,KAAK,WAAW,MAAM,GAAG;AAC3B,WAAO;AAAA,EACT;AACA,SAAO,GAAG,OAAO,GAAG,KAAK,WAAW,GAAG,IAAI,OAAO,IAAI,IAAI,EAAE;AAC9D;AASO,MAAM,2BAA2B,CAAC,MAAc,aAAqB,cAAsB;AAEhG,QAAM,MAAM,IAAI,IAAI,MAAM,OAAO,SAAS,MAAM;AAGhD,MAAI,eAAe,CAAC,YAAY,WAAW,SAAS,GAAG;AAErD,UAAM,kBAAkB,YAAY,WAAW,MAAM,IACjD,cACA,iBAAiB,WAAW;AAEhC,QAAI,aAAa,IAAI,gBAAgB,eAAe;AAAA,EACtD;AAEA,SAAO,IAAI,SAAS;AACtB;AAQO,MAAM,sBAAsB,CACjC,aACA,iBACW;AACX,QAAM,WAAW,eAAe,aAAa,IAAI,cAAc,KAAK;AAEpE,MAAI;AACF,QAAI,SAAS,WAAW,MAAM,GAAG;AAC/B,YAAM,MAAM,IAAI,IAAI,QAAQ;AAC5B,UAAI,IAAI,WAAW,OAAO,SAAS,QAAQ;AACzC,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AACA,WAAO,iBAAiB,QAAQ;AAAA,EAClC,SAAS,GAAG;AACV,YAAQ,MAAM,yBAAyB,CAAC;AACxC,WAAO,iBAAiB,GAAG;AAAA,EAC7B;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/utils/construct.ts"],"sourcesContent":["//v2: redict with taking priority from the sign-in page\n\nimport { isInternalRoute, isAuthRoute } from \"../app-router/route-handler/internal-route\"\n\n/**\n * Constructs a full URL with the current origin\n * @param path - The path to construct the URL for\n * @returns The full URL with origin\n */\nexport const constructFullUrl = (path: string) => {\n if (typeof window === \"undefined\") return path\n const baseUrl = window.location.origin\n if (path.startsWith('http')) {\n return path\n }\n return `${baseUrl}${path.startsWith('/') ? path : `/${path}`}`\n }\n\n\n/**\n * Checks if the current URL has a redirect loop\n * @param currentPath - The current pathname\n * @param redirectPath - The path we're trying to redirect to\n * @returns boolean indicating if there's a redirect loop\n */\nexport const hasRedirectLoop = (currentPath: string, redirectPath: string): boolean => {\n if (!currentPath || !redirectPath) return false\n\n // Remove any query parameters for comparison\n const cleanCurrentPath = currentPath.split(\"?\")[0]\n const cleanRedirectPath = redirectPath.split(\"?\")[0]\n\n return cleanCurrentPath === cleanRedirectPath\n}\n \n/**\n * Constructs a URL with redirect parameters while preventing loops\n * @param path - The base path (usually login path)\n * @param redirectUrl - The URL to redirect to after action completes\n * @param loginPath - The login path to check against\n * @param signUpPath - The sign up path to check against\n * @returns The full URL with redirect parameters\n */\nexport const constructUrlWithRedirect = (\n path: string,\n redirectUrl: string | undefined,\n): string => {\n const url = new URL(path, typeof window !== \"undefined\" ? window.location.origin : undefined)\n \n if (redirectUrl && !isAuthRoute(redirectUrl) && !isInternalRoute(redirectUrl)) {\n url.searchParams.set(\"redirect\", redirectUrl)\n }\n \n return url.toString()\n}\n\n/**\n * Stores the current path before signing out\n */\nexport const storePreviousPath = (path: string): void => {\n if (typeof window !== \"undefined\" && !isAuthRoute(path)) {\n sessionStorage.setItem(\"previousPath\", path)\n }\n}\n\n/**\n * Gets the stored previous path\n */\nexport const getPreviousPath = (): string | null => {\n if (typeof window !== \"undefined\") {\n return sessionStorage.getItem(\"previousPath\")\n }\n return null\n}\n\n\n \n/**\n * Gets a validated redirect URL ensuring it's from the same origin\n * @param redirectUrl - The URL to validate\n * @param searchParams - The search parameters to check for redirect\n * @returns A validated redirect URL\n */\nexport const getValidRedirectUrl = (\n searchParams: URLSearchParams,\n configuredRedirect?: string,\n): string => {\n // Check URL search param first (highest priority)\n const urlRedirect = searchParams.get(\"redirect\")\n if (urlRedirect) {\n return validateUrl(urlRedirect)\n }\n\n // Then check configured redirect (for first visits)\n if (configuredRedirect) {\n return validateUrl(configuredRedirect)\n }\n\n // Default fallback\n return \"/\"\n}\n\n/**\n * Validates and sanitizes URLs\n */\nconst validateUrl = (url: string): string => {\n try {\n // For absolute URLs\n if (url.startsWith(\"http\")) {\n const urlObj = new URL(url)\n if (typeof window !== \"undefined\" && urlObj.origin !== window.location.origin) {\n return \"/\"\n }\n return !isAuthRoute(urlObj.pathname) && !isInternalRoute(urlObj.pathname) \n ? urlObj.pathname \n : \"/\"\n }\n \n // For relative URLs\n return !isAuthRoute(url) && !isInternalRoute(url) ? url : \"/\"\n } catch {\n return \"/\"\n }\n}\n\n\n\n\n\n\n\n"],"mappings":"AAEA,SAAS,iBAAiB,mBAAmB;AAOtC,MAAM,mBAAmB,CAAC,SAAiB;AAChD,MAAI,OAAO,WAAW,YAAa,QAAO;AACxC,QAAM,UAAU,OAAO,SAAS;AAChC,MAAI,KAAK,WAAW,MAAM,GAAG;AAC3B,WAAO;AAAA,EACT;AACA,SAAO,GAAG,OAAO,GAAG,KAAK,WAAW,GAAG,IAAI,OAAO,IAAI,IAAI,EAAE;AAC9D;AASK,MAAM,kBAAkB,CAAC,aAAqB,iBAAkC;AACrF,MAAI,CAAC,eAAe,CAAC,aAAc,QAAO;AAG1C,QAAM,mBAAmB,YAAY,MAAM,GAAG,EAAE,CAAC;AACjD,QAAM,oBAAoB,aAAa,MAAM,GAAG,EAAE,CAAC;AAEnD,SAAO,qBAAqB;AAC9B;AAUO,MAAM,2BAA2B,CACtC,MACA,gBACW;AACX,QAAM,MAAM,IAAI,IAAI,MAAM,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS,MAAS;AAE5F,MAAI,eAAe,CAAC,YAAY,WAAW,KAAK,CAAC,gBAAgB,WAAW,GAAG;AAC7E,QAAI,aAAa,IAAI,YAAY,WAAW;AAAA,EAC9C;AAEA,SAAO,IAAI,SAAS;AACtB;AAKO,MAAM,oBAAoB,CAAC,SAAuB;AACvD,MAAI,OAAO,WAAW,eAAe,CAAC,YAAY,IAAI,GAAG;AACvD,mBAAe,QAAQ,gBAAgB,IAAI;AAAA,EAC7C;AACF;AAKO,MAAM,kBAAkB,MAAqB;AAClD,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,eAAe,QAAQ,cAAc;AAAA,EAC9C;AACA,SAAO;AACT;AAUO,MAAM,sBAAsB,CACjC,cACA,uBACW;AAEX,QAAM,cAAc,aAAa,IAAI,UAAU;AAC/C,MAAI,aAAa;AACf,WAAO,YAAY,WAAW;AAAA,EAChC;AAGA,MAAI,oBAAoB;AACtB,WAAO,YAAY,kBAAkB;AAAA,EACvC;AAGA,SAAO;AACT;AAKA,MAAM,cAAc,CAAC,QAAwB;AAC3C,MAAI;AAEF,QAAI,IAAI,WAAW,MAAM,GAAG;AAC1B,YAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,UAAI,OAAO,WAAW,eAAe,OAAO,WAAW,OAAO,SAAS,QAAQ;AAC7E,eAAO;AAAA,MACT;AACA,aAAO,CAAC,YAAY,OAAO,QAAQ,KAAK,CAAC,gBAAgB,OAAO,QAAQ,IACpE,OAAO,WACP;AAAA,IACN;AAGA,WAAO,CAAC,YAAY,GAAG,KAAK,CAAC,gBAAgB,GAAG,IAAI,MAAM;AAAA,EAC5D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}