@tern-secure/nextjs 3.2.41 → 3.2.43

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 (110) hide show
  1. package/README.md +34 -0
  2. package/dist/cjs/app-router/client/TernSecureProvider.js +1 -1
  3. package/dist/cjs/app-router/client/TernSecureProvider.js.map +1 -1
  4. package/dist/cjs/app-router/client/actions.js +52 -2
  5. package/dist/cjs/app-router/client/actions.js.map +1 -1
  6. package/dist/cjs/app-router/server/sessionTernSecure.js +21 -1
  7. package/dist/cjs/app-router/server/sessionTernSecure.js.map +1 -1
  8. package/dist/cjs/boundary/TernSecureClientProvider.js +1 -2
  9. package/dist/cjs/boundary/TernSecureClientProvider.js.map +1 -1
  10. package/dist/cjs/boundary/hooks/useAuth.js +0 -6
  11. package/dist/cjs/boundary/hooks/useAuth.js.map +1 -1
  12. package/dist/cjs/components/background.js +65 -0
  13. package/dist/cjs/components/background.js.map +1 -0
  14. package/dist/cjs/components/sign-in.js +162 -56
  15. package/dist/cjs/components/sign-in.js.map +1 -1
  16. package/dist/cjs/components/sign-out.js +69 -0
  17. package/dist/cjs/components/sign-out.js.map +1 -0
  18. package/dist/cjs/components/ui/alert.js +88 -0
  19. package/dist/cjs/components/ui/alert.js.map +1 -0
  20. package/dist/cjs/components/ui/button.js +84 -0
  21. package/dist/cjs/components/ui/button.js.map +1 -0
  22. package/dist/cjs/components/ui/card.js +101 -0
  23. package/dist/cjs/components/ui/card.js.map +1 -0
  24. package/dist/cjs/components/ui/input.js +58 -0
  25. package/dist/cjs/components/ui/input.js.map +1 -0
  26. package/dist/cjs/components/ui/label.js +55 -0
  27. package/dist/cjs/components/ui/label.js.map +1 -0
  28. package/dist/cjs/components/ui/separator.js +59 -0
  29. package/dist/cjs/components/ui/separator.js.map +1 -0
  30. package/dist/cjs/index.js +3 -0
  31. package/dist/cjs/index.js.map +1 -1
  32. package/dist/cjs/lib/utils.d.js +17 -0
  33. package/dist/cjs/lib/utils.d.js.map +1 -0
  34. package/dist/cjs/lib/utils.js +33 -0
  35. package/dist/cjs/lib/utils.js.map +1 -0
  36. package/dist/cjs/utils/client-init.js.map +1 -1
  37. package/dist/cjs/utils/construct.js +63 -0
  38. package/dist/cjs/utils/construct.js.map +1 -0
  39. package/dist/esm/app-router/client/TernSecureProvider.js +1 -1
  40. package/dist/esm/app-router/client/TernSecureProvider.js.map +1 -1
  41. package/dist/esm/app-router/client/actions.js +49 -2
  42. package/dist/esm/app-router/client/actions.js.map +1 -1
  43. package/dist/esm/app-router/server/sessionTernSecure.js +20 -1
  44. package/dist/esm/app-router/server/sessionTernSecure.js.map +1 -1
  45. package/dist/esm/boundary/TernSecureClientProvider.js +1 -2
  46. package/dist/esm/boundary/TernSecureClientProvider.js.map +1 -1
  47. package/dist/esm/boundary/hooks/useAuth.js +0 -6
  48. package/dist/esm/boundary/hooks/useAuth.js.map +1 -1
  49. package/dist/esm/components/background.js +41 -0
  50. package/dist/esm/components/background.js.map +1 -0
  51. package/dist/esm/components/sign-in.js +160 -54
  52. package/dist/esm/components/sign-in.js.map +1 -1
  53. package/dist/esm/components/sign-out.js +45 -0
  54. package/dist/esm/components/sign-out.js.map +1 -0
  55. package/dist/esm/components/ui/alert.js +52 -0
  56. package/dist/esm/components/ui/alert.js.map +1 -0
  57. package/dist/esm/components/ui/button.js +49 -0
  58. package/dist/esm/components/ui/button.js.map +1 -0
  59. package/dist/esm/components/ui/card.js +62 -0
  60. package/dist/esm/components/ui/card.js.map +1 -0
  61. package/dist/esm/components/ui/input.js +24 -0
  62. package/dist/esm/components/ui/input.js.map +1 -0
  63. package/dist/esm/components/ui/label.js +21 -0
  64. package/dist/esm/components/ui/label.js.map +1 -0
  65. package/dist/esm/components/ui/separator.js +25 -0
  66. package/dist/esm/components/ui/separator.js.map +1 -0
  67. package/dist/esm/index.js +2 -0
  68. package/dist/esm/index.js.map +1 -1
  69. package/dist/esm/lib/utils.d.js +1 -0
  70. package/dist/esm/lib/utils.d.js.map +1 -0
  71. package/dist/esm/lib/utils.js +9 -0
  72. package/dist/esm/lib/utils.js.map +1 -0
  73. package/dist/esm/utils/client-init.js.map +1 -1
  74. package/dist/esm/utils/construct.js +37 -0
  75. package/dist/esm/utils/construct.js.map +1 -0
  76. package/dist/types/app-router/client/TernSecureProvider.d.ts +1 -1
  77. package/dist/types/app-router/client/TernSecureProvider.d.ts.map +1 -1
  78. package/dist/types/app-router/client/actions.d.ts +34 -0
  79. package/dist/types/app-router/client/actions.d.ts.map +1 -1
  80. package/dist/types/app-router/server/sessionTernSecure.d.ts +4 -0
  81. package/dist/types/app-router/server/sessionTernSecure.d.ts.map +1 -1
  82. package/dist/types/boundary/TernSecureClientProvider.d.ts.map +1 -1
  83. package/dist/types/boundary/hooks/useAuth.d.ts +0 -1
  84. package/dist/types/boundary/hooks/useAuth.d.ts.map +1 -1
  85. package/dist/types/components/background.d.ts +2 -0
  86. package/dist/types/components/background.d.ts.map +1 -0
  87. package/dist/types/components/sign-in.d.ts +8 -10
  88. package/dist/types/components/sign-in.d.ts.map +1 -1
  89. package/dist/types/components/sign-out.d.ts +10 -0
  90. package/dist/types/components/sign-out.d.ts.map +1 -0
  91. package/dist/types/components/ui/alert.d.ts +9 -0
  92. package/dist/types/components/ui/alert.d.ts.map +1 -0
  93. package/dist/types/components/ui/button.d.ts +12 -0
  94. package/dist/types/components/ui/button.d.ts.map +1 -0
  95. package/dist/types/components/ui/card.d.ts +9 -0
  96. package/dist/types/components/ui/card.d.ts.map +1 -0
  97. package/dist/types/components/ui/input.d.ts +4 -0
  98. package/dist/types/components/ui/input.d.ts.map +1 -0
  99. package/dist/types/components/ui/label.d.ts +6 -0
  100. package/dist/types/components/ui/label.d.ts.map +1 -0
  101. package/dist/types/components/ui/separator.d.ts +5 -0
  102. package/dist/types/components/ui/separator.d.ts.map +1 -0
  103. package/dist/types/index.d.ts +1 -0
  104. package/dist/types/index.d.ts.map +1 -1
  105. package/dist/types/lib/utils.d.ts +3 -0
  106. package/dist/types/lib/utils.d.ts.map +1 -0
  107. package/dist/types/utils/client-init.d.ts.map +1 -1
  108. package/dist/types/utils/construct.d.ts +22 -0
  109. package/dist/types/utils/construct.d.ts.map +1 -0
  110. package/package.json +79 -65
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/app-router/server/sessionTernSecure.ts"],"sourcesContent":["'use server'\r\n\r\nimport { cookies } from 'next/headers';\r\nimport { adminTernSecureAuth as adminAuth } from '../../utils/admin-init';\r\n\r\ninterface FirebaseAuthError extends Error {\r\n code?: string;\r\n}\r\n\r\nexport interface User {\r\n uid: string | null;\r\n email: string | null;\r\n }\r\n\r\nexport interface Session {\r\n user: User | null;\r\n token: string | null;\r\n error: Error | null;\r\n}\r\n\r\nexport async function createSessionCookie(idToken: string) {\r\n try {\r\n const expiresIn = 60 * 60 * 24 * 5 * 1000;\r\n const sessionCookie = await adminAuth.createSessionCookie(idToken, { expiresIn });\r\n\r\n const cookieStore = await cookies();\r\n cookieStore.set('_session_cookie', sessionCookie, {\r\n maxAge: expiresIn,\r\n httpOnly: true,\r\n secure: process.env.NODE_ENV === 'production',\r\n path: '/',\r\n });\r\n return { success: true, message: 'Session created' };\r\n } catch (error) {\r\n return { success: false, message: 'Failed to create session' };\r\n }\r\n}\r\n\r\n\r\n\r\nexport async function getServerSessionCookie() {\r\n const cookieStore = await cookies();\r\n const sessionCookie = cookieStore.get('_session_cookie')?.value;\r\n\r\n if (!sessionCookie) {\r\n throw new Error('No session cookie found')\r\n }\r\n \r\n try {\r\n const decondeClaims = await adminAuth.verifySessionCookie(sessionCookie, true)\r\n return {\r\n token: sessionCookie,\r\n userId: decondeClaims.uid\r\n }\r\n } catch (error) {\r\n console.error('Error verifying session:', error)\r\n throw new Error('Invalid Session')\r\n }\r\n}\r\n\r\n\r\nexport async function getIdToken() {\r\n const cookieStore = await cookies();\r\n const token = cookieStore.get('_session_token')?.value;\r\n\r\n if (!token) {\r\n throw new Error('No session cookie found')\r\n }\r\n \r\n try {\r\n const decodedClaims = await adminAuth.verifyIdToken(token)\r\n return {\r\n token: token,\r\n userId: decodedClaims.uid\r\n }\r\n } catch (error) {\r\n console.error('Error verifying session:', error)\r\n throw new Error('Invalid Session')\r\n }\r\n}\r\n\r\nexport async function setServerSession(token: string) {\r\n const cookieStore = await cookies();\r\n cookieStore.set('_session', token, {\r\n httpOnly: true,\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'strict',\r\n maxAge: 60 * 60, // 1 hour\r\n path: '/',\r\n });\r\n }\r\n\r\n export async function verifyTernIdToken(token: string): Promise<{ valid: boolean; uid?: string; error?: string }> {\r\n try {\r\n const decodedToken = await adminAuth.verifyIdToken(token);\r\n return { valid: true, uid: decodedToken.uid };\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n const firebaseError = error as FirebaseAuthError;\r\n if (error.name === 'FirebaseAuthError') {\r\n // Handle specific Firebase Auth errors\r\n switch (firebaseError.code) {\r\n case 'auth/id-token-expired':\r\n return { valid: false, error: 'Token has expired' };\r\n case 'auth/id-token-revoked':\r\n return { valid: false, error: 'Token has been revoked' };\r\n case 'auth/user-disabled':\r\n return { valid: false, error: 'User account has been disabled' };\r\n default:\r\n return { valid: false, error: 'Invalid token' };\r\n }\r\n }\r\n }\r\n return { valid: false, error: 'Error verifying token' };\r\n }\r\n }\r\n \r\n\r\n export async function verifyTernSessionCookie(session: string): Promise<{ valid: boolean; uid?: any; error?: any }>{\r\n try {\r\n const res = await adminAuth.verifySessionCookie(session, true);\r\n if (res) {\r\n return { valid: true, uid: res.uid };\r\n } else {\r\n return { valid: false, error: 'Invalid session'};\r\n }\r\n } catch (error) {\r\n return {error: error, valid: false}\r\n }\r\n }\r\n\r\n\r\n\r\n/*\r\n export async function GET(request: NextRequest) {\r\n const cookieStore = await cookies();\r\n const sessionCookie = cookieStore.get('session')?.value\r\n \r\n if (!sessionCookie) {\r\n return NextResponse.json({ isAuthenticated: false }, { status: 401 })\r\n }\r\n \r\n try {\r\n const decodedClaims = await adminAuth.verifySessionCookie(sessionCookie, true)\r\n return NextResponse.json({ isAuthenticated: true, user: decodedClaims }, { status: 200 })\r\n } catch (error) {\r\n console.error('Error verifying session cookie:', error)\r\n return NextResponse.json({ isAuthenticated: false }, { status: 401 })\r\n }\r\n }\r\n\r\n*/"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/app-router/server/sessionTernSecure.ts"],"sourcesContent":["'use server'\r\n\r\nimport { cookies } from 'next/headers';\r\nimport { adminTernSecureAuth as adminAuth } from '../../utils/admin-init';\r\n\r\ninterface FirebaseAuthError extends Error {\r\n code?: string;\r\n}\r\n\r\nexport interface User {\r\n uid: string | null;\r\n email: string | null;\r\n }\r\n\r\nexport interface Session {\r\n user: User | null;\r\n token: string | null;\r\n error: Error | null;\r\n}\r\n\r\nexport async function createSessionCookie(idToken: string) {\r\n try {\r\n const expiresIn = 60 * 60 * 24 * 5 * 1000;\r\n const sessionCookie = await adminAuth.createSessionCookie(idToken, { expiresIn });\r\n\r\n const cookieStore = await cookies();\r\n cookieStore.set('_session_cookie', sessionCookie, {\r\n maxAge: expiresIn,\r\n httpOnly: true,\r\n secure: process.env.NODE_ENV === 'production',\r\n path: '/',\r\n });\r\n return { success: true, message: 'Session created' };\r\n } catch (error) {\r\n return { success: false, message: 'Failed to create session' };\r\n }\r\n}\r\n\r\n\r\n\r\nexport async function getServerSessionCookie() {\r\n const cookieStore = await cookies();\r\n const sessionCookie = cookieStore.get('_session_cookie')?.value;\r\n\r\n if (!sessionCookie) {\r\n throw new Error('No session cookie found')\r\n }\r\n \r\n try {\r\n const decondeClaims = await adminAuth.verifySessionCookie(sessionCookie, true)\r\n return {\r\n token: sessionCookie,\r\n userId: decondeClaims.uid\r\n }\r\n } catch (error) {\r\n console.error('Error verifying session:', error)\r\n throw new Error('Invalid Session')\r\n }\r\n}\r\n\r\n\r\nexport async function getIdToken() {\r\n const cookieStore = await cookies();\r\n const token = cookieStore.get('_session_token')?.value;\r\n\r\n if (!token) {\r\n throw new Error('No session cookie found')\r\n }\r\n \r\n try {\r\n const decodedClaims = await adminAuth.verifyIdToken(token)\r\n return {\r\n token: token,\r\n userId: decodedClaims.uid\r\n }\r\n } catch (error) {\r\n console.error('Error verifying session:', error)\r\n throw new Error('Invalid Session')\r\n }\r\n}\r\n\r\nexport async function setServerSession(token: string) {\r\n const cookieStore = await cookies();\r\n cookieStore.set('_session', token, {\r\n httpOnly: true,\r\n secure: process.env.NODE_ENV === 'production',\r\n sameSite: 'strict',\r\n maxAge: 60 * 60, // 1 hour\r\n path: '/',\r\n });\r\n }\r\n\r\n export async function verifyTernIdToken(token: string): Promise<{ valid: boolean; uid?: string; error?: string }> {\r\n try {\r\n const decodedToken = await adminAuth.verifyIdToken(token, true);\r\n return { valid: true, uid: decodedToken.uid };\r\n } catch (error) {\r\n if (error instanceof Error) {\r\n const firebaseError = error as FirebaseAuthError;\r\n if (error.name === 'FirebaseAuthError') {\r\n // Handle specific Firebase Auth errors\r\n switch (firebaseError.code) {\r\n case 'auth/id-token-expired':\r\n return { valid: false, error: 'Token has expired' };\r\n case 'auth/id-token-revoked':\r\n return { valid: false, error: 'Token has been revoked' };\r\n case 'auth/user-disabled':\r\n return { valid: false, error: 'User account has been disabled' };\r\n default:\r\n return { valid: false, error: 'Invalid token' };\r\n }\r\n }\r\n }\r\n return { valid: false, error: 'Error verifying token' };\r\n }\r\n }\r\n \r\n\r\n export async function verifyTernSessionCookie(session: string): Promise<{ valid: boolean; uid?: any; error?: any }>{\r\n try {\r\n const res = await adminAuth.verifySessionCookie(session, true);\r\n if (res) {\r\n return { valid: true, uid: res.uid };\r\n } else {\r\n return { valid: false, error: 'Invalid session'};\r\n }\r\n } catch (error) {\r\n return {error: error, valid: false}\r\n }\r\n }\r\n\r\n\r\n export async function clearSessionCookie() {\r\n const cookieStore = await cookies()\r\n \r\n cookieStore.delete('_session_cookie')\r\n cookieStore.delete('_session_token')\r\n cookieStore.delete('_session')\r\n \r\n try {\r\n // Verify if there's an active session before revoking\r\n const sessionCookie = cookieStore.get('_session_cookie')?.value\r\n if (sessionCookie) {\r\n // Get the decoded claims to get the user's ID\r\n const decodedClaims = await adminAuth.verifySessionCookie(sessionCookie)\r\n \r\n // Revoke all sessions for the user\r\n await adminAuth.revokeRefreshTokens(decodedClaims.uid)\r\n }\r\n \r\n return { success: true, message: 'Session cleared successfully' }\r\n } catch (error) {\r\n console.error('Error clearing session:', error)\r\n // Still return success even if revoking fails, as cookies are cleared\r\n return { success: true, message: 'Session cookies cleared' }\r\n }\r\n }\r\n\r\n\r\n\r\n/*\r\n export async function GET(request: NextRequest) {\r\n const cookieStore = await cookies();\r\n const sessionCookie = cookieStore.get('session')?.value\r\n \r\n if (!sessionCookie) {\r\n return NextResponse.json({ isAuthenticated: false }, { status: 401 })\r\n }\r\n \r\n try {\r\n const decodedClaims = await adminAuth.verifySessionCookie(sessionCookie, true)\r\n return NextResponse.json({ isAuthenticated: true, user: decodedClaims }, { status: 200 })\r\n } catch (error) {\r\n console.error('Error verifying session cookie:', error)\r\n return NextResponse.json({ isAuthenticated: false }, { status: 401 })\r\n }\r\n }\r\n\r\n*/"],"mappings":"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","names":[]}
@@ -33,7 +33,6 @@ function TernSecureClientProvider({
33
33
  useEffect(() => {
34
34
  const unsubscribe = onAuthStateChanged(auth, async (user) => {
35
35
  if (user) {
36
- await user.getIdToken();
37
36
  setAuthState({
38
37
  isLoaded: true,
39
38
  userId: user.uid,
@@ -55,7 +54,7 @@ function TernSecureClientProvider({
55
54
  handleSignOut(error instanceof Error ? error : new Error("Authentication error occurred"));
56
55
  });
57
56
  return () => unsubscribe();
58
- }, []);
57
+ }, [auth, handleSignOut, router, loginPath]);
59
58
  const contextValue = useMemo(() => ({
60
59
  ...authState,
61
60
  signOut: handleSignOut
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/boundary/TernSecureClientProvider.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport React, { useState, useEffect, useMemo, useCallback } from 'react'\r\nimport { ternSecureAuth } from '../utils/client-init'\r\nimport { onAuthStateChanged, User } from \"firebase/auth\"\r\nimport { TernSecureCtx, TernSecureCtxValue, TernSecureState } from './TernSecureCtx'\r\nimport { useRouter } from 'next/navigation'\r\n\r\ninterface TernSecureClientProviderProps {\r\n children: React.ReactNode;\r\n onUserChanged?: (user: User | null) => Promise<void>;\r\n loginPath?: string;\r\n loadingComponent?: React.ReactNode;\r\n}\r\n\r\nexport function TernSecureClientProvider({ \r\n children, \r\n loginPath = '/sign-in',\r\n loadingComponent\r\n}: TernSecureClientProviderProps) {\r\n const auth = useMemo(() => ternSecureAuth, []);\r\n const router = useRouter();\r\n const [authState, setAuthState] = useState<TernSecureState>(() => ({\r\n userId: null,\r\n isLoaded: false,\r\n error: null,\r\n isValid: false,\r\n token: null\r\n }));\r\n\r\n const handleSignOut = useCallback(async (error?: Error) => {\r\n await auth.signOut();\r\n setAuthState({\r\n isLoaded: true,\r\n userId: null,\r\n error: error || null,\r\n isValid: false,\r\n token: null\r\n });\r\n router.push(loginPath);\r\n }, [auth, router, loginPath]);\r\n\r\nuseEffect(() => {\r\n const unsubscribe = onAuthStateChanged(auth, async (user: User | null) => {\r\n if (user) {\r\n await user.getIdToken()\r\n setAuthState({\r\n isLoaded: true,\r\n userId: user.uid,\r\n isValid: true,\r\n token: user.getIdToken(),\r\n error: null\r\n })\r\n } else {\r\n setAuthState({\r\n isLoaded: true,\r\n userId: null,\r\n isValid: false,\r\n token: null,\r\n error: new Error('User is not authenticated')\r\n })\r\n router.push(loginPath);\r\n }\r\n }, (error) => {\r\n handleSignOut(error instanceof Error ? error : new Error('Authentication error occurred'));\r\n })\r\n \r\n return () => unsubscribe()\r\n }, [])\r\n\r\n const contextValue: TernSecureCtxValue = useMemo(() => ({\r\n ...authState,\r\n signOut: handleSignOut,\r\n }), [authState, auth, handleSignOut]);\r\n\r\n if (!authState.isLoaded) {\r\n return (\r\n <TernSecureCtx.Provider value={contextValue}>\r\n {loadingComponent || (\r\n <div aria-live=\"polite\" aria-busy=\"true\">\r\n <span className=\"sr-only\">Loading authentication state...</span>\r\n </div>\r\n )}\r\n </TernSecureCtx.Provider>\r\n );\r\n }\r\n\r\n return (\r\n <TernSecureCtx.Provider value={contextValue}>\r\n {children}\r\n </TernSecureCtx.Provider>\r\n )\r\n}"],"mappings":";AAgFY;AA9EZ,SAAgB,UAAU,WAAW,SAAS,mBAAmB;AACjE,SAAS,sBAAsB;AAC/B,SAAS,0BAAgC;AACzC,SAAS,qBAA0D;AACnE,SAAS,iBAAiB;AASnB,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA,YAAY;AAAA,EACZ;AACF,GAAkC;AAChC,QAAM,OAAO,QAAQ,MAAM,gBAAgB,CAAC,CAAC;AAC7C,QAAM,SAAS,UAAU;AACzB,QAAM,CAAC,WAAW,YAAY,IAAI,SAA0B,OAAO;AAAA,IACjE,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,OAAO;AAAA,EACT,EAAE;AAEF,QAAM,gBAAgB,YAAY,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,IACT,CAAC;AACD,WAAO,KAAK,SAAS;AAAA,EACvB,GAAG,CAAC,MAAM,QAAQ,SAAS,CAAC;AAE9B,YAAU,MAAM;AACZ,UAAM,cAAc,mBAAmB,MAAM,OAAO,SAAsB;AACxE,UAAI,MAAM;AACR,cAAM,KAAK,WAAW;AACtB,qBAAa;AAAA,UACX,UAAU;AAAA,UACV,QAAQ,KAAK;AAAA,UACb,SAAS;AAAA,UACT,OAAO,KAAK,WAAW;AAAA,UACvB,OAAO;AAAA,QACT,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,QAC9C,CAAC;AACD,eAAO,KAAK,SAAS;AAAA,MACvB;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,CAAC;AAEL,QAAM,eAAmC,QAAQ,OAAO;AAAA,IACtD,GAAG;AAAA,IACH,SAAS;AAAA,EACX,IAAI,CAAC,WAAW,MAAM,aAAa,CAAC;AAEpC,MAAI,CAAC,UAAU,UAAU;AACvB,WACE,oBAAC,cAAc,UAAd,EAAuB,OAAO,cAC5B,8BACC,oBAAC,SAAI,aAAU,UAAS,aAAU,QAChC,8BAAC,UAAK,WAAU,WAAU,6CAA+B,GAC3D,GAEJ;AAAA,EAEJ;AAEA,SACI,oBAAC,cAAc,UAAd,EAAuB,OAAO,cAC7B,UACF;AAEN;","names":[]}
1
+ {"version":3,"sources":["../../../src/boundary/TernSecureClientProvider.tsx"],"sourcesContent":["\"use client\"\r\n\r\nimport React, { useState, useEffect, useMemo, useCallback } from 'react'\r\nimport { ternSecureAuth } from '../utils/client-init'\r\nimport { onAuthStateChanged, User } from \"firebase/auth\"\r\nimport { TernSecureCtx, TernSecureCtxValue, TernSecureState } from './TernSecureCtx'\r\nimport { useRouter } from 'next/navigation'\r\n\r\ninterface TernSecureClientProviderProps {\r\n children: React.ReactNode;\r\n onUserChanged?: (user: User | null) => Promise<void>;\r\n loginPath?: string;\r\n loadingComponent?: React.ReactNode;\r\n}\r\n\r\nexport function TernSecureClientProvider({ \r\n children, \r\n loginPath = '/sign-in',\r\n loadingComponent\r\n}: TernSecureClientProviderProps) {\r\n const auth = useMemo(() => ternSecureAuth, []);\r\n const router = useRouter();\r\n const [authState, setAuthState] = useState<TernSecureState>(() => ({\r\n userId: null,\r\n isLoaded: false,\r\n error: null,\r\n isValid: false,\r\n token: null\r\n }));\r\n\r\n const handleSignOut = useCallback(async (error?: Error) => {\r\n await auth.signOut();\r\n setAuthState({\r\n isLoaded: true,\r\n userId: null,\r\n error: error || null,\r\n isValid: false,\r\n token: null\r\n });\r\n router.push(loginPath);\r\n }, [auth, router, loginPath]);\r\n\r\nuseEffect(() => {\r\n const unsubscribe = onAuthStateChanged(auth, async (user: User | null) => {\r\n if (user) {\r\n setAuthState({\r\n isLoaded: true,\r\n userId: user.uid,\r\n isValid: true,\r\n token: user.getIdToken(),\r\n error: null\r\n })\r\n } else {\r\n setAuthState({\r\n isLoaded: true,\r\n userId: null,\r\n isValid: false,\r\n token: null,\r\n error: new Error('User is not authenticated')\r\n })\r\n router.push(loginPath);\r\n }\r\n }, (error) => {\r\n handleSignOut(error instanceof Error ? error : new Error('Authentication error occurred'));\r\n })\r\n \r\n return () => unsubscribe()\r\n }, [auth, handleSignOut, router, loginPath])\r\n\r\n const contextValue: TernSecureCtxValue = useMemo(() => ({\r\n ...authState,\r\n signOut: handleSignOut,\r\n }), [authState, auth, handleSignOut]);\r\n\r\n if (!authState.isLoaded) {\r\n return (\r\n <TernSecureCtx.Provider value={contextValue}>\r\n {loadingComponent || (\r\n <div aria-live=\"polite\" aria-busy=\"true\">\r\n <span className=\"sr-only\">Loading authentication state...</span>\r\n </div>\r\n )}\r\n </TernSecureCtx.Provider>\r\n );\r\n }\r\n\r\n return (\r\n <TernSecureCtx.Provider value={contextValue}>\r\n {children}\r\n </TernSecureCtx.Provider>\r\n )\r\n}"],"mappings":";AA+EY;AA7EZ,SAAgB,UAAU,WAAW,SAAS,mBAAmB;AACjE,SAAS,sBAAsB;AAC/B,SAAS,0BAAgC;AACzC,SAAS,qBAA0D;AACnE,SAAS,iBAAiB;AASnB,SAAS,yBAAyB;AAAA,EACvC;AAAA,EACA,YAAY;AAAA,EACZ;AACF,GAAkC;AAChC,QAAM,OAAO,QAAQ,MAAM,gBAAgB,CAAC,CAAC;AAC7C,QAAM,SAAS,UAAU;AACzB,QAAM,CAAC,WAAW,YAAY,IAAI,SAA0B,OAAO;AAAA,IACjE,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,OAAO;AAAA,IACP,SAAS;AAAA,IACT,OAAO;AAAA,EACT,EAAE;AAEF,QAAM,gBAAgB,YAAY,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,IACT,CAAC;AACD,WAAO,KAAK,SAAS;AAAA,EACvB,GAAG,CAAC,MAAM,QAAQ,SAAS,CAAC;AAE9B,YAAU,MAAM;AACZ,UAAM,cAAc,mBAAmB,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,QACT,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,QAC9C,CAAC;AACD,eAAO,KAAK,SAAS;AAAA,MACvB;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,eAAmC,QAAQ,OAAO;AAAA,IACtD,GAAG;AAAA,IACH,SAAS;AAAA,EACX,IAAI,CAAC,WAAW,MAAM,aAAa,CAAC;AAEpC,MAAI,CAAC,UAAU,UAAU;AACvB,WACE,oBAAC,cAAc,UAAd,EAAuB,OAAO,cAC5B,8BACC,oBAAC,SAAI,aAAU,UAAS,aAAU,QAChC,8BAAC,UAAK,WAAU,WAAU,6CAA+B,GAC3D,GAEJ;AAAA,EAEJ;AAEA,SACI,oBAAC,cAAc,UAAd,EAAuB,OAAO,cAC7B,UACF;AAEN;","names":[]}
@@ -1,5 +1,4 @@
1
1
  "use client";
2
- import { useCallback } from "react";
3
2
  import { useTernSecure } from "../TernSecureCtx";
4
3
  import { TernSecureUser } from "../TernSecureCtx";
5
4
  function useAuth() {
@@ -12,10 +11,6 @@ function useAuth() {
12
11
  signOut
13
12
  } = useTernSecure("useAuth");
14
13
  const user = TernSecureUser();
15
- const refreshToken = useCallback(async () => {
16
- if (!user) return null;
17
- return await user.getIdToken(true);
18
- }, [user]);
19
14
  return {
20
15
  user,
21
16
  userId,
@@ -23,7 +18,6 @@ function useAuth() {
23
18
  error,
24
19
  isAuthenticated: isValid,
25
20
  token,
26
- refreshToken,
27
21
  signOut
28
22
  };
29
23
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/boundary/hooks/useAuth.ts"],"sourcesContent":["\"use client\"\r\n\r\nimport { useCallback } from 'react'\r\nimport { useTernSecure } from '../TernSecureCtx'\r\nimport { User } from 'firebase/auth'\r\nimport { TernSecureUser } from '../TernSecureCtx'\r\n\r\nexport function useAuth() {\r\n const {\r\n userId,\r\n isLoaded,\r\n error,\r\n isValid,\r\n token,\r\n signOut\r\n } = useTernSecure('useAuth')\r\n\r\n const user: User | null = TernSecureUser()\r\n\r\n const refreshToken = useCallback(async () => {\r\n if (!user) return null\r\n return await user.getIdToken(true) // Force refresh the token\r\n }, [user])\r\n\r\n return {\r\n user,\r\n userId,\r\n isLoaded,\r\n error,\r\n isAuthenticated: isValid,\r\n token,\r\n refreshToken,\r\n signOut\r\n }\r\n}\r\n"],"mappings":";AAEA,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAE9B,SAAS,sBAAsB;AAExB,SAAS,UAAU;AACxB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,cAAc,SAAS;AAE3B,QAAM,OAAoB,eAAe;AAEzC,QAAM,eAAe,YAAY,YAAY;AAC3C,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,MAAM,KAAK,WAAW,IAAI;AAAA,EACnC,GAAG,CAAC,IAAI,CAAC;AAET,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../src/boundary/hooks/useAuth.ts"],"sourcesContent":["\"use client\"\r\n\r\nimport { useTernSecure } from '../TernSecureCtx'\r\nimport { User } from 'firebase/auth'\r\nimport { TernSecureUser } from '../TernSecureCtx'\r\n\r\nexport function useAuth() {\r\n const {\r\n userId,\r\n isLoaded,\r\n error,\r\n isValid,\r\n token,\r\n signOut\r\n } = useTernSecure('useAuth')\r\n\r\n const user: User | null = TernSecureUser()\r\n\r\n return {\r\n user,\r\n userId,\r\n isLoaded,\r\n error,\r\n isAuthenticated: isValid,\r\n token,\r\n signOut\r\n }\r\n}\r\n"],"mappings":";AAEA,SAAS,qBAAqB;AAE9B,SAAS,sBAAsB;AAExB,SAAS,UAAU;AACxB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,cAAc,SAAS;AAE3B,QAAM,OAAoB,eAAe;AAEzC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,iBAAiB;AAAA,IACjB;AAAA,IACA;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,41 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ function AuthBackground() {
3
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4
+ /* @__PURE__ */ jsx(
5
+ "div",
6
+ {
7
+ className: "absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80",
8
+ "aria-hidden": "true",
9
+ children: /* @__PURE__ */ jsx(
10
+ "div",
11
+ {
12
+ className: "relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]",
13
+ style: {
14
+ clipPath: "polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)"
15
+ }
16
+ }
17
+ )
18
+ }
19
+ ),
20
+ /* @__PURE__ */ jsx(
21
+ "div",
22
+ {
23
+ className: "absolute inset-x-0 top-[calc(100%-13rem)] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[calc(100%-30rem)]",
24
+ "aria-hidden": "true",
25
+ children: /* @__PURE__ */ jsx(
26
+ "div",
27
+ {
28
+ className: "relative left-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[hsl(var(--secondary)_/_0.3)] to-[hsl(var(--primary)_/_0.3)] opacity-30 sm:left-[calc(50%+36rem)] sm:w-[72.1875rem]",
29
+ style: {
30
+ clipPath: "polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)"
31
+ }
32
+ }
33
+ )
34
+ }
35
+ )
36
+ ] });
37
+ }
38
+ export {
39
+ AuthBackground
40
+ };
41
+ //# sourceMappingURL=background.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/background.tsx"],"sourcesContent":["export function AuthBackground() {\r\n return (\r\n <>\r\n {/* Primary gradient blob */}\r\n <div\r\n className=\"absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80\"\r\n aria-hidden=\"true\"\r\n >\r\n <div\r\n className=\"relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]\"\r\n style={{\r\n clipPath:\r\n 'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',\r\n }}\r\n />\r\n </div>\r\n \r\n {/* Secondary gradient blob */}\r\n <div\r\n className=\"absolute inset-x-0 top-[calc(100%-13rem)] -z-10 transform-gpu overflow-hidden blur-3xl sm:top-[calc(100%-30rem)]\"\r\n aria-hidden=\"true\"\r\n >\r\n <div\r\n className=\"relative left-[calc(50%+3rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 bg-gradient-to-tr from-[hsl(var(--secondary)_/_0.3)] to-[hsl(var(--primary)_/_0.3)] opacity-30 sm:left-[calc(50%+36rem)] sm:w-[72.1875rem]\"\r\n style={{\r\n clipPath:\r\n 'polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)',\r\n }}\r\n />\r\n </div>\r\n </>\r\n )\r\n }\r\n \r\n "],"mappings":"AAEM,mBAMM,KANN;AAFC,SAAS,iBAAiB;AAC7B,SACE,iCAEE;AAAA;AAAA,MAAC;AAAA;AAAA,QACG,WAAU;AAAA,QACV,eAAY;AAAA,QAEZ;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,UACE;AAAA,YACJ;AAAA;AAAA,QACF;AAAA;AAAA,IACF;AAAA,IAGF;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,eAAY;AAAA,QAEZ;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,UACE;AAAA,YACJ;AAAA;AAAA,QACF;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}
@@ -1,27 +1,84 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useState } from "react";
4
- import { signInWithEmail } from "../app-router/client/actions";
5
- import { styles } from "../utils/create-styles";
6
- import { useRouter } from "next/navigation";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState, useCallback, useEffect } from "react";
4
+ import { useSearchParams } from "next/navigation";
5
+ import { signInWithEmail, signInWithRedirectGoogle, signInWithMicrosoft } from "../app-router/client/actions";
6
+ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./ui/card";
7
+ import { Input } from "./ui/input";
8
+ import { Label } from "./ui/label";
9
+ import { Button } from "./ui/button";
10
+ import { Alert, AlertDescription } from "./ui/alert";
11
+ import { Separator } from "./ui/separator";
12
+ import { cn } from "../lib/utils";
13
+ import { Loader2 } from "lucide-react";
14
+ import { getRedirectResult } from "firebase/auth";
15
+ import { ternSecureAuth } from "../utils/client-init";
16
+ import { createSessionCookie } from "../app-router/server/sessionTernSecure";
17
+ import { AuthBackground } from "./background";
18
+ import { getValidRedirectUrl } from "../utils/construct";
19
+ const isLocalhost = typeof window !== "undefined" && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1");
20
+ const authDomain = process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN;
7
21
  function SignIn({
22
+ redirectUrl,
8
23
  onError,
24
+ onSuccess,
9
25
  className,
10
- style,
11
26
  customStyles = {}
12
27
  }) {
13
28
  const [loading, setLoading] = useState(false);
29
+ const [checkingRedirect, setCheckingRedirect] = useState(true);
14
30
  const [error, setError] = useState("");
15
31
  const [email, setEmail] = useState("");
16
32
  const [password, setPassword] = useState("");
17
- const router = useRouter();
33
+ const searchParams = useSearchParams();
34
+ const isRedirectSignIn = searchParams.get("signInRedirect") === "true";
35
+ const handleRedirectResult = useCallback(async () => {
36
+ if (!isRedirectSignIn) return false;
37
+ setCheckingRedirect(true);
38
+ try {
39
+ console.log("Checking redirect result...");
40
+ console.log("Current hostname:", window.location.hostname);
41
+ console.log("Auth domain hostname:", authDomain);
42
+ const isOnAuth = authDomain && window.location.hostname === authDomain.replace(/https?:\/\//, "");
43
+ console.log("Is on AuthDomain:", isOnAuth);
44
+ const result = await getRedirectResult(ternSecureAuth);
45
+ console.log("Redirect result:", result);
46
+ if (result) {
47
+ const idToken = await result.user.getIdToken();
48
+ const sessionResult = await createSessionCookie(idToken);
49
+ if (!sessionResult.success) {
50
+ throw new Error("Failed to create session");
51
+ }
52
+ const storedRedirectUrl = sessionStorage.getItem("auth_return_url");
53
+ sessionStorage.removeItem("auth_redirect_url");
54
+ onSuccess == null ? void 0 : onSuccess();
55
+ window.location.href = storedRedirectUrl || getValidRedirectUrl(redirectUrl, searchParams);
56
+ return true;
57
+ }
58
+ setCheckingRedirect(false);
59
+ } catch (err) {
60
+ console.error("Redirect result error:", err);
61
+ const errorMessage = err instanceof Error ? err.message : "Authentication failed";
62
+ setError(errorMessage);
63
+ onError == null ? void 0 : onError(err instanceof Error ? err : new Error(errorMessage));
64
+ sessionStorage.removeItem("auth_redirect_url");
65
+ return false;
66
+ }
67
+ }, [isRedirectSignIn, redirectUrl, searchParams, onSuccess, onError]);
68
+ useEffect(() => {
69
+ if (isRedirectSignIn) {
70
+ handleRedirectResult();
71
+ }
72
+ ;
73
+ }, [handleRedirectResult, isRedirectSignIn]);
18
74
  const handleSubmit = async (e) => {
19
75
  e.preventDefault();
20
76
  setLoading(true);
21
77
  try {
22
78
  const user = await signInWithEmail(email, password);
23
79
  if (user.success) {
24
- router.push("/");
80
+ onSuccess == null ? void 0 : onSuccess();
81
+ window.location.href = getValidRedirectUrl(redirectUrl, searchParams);
25
82
  }
26
83
  } catch (err) {
27
84
  const errorMessage = err instanceof Error ? err.message : "Failed to sign in";
@@ -31,76 +88,125 @@ function SignIn({
31
88
  setLoading(false);
32
89
  }
33
90
  };
34
- return /* @__PURE__ */ jsxs("div", { className: `${styles.container} ${customStyles.container || ""}`, style, children: [
35
- /* @__PURE__ */ jsx("div", { className: `${styles.header} ${customStyles.header || ""}`, children: /* @__PURE__ */ jsx("h2", { className: `${styles.title} ${customStyles.title || ""}`, children: "Sign in to your account" }) }),
36
- /* @__PURE__ */ jsx("div", { className: `${styles.formWrapper} ${customStyles.formWrapper || ""}`, children: /* @__PURE__ */ jsx("div", { className: `${styles.formContainer} ${customStyles.formContainer || ""}`, children: /* @__PURE__ */ jsxs(
37
- "form",
38
- {
39
- onSubmit: handleSubmit,
40
- className: `${styles.form} ${customStyles.form || ""} ${className}`,
41
- role: "form",
42
- "aria-label": "Sign in form",
43
- children: [
44
- error && /* @__PURE__ */ jsx(
45
- "div",
46
- {
47
- className: `${styles.error} ${customStyles.errorText || ""}`,
48
- role: "alert",
49
- "aria-live": "polite",
50
- children: error
51
- }
52
- ),
53
- /* @__PURE__ */ jsxs("div", { children: [
54
- /* @__PURE__ */ jsx("label", { htmlFor: "email", className: `${styles.label} ${customStyles.label || ""}`, children: "Email" }),
91
+ const handleSocialSignIn = async (provider) => {
92
+ setLoading(true);
93
+ try {
94
+ const validRedirectUrl = getValidRedirectUrl(redirectUrl, searchParams);
95
+ sessionStorage.setItem("auth_redirect_url", validRedirectUrl);
96
+ const currentUrl = new URL(window.location.href);
97
+ currentUrl.searchParams.set("signInRedirect", "true");
98
+ window.history.replaceState({}, "", currentUrl.toString());
99
+ const result = provider === "google" ? await signInWithRedirectGoogle() : await signInWithMicrosoft();
100
+ if (!result.success) {
101
+ throw new Error(result.error);
102
+ }
103
+ } catch (err) {
104
+ const errorMessage = err instanceof Error ? err.message : `Failed to sign in with ${provider}`;
105
+ setError(errorMessage);
106
+ onError == null ? void 0 : onError(err instanceof Error ? err : new Error(`Failed to sign in with ${provider}`));
107
+ setLoading(false);
108
+ sessionStorage.removeItem("auth_redirect_url");
109
+ }
110
+ };
111
+ if (checkingRedirect && isRedirectSignIn) {
112
+ return /* @__PURE__ */ jsx("div", { className: "flex min-h-screen items-center justify-center", children: /* @__PURE__ */ jsx("div", { className: "text-center space-y-4", children: /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto" }) }) });
113
+ }
114
+ return /* @__PURE__ */ jsxs("div", { className: "relative flex items-center justify-center", children: [
115
+ /* @__PURE__ */ jsx(AuthBackground, {}),
116
+ /* @__PURE__ */ jsxs(Card, { className: cn("w-full max-w-md mx-auto mt-8", className, customStyles.card), children: [
117
+ /* @__PURE__ */ jsxs(CardHeader, { className: "space-y-1 text-center", children: [
118
+ /* @__PURE__ */ jsx(CardTitle, { className: cn("font-bold", customStyles.title), children: "Sign in to TernSecure" }),
119
+ /* @__PURE__ */ jsx(CardDescription, { className: cn("text-muted-foreground", customStyles.description), children: "Please sign in to continue" })
120
+ ] }),
121
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
122
+ /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
123
+ error && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: error }) }),
124
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
125
+ /* @__PURE__ */ jsx(Label, { htmlFor: "email", className: cn(customStyles.label), children: "Email" }),
55
126
  /* @__PURE__ */ jsx(
56
- "input",
127
+ Input,
57
128
  {
58
129
  id: "email",
59
- name: "email",
60
130
  type: "email",
61
- placeholder: "Enter your email",
62
- required: true,
131
+ placeholder: "m@example.com",
63
132
  value: email,
64
133
  onChange: (e) => setEmail(e.target.value),
65
- className: `${styles.input} ${customStyles.input || ""}`,
66
134
  disabled: loading,
67
- "aria-required": "true",
68
- "aria-invalid": !!error
135
+ className: cn(customStyles.input),
136
+ required: true
69
137
  }
70
138
  )
71
139
  ] }),
72
- /* @__PURE__ */ jsxs("div", { children: [
73
- /* @__PURE__ */ jsx("label", { htmlFor: "password", className: `${styles.label} ${customStyles.label || ""}`, children: "Password" }),
140
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
141
+ /* @__PURE__ */ jsx(Label, { htmlFor: "password", className: cn(customStyles.label), children: "Password" }),
74
142
  /* @__PURE__ */ jsx(
75
- "input",
143
+ Input,
76
144
  {
77
145
  id: "password",
78
- name: "password",
79
146
  type: "password",
80
- placeholder: "Enter your password",
81
- required: true,
82
147
  value: password,
83
148
  onChange: (e) => setPassword(e.target.value),
84
- className: `${styles.input} ${customStyles.input || ""}`,
85
149
  disabled: loading,
86
- "aria-required": "true",
87
- "aria-invalid": !!error
150
+ className: cn(customStyles.input),
151
+ required: true
88
152
  }
89
153
  )
90
154
  ] }),
91
- /* @__PURE__ */ jsx(
92
- "button",
155
+ /* @__PURE__ */ jsx(Button, { type: "submit", disabled: loading, className: cn("w-full", customStyles.button), children: loading ? /* @__PURE__ */ jsxs(Fragment, { children: [
156
+ /* @__PURE__ */ jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }),
157
+ "Signing in..."
158
+ ] }) : "Sign in" })
159
+ ] }),
160
+ /* @__PURE__ */ jsxs("div", { className: "relative", children: [
161
+ /* @__PURE__ */ jsx(Separator, { className: cn(customStyles.separator) }),
162
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "bg-background px-2 text-muted-foreground text-sm", children: "Or continue with" }) })
163
+ ] }),
164
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
165
+ /* @__PURE__ */ jsxs(
166
+ Button,
93
167
  {
94
- type: "submit",
168
+ variant: "outline",
95
169
  disabled: loading,
96
- className: `${styles.button} ${customStyles.button || ""}`,
97
- "data-testid": "sign-in-submit",
98
- children: loading ? "Signing in..." : "Sign in"
170
+ onClick: () => handleSocialSignIn("google"),
171
+ className: cn("flex items-center justify-center", customStyles.socialButton),
172
+ children: [
173
+ /* @__PURE__ */ jsxs("svg", { className: "w-5 h-5 mr-2", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", children: [
174
+ /* @__PURE__ */ jsx("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" }),
175
+ /* @__PURE__ */ jsx("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" }),
176
+ /* @__PURE__ */ jsx("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" }),
177
+ /* @__PURE__ */ jsx("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" })
178
+ ] }),
179
+ "Google"
180
+ ]
181
+ }
182
+ ),
183
+ /* @__PURE__ */ jsxs(
184
+ Button,
185
+ {
186
+ variant: "outline",
187
+ disabled: loading,
188
+ onClick: () => handleSocialSignIn("microsoft"),
189
+ className: cn("flex items-center justify-center", customStyles.socialButton),
190
+ children: [
191
+ /* @__PURE__ */ jsxs("svg", { className: "w-5 h-5 mr-2", viewBox: "0 0 23 23", xmlns: "http://www.w3.org/2000/svg", children: [
192
+ /* @__PURE__ */ jsx("path", { fill: "#f3f3f3", d: "M0 0h23v23H0z" }),
193
+ /* @__PURE__ */ jsx("path", { fill: "#f35325", d: "M1 1h10v10H1z" }),
194
+ /* @__PURE__ */ jsx("path", { fill: "#81bc06", d: "M12 1h10v10H12z" }),
195
+ /* @__PURE__ */ jsx("path", { fill: "#05a6f0", d: "M1 12h10v10H1z" }),
196
+ /* @__PURE__ */ jsx("path", { fill: "#ffba08", d: "M12 12h10v10H12z" })
197
+ ] }),
198
+ "Microsoft"
199
+ ]
99
200
  }
100
201
  )
101
- ]
102
- }
103
- ) }) })
202
+ ] })
203
+ ] }),
204
+ /* @__PURE__ */ jsx(CardFooter, { className: "flex justify-center", children: /* @__PURE__ */ jsxs("p", { className: "text-sm text-muted-foreground", children: [
205
+ "Don't have an account?",
206
+ " ",
207
+ /* @__PURE__ */ jsx("a", { href: "#", className: "text-primary hover:underline", children: "Sign up" })
208
+ ] }) })
209
+ ] })
104
210
  ] });
