@tern-secure/nextjs 3.4.3 → 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 +55 -55
  4. package/dist/cjs/app-router/client/actions.js.map +1 -1
  5. package/dist/cjs/app-router/route-handler/internal-route.js +22 -3
  6. package/dist/cjs/app-router/route-handler/internal-route.js.map +1 -1
  7. package/dist/cjs/boundary/TernSecureClientProvider.js +167 -34
  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 +15 -2
  11. package/dist/cjs/boundary/hooks/useAuth.js.map +1 -1
  12. package/dist/cjs/components/sign-in.js +158 -35
  13. package/dist/cjs/components/sign-in.js.map +1 -1
  14. package/dist/cjs/components/sign-out-button.js +84 -0
  15. package/dist/cjs/components/sign-out-button.js.map +1 -0
  16. package/dist/cjs/components/sign-out.js +39 -9
  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 +233 -5
  21. package/dist/cjs/errors.js.map +1 -1
  22. package/dist/cjs/index.js +3 -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 +64 -56
  33. package/dist/esm/app-router/client/actions.js.map +1 -1
  34. package/dist/esm/app-router/route-handler/internal-route.js +18 -2
  35. package/dist/esm/app-router/route-handler/internal-route.js.map +1 -1
  36. package/dist/esm/boundary/TernSecureClientProvider.js +168 -35
  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 +15 -2
  40. package/dist/esm/boundary/hooks/useAuth.js.map +1 -1
  41. package/dist/esm/components/sign-in.js +160 -37
  42. package/dist/esm/components/sign-in.js.map +1 -1
  43. package/dist/esm/components/sign-out-button.js +60 -0
  44. package/dist/esm/components/sign-out-button.js.map +1 -0
  45. package/dist/esm/components/sign-out.js +30 -10
  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 +229 -4
  50. package/dist/esm/errors.js.map +1 -1
  51. package/dist/esm/index.js +2 -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 +24 -18
  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 +8 -1
  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 -8
  68. package/dist/types/boundary/TernSecureCtx.d.ts.map +1 -1
  69. package/dist/types/boundary/hooks/useAuth.d.ts +6 -1
  70. package/dist/types/boundary/hooks/useAuth.d.ts.map +1 -1
  71. package/dist/types/components/sign-in.d.ts.map +1 -1
  72. package/dist/types/components/sign-out-button.d.ts +14 -0
  73. package/dist/types/components/sign-out-button.d.ts.map +1 -0
  74. package/dist/types/components/sign-out.d.ts +7 -5
  75. package/dist/types/components/sign-out.d.ts.map +1 -1
  76. package/dist/types/components/sign-up.d.ts +4 -0
  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 +37 -2
  81. package/dist/types/errors.d.ts.map +1 -1
  82. package/dist/types/index.d.ts +1 -1
  83. package/dist/types/index.d.ts.map +1 -1
  84. package/dist/types/types.d.ts +45 -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
@@ -23,8 +23,23 @@ __export(TernSecureProvider_exports, {
23
23
  module.exports = __toCommonJS(TernSecureProvider_exports);
24
24
  var import_jsx_runtime = require("react/jsx-runtime");
25
25
  var import_TernSecureClientProvider = require("../../boundary/TernSecureClientProvider");
26
- async function TernSecureProvider({ children }) {
27
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_TernSecureClientProvider.TernSecureClientProvider, { children });
26
+ async function TernSecureProvider({
27
+ children,
28
+ requiresVerification = true,
29
+ loginPath,
30
+ signUpPath,
31
+ loadingComponent
32
+ }) {
33
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
34
+ import_TernSecureClientProvider.TernSecureClientProvider,
35
+ {
36
+ requiresVerification,
37
+ loginPath,
38
+ signUpPath,
39
+ loadingComponent,
40
+ children
41
+ }
42
+ );
28
43
  }
29
44
  // Annotate the CommonJS export names for ESM import in node:
30
45
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/app-router/client/TernSecureProvider.tsx"],"sourcesContent":["import React from \"react\"\nimport { TernSecureClientProvider } from \"../../boundary/TernSecureClientProvider\"\n\n\n// Loading fallback component\n/*function TernSecureLoadingFallback() {\n return (\n <div>\n <span className=\"sr-only\">Loading...</span>\n </div>\n )\n}*/\n/**\n * Root Provider for TernSecure\n * Use this in your Next.js App Router root layout\n * Automatically handles client/server boundary and authentication state\n * \n * @example\n * /// app/layout.tsx\n * import { TernSecureProvider } from '@tern/secure'\n * \n * export default function RootLayout({ children }) {\n * return (\n * <html>\n * <body>\n * <TernSecureProvider>\n * {children}\n * </TernSecureProvider>\n * </body>\n * </html>\n * )\n * }\n */\nexport async function TernSecureProvider({ children }: { children: React.ReactNode }) {\n return (\n <TernSecureClientProvider>\n {children}\n </TernSecureClientProvider>\n )\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCI;AAlCJ,sCAAyC;AAgCzC,eAAsB,mBAAmB,EAAE,SAAS,GAAkC;AACpF,SACE,4CAAC,4DACI,UACL;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../../src/app-router/client/TernSecureProvider.tsx"],"sourcesContent":["import React from \"react\"\nimport { TernSecureClientProvider } from \"../../boundary/TernSecureClientProvider\"\n\n\n/**\n * Configuration options for TernSecure authentication\n */\nexport interface TernSecureConfig {\n /** Whether email verification is required (defaults to true) */\n requiresVerification?: boolean\n /** Custom path for login page (defaults to /sign-in) */\n loginPath?: string\n /** Custom path for signup page (defaults to /sign-up) */\n signUpPath?: string\n /** Custom loading component */\n loadingComponent?: React.ReactNode\n}\n\n// Loading fallback component\n/*function TernSecureLoadingFallback() {\n return (\n <div>\n <span className=\"sr-only\">Loading...</span>\n </div>\n )\n}*/\n/**\n * Root Provider for TernSecure\n * Use this in your Next.js App Router root layout\n * Automatically handles client/server boundary and authentication state\n * \n * @example\n * /// app/layout.tsx\n * import { TernSecureProvider } from '@tern/secure'\n * \n * export default function RootLayout({ children }) {\n * return (\n * <html>\n * <body>\n * <TernSecureProvider>\n * {children}\n * </TernSecureProvider>\n * </body>\n * </html>\n * )\n * }\n */\nexport async function TernSecureProvider({ \n children,\n requiresVerification = true,\n loginPath,\n signUpPath,\n loadingComponent,\n }: React.PropsWithChildren<TernSecureConfig>) {\n return (\n <TernSecureClientProvider\n requiresVerification={requiresVerification}\n loginPath={loginPath}\n signUpPath={signUpPath}\n loadingComponent={loadingComponent}\n >\n {children}\n </TernSecureClientProvider>\n )\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAuDI;AAtDJ,sCAAyC;AA8CzC,eAAsB,mBAAmB;AAAA,EACvC;AAAA,EACA,uBAAuB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AACD,GAA8C;AAC7C,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAEG;AAAA;AAAA,EACL;AAEJ;","names":[]}
@@ -28,7 +28,7 @@ __export(actions_exports, {
28
28
  module.exports = __toCommonJS(actions_exports);
29
29
  var import_client_init = require("../../utils/client-init");
30
30
  var import_auth = require("firebase/auth");
31
- var import_sessionTernSecure = require("../server/sessionTernSecure");
31
+ var import_errors = require("../../errors");
32
32
  async function createUser(email, password) {
33
33
  const auth = (0, import_client_init.TernSecureAuth)();
34
34
  try {
@@ -38,43 +38,40 @@ async function createUser(email, password) {
38
38
  };
39
39
  const userCredential = await (0, import_auth.createUserWithEmailAndPassword)(auth, email, password);
40
40
  await (0, import_auth.sendEmailVerification)(userCredential.user, actionCodeSettings);
41
- return { success: true, message: "Account created successfully.", user: userCredential.user };
41
+ return {
42
+ success: true,
43
+ message: "Account created successfully. Please check your email for verification",
44
+ user: userCredential.user
45
+ };
42
46
  } catch (error) {
43
- if (error instanceof Error) {
44
- switch (error.message) {
45
- case "auth/too-many-requests":
46
- throw new Error("Too many attempts. Please try again later.");
47
- case "auth/network-request-failed":
48
- throw new Error("Network disconnected. Please try again later.");
49
- case "auth/email-already-in-use":
50
- throw new Error("Email is already registered.");
51
- case "auth/invalid-email":
52
- throw new Error("Invalid email address.");
53
- case "auth/operation-not-allowed":
54
- throw new Error("Email/password accounts are not enabled.");
55
- case "auth/weak-password":
56
- throw new Error("Password is too weak.");
57
- default:
58
- throw new Error(error.message);
59
- }
60
- }
61
- throw new Error("Failed to create account");
47
+ const authError = (0, import_errors.handleFirebaseAuthError)(error);
48
+ return {
49
+ success: false,
50
+ message: authError.message,
51
+ error: authError.code,
52
+ user: null
53
+ };
62
54
  }
63
55
  }
64
56
  async function signInWithEmail(email, password) {
65
57
  const auth = (0, import_client_init.TernSecureAuth)();
66
58
  try {
67
59
  const UserCredential = await (0, import_auth.signInWithEmailAndPassword)(auth, email, password);
68
- const idToken = await UserCredential.user.getIdToken();
69
- const res = await (0, import_sessionTernSecure.createSessionCookie)(idToken);
70
- if (res.success) {
71
- return { success: true, message: "Connected." };
72
- } else {
73
- throw new Error(res.message);
74
- }
60
+ const user = UserCredential.user;
61
+ return {
62
+ success: true,
63
+ message: "Authentication successful",
64
+ user,
65
+ error: !user.emailVerified ? "REQUIRES_VERIFICATION" : "AUTHENTICATED"
66
+ };
75
67
  } catch (error) {
76
- const errorMessage = error instanceof Error ? error.message : "Failed to sign in";
77
- throw new Error(errorMessage);
68
+ const authError = (0, import_errors.handleFirebaseAuthError)(error);
69
+ return {
70
+ success: false,
71
+ message: authError.message,
72
+ error: authError.code,
73
+ user: null
74
+ };
78
75
  }
79
76
  }
80
77
  async function signInWithRedirectGoogle() {
@@ -88,8 +85,13 @@ async function signInWithRedirectGoogle() {
88
85
  await (0, import_auth.signInWithRedirect)(auth, provider);
89
86
  return { success: true, message: "Redirect initiated" };
90
87
  } catch (error) {
91
- console.error("Error during Google sign-in:", error);
92
- return { success: false, error: "Failed to sign in with Google" };
88
+ const authError = (0, import_errors.handleFirebaseAuthError)(error);
89
+ return {
90
+ success: false,
91
+ message: authError.message,
92
+ error: authError.code,
93
+ user: null
94
+ };
93
95
  }
94
96
  }
95
97
  async function signInWithMicrosoft() {
@@ -102,8 +104,13 @@ async function signInWithMicrosoft() {
102
104
  await (0, import_auth.signInWithRedirect)(auth, provider);
103
105
  return { success: true, message: "Redirect initiated" };
104
106
  } catch (error) {
105
- console.error("Error during Google sign-in:", error);
106
- return { success: false, error: "Failed to sign in with Google" };
107
+ const authError = (0, import_errors.handleFirebaseAuthError)(error);
108
+ return {
109
+ success: false,
110
+ message: authError.message,
111
+ error: authError.code,
112
+ user: null
113
+ };
107
114
  }
108
115
  }
109
116
  async function handleAuthRedirectResult() {
@@ -117,8 +124,13 @@ async function handleAuthRedirectResult() {
117
124
  return { success: false, error: "No redirect result" };
118
125
  }
119
126
  } catch (error) {
120
- console.error("Error handling auth redirect result:", error);
121
- return { success: false, error: error.message || "Failed to handle auth redirect", code: error.code };
127
+ const authError = (0, import_errors.handleFirebaseAuthError)(error);
128
+ return {
129
+ success: false,
130
+ message: authError.message,
131
+ error: authError.code,
132
+ user: null
133
+ };
122
134
  }
123
135
  }
124
136
  async function resendEmailVerification() {
@@ -147,25 +159,13 @@ async function resendEmailVerification() {
147
159
  isVerified: false
148
160
  };
149
161
  } catch (error) {
150
- if (error instanceof Error) {
151
- switch (error.message) {
152
- case "auth/too-many-requests":
153
- throw new Error("Too many attempts. Please try again later.");
154
- case "auth/network-request-failed":
155
- throw new Error("Network disconnected. Please try again later.");
156
- case "auth/email-already-in-use":
157
- throw new Error("Email is already registered.");
158
- case "auth/invalid-email":
159
- throw new Error("Invalid email address.");
160
- case "auth/operation-not-allowed":
161
- throw new Error("Email/password accounts are not enabled.");
162
- case "auth/weak-password":
163
- throw new Error("Password is too weak.");
164
- default:
165
- throw new Error(error.message);
166
- }
167
- }
168
- throw new Error("Failed to resend verification email.");
162
+ const authError = (0, import_errors.handleFirebaseAuthError)(error);
163
+ return {
164
+ success: false,
165
+ message: authError.message,
166
+ error: authError.code,
167
+ user: null
168
+ };
169
169
  }
170
170
  }