105
211
  }
106
212
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/sign-in.tsx"],"sourcesContent":["'use client'\r\n\r\nimport React from 'react'\r\nimport { useState } from 'react'\r\nimport { signInWithEmail } from '../app-router/client/actions'\r\nimport { styles } from '../utils/create-styles'\r\nimport { useRouter } from 'next/navigation'\r\n\r\nexport interface SignInProps {\r\n onError?: (error: Error) => void\r\n className?: string\r\n style?: React.CSSProperties\r\n customStyles?: {\r\n container?: string\r\n header?: string\r\n title?: string\r\n formWrapper?: string\r\n formContainer?: string\r\n form?: string\r\n input?: string\r\n button?: string\r\n errorText?: string\r\n label?: string\r\n }\r\n}\r\n\r\nexport function SignIn({ \r\n onError, \r\n className,\r\n style,\r\n customStyles = {}\r\n}: SignInProps) {\r\n\r\n const [loading, setLoading] = useState(false)\r\n const [error, setError] = useState('')\r\n const [email, setEmail] = useState('')\r\n const [password, setPassword] = useState('')\r\n const router = useRouter()\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault()\r\n setLoading(true)\r\n try {\r\n const user = await signInWithEmail(email, password)\r\n if (user.success) {\r\n router.push('/')\r\n }\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : 'Failed to sign in'\r\n setError(errorMessage)\r\n onError?.(err instanceof Error ? err : new Error('Failed to sign in'))\r\n } finally {\r\n setLoading(false)\r\n }\r\n }\r\n\r\n return (\r\n <div className={`${styles.container} ${customStyles.container || ''}`} style={style}>\r\n <div className={`${styles.header} ${customStyles.header || ''}`}>\r\n <h2 className={`${styles.title} ${customStyles.title || ''}`}>\r\n Sign in to your account\r\n </h2>\r\n </div>\r\n \r\n <div className={`${styles.formWrapper} ${customStyles.formWrapper || ''}`}>\r\n <div className={`${styles.formContainer} ${customStyles.formContainer || ''}`}>\r\n <form \r\n onSubmit={handleSubmit} \r\n className={`${styles.form} ${customStyles.form || ''} ${className}`}\r\n role=\"form\"\r\n aria-label=\"Sign in form\"\r\n >\r\n {error && (\r\n <div \r\n className={`${styles.error} ${customStyles.errorText || ''}`}\r\n role=\"alert\"\r\n aria-live=\"polite\"\r\n >\r\n {error}\r\n </div>\r\n )}\r\n <div>\r\n <label htmlFor=\"email\" className={`${styles.label} ${customStyles.label || ''}`}>\r\n Email\r\n </label>\r\n <input\r\n id=\"email\"\r\n name=\"email\"\r\n type=\"email\"\r\n placeholder=\"Enter your email\"\r\n required\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n className={`${styles.input} ${customStyles.input || ''}`}\r\n disabled={loading}\r\n aria-required=\"true\"\r\n aria-invalid={!!error}\r\n />\r\n </div>\r\n <div>\r\n <label htmlFor=\"password\" className={`${styles.label} ${customStyles.label || ''}`}>\r\n Password\r\n </label>\r\n <input\r\n id=\"password\"\r\n name=\"password\"\r\n type=\"password\"\r\n placeholder=\"Enter your password\"\r\n required\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n className={`${styles.input} ${customStyles.input || ''}`}\r\n disabled={loading}\r\n aria-required=\"true\"\r\n aria-invalid={!!error}\r\n />\r\n </div>\r\n <button \r\n type=\"submit\" \r\n disabled={loading}\r\n className={`${styles.button} ${customStyles.button || ''}`}\r\n data-testid=\"sign-in-submit\"\r\n >\r\n {loading ? 'Signing in...' : 'Sign in'}\r\n </button>\r\n </form>\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}\r\n\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/components/sign-in.tsx"],"sourcesContent":["'use client'\r\n\r\nimport React, { useState, useCallback, useEffect } from 'react'\r\nimport { useSearchParams } from 'next/navigation'\r\nimport { signInWithEmail, signInWithRedirectGoogle, signInWithMicrosoft } from '../app-router/client/actions'\r\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from \"./ui/card\"\r\nimport { Input } from \"./ui/input\"\r\nimport { Label } from \"./ui/label\"\r\nimport { Button } from \"./ui/button\"\r\nimport { Alert, AlertDescription } from \"./ui/alert\"\r\nimport { Separator } from \"./ui/separator\"\r\nimport { cn } from \"../lib/utils\"\r\nimport { Loader2 } from 'lucide-react'\r\nimport { getRedirectResult } from 'firebase/auth'\r\nimport { ternSecureAuth } from '../utils/client-init'\r\nimport { createSessionCookie } from '../app-router/server/sessionTernSecure'\r\nimport { AuthBackground } from './background'\r\nimport { getValidRedirectUrl } from '../utils/construct'\r\n\r\nconst isLocalhost = typeof window !== 'undefined' && \r\n (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1');\r\n\r\nconst authDomain = process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN;\r\n\r\n\r\nexport interface SignInProps {\r\n redirectUrl?: string\r\n onError?: (error: Error) => void\r\n onSuccess?: () => void\r\n className?: string\r\n customStyles?: {\r\n card?: string\r\n input?: string\r\n button?: string\r\n label?: string\r\n separator?: string\r\n title?: string\r\n description?: string\r\n socialButton?: string\r\n }\r\n}\r\n\r\nexport function SignIn({\r\n redirectUrl,\r\n onError,\r\n onSuccess,\r\n className,\r\n customStyles = {}\r\n}: SignInProps) {\r\n const [loading, setLoading] = useState(false)\r\n const [checkingRedirect, setCheckingRedirect] = useState(true)\r\n const [error, setError] = useState('')\r\n const [email, setEmail] = useState('')\r\n const [password, setPassword] = useState('')\r\n const searchParams = useSearchParams()\r\n const isRedirectSignIn = searchParams.get('signInRedirect') === 'true'\r\n\r\n\r\n const handleRedirectResult = useCallback(async () => {\r\n if (!isRedirectSignIn) return false\r\n setCheckingRedirect(true)\r\n try {\r\n console.log('Checking redirect result...');\r\n console.log('Current hostname:', window.location.hostname);\r\n console.log('Auth domain hostname:', authDomain);\r\n\r\n const isOnAuth = authDomain && \r\n window.location.hostname === authDomain.replace(/https?:\\/\\//, '');\r\n console.log('Is on AuthDomain:', isOnAuth);\r\n\r\n\r\n const result = await getRedirectResult(ternSecureAuth)\r\n console.log('Redirect result:', result);\r\n if (result) {\r\n const idToken = await result.user.getIdToken()\r\n const sessionResult = await createSessionCookie(idToken)\r\n if (!sessionResult.success) {\r\n throw new Error('Failed to create session')\r\n }\r\n const storedRedirectUrl = sessionStorage.getItem('auth_return_url')\r\n sessionStorage.removeItem('auth_redirect_url') \r\n onSuccess?.()\r\n window.location.href = storedRedirectUrl || getValidRedirectUrl(redirectUrl, searchParams)\r\n return true\r\n }\r\n setCheckingRedirect(false)\r\n } catch (err) {\r\n console.error('Redirect result error:', err)\r\n const errorMessage = err instanceof Error ? err.message : 'Authentication failed'\r\n setError(errorMessage)\r\n onError?.(err instanceof Error ? err : new Error(errorMessage))\r\n sessionStorage.removeItem('auth_redirect_url')\r\n return false\r\n }\r\n }, [isRedirectSignIn, redirectUrl, searchParams, onSuccess, onError])\r\n\r\n //const REDIRECT_TIMEOUT = 5000;\r\n\r\n useEffect(() => {\r\n //let timeoutId: NodeJS.Timeout;\r\n\r\n if (isRedirectSignIn) {\r\n handleRedirectResult();\r\n\r\n /*timeoutId = setTimeout(() => {\r\n console.warn('Redirect check timed out');\r\n setCheckingRedirect(false);\r\n setError('Sign in took too long. Please try again.');\r\n \r\n }, REDIRECT_TIMEOUT);\r\n }\r\n\r\n return () => {\r\n if (timeoutId) {\r\n clearTimeout(timeoutId);\r\n }*/\r\n };\r\n }, [handleRedirectResult, isRedirectSignIn])\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault()\r\n setLoading(true)\r\n try {\r\n const user = await signInWithEmail(email, password)\r\n if (user.success) {\r\n onSuccess?.()\r\n window.location.href = getValidRedirectUrl(redirectUrl, searchParams)\r\n }\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : 'Failed to sign in'\r\n setError(errorMessage)\r\n onError?.(err instanceof Error ? err : new Error('Failed to sign in'))\r\n } finally {\r\n setLoading(false)\r\n }\r\n }\r\n\r\n const handleSocialSignIn = async (provider: 'google' | 'microsoft') => {\r\n setLoading(true)\r\n try {\r\n\r\n const validRedirectUrl = getValidRedirectUrl(redirectUrl, searchParams)\r\n sessionStorage.setItem('auth_redirect_url', validRedirectUrl)\r\n\r\n const currentUrl = new URL(window.location.href)\r\n currentUrl.searchParams.set('signInRedirect', 'true')\r\n window.history.replaceState({}, '', currentUrl.toString())\r\n\r\n const result = provider === 'google' ? await signInWithRedirectGoogle() : await signInWithMicrosoft()\r\n if (!result.success) {\r\n throw new Error(result.error)\r\n }\r\n } catch (err) {\r\n const errorMessage = err instanceof Error ? err.message : `Failed to sign in with ${provider}`\r\n setError(errorMessage)\r\n onError?.(err instanceof Error ? err : new Error(`Failed to sign in with ${provider}`))\r\n setLoading(false)\r\n sessionStorage.removeItem('auth_redirect_url')\r\n }\r\n }\r\n\r\n if (checkingRedirect && isRedirectSignIn) {\r\n return (\r\n <div className=\"flex min-h-screen items-center justify-center\">\r\n <div className=\"text-center space-y-4\">\r\n <div className=\"animate-spin rounded-full h-12 w-12 border-b-2 border-primary mx-auto\" />\r\n \r\n </div>\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <div className=\"relative flex items-center justify-center\">\r\n <AuthBackground />\r\n <Card className={cn(\"w-full max-w-md mx-auto mt-8\", className, customStyles.card)}>\r\n <CardHeader className=\"space-y-1 text-center\">\r\n <CardTitle className={cn(\"font-bold\", customStyles.title)}>Sign in to TernSecure</CardTitle>\r\n <CardDescription className={cn(\"text-muted-foreground\", customStyles.description)}>\r\n Please sign in to continue\r\n </CardDescription>\r\n </CardHeader>\r\n <CardContent className=\"space-y-4\">\r\n <form onSubmit={handleSubmit} className=\"space-y-4\">\r\n {error && (\r\n <Alert variant=\"destructive\">\r\n <AlertDescription>{error}</AlertDescription>\r\n </Alert>\r\n )}\r\n <div className=\"space-y-2\">\r\n <Label htmlFor=\"email\" className={cn(customStyles.label)}>Email</Label>\r\n <Input\r\n id=\"email\"\r\n type=\"email\"\r\n placeholder=\"m@example.com\"\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n disabled={loading}\r\n className={cn(customStyles.input)}\r\n required\r\n />\r\n </div>\r\n <div className=\"space-y-2\">\r\n <Label htmlFor=\"password\" className={cn(customStyles.label)}>Password</Label>\r\n <Input\r\n id=\"password\"\r\n type=\"password\"\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n disabled={loading}\r\n className={cn(customStyles.input)}\r\n required\r\n />\r\n </div>\r\n <Button type=\"submit\" disabled={loading} className={cn(\"w-full\", customStyles.button)}>\r\n {loading ? (\r\n <>\r\n <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" />\r\n Signing in...\r\n </>\r\n ) : (\r\n 'Sign in'\r\n )}\r\n </Button>\r\n </form>\r\n <div className=\"relative\">\r\n <Separator className={cn(customStyles.separator)} />\r\n <div className=\"absolute inset-0 flex items-center justify-center\">\r\n <span className=\"bg-background px-2 text-muted-foreground text-sm\">Or continue with</span>\r\n </div>\r\n </div>\r\n <div className=\"grid grid-cols-2 gap-4\">\r\n <Button \r\n variant=\"outline\" \r\n disabled={loading} \r\n onClick={() => handleSocialSignIn('google')} \r\n className={cn(\"flex items-center justify-center\", customStyles.socialButton)}\r\n >\r\n <svg className=\"w-5 h-5 mr-2\" viewBox=\"0 0 24 24\" xmlns=\"http://www.w3.org/2000/svg\">\r\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\"/>\r\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\"/>\r\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\"/>\r\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\"/>\r\n </svg>\r\n Google\r\n </Button>\r\n <Button \r\n variant=\"outline\" \r\n disabled={loading} \r\n onClick={() => handleSocialSignIn('microsoft')} \r\n className={cn(\"flex items-center justify-center\", customStyles.socialButton)}\r\n >\r\n <svg className=\"w-5 h-5 mr-2\" viewBox=\"0 0 23 23\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path fill=\"#f3f3f3\" d=\"M0 0h23v23H0z\"/>\r\n <path fill=\"#f35325\" d=\"M1 1h10v10H1z\"/>\r\n <path fill=\"#81bc06\" d=\"M12 1h10v10H12z\"/>\r\n <path fill=\"#05a6f0\" d=\"M1 12h10v10H1z\"/>\r\n <path fill=\"#ffba08\" d=\"M12 12h10v10H12z\"/>\r\n </svg>\r\n Microsoft\r\n </Button>\r\n </div>\r\n </CardContent>\r\n <CardFooter className=\"flex justify-center\">\r\n <p className=\"text-sm text-muted-foreground\">\r\n Don&apos;t have an account?{' '}\r\n <a href=\"#\" className=\"text-primary hover:underline\">\r\n Sign up\r\n </a>\r\n </p>\r\n </CardFooter>\r\n </Card>\r\n </div>\r\n )\r\n}\r\n\r\n"],"mappings":";AAqKU,SAmDI,UAnDJ,KAWJ,YAXI;AAnKV,SAAgB,UAAU,aAAa,iBAAiB;AACxD,SAAS,uBAAuB;AAChC,SAAS,iBAAiB,0BAA0B,2BAA2B;AAC/E,SAAS,MAAM,aAAa,iBAAiB,YAAY,YAAY,iBAAiB;AACtF,SAAS,aAAa;AACtB,SAAS,aAAa;AACtB,SAAS,cAAc;AACvB,SAAS,OAAO,wBAAwB;AACxC,SAAS,iBAAiB;AAC1B,SAAS,UAAU;AACnB,SAAS,eAAe;AACxB,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;AAC/B,SAAS,2BAA2B;AACpC,SAAS,sBAAsB;AAC/B,SAAS,2BAA2B;AAEpC,MAAM,cAAc,OAAO,WAAW,gBACnC,OAAO,SAAS,aAAa,eAAe,OAAO,SAAS,aAAa;AAE5E,MAAM,aAAa,QAAQ,IAAI;AAoBxB,SAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe,CAAC;AAClB,GAAgB;AACd,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,SAAS,IAAI;AAC7D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,EAAE;AAC3C,QAAM,eAAe,gBAAgB;AACrC,QAAM,mBAAmB,aAAa,IAAI,gBAAgB,MAAM;AAGhE,QAAM,uBAAuB,YAAY,YAAY;AACnD,QAAI,CAAC,iBAAkB,QAAO;AAC9B,wBAAoB,IAAI;AACxB,QAAI;AACF,cAAQ,IAAI,6BAA6B;AACzC,cAAQ,IAAI,qBAAqB,OAAO,SAAS,QAAQ;AACzD,cAAQ,IAAI,yBAAyB,UAAU;AAEjD,YAAM,WAAW,cACjB,OAAO,SAAS,aAAa,WAAW,QAAQ,eAAe,EAAE;AACjE,cAAQ,IAAI,sBAAsB,QAAQ;AAGxC,YAAM,SAAS,MAAM,kBAAkB,cAAc;AACrD,cAAQ,IAAI,oBAAoB,MAAM;AACtC,UAAI,QAAQ;AACV,cAAM,UAAU,MAAM,OAAO,KAAK,WAAW;AAC7C,cAAM,gBAAgB,MAAM,oBAAoB,OAAO;AACvD,YAAI,CAAC,cAAc,SAAS;AAC1B,gBAAM,IAAI,MAAM,0BAA0B;AAAA,QAC5C;AACA,cAAM,oBAAoB,eAAe,QAAQ,iBAAiB;AAClE,uBAAe,WAAW,mBAAmB;AAC7C;AACA,eAAO,SAAS,OAAO,qBAAqB,oBAAoB,aAAa,YAAY;AACzF,eAAO;AAAA,MACT;AACA,0BAAoB,KAAK;AAAA,IAC3B,SAAS,KAAK;AACZ,cAAQ,MAAM,0BAA0B,GAAG;AAC3C,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,yCAAU,eAAe,QAAQ,MAAM,IAAI,MAAM,YAAY;AAC7D,qBAAe,WAAW,mBAAmB;AAC7C,aAAO;AAAA,IACT;AAAA,EACF,GAAG,CAAC,kBAAkB,aAAa,cAAc,WAAW,OAAO,CAAC;AAIpE,YAAU,MAAM;AAGd,QAAI,kBAAkB;AACpB,2BAAqB;AAAA,IAcvB;AAAC;AAAA,EACH,GAAG,CAAC,sBAAsB,gBAAgB,CAAC;AAE3C,QAAM,eAAe,OAAO,MAAuB;AACjD,MAAE,eAAe;AACjB,eAAW,IAAI;AACf,QAAI;AACF,YAAM,OAAO,MAAM,gBAAgB,OAAO,QAAQ;AAClD,UAAI,KAAK,SAAS;AAChB;AACA,eAAO,SAAS,OAAO,oBAAoB,aAAa,YAAY;AAAA,MACtE;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU;AAC1D,eAAS,YAAY;AACrB,yCAAU,eAAe,QAAQ,MAAM,IAAI,MAAM,mBAAmB;AAAA,IACtE,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,qBAAqB,OAAO,aAAqC;AACrE,eAAW,IAAI;AACf,QAAI;AAEF,YAAM,mBAAmB,oBAAoB,aAAa,YAAY;AACtE,qBAAe,QAAQ,qBAAqB,gBAAgB;AAE5D,YAAM,aAAa,IAAI,IAAI,OAAO,SAAS,IAAI;AAC/C,iBAAW,aAAa,IAAI,kBAAkB,MAAM;AACpD,aAAO,QAAQ,aAAa,CAAC,GAAG,IAAI,WAAW,SAAS,CAAC;AAEzD,YAAM,SAAS,aAAa,WAAW,MAAM,yBAAyB,IAAI,MAAM,oBAAoB;AACpG,UAAI,CAAC,OAAO,SAAS;AACnB,cAAM,IAAI,MAAM,OAAO,KAAK;AAAA,MAC9B;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,eAAe,eAAe,QAAQ,IAAI,UAAU,0BAA0B,QAAQ;AAC5F,eAAS,YAAY;AACrB,yCAAU,eAAe,QAAQ,MAAM,IAAI,MAAM,0BAA0B,QAAQ,EAAE;AACrF,iBAAW,KAAK;AAChB,qBAAe,WAAW,mBAAmB;AAAA,IAC/C;AAAA,EACF;AAEA,MAAI,oBAAoB,kBAAkB;AACxC,WACE,oBAAC,SAAI,WAAU,iDACb,8BAAC,SAAI,WAAU,yBACb,8BAAC,SAAI,WAAU,yEAAwE,GAEzF,GACF;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAU,6CACb;AAAA,wBAAC,kBAAe;AAAA,IAClB,qBAAC,QAAK,WAAW,GAAG,gCAAgC,WAAW,aAAa,IAAI,GAC9E;AAAA,2BAAC,cAAW,WAAU,yBACpB;AAAA,4BAAC,aAAU,WAAW,GAAG,aAAa,aAAa,KAAK,GAAG,mCAAqB;AAAA,QAChF,oBAAC,mBAAgB,WAAW,GAAG,yBAAyB,aAAa,WAAW,GAAG,wCAEnF;AAAA,SACF;AAAA,MACA,qBAAC,eAAY,WAAU,aACrB;AAAA,6BAAC,UAAK,UAAU,cAAc,WAAU,aACrC;AAAA,mBACC,oBAAC,SAAM,SAAQ,eACb,8BAAC,oBAAkB,iBAAM,GAC3B;AAAA,UAEF,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,SAAM,SAAQ,SAAQ,WAAW,GAAG,aAAa,KAAK,GAAG,mBAAK;AAAA,YAC/D;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,MAAK;AAAA,gBACL,aAAY;AAAA,gBACZ,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,gBACxC,UAAU;AAAA,gBACV,WAAW,GAAG,aAAa,KAAK;AAAA,gBAChC,UAAQ;AAAA;AAAA,YACV;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,aACb;AAAA,gCAAC,SAAM,SAAQ,YAAW,WAAW,GAAG,aAAa,KAAK,GAAG,sBAAQ;AAAA,YACrE;AAAA,cAAC;AAAA;AAAA,gBACC,IAAG;AAAA,gBACH,MAAK;AAAA,gBACL,OAAO;AAAA,gBACP,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA,gBAC3C,UAAU;AAAA,gBACV,WAAW,GAAG,aAAa,KAAK;AAAA,gBAChC,UAAQ;AAAA;AAAA,YACV;AAAA,aACF;AAAA,UACA,oBAAC,UAAO,MAAK,UAAS,UAAU,SAAS,WAAW,GAAG,UAAU,aAAa,MAAM,GACjF,oBACC,iCACE;AAAA,gCAAC,WAAQ,WAAU,6BAA4B;AAAA,YAAE;AAAA,aAEnD,IAEA,WAEJ;AAAA,WACF;AAAA,QACA,qBAAC,SAAI,WAAU,YACb;AAAA,8BAAC,aAAU,WAAW,GAAG,aAAa,SAAS,GAAG;AAAA,UAClD,oBAAC,SAAI,WAAU,qDACb,8BAAC,UAAK,WAAU,oDAAmD,8BAAgB,GACrF;AAAA,WACF;AAAA,QACA,qBAAC,SAAI,WAAU,0BACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,UAAU;AAAA,cACV,SAAS,MAAM,mBAAmB,QAAQ;AAAA,cAC1C,WAAW,GAAG,oCAAoC,aAAa,YAAY;AAAA,cAE3E;AAAA,qCAAC,SAAI,WAAU,gBAAe,SAAQ,aAAY,OAAM,8BACtD;AAAA,sCAAC,UAAK,GAAE,2HAA0H,MAAK,WAAS;AAAA,kBAChJ,oBAAC,UAAK,GAAE,yIAAwI,MAAK,WAAS;AAAA,kBAC9J,oBAAC,UAAK,GAAE,iIAAgI,MAAK,WAAS;AAAA,kBACtJ,oBAAC,UAAK,GAAE,uIAAsI,MAAK,WAAS;AAAA,mBAC9J;AAAA,gBAAM;AAAA;AAAA;AAAA,UAER;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,UAAU;AAAA,cACV,SAAS,MAAM,mBAAmB,WAAW;AAAA,cAC7C,WAAW,GAAG,oCAAoC,aAAa,YAAY;AAAA,cAE3E;AAAA,qCAAC,SAAI,WAAU,gBAAe,SAAQ,aAAY,OAAM,8BACtD;AAAA,sCAAC,UAAK,MAAK,WAAU,GAAE,iBAAe;AAAA,kBACtC,oBAAC,UAAK,MAAK,WAAU,GAAE,iBAAe;AAAA,kBACtC,oBAAC,UAAK,MAAK,WAAU,GAAE,mBAAiB;AAAA,kBACxC,oBAAC,UAAK,MAAK,WAAU,GAAE,kBAAgB;AAAA,kBACvC,oBAAC,UAAK,MAAK,WAAU,GAAE,oBAAkB;AAAA,mBAC3C;AAAA,gBAAM;AAAA;AAAA;AAAA,UAER;AAAA,WACF;AAAA,SACF;AAAA,MACA,oBAAC,cAAW,WAAU,uBACpB,+BAAC,OAAE,WAAU,iCAAgC;AAAA;AAAA,QACjB;AAAA,QAC1B,oBAAC,OAAE,MAAK,KAAI,WAAU,gCAA+B,qBAErD;AAAA,SACF,GACF;AAAA,OACF;AAAA,KACA;AAEJ;","names":[]}
@@ -0,0 +1,45 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import { useRouter } from "next/navigation";
5
+ import { signOut } from "firebase/auth";
6
+ import { Button } from "./ui/button";
7
+ import { ternSecureAuth } from "../utils/client-init";
8
+ import { clearSessionCookie } from "../app-router/server/sessionTernSecure";
9
+ function SignOut({
10
+ children = "Sign out",
11
+ onError,
12
+ onSignOutSuccess,
13
+ ...buttonProps
14
+ }) {
15
+ const router = useRouter();
16
+ const [isLoading, setIsLoading] = useState(false);
17
+ const handleSignOut = async () => {
18
+ setIsLoading(true);
19
+ try {
20
+ await signOut(ternSecureAuth);
21
+ await clearSessionCookie();
22
+ onSignOutSuccess == null ? void 0 : onSignOutSuccess();
23
+ router.push("/sign-in");
24
+ } catch (error) {
25
+ console.error("Sign out error:", error);
26
+ onError == null ? void 0 : onError(error instanceof Error ? error : new Error("Failed to sign out"));
27
+ } finally {
28
+ setIsLoading(false);
29
+ }
30
+ };
31
+ return /* @__PURE__ */ jsx(
32
+ Button,
33
+ {
34
+ variant: "outline",
35
+ onClick: handleSignOut,
36
+ disabled: isLoading,
37
+ ...buttonProps,
38
+ children: isLoading ? "Signing out..." : children
39
+ }
40
+ );
41
+ }
42
+ export {
43
+ SignOut
44
+ };
45
+ //# sourceMappingURL=sign-out.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/sign-out.tsx"],"sourcesContent":["'use client'\r\n\r\nimport { useState } from 'react'\r\nimport { useRouter } from 'next/navigation'\r\nimport { signOut } from 'firebase/auth'\r\nimport { Button, type ButtonProps } from './ui/button'\r\nimport { ternSecureAuth } from '../utils/client-init'\r\nimport { clearSessionCookie } from '../app-router/server/sessionTernSecure'\r\n\r\ntype SignOutCustomProps = {\r\n children?: React.ReactNode\r\n onError?: (error: Error) => void\r\n onSignOutSuccess?: () => void\r\n}\r\n\r\ntype SignOutProps = Omit<ButtonProps, 'onClick'> & SignOutCustomProps\r\n\r\nexport function SignOut({ \r\n children = 'Sign out', \r\n onError,\r\n onSignOutSuccess,\r\n ...buttonProps \r\n}: SignOutProps) {\r\n const router = useRouter()\r\n const [isLoading, setIsLoading] = useState(false)\r\n\r\n const handleSignOut = async () => {\r\n setIsLoading(true)\r\n try {\r\n // Sign out from Firebase\r\n await signOut(ternSecureAuth)\r\n \r\n // Clear the session cookie\r\n await clearSessionCookie()\r\n \r\n // Call success callback if provided\r\n onSignOutSuccess?.()\r\n \r\n // Redirect to sign-in page\r\n router.push('/sign-in')\r\n } catch (error) {\r\n console.error('Sign out error:', error)\r\n onError?.(error instanceof Error ? error : new Error('Failed to sign out'))\r\n } finally {\r\n setIsLoading(false)\r\n }\r\n }\r\n\r\n return (\r\n <Button\r\n variant=\"outline\"\r\n onClick={handleSignOut}\r\n disabled={isLoading}\r\n {...buttonProps}\r\n >\r\n {isLoading ? 'Signing out...' : children}\r\n </Button>\r\n )\r\n}\r\n\r\n"],"mappings":";AAiDI;AA/CJ,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,eAAe;AACxB,SAAS,cAAgC;AACzC,SAAS,sBAAsB;AAC/B,SAAS,0BAA0B;AAU5B,SAAS,QAAQ;AAAA,EACtB,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAiB;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAEhD,QAAM,gBAAgB,YAAY;AAChC,iBAAa,IAAI;AACjB,QAAI;AAEF,YAAM,QAAQ,cAAc;AAG5B,YAAM,mBAAmB;AAGzB;AAGA,aAAO,KAAK,UAAU;AAAA,IACxB,SAAS,OAAO;AACd,cAAQ,MAAM,mBAAmB,KAAK;AACtC,yCAAU,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,oBAAoB;AAAA,IAC3E,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU;AAAA,MACT,GAAG;AAAA,MAEH,sBAAY,mBAAmB;AAAA;AAAA,EAClC;AAEJ;","names":[]}
@@ -0,0 +1,52 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cva } from "class-variance-authority";
4
+ import { cn } from "../../lib/utils";
5
+ const alertVariants = cva(
6
+ "relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
7
+ {
8
+ variants: {
9
+ variant: {
10
+ default: "bg-background text-foreground",
11
+ destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive"
12
+ }
13
+ },
14
+ defaultVariants: {
15
+ variant: "default"
16
+ }
17
+ }
18
+ );
19
+ const Alert = React.forwardRef(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx(
20
+ "div",
21
+ {
22
+ ref,
23
+ role: "alert",
24
+ className: cn(alertVariants({ variant }), className),
25
+ ...props
26
+ }
27
+ ));
28
+ Alert.displayName = "Alert";
29
+ const AlertTitle = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
30
+ "h5",
31
+ {
32
+ ref,
33
+ className: cn("mb-1 font-medium leading-none tracking-tight", className),
34
+ ...props
35
+ }
36
+ ));
37
+ AlertTitle.displayName = "AlertTitle";
38
+ const AlertDescription = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
39
+ "div",
40
+ {
41
+ ref,
42
+ className: cn("text-sm [&_p]:leading-relaxed", className),
43
+ ...props
44
+ }
45
+ ));
46
+ AlertDescription.displayName = "AlertDescription";
47
+ export {
48
+ Alert,
49
+ AlertDescription,
50
+ AlertTitle
51
+ };
52
+ //# sourceMappingURL=alert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/components/ui/alert.tsx"],"sourcesContent":["import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"../../lib/utils\"\n\nconst alertVariants = cva(\n \"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7\",\n {\n variants: {\n variant: {\n default: \"bg-background text-foreground\",\n destructive:\n \"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n)\n\nconst Alert = React.forwardRef<\n HTMLDivElement,\n React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>\n>(({ className, variant, ...props }, ref) => (\n <div\n ref={ref}\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n))\nAlert.displayName = \"Alert\"\n\nconst AlertTitle = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLHeadingElement>\n>(({ className, ...props }, ref) => (\n <h5\n ref={ref}\n className={cn(\"mb-1 font-medium leading-none tracking-tight\", className)}\n {...props}\n />\n))\nAlertTitle.displayName = \"AlertTitle\"\n\nconst AlertDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"text-sm [&_p]:leading-relaxed\", className)}\n {...props}\n />\n))\nAlertDescription.displayName = \"AlertDescription\"\n\nexport { Alert, AlertTitle, AlertDescription }\n"],"mappings":"AAyBE;AAzBF,YAAY,WAAW;AACvB,SAAS,WAA8B;AAEvC,SAAS,UAAU;AAEnB,MAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,aACE;AAAA,MACJ;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAEA,MAAM,QAAQ,MAAM,WAGlB,CAAC,EAAE,WAAW,SAAS,GAAG,MAAM,GAAG,QACnC;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,MAAK;AAAA,IACL,WAAW,GAAG,cAAc,EAAE,QAAQ,CAAC,GAAG,SAAS;AAAA,IAClD,GAAG;AAAA;AACN,CACD;AACD,MAAM,cAAc;AAEpB,MAAM,aAAa,MAAM,WAGvB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,gDAAgD,SAAS;AAAA,IACtE,GAAG;AAAA;AACN,CACD;AACD,WAAW,cAAc;AAEzB,MAAM,mBAAmB,MAAM,WAG7B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,iCAAiC,SAAS;AAAA,IACvD,GAAG;AAAA;AACN,CACD;AACD,iBAAiB,cAAc;","names":[]}