171
171
  // Annotate the CommonJS export names for ESM import in node:
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/app-router/client/actions.ts"],"sourcesContent":["import { TernSecureAuth } from '../../utils/client-init'\nimport { signInWithEmailAndPassword, signInWithRedirect, getRedirectResult, GoogleAuthProvider, OAuthProvider, createUserWithEmailAndPassword, sendEmailVerification } from 'firebase/auth'\nimport { createSessionCookie } from '../server/sessionTernSecure'\n\nexport async function createUser(email: string, password: string) {\n const auth = TernSecureAuth()\n try {\n \n const actionCodeSettings = {\n url: `${window.location.origin}/sign-in`,\n handleCodeInApp: true\n };\n\n const userCredential = await createUserWithEmailAndPassword(auth, email, password);\n\n await sendEmailVerification(userCredential.user, actionCodeSettings)\n \n return { success: true, message: 'Account created successfully.', user: userCredential.user };\n\n } catch (error) {\n // Handle specific Firebase auth errors\n if (error instanceof Error) {\n switch (error.message) {\n case 'auth/too-many-requests':\n throw new Error('Too many attempts. Please try again later.');\n case 'auth/network-request-failed':\n throw new Error('Network disconnected. Please try again later.');\n case 'auth/email-already-in-use':\n throw new Error('Email is already registered.');\n case 'auth/invalid-email':\n throw new Error('Invalid email address.');\n case 'auth/operation-not-allowed':\n throw new Error('Email/password accounts are not enabled.');\n case 'auth/weak-password':\n throw new Error('Password is too weak.');\n default:\n throw new Error(error.message);\n }\n }\n throw new Error('Failed to create account');\n }\n}\n\n\nexport async function signInWithEmail(email: string, password: string){\n const auth = TernSecureAuth()\n try {\n const UserCredential = await signInWithEmailAndPassword(auth, email, password)\n const idToken = await UserCredential.user.getIdToken();\n\n const res = await createSessionCookie(idToken);\n\n if(res.success) {\n return { success: true, message: 'Connected.' };\n } else {\n throw new Error(res.message);\n }\n} catch (error){\n const errorMessage = error instanceof Error ? error.message : 'Failed to sign in';\n throw new Error(errorMessage);\n}\n} \n\nexport async function signInWithRedirectGoogle() {\n const auth = TernSecureAuth()\n const provider = new GoogleAuthProvider()\n provider.setCustomParameters({\n login_hint: 'user@example.com',\n prompt: 'select_account'\n })\n\n try {\n await signInWithRedirect(auth, provider)\n return { success: true, message: 'Redirect initiated' }\n } catch (error) {\n console.error('Error during Google sign-in:', error)\n return { success: false, error: 'Failed to sign in with Google' }\n }\n}\n\n\nexport async function signInWithMicrosoft() {\n const auth = TernSecureAuth()\n const provider = new OAuthProvider('microsoft.com')\n provider.setCustomParameters({\n prompt: 'consent'\n })\n\n try {\n await signInWithRedirect(auth, provider)\n return { success: true, message: 'Redirect initiated' }\n } catch (error) {\n console.error('Error during Google sign-in:', error)\n return { success: false, error: 'Failed to sign in with Google' }\n }\n}\n\n\nexport async function handleAuthRedirectResult() {\n const auth = TernSecureAuth()\n try {\n const result = await getRedirectResult(auth)\n if (result) {\n const user = result.user\n return { success: true, user }\n } else {\n return { success: false, error: 'No redirect result' }\n }\n } catch (error: any) {\n console.error('Error handling auth redirect result:', error)\n return { success: false, error: error.message || 'Failed to handle auth redirect', code: error.code }\n }\n}\n\n\nexport async function resendEmailVerification() {\n const auth = TernSecureAuth()\n try {\n const user = auth.currentUser;\n if (!user) {\n throw new Error('No user found. Please try signing up again.');\n }\n\n await user.reload();\n\n if (user.emailVerified) {\n return { \n success: true, \n message: 'Email is already verified. You can sign in.',\n isVerified: true \n };\n }\n\n const actionCodeSettings = {\n url: `${window.location.origin}/sign-in`,\n handleCodeInApp: true,\n };\n\n await sendEmailVerification(user, actionCodeSettings);\n return { \n success: true, \n message: 'Verification email sent successfully.',\n isVerified: false\n };\n } catch (error) {\n if (error instanceof Error) {\n switch (error.message) {\n case 'auth/too-many-requests':\n throw new Error('Too many attempts. Please try again later.');\n case 'auth/network-request-failed':\n throw new Error('Network disconnected. Please try again later.');\n case 'auth/email-already-in-use':\n throw new Error('Email is already registered.');\n case 'auth/invalid-email':\n throw new Error('Invalid email address.');\n case 'auth/operation-not-allowed':\n throw new Error('Email/password accounts are not enabled.');\n case 'auth/weak-password':\n throw new Error('Password is too weak.');\n default:\n throw new Error(error.message);\n }\n }\n throw new Error('Failed to resend verification email.');\n }\n}"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/app-router/client/actions.ts"],"sourcesContent":["import { TernSecureAuth } from '../../utils/client-init'\nimport { \n signInWithEmailAndPassword, \n signInWithRedirect, \n getRedirectResult, \n GoogleAuthProvider, \n OAuthProvider, \n createUserWithEmailAndPassword, \n sendEmailVerification } from 'firebase/auth'\nimport type { SignInResponse } from '../../types'\nimport { handleFirebaseAuthError } from '../../errors'\n\n\nexport async function createUser(email: string, password: string): Promise<SignInResponse> {\n const auth = TernSecureAuth()\n try {\n \n const actionCodeSettings = {\n url: `${window.location.origin}/sign-in`,\n handleCodeInApp: true\n };\n\n const userCredential = await createUserWithEmailAndPassword(auth, email, password);\n\n await sendEmailVerification(userCredential.user, actionCodeSettings)\n \n return { \n success: true, \n message: 'Account created successfully. Please check your email for verification', \n user: userCredential.user \n };\n\n } catch (error) {\n const authError = handleFirebaseAuthError(error)\n return { \n success: false, \n message: authError.message, \n error: authError.code,\n user: null\n }\n }\n}\n\n\nexport async function signInWithEmail(email: string, password: string): Promise<SignInResponse> {\n const auth = TernSecureAuth()\n try {\n const UserCredential = await signInWithEmailAndPassword(auth, email, password)\n const user = UserCredential.user\n \n return { \n success: true, \n message: 'Authentication successful',\n user: user,\n error: !user.emailVerified ? 'REQUIRES_VERIFICATION' : 'AUTHENTICATED'\n };\n\n} catch (error){\n const authError = handleFirebaseAuthError(error)\n return { \n success: false,\n message: authError.message,\n error: authError.code,\n user: null\n }\n}\n}\n\nexport async function signInWithRedirectGoogle() {\n const auth = TernSecureAuth()\n const provider = new GoogleAuthProvider()\n provider.setCustomParameters({\n login_hint: 'user@example.com',\n prompt: 'select_account'\n })\n\n try {\n await signInWithRedirect(auth, provider)\n return { success: true, message: 'Redirect initiated' }\n } catch (error) {\n const authError = handleFirebaseAuthError(error)\n return {\n success: false,\n message: authError.message,\n error: authError.code,\n user: null\n }\n }\n}\n\n\nexport async function signInWithMicrosoft() {\n const auth = TernSecureAuth()\n const provider = new OAuthProvider('microsoft.com')\n provider.setCustomParameters({\n prompt: 'consent'\n })\n\n try {\n await signInWithRedirect(auth, provider)\n return { success: true, message: 'Redirect initiated' }\n } catch (error) {\n const authError = handleFirebaseAuthError(error)\n return {\n success: false, \n message: authError.message,\n error: authError.code,\n user: null\n }\n }\n}\n\n\nexport async function handleAuthRedirectResult() {\n const auth = TernSecureAuth()\n try {\n const result = await getRedirectResult(auth)\n if (result) {\n const user = result.user\n return { success: true, user }\n } else {\n return { success: false, error: 'No redirect result' }\n }\n } catch (error: any) {\n const authError = handleFirebaseAuthError(error)\n return {\n success: false,\n message: authError.message,\n error: authError.code,\n user: null\n }\n }\n}\n\n\nexport async function resendEmailVerification() {\n const auth = TernSecureAuth()\n try {\n const user = auth.currentUser;\n if (!user) {\n throw new Error('No user found. Please try signing up again.');\n }\n\n await user.reload();\n\n if (user.emailVerified) {\n return { \n success: true, \n message: 'Email is already verified. You can sign in.',\n isVerified: true \n };\n }\n\n const actionCodeSettings = {\n url: `${window.location.origin}/sign-in`,\n handleCodeInApp: true,\n };\n\n await sendEmailVerification(user, actionCodeSettings);\n return { \n success: true, \n message: 'Verification email sent successfully.',\n isVerified: false\n };\n } catch (error) {\n const authError = handleFirebaseAuthError(error)\n return {\n success: false,\n message: authError.message,\n error: authError.code,\n user: null\n }\n }\n}"],"mappings":"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","names":[]}
@@ -19,16 +19,32 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var internal_route_exports = {};
20
20
  __export(internal_route_exports, {
21
21
  handleInternalRoute: () => handleInternalRoute,
22
- internalRoutes: () => internalRoutes
22
+ internalRoutes: () => internalRoutes,
23
+ isAuthRoute: () => isAuthRoute,
24
+ isBaseAuthRoute: () => isBaseAuthRoute,
25
+ isInternalRoute: () => isInternalRoute
23
26
  });
24
27
  module.exports = __toCommonJS(internal_route_exports);
25
28
  var import_verify = require("../../components/verify");
26
29
  const internalRoutes = {
27
- verify: {
30
+ signUpVerify: {
28
31
  pattern: /^\/sign-up\/verify$/,
29
32
  component: import_verify.Verify
33
+ },
34
+ signInVerify: {
35
+ pattern: /^\/sign-in\/verify$/,
36
+ component: import_verify.Verify
30
37
  }
31
38
  };
39
+ function isInternalRoute(pathname) {
40
+ return Object.values(internalRoutes).some((route) => route.pattern.test(pathname));
41
+ }
42
+ function isAuthRoute(pathname) {
43
+ return pathname.startsWith("/sign-in") || pathname.startsWith("/sign-up");
44
+ }
45
+ function isBaseAuthRoute(pathname) {
46
+ return pathname === "/sign-in" || pathname === "/sign-up";
47
+ }
32
48
  function handleInternalRoute(pathname) {
33
49
  for (const [key, route] of Object.entries(internalRoutes)) {
34
50
  if (route.pattern.test(pathname)) {
@@ -40,6 +56,9 @@ function handleInternalRoute(pathname) {
40
56
  // Annotate the CommonJS export names for ESM import in node:
41
57
  0 && (module.exports = {
42
58
  handleInternalRoute,
43
- internalRoutes
59
+ internalRoutes,
60
+ isAuthRoute,
61
+ isBaseAuthRoute,
62
+ isInternalRoute
44
63
  });
45
64
  //# sourceMappingURL=internal-route.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/app-router/route-handler/internal-route.tsx"],"sourcesContent":["import { Verify } from \"../../components/verify\"\n\n// Internal route mapping\nexport const internalRoutes = {\n verify: {\n pattern: /^\\/sign-up\\/verify$/,\n component: Verify,\n },\n}\n\n// Internal route handler\nexport function handleInternalRoute(pathname: string) {\n for (const [key, route] of Object.entries(internalRoutes)) {\n if (route.pattern.test(pathname)) {\n return route.component\n }\n }\n return null\n}\n\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAuB;AAGhB,MAAM,iBAAiB;AAAA,EAC5B,QAAQ;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,EACb;AACF;AAGO,SAAS,oBAAoB,UAAkB;AACpD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,cAAc,GAAG;AACzD,QAAI,MAAM,QAAQ,KAAK,QAAQ,GAAG;AAChC,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../../../src/app-router/route-handler/internal-route.tsx"],"sourcesContent":["import { Verify } from \"../../components/verify\"\n\n// Internal route mapping\nexport const internalRoutes = {\n signUpVerify: {\n pattern: /^\\/sign-up\\/verify$/,\n component: Verify,\n },\n signInVerify: {\n pattern: /^\\/sign-in\\/verify$/,\n component: Verify,\n },\n}\n\n// Check if path is an internal route\nexport function isInternalRoute(pathname: string): boolean {\n return Object.values(internalRoutes).some((route) => route.pattern.test(pathname))\n}\n\n// Check if path is within auth routes\nexport function isAuthRoute(pathname: string): boolean {\n return pathname.startsWith(\"/sign-in\") || pathname.startsWith(\"/sign-up\")\n}\n\n// Check if path is exactly the base auth route\nexport function isBaseAuthRoute(pathname: string): boolean {\n return pathname === \"/sign-in\" || pathname === \"/sign-up\"\n}\n\n// Internal route handler\nexport function handleInternalRoute(pathname: string) {\n for (const [key, route] of Object.entries(internalRoutes)) {\n if (route.pattern.test(pathname)) {\n return route.component\n }\n }\n return null\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAuB;AAGhB,MAAM,iBAAiB;AAAA,EAC5B,cAAc;AAAA,IACZ,SAAS;AAAA,IACT,WAAW;AAAA,EACb;AAAA,EACA,cAAc;AAAA,IACZ,SAAS;AAAA,IACT,WAAW;AAAA,EACb;AACF;AAGO,SAAS,gBAAgB,UAA2B;AACzD,SAAO,OAAO,OAAO,cAAc,EAAE,KAAK,CAAC,UAAU,MAAM,QAAQ,KAAK,QAAQ,CAAC;AACnF;AAGO,SAAS,YAAY,UAA2B;AACrD,SAAO,SAAS,WAAW,UAAU,KAAK,SAAS,WAAW,UAAU;AAC1E;AAGO,SAAS,gBAAgB,UAA2B;AACzD,SAAO,aAAa,cAAc,aAAa;AACjD;AAGO,SAAS,oBAAoB,UAAkB;AACpD,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,cAAc,GAAG;AACzD,QAAI,MAAM,QAAQ,KAAK,QAAQ,GAAG;AAChC,aAAO,MAAM;AAAA,IACf;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
@@ -28,22 +28,79 @@ var import_client_init = require("../utils/client-init");
28
28
  var import_auth = require("firebase/auth");
29
29
  var import_TernSecureCtx = require("./TernSecureCtx");
30
30
  var import_navigation = require("next/navigation");
31
+ var import_internal_route = require("../app-router/route-handler/internal-route");
32
+ var import_construct = require("../utils/construct");
31
33
  function TernSecureClientProvider({
32
34
  children,
33
- loginPath = "/sign-in",
34
- loadingComponent
35
+ loginPath = process.env.NEXT_PUBLIC_SIGN_IN_PATH || "/sign-in",
36
+ signUpPath = process.env.NEXT_PUBLIC_SIGN_UP_PATH || "/sign-up",
37
+ loadingComponent,
38
+ requiresVerification
35
39
  }) {
36
40
  const auth = (0, import_react.useMemo)(() => import_client_init.ternSecureAuth, []);
37
41
  const router = (0, import_navigation.useRouter)();
42
+ const pathname = (0, import_navigation.usePathname)();
43
+ const [isRedirecting, setIsRedirecting] = (0, import_react.useState)(false);
38
44
  const [authState, setAuthState] = (0, import_react.useState)(() => ({
39
45
  userId: null,
40
46
  isLoaded: false,
41
47
  error: null,
42
48
  isValid: false,
49
+ isVerified: false,
50
+ isAuthenticated: false,
43
51
  token: null,
44
- email: null
52
+ email: null,
53
+ status: "loading",
54
+ requiresVerification
45
55
  }));
56
+ const constructUrlWithRedirect = (0, import_react.useCallback)(
57
+ (loginPath2, currentPath, loginPathParam, signUpPathParam) => {
58
+ const baseUrl = window.location.origin;
59
+ const signInUrl = new URL(loginPath2, baseUrl);
60
+ if (!currentPath.includes(loginPathParam) && !currentPath.includes(signUpPathParam)) {
61
+ signInUrl.searchParams.set("redirect", currentPath);
62
+ }
63
+ return signInUrl.toString();
64
+ },
65
+ []
66
+ );
67
+ const shouldRedirect = (0, import_react.useCallback)(
68
+ (pathname2, isVerified) => {
69
+ const searchParams = new URLSearchParams(window.location.search);
70
+ if ((0, import_internal_route.isBaseAuthRoute)(pathname2) && !searchParams.has("redirect")) {
71
+ return false;
72
+ }
73
+ if ((0, import_internal_route.isInternalRoute)(pathname2)) {
74
+ return false;
75
+ }
76
+ if ((0, import_internal_route.isAuthRoute)(pathname2) && (!requiresVerification || isVerified)) {
77
+ return false;
78
+ }
79
+ return true;
80
+ },
81
+ [requiresVerification]
82
+ );
83
+ const redirectToLogin = (0, import_react.useCallback)(
84
+ (currentPath) => {
85
+ const path = currentPath || pathname || "/";
86
+ if ((0, import_internal_route.isInternalRoute)(path)) {
87
+ return;
88
+ }
89
+ if ((0, import_construct.hasRedirectLoop)(path, loginPath)) {
90
+ return;
91
+ }
92
+ setIsRedirecting(true);
93
+ const loginUrl = constructUrlWithRedirect(loginPath, path, loginPath, signUpPath);
94
+ if (process.env.NODE_ENV === "production") {
95
+ window.location.href = loginUrl;
96
+ } else {
97
+ router.push(loginUrl);
98
+ }
99
+ },
100
+ [router, loginPath, signUpPath, pathname, constructUrlWithRedirect]
101
+ );
46
102
  const handleSignOut = (0, import_react.useCallback)(async (error) => {
103
+ const currentPath = window.location.pathname;
47
104
  await auth.signOut();
48
105
  setAuthState({
49
106
  isLoaded: true,
@@ -51,50 +108,126 @@ function TernSecureClientProvider({
51
108
  error: error || null,
52
109
  isValid: false,
53
110
  token: null,
54
- email: null
111
+ email: null,
112
+ isVerified: false,
113
+ isAuthenticated: false,
114
+ status: "unauthenticated",
115
+ requiresVerification
55
116
  });
56
- router.push(loginPath);
57
- }, [auth, router, loginPath]);
117
+ redirectToLogin(currentPath);
118
+ }, [auth, redirectToLogin, requiresVerification]);
58
119
  const setEmail = (0, import_react.useCallback)((email) => {
59
120
  setAuthState((prev) => ({
60
121
  ...prev,
61
122
  email
62
123
  }));
63
124
  }, []);
125
+ const getAuthError = (0, import_react.useCallback)(() => {
126
+ if (authState.error) {
127
+ const error = authState.error;
128
+ return {
129
+ success: false,
130
+ message: error.message,
131
+ error: error.code,
132
+ user: null
133
+ };
134
+ }
135
+ if (authState.requiresVerification && authState.isValid && !authState.isVerified) {
136
+ return {
137
+ success: false,
138
+ message: "Email verification required",
139
+ error: "EMAIL_NOT_VERIFIED",
140
+ user: null
141
+ };
142
+ }
143
+ if (!authState.isAuthenticated && authState.status !== "loading") {
144
+ return {
145
+ success: false,
146
+ message: "User is not authenticated",
147
+ error: "AUTHENTICATED",
148
+ user: null
149
+ };
150
+ }
151
+ return {
152
+ success: true,
153
+ user: import_client_init.ternSecureAuth.currentUser
154
+ };
155
+ }, [
156
+ authState.error,
157
+ authState.isValid,
158
+ authState.isVerified,
159
+ authState.isAuthenticated,
160
+ authState.status,
161
+ authState.requiresVerification
162
+ ]);
64
163
  (0, import_react.useEffect)(() => {
65
- const unsubscribe = (0, import_auth.onAuthStateChanged)(auth, async (user) => {
66
- if (user) {
67
- setAuthState({
68
- isLoaded: true,
69
- userId: user.uid,
70
- isValid: true,
71
- token: user.getIdToken(),
72
- error: null,
73
- email: user.email
74
- });
75
- } else {
76
- setAuthState({
77
- isLoaded: true,
78
- userId: null,
79
- isValid: false,
80
- token: null,
81
- error: new Error("User is not authenticated"),
82
- email: null
83
- });
84
- if (!window.location.pathname.includes("/sign-up")) {
85
- router.push(loginPath);
164
+ let mounted = true;
165
+ let initialLoad = true;
166
+ const unsubscribe = (0, import_auth.onAuthStateChanged)(
167
+ auth,
168
+ async (user) => {
169
+ if (!mounted) return;
170
+ try {
171
+ if (user) {
172
+ const isValid = !!user.uid;
173
+ const isVerified = user.emailVerified;
174
+ const isAuthenticated = isValid && (!requiresVerification || isVerified);
175
+ setAuthState({
176
+ isLoaded: true,
177
+ userId: user.uid,
178
+ isValid,
179
+ isVerified,
180
+ isAuthenticated: isValid && isVerified,
181
+ token: user.getIdToken(),
182
+ error: null,
183
+ email: user.email,
184
+ status: isAuthenticated ? "authenticated" : "unverified",
185
+ requiresVerification
186
+ });
187
+ if (requiresVerification && !isVerified && shouldRedirect(pathname || "", isVerified)) {
188
+ if (initialLoad || !isRedirecting) {
189
+ redirectToLogin(pathname);
190
+ }
191
+ }
192
+ } else {
193
+ setAuthState({
194
+ isLoaded: true,
195
+ userId: null,
196
+ isValid: false,
197
+ isVerified: false,
198
+ isAuthenticated: false,
199
+ token: null,
200
+ error: null,
201
+ email: null,
202
+ status: "unauthenticated",
203
+ requiresVerification
204
+ });
205
+ if (shouldRedirect(pathname || "", false) && initialLoad) {
206
+ redirectToLogin();
207
+ }
208
+ }
209
+ } catch (error) {
210
+ console.error("Auth state change error:", error);
211
+ if (mounted) {
212
+ handleSignOut(error instanceof Error ? error : new Error("Authentication error occurred"));
213
+ }
214
+ } finally {
215
+ initialLoad = false;
86
216
  }
87
217
  }
88
- }, (error) => {
89
- handleSignOut(error instanceof Error ? error : new Error("Authentication error occurred"));
90
- });
91
- return () => unsubscribe();
92
- }, [auth, handleSignOut, router, loginPath]);
218
+ );
219
+ return () => {
220
+ mounted = false;
221
+ unsubscribe();
222
+ };
223
+ }, [auth, handleSignOut, redirectToLogin, requiresVerification, pathname, isRedirecting, shouldRedirect]);
93
224
  const contextValue = (0, import_react.useMemo)(() => ({
94
225
  ...authState,
95
226
  signOut: handleSignOut,
96
- setEmail
97
- }), [authState, auth, handleSignOut, setEmail]);
227
+ setEmail,
228
+ getAuthError,
229
+ redirectToLogin
230
+ }), [authState, handleSignOut, setEmail, getAuthError, redirectToLogin]);
98
231
  if (!authState.isLoaded) {
99
232
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_TernSecureCtx.TernSecureCtx.Provider, { value: contextValue, children: loadingComponent || /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "aria-live": "polite", "aria-busy": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "sr-only", children: "Loading authentication state..." }) }) });
100
233
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/boundary/TernSecureClientProvider.tsx"],"sourcesContent":["\"use client\"\n\nimport React, { useState, useEffect, useMemo, useCallback } from 'react'\nimport { ternSecureAuth } from '../utils/client-init'\nimport { onAuthStateChanged, User } from \"firebase/auth\"\nimport { TernSecureCtx, TernSecureCtxValue, TernSecureState } from './TernSecureCtx'\nimport { useRouter } from 'next/navigation'\n\ninterface TernSecureClientProviderProps {\n children: React.ReactNode;\n onUserChanged?: (user: User | null) => Promise<void>;\n loginPath?: string;\n loadingComponent?: React.ReactNode;\n}\n\nexport function TernSecureClientProvider({ \n children, \n loginPath = '/sign-in',\n loadingComponent\n}: TernSecureClientProviderProps) {\n const auth = useMemo(() => ternSecureAuth, []);\n const router = useRouter();\n const [authState, setAuthState] = useState<TernSecureState>(() => ({\n userId: null,\n isLoaded: false,\n error: null,\n isValid: false,\n token: null,\n email: null\n }));\n\n const handleSignOut = useCallback(async (error?: Error) => {\n await auth.signOut();\n setAuthState({\n isLoaded: true,\n userId: null,\n error: error || null,\n isValid: false,\n token: null,\n email: null\n });\n router.push(loginPath);\n }, [auth, router, loginPath]);\n\n const setEmail = useCallback((email: string) => {\n setAuthState((prev) => ({\n ...prev,\n email,\n }))\n }, [])\n\nuseEffect(() => {\n const unsubscribe = onAuthStateChanged(auth, async (user: User | null) => {\n if (user) {\n setAuthState({\n isLoaded: true,\n userId: user.uid,\n isValid: true,\n token: user.getIdToken(),\n error: null,\n email: user.email,\n })\n } else {\n setAuthState({\n isLoaded: true,\n userId: null,\n isValid: false,\n token: null,\n error: new Error('User is not authenticated'),\n email: null\n })\n if (!window.location.pathname.includes(\"/sign-up\")) {\n router.push(loginPath)\n }\n }\n }, (error) => {\n handleSignOut(error instanceof Error ? error : new Error('Authentication error occurred'));\n })\n \n return () => unsubscribe()\n }, [auth, handleSignOut, router, loginPath])\n\n const contextValue: TernSecureCtxValue = useMemo(() => ({\n ...authState,\n signOut: handleSignOut,\n setEmail\n }), [authState, auth, handleSignOut, setEmail]);\n\n if (!authState.isLoaded) {\n return (\n <TernSecureCtx.Provider value={contextValue}>\n {loadingComponent || (\n <div aria-live=\"polite\" aria-busy=\"true\">\n <span className=\"sr-only\">Loading authentication state...</span>\n </div>\n )}\n </TernSecureCtx.Provider>\n );\n }\n\n return (\n <TernSecureCtx.Provider value={contextValue}>\n {children}\n </TernSecureCtx.Provider>\n )\n}"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA6FY;AA3FZ,mBAAiE;AACjE,yBAA+B;AAC/B,kBAAyC;AACzC,2BAAmE;AACnE,wBAA0B;AASnB,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA,YAAY;AAAA,EACZ;AACF,GAAkC;AAChC,QAAM,WAAO,sBAAQ,MAAM,mCAAgB,CAAC,CAAC;AAC7C,QAAM,aAAS,6BAAU;AACzB,QAAM,CAAC,WAAW,YAAY,QAAI,uBAA0B,OAAO;AAAA,IACjE,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,OAAO;AAAA,IACP,OAAO;AAAA,EACT,EAAE;AAEF,QAAM,oBAAgB,0BAAY,OAAO,UAAkB;AACzD,UAAM,KAAK,QAAQ;AACnB,iBAAa;AAAA,MACX,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO,SAAS;AAAA,MAChB,SAAS;AAAA,MACT,OAAO;AAAA,MACP,OAAO;AAAA,IACT,CAAC;AACD,WAAO,KAAK,SAAS;AAAA,EACvB,GAAG,CAAC,MAAM,QAAQ,SAAS,CAAC;AAE5B,QAAM,eAAW,0BAAY,CAAC,UAAkB;AAC9C,iBAAa,CAAC,UAAU;AAAA,MACtB,GAAG;AAAA,MACH;AAAA,IACF,EAAE;AAAA,EACJ,GAAG,CAAC,CAAC;AAEP,8BAAU,MAAM;AACZ,UAAM,kBAAc,gCAAmB,MAAM,OAAO,SAAsB;AACxE,UAAI,MAAM;AACR,qBAAa;AAAA,UACX,UAAU;AAAA,UACV,QAAQ,KAAK;AAAA,UACb,SAAS;AAAA,UACT,OAAO,KAAK,WAAW;AAAA,UACvB,OAAO;AAAA,UACP,OAAO,KAAK;AAAA,QACd,CAAC;AAAA,MACH,OAAO;AACL,qBAAa;AAAA,UACX,UAAU;AAAA,UACV,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,OAAO;AAAA,UACP,OAAO,IAAI,MAAM,2BAA2B;AAAA,UAC5C,OAAO;AAAA,QACT,CAAC;AACD,YAAI,CAAC,OAAO,SAAS,SAAS,SAAS,UAAU,GAAG;AAClD,iBAAO,KAAK,SAAS;AAAA,QACvB;AAAA,MACF;AAAA,IACF,GAAG,CAAC,UAAU;AACZ,oBAAc,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,+BAA+B,CAAC;AAAA,IAC3F,CAAC;AAED,WAAO,MAAM,YAAY;AAAA,EAC3B,GAAG,CAAC,MAAM,eAAe,QAAQ,SAAS,CAAC;AAE3C,QAAM,mBAAmC,sBAAQ,OAAO;AAAA,IACtD,GAAG;AAAA,IACH,SAAS;AAAA,IACT;AAAA,EACF,IAAI,CAAC,WAAW,MAAM,eAAe,QAAQ,CAAC;AAE9C,MAAI,CAAC,UAAU,UAAU;AACvB,WACE,4CAAC,mCAAc,UAAd,EAAuB,OAAO,cAC5B,8BACC,4CAAC,SAAI,aAAU,UAAS,aAAU,QAChC,sDAAC,UAAK,WAAU,WAAU,6CAA+B,GAC3D,GAEJ;AAAA,EAEJ;AAEA,SACI,4CAAC,mCAAc,UAAd,EAAuB,OAAO,cAC7B,UACF;AAEN;","names":[]}
1
+ {"version":3,"sources":["../../../src/boundary/TernSecureClientProvider.tsx"],"sourcesContent":["\"use client\"\n\nimport React, { useState, useEffect, useMemo, useCallback } from 'react'\nimport { ternSecureAuth } from '../utils/client-init'\nimport { onAuthStateChanged, User } from \"firebase/auth\"\nimport { TernSecureCtx, TernSecureCtxValue } from './TernSecureCtx'\nimport type { TernSecureState, AuthError, SignInResponse } from \"../types\"\nimport type { ERRORS } from '../errors'\nimport { useRouter, usePathname } from 'next/navigation'\nimport { isBaseAuthRoute, isInternalRoute, isAuthRoute} from '../app-router/route-handler/internal-route'\nimport { hasRedirectLoop } from '../utils/construct'\n\n\n\n/**\n * @internal\n * Internal provider props - not meant for direct usage\n */\ninterface TernSecureClientProviderProps {\n children: React.ReactNode\n /** Callback when user state changes */\n onUserChanged?: (user: User | null) => Promise<void>\n /** Login page path */\n loginPath?: string\n /** Signup page path */\n signUpPath?: string\n /** Custom loading component */\n loadingComponent?: React.ReactNode\n /** Whether email verification is required */\n requiresVerification: boolean\n}\n\n/**\n * @internal\n * Internal provider component that handles authentication state\n * This is wrapped by the public TernSecureProvider\n */\n\nexport function TernSecureClientProvider({ \n children, \n loginPath = process.env.NEXT_PUBLIC_SIGN_IN_PATH || '/sign-in',\n signUpPath = process.env.NEXT_PUBLIC_SIGN_UP_PATH || '/sign-up',\n loadingComponent,\n requiresVerification,\n}: TernSecureClientProviderProps) {\n const auth = useMemo(() => ternSecureAuth, []);\n const router = useRouter();\n const pathname = usePathname() // Get current pathname\n const [isRedirecting, setIsRedirecting] = useState(false)\n\n const [authState, setAuthState] = useState<TernSecureState>(() => ({\n userId: null,\n isLoaded: false,\n error: null,\n isValid: false,\n isVerified: false,\n isAuthenticated: false,\n token: null,\n email: null,\n status: \"loading\",\n requiresVerification,\n }));\n\n const constructUrlWithRedirect = useCallback(\n (loginPath: string, currentPath: string, loginPathParam: string, signUpPathParam: string): string => {\n const baseUrl = window.location.origin\n const signInUrl = new URL(loginPath, baseUrl)\n\n // Only add redirect if not already on login or signup page\n if (!currentPath.includes(loginPathParam) && !currentPath.includes(signUpPathParam)) {\n signInUrl.searchParams.set(\"redirect\", currentPath)\n }\n return signInUrl.toString()\n },\n [],\n )\n\n\n const shouldRedirect = useCallback(\n (pathname: string, isVerified: boolean) => {\n // Get current search params\n const searchParams = new URLSearchParams(window.location.search)\n\n // Don't redirect if we're on the base sign-in page with no redirect param\n if (isBaseAuthRoute(pathname) && !searchParams.has(\"redirect\")) {\n return false\n }\n\n // Don't redirect if we're on an internal route\n if (isInternalRoute(pathname)) {\n return false\n }\n\n // Don't redirect if we're in auth routes (except when handling verification)\n if (isAuthRoute(pathname) && (!requiresVerification || isVerified)) {\n return false\n }\n\n return true\n },\n [requiresVerification],\n )\n\n const redirectToLogin = useCallback(\n (currentPath?: string) => {\n const path = currentPath || pathname || \"/\"\n\n\n if (isInternalRoute(path)) { // Don't redirect if we're already on an internal route\n return\n }\n\n // Check for redirect loops\n if (hasRedirectLoop(path, loginPath)) {\n return\n }\n\n setIsRedirecting(true)\n\n const loginUrl = constructUrlWithRedirect(loginPath, path, loginPath, signUpPath)\n\n if (process.env.NODE_ENV === \"production\") {\n window.location.href = loginUrl\n } else {\n // Use router.push for development\n router.push(loginUrl)\n }\n }, \n [router, loginPath, signUpPath, pathname, constructUrlWithRedirect]\n)\n\n const handleSignOut = useCallback(async (error?: Error) => {\n const currentPath = window.location.pathname\n await auth.signOut();\n setAuthState({\n isLoaded: true,\n userId: null,\n error: error || null,\n isValid: false,\n token: null,\n email: null,\n isVerified: false,\n isAuthenticated: false,\n status: \"unauthenticated\",\n requiresVerification,\n })\n redirectToLogin(currentPath)\n }, [auth, redirectToLogin, requiresVerification])\n\n const setEmail = useCallback((email: string) => {\n setAuthState((prev) => ({\n ...prev,\n email,\n }))\n }, [])\n\n const getAuthError = useCallback((): SignInResponse => {\n if (authState.error) {\n const error = authState.error as AuthError;\n return {\n success: false,\n message: error.message,\n error: error.code as keyof typeof ERRORS,\n user: null,\n }\n }\n\n if (authState.requiresVerification && authState.isValid && !authState.isVerified) {\n return {\n success: false,\n message: 'Email verification required',\n error: 'EMAIL_NOT_VERIFIED',\n user: null,\n }\n }\n\n if (!authState.isAuthenticated && authState.status !== \"loading\") {\n return {\n success: false,\n message: 'User is not authenticated',\n error: 'AUTHENTICATED',\n user: null,\n }\n }\n\n return {\n success: true,\n user: ternSecureAuth.currentUser,\n }\n }, [\n authState.error,\n authState.isValid,\n authState.isVerified,\n authState.isAuthenticated,\n authState.status,\n authState.requiresVerification,\n ])\n\nuseEffect(() => {\n let mounted = true\n let initialLoad = true\n\n const unsubscribe = onAuthStateChanged(\n auth,\n async (user: User | null) => {\n if (!mounted) return\n try {\n if (user) {\n const isValid = !!user.uid;\n const isVerified = user.emailVerified;\n const isAuthenticated = isValid && (!requiresVerification || isVerified) // Consider user authenticated if verification is not required or if email is verified\n\n setAuthState({\n isLoaded: true,\n userId: user.uid,\n isValid,\n isVerified,\n isAuthenticated: isValid && isVerified,\n token: user.getIdToken(),\n error: null,\n email: user.email,\n status: isAuthenticated ? \"authenticated\" : \"unverified\",\n requiresVerification,\n })\n \n if (requiresVerification && !isVerified && shouldRedirect(pathname || \"\", isVerified)) {\n if(initialLoad || !isRedirecting) {\n redirectToLogin(pathname)\n }\n }\n } else {\n setAuthState({\n isLoaded: true,\n userId: null,\n isValid: false,\n isVerified: false,\n isAuthenticated: false,\n token: null,\n error: null,\n email: null,\n status: \"unauthenticated\",\n requiresVerification,\n })\n \n if (shouldRedirect(pathname || \"\", false) && initialLoad) {\n redirectToLogin()\n }\n }\n } catch (error){\n console.error(\"Auth state change error:\", error)\n if (mounted) {\n handleSignOut(error instanceof Error ? error : new Error(\"Authentication error occurred\"))\n }\n } finally {\n initialLoad = false\n }\n })\n \n return () => {\n mounted = false\n unsubscribe()\n }\n }, [auth, handleSignOut, redirectToLogin, requiresVerification, pathname, isRedirecting, shouldRedirect])\n\n const contextValue: TernSecureCtxValue = useMemo(() => ({\n ...authState,\n signOut: handleSignOut,\n setEmail,\n getAuthError,\n redirectToLogin,\n }), [authState, handleSignOut, setEmail, getAuthError, redirectToLogin]);\n\n if (!authState.isLoaded) {\n return (\n <TernSecureCtx.Provider value={contextValue}>\n {loadingComponent || (\n <div aria-live=\"polite\" aria-busy=\"true\">\n <span className=\"sr-only\">Loading authentication state...</span>\n </div>\n )}\n </TernSecureCtx.Provider>\n );\n }\n\n return (\n <TernSecureCtx.Provider value={contextValue}>\n {children}\n </TernSecureCtx.Provider>\n )\n}"],"mappings":"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","names":["loginPath","pathname"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/boundary/TernSecureCtx.tsx"],"sourcesContent":["\"use client\"\n\nimport { createContext, useContext } from 'react'\nimport { ternSecureAuth } from '../utils/client-init';\nimport { User } from 'firebase/auth';\n\nexport const TernSecureUser = (): User | null => {\n return ternSecureAuth.currentUser;\n}\n\nexport interface TernSecureState {\n userId: string | null\n isLoaded: boolean\n error: Error | null\n isValid: boolean\n token: any | null\n email: string | null\n}\n\nexport interface TernSecureCtxValue extends TernSecureState {\n signOut: () => Promise<void>\n setEmail: (email: string) => void\n}\n\nexport const TernSecureCtx = createContext<TernSecureCtxValue | null>(null)\n\nTernSecureCtx.displayName = 'TernSecureCtx'\n\nexport const useTernSecure = (hookName: string) => {\n const context = useContext(TernSecureCtx)\n \n if (!context) {\n throw new Error(\n `${hookName} must be used within TernSecureProvider`\n )\n }\n\n return context\n}\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,mBAA0C;AAC1C,yBAA+B;AAGxB,MAAM,iBAAiB,MAAmB;AAC/C,SAAO,kCAAe;AACxB;AAgBO,MAAM,oBAAgB,4BAAyC,IAAI;AAE1E,cAAc,cAAc;AAErB,MAAM,gBAAgB,CAAC,aAAqB;AACjD,QAAM,cAAU,yBAAW,aAAa;AAExC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ;AAAA,IACb;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../../src/boundary/TernSecureCtx.tsx"],"sourcesContent":["\"use client\"\n\nimport { createContext, useContext } from 'react'\nimport { ternSecureAuth } from '../utils/client-init';\nimport { User } from 'firebase/auth';\nimport type { TernSecureState, SignInResponse } from '../types';\n\nexport const TernSecureUser = (): User | null => {\n return ternSecureAuth.currentUser;\n}\n\nexport interface TernSecureCtxValue extends TernSecureState {\n signOut: () => Promise<void>\n setEmail: (email: string) => void\n getAuthError: () => SignInResponse\n redirectToLogin: () => void\n}\n\nexport const TernSecureCtx = createContext<TernSecureCtxValue | null>(null)\n\nTernSecureCtx.displayName = 'TernSecureCtx'\n\nexport const useTernSecure = (hookName: string) => {\n const context = useContext(TernSecureCtx)\n \n if (!context) {\n throw new Error(\n `${hookName} must be used within TernSecureProvider`\n )\n }\n\n return context\n}\n\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,mBAA0C;AAC1C,yBAA+B;AAIxB,MAAM,iBAAiB,MAAmB;AAC/C,SAAO,kCAAe;AACxB;AASO,MAAM,oBAAgB,4BAAyC,IAAI;AAE1E,cAAc,cAAc;AAErB,MAAM,gBAAgB,CAAC,aAAqB;AACjD,QAAM,cAAU,yBAAW,aAAa;AAExC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI;AAAA,MACR,GAAG,QAAQ;AAAA,IACb;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}
@@ -30,17 +30,30 @@ function useAuth() {
30
30
  isLoaded,
31
31
  error,
32
32
  isValid,
33
+ isVerified,
34
+ isAuthenticated,
33
35
  token,
36
+ getAuthError,
37
+ status,
38
+ requiresVerification,
34
39
  signOut
35
40
  } = (0, import_TernSecureCtx.useTernSecure)("useAuth");
36
41
  const user = (0, import_TernSecureCtx2.TernSecureUser)();
42
+ const authResponse = getAuthError();
37
43
  return {
38
44
  user,
39
45
  userId,
40
46
  isLoaded,
41
- error,
42
- isAuthenticated: isValid,
47
+ error: authResponse.success ? null : authResponse,
48
+ isValid,
49
+ // User is signed in
50
+ isVerified,
51
+ // Email is verified
52
+ isAuthenticated,
53
+ // User is both signed in and verified
43
54
  token,
55
+ status,
56
+ requiresVerification,
44
57
  signOut
45
58
  };
46
59
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/boundary/hooks/useAuth.ts"],"sourcesContent":["\"use client\"\n\nimport { useTernSecure } from '../TernSecureCtx'\nimport { User } from 'firebase/auth'\nimport { TernSecureUser } from '../TernSecureCtx'\n\nexport function useAuth() {\n const {\n userId,\n isLoaded,\n error,\n isValid,\n token,\n signOut\n } = useTernSecure('useAuth')\n\n const user: User | null = TernSecureUser()\n\n return {\n user,\n userId,\n isLoaded,\n error,\n isAuthenticated: isValid,\n token,\n signOut\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,2BAA8B;AAE9B,IAAAA,wBAA+B;AAExB,SAAS,UAAU;AACxB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,QAAI,oCAAc,SAAS;AAE3B,QAAM,WAAoB,sCAAe;AAEzC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AACF;","names":["import_TernSecureCtx"]}
1
+ {"version":3,"sources":["../../../../src/boundary/hooks/useAuth.ts"],"sourcesContent":["\"use client\"\n\nimport { useTernSecure } from '../TernSecureCtx'\nimport { User } from 'firebase/auth'\nimport { TernSecureUser } from '../TernSecureCtx'\nimport type { SignInResponse } from '../../types'\n\n\nexport function useAuth() {\n const {\n userId,\n isLoaded,\n error,\n isValid,\n isVerified,\n isAuthenticated,\n token,\n getAuthError,\n status,\n requiresVerification,\n signOut\n } = useTernSecure('useAuth')\n\n const user: User | null = TernSecureUser()\n const authResponse: SignInResponse = getAuthError()\n\n\n return {\n user,\n userId,\n isLoaded,\n error: authResponse.success ? null : authResponse,\n isValid, // User is signed in\n isVerified, // Email is verified\n isAuthenticated, // User is both signed in and verified\n token,\n status,\n requiresVerification,\n signOut\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,2BAA8B;AAE9B,IAAAA,wBAA+B;AAIxB,SAAS,UAAU;AACxB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,QAAI,oCAAc,SAAS;AAE3B,QAAM,WAAoB,sCAAe;AACzC,QAAM,eAA+B,aAAa;AAGlD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,aAAa,UAAU,OAAO;AAAA,IACrC;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":["import_TernSecureCtx"]}