@ezcoder.dev/sdk 1.3.3 → 1.4.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.
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  AuthContext
3
- } from "../chunk-QHB7LGCA.js";
3
+ } from "../chunk-NTA3RMYR.js";
4
4
  import {
5
5
  ezcoder,
6
6
  ezcoderAuthIntegration
7
- } from "../chunk-HJ2EIZ4S.js";
7
+ } from "../chunk-DU6N3HVQ.js";
8
8
  import {
9
9
  isSupabaseConfigured,
10
10
  supabase
11
- } from "../chunk-I2YGB7Z6.js";
11
+ } from "../chunk-KKTY5NCR.js";
12
12
  import {
13
13
  env,
14
14
  features
15
- } from "../chunk-LIUE7M7K.js";
15
+ } from "../chunk-X4JP7DCK.js";
16
16
 
17
17
  // src/analytics/useAnalytics.ts
18
18
  import { useEffect, useRef, useCallback, useContext } from "react";
@@ -2,6 +2,8 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { User, Session } from '@supabase/supabase-js';
4
4
  import { U as UserProfile, e as SubscriptionTier } from '../types-1uP3V_pe.js';
5
+ import { createAuthClient } from 'better-auth/react';
6
+ export { a as isNeonAuthConfigured } from '../config-D5ajnLCe.js';
5
7
 
6
8
  interface AuthResult<T = unknown> {
7
9
  data: T | null;
@@ -78,4 +80,29 @@ interface AuthCallbackProps {
78
80
  }
79
81
  declare function AuthCallback({ redirectTo, loadingComponent }: AuthCallbackProps): react_jsx_runtime.JSX.Element;
80
82
 
81
- export { AuthCallback, AuthContext, type AuthContextType, AuthProvider, type AuthResult, ForgotPasswordForm, LoginForm, ProtectedRoute, type SignInWithProviderOptions, type SignUpOptions, SignupForm, useAuth };
83
+ /**
84
+ * Per-project Neon Auth (Better Auth) client.
85
+ *
86
+ * A project uses Neon Auth when `env.NEON_AUTH_URL` (the per-project Better Auth
87
+ * `base_url`, e.g. `https://ep-xxx.neonauth.<region>.aws.neon.tech/neondb/auth`)
88
+ * is injected as `VITE_NEON_AUTH_URL`. When present, the SDK authenticates the
89
+ * generated app against its OWN isolated Neon Auth server rather than the shared
90
+ * tenant Supabase.
91
+ *
92
+ * The client is created lazily so that:
93
+ * - non-Neon projects never instantiate it (zero behavioural change), and
94
+ * - SSR/build passes that import the SDK without a base URL don't throw.
95
+ *
96
+ * This is the official Better Auth React client (`createAuthClient` from
97
+ * `better-auth/react`). It owns token storage and cross-origin session handling;
98
+ * do NOT hand-roll fetch against the Better Auth endpoints.
99
+ */
100
+ type NeonAuthClient = ReturnType<typeof createAuthClient>;
101
+ /**
102
+ * Returns the lazily-created Better Auth client, or `null` when Neon Auth is not
103
+ * configured for this project. Callers on the Neon path should treat a `null`
104
+ * return as "not configured" and surface a clear error.
105
+ */
106
+ declare function getNeonAuthClient(): NeonAuthClient | null;
107
+
108
+ export { AuthCallback, AuthContext, type AuthContextType, AuthProvider, type AuthResult, ForgotPasswordForm, LoginForm, type NeonAuthClient, ProtectedRoute, type SignInWithProviderOptions, type SignUpOptions, SignupForm, getNeonAuthClient, useAuth };
@@ -1,13 +1,16 @@
1
1
  import {
2
2
  AuthContext,
3
3
  AuthProvider,
4
+ getNeonAuthClient,
4
5
  useAuth
5
- } from "../chunk-QHB7LGCA.js";
6
- import "../chunk-HJ2EIZ4S.js";
6
+ } from "../chunk-NTA3RMYR.js";
7
+ import "../chunk-DU6N3HVQ.js";
7
8
  import {
8
9
  supabase
9
- } from "../chunk-I2YGB7Z6.js";
10
- import "../chunk-LIUE7M7K.js";
10
+ } from "../chunk-KKTY5NCR.js";
11
+ import {
12
+ isNeonAuthConfigured
13
+ } from "../chunk-X4JP7DCK.js";
11
14
 
12
15
  // src/auth/ProtectedRoute.tsx
13
16
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -430,6 +433,18 @@ function AuthCallback({ redirectTo = "/", loadingComponent }) {
430
433
  useEffect(() => {
431
434
  const handleCallback = async () => {
432
435
  try {
436
+ if (isNeonAuthConfigured) {
437
+ if (typeof window !== "undefined" && window.opener && window.opener !== window) {
438
+ try {
439
+ window.opener.postMessage({ type: "ezc-auth-complete" }, "*");
440
+ } catch {
441
+ }
442
+ window.close();
443
+ return;
444
+ }
445
+ if (typeof window !== "undefined") window.location.href = redirectTo;
446
+ return;
447
+ }
433
448
  let session = null;
434
449
  const got = await supabase.auth.getSession();
435
450
  if (got.error) {
@@ -477,6 +492,8 @@ export {
477
492
  LoginForm,
478
493
  ProtectedRoute,
479
494
  SignupForm,
495
+ getNeonAuthClient,
496
+ isNeonAuthConfigured,
480
497
  useAuth
481
498
  };
482
499
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/auth/ProtectedRoute.tsx","../../src/auth/LoginForm.tsx","../../src/auth/SignupForm.tsx","../../src/auth/ForgotPasswordForm.tsx","../../src/auth/AuthCallback.tsx"],"sourcesContent":["import { useAuth } from './AuthProvider';\r\nimport type { SubscriptionTier } from '../core/types';\r\n\r\ninterface ProtectedRouteProps {\r\n children: React.ReactNode;\r\n requiredRoles?: string[];\r\n requiredTier?: SubscriptionTier;\r\n fallback?: React.ReactNode;\r\n unauthorizedFallback?: React.ReactNode;\r\n allowUnconfigured?: boolean;\r\n loadingComponent?: React.ReactNode;\r\n loginPath?: string;\r\n}\r\n\r\nconst TIER_LEVELS: Record<string, number> = {\r\n free: 0,\r\n starter: 1,\r\n creator: 2,\r\n pro: 3,\r\n business: 4,\r\n enterprise: 5,\r\n};\r\n\r\nfunction DefaultLoadingSpinner() {\r\n return (\r\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '200px' }}>\r\n <div style={{\r\n width: '32px', height: '32px',\r\n border: '3px solid #e5e7eb', borderTopColor: '#3b82f6',\r\n borderRadius: '50%',\r\n animation: 'spin 0.6s linear infinite',\r\n }} />\r\n <style>{`@keyframes spin { to { transform: rotate(360deg); } }`}</style>\r\n </div>\r\n );\r\n}\r\n\r\nexport function ProtectedRoute({\r\n children,\r\n requiredTier,\r\n fallback,\r\n loadingComponent,\r\n allowUnconfigured = false,\r\n loginPath = '/login',\r\n}: ProtectedRouteProps) {\r\n const { user, profile, loading, isConfigured } = useAuth();\r\n\r\n if (loading) {\r\n return <>{loadingComponent || <DefaultLoadingSpinner />}</>;\r\n }\r\n\r\n if (!isConfigured && allowUnconfigured) {\r\n return <>{children}</>;\r\n }\r\n\r\n if (!user) {\r\n if (fallback) return <>{fallback}</>;\r\n if (typeof window !== 'undefined') {\r\n window.location.href = loginPath;\r\n }\r\n return null;\r\n }\r\n\r\n if (requiredTier) {\r\n const userTier = profile?.subscription_tier || 'free';\r\n const userLevel = TIER_LEVELS[userTier] ?? 0;\r\n const requiredLevel = TIER_LEVELS[requiredTier] ?? 0;\r\n\r\n if (userLevel < requiredLevel) {\r\n return (\r\n <div style={{ textAlign: 'center', padding: '40px' }}>\r\n <h2 style={{ fontSize: '1.5rem', fontWeight: 600, marginBottom: '8px' }}>Upgrade Required</h2>\r\n <p style={{ color: '#6b7280' }}>\r\n This feature requires the {requiredTier} plan or higher.\r\n </p>\r\n </div>\r\n );\r\n }\r\n }\r\n\r\n return <>{children}</>;\r\n}\r\n","import { useState } from 'react';\r\nimport { useAuth } from './AuthProvider';\r\n\r\ninterface LoginFormProps {\r\n onSuccess?: () => void;\r\n onForgotPassword?: () => void;\r\n onSignupClick?: () => void;\r\n showOAuth?: boolean;\r\n className?: string;\r\n}\r\n\r\nexport function LoginForm({\r\n onSuccess,\r\n onForgotPassword,\r\n onSignupClick,\r\n showOAuth = true,\r\n className = '',\r\n}: LoginFormProps) {\r\n const { signIn, signInWithProvider, isConfigured } = useAuth();\r\n const [email, setEmail] = useState('');\r\n const [password, setPassword] = useState('');\r\n const [error, setError] = useState<string | null>(null);\r\n const [loading, setLoading] = useState(false);\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n setLoading(true);\r\n\r\n const result = await signIn(email, password);\r\n setLoading(false);\r\n\r\n if (result.error) {\r\n setError(result.error.message);\r\n } else {\r\n onSuccess?.();\r\n }\r\n };\r\n\r\n const handleOAuth = async (provider: string) => {\r\n setError(null);\r\n const result = await signInWithProvider(provider);\r\n if (result.error) {\r\n setError(result.error.message);\r\n }\r\n };\r\n\r\n if (!isConfigured) {\r\n return (\r\n <div style={{ padding: '20px', textAlign: 'center', color: '#6b7280' }}>\r\n Authentication is not configured. Connect a database to enable login.\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className={className} style={{ maxWidth: '400px', margin: '0 auto' }}>\r\n <h2 style={{ fontSize: '1.5rem', fontWeight: 600, marginBottom: '24px', textAlign: 'center' }}>\r\n Sign In\r\n </h2>\r\n\r\n {error && (\r\n <div style={{ padding: '12px', marginBottom: '16px', backgroundColor: '#fef2f2', color: '#dc2626', borderRadius: '8px', fontSize: '14px' }}>\r\n {error}\r\n </div>\r\n )}\r\n\r\n <form onSubmit={handleSubmit}>\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '14px', fontWeight: 500 }}>Email</label>\r\n <input\r\n type=\"email\"\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n required\r\n style={{ width: '100%', padding: '8px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }}\r\n />\r\n </div>\r\n\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '14px', fontWeight: 500 }}>Password</label>\r\n <input\r\n type=\"password\"\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n required\r\n style={{ width: '100%', padding: '8px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }}\r\n />\r\n </div>\r\n\r\n {onForgotPassword && (\r\n <div style={{ marginBottom: '16px', textAlign: 'right' }}>\r\n <button type=\"button\" onClick={onForgotPassword} style={{ background: 'none', border: 'none', color: '#3b82f6', cursor: 'pointer', fontSize: '14px' }}>\r\n Forgot password?\r\n </button>\r\n </div>\r\n )}\r\n\r\n <button\r\n type=\"submit\"\r\n disabled={loading}\r\n style={{\r\n width: '100%', padding: '10px', backgroundColor: '#3b82f6', color: 'white',\r\n border: 'none', borderRadius: '6px', fontSize: '14px', fontWeight: 500,\r\n cursor: loading ? 'not-allowed' : 'pointer', opacity: loading ? 0.7 : 1,\r\n }}\r\n >\r\n {loading ? 'Signing in...' : 'Sign In'}\r\n </button>\r\n </form>\r\n\r\n {showOAuth && (\r\n <div style={{ marginTop: '24px' }}>\r\n <div style={{ textAlign: 'center', color: '#9ca3af', fontSize: '14px', marginBottom: '16px' }}>or continue with</div>\r\n <div style={{ display: 'flex', gap: '12px' }}>\r\n <button\r\n onClick={() => handleOAuth('google')}\r\n style={{ flex: 1, padding: '10px', border: '1px solid #d1d5db', borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '14px' }}\r\n >\r\n Google\r\n </button>\r\n <button\r\n onClick={() => handleOAuth('github')}\r\n style={{ flex: 1, padding: '10px', border: '1px solid #d1d5db', borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '14px' }}\r\n >\r\n GitHub\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {onSignupClick && (\r\n <div style={{ marginTop: '24px', textAlign: 'center', fontSize: '14px' }}>\r\n Don&apos;t have an account?{' '}\r\n <button type=\"button\" onClick={onSignupClick} style={{ background: 'none', border: 'none', color: '#3b82f6', cursor: 'pointer', fontWeight: 500 }}>\r\n Sign up\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState } from 'react';\r\nimport { useAuth } from './AuthProvider';\r\n\r\ninterface SignupFormProps {\r\n onSuccess?: () => void;\r\n onLoginClick?: () => void;\r\n showOAuth?: boolean;\r\n className?: string;\r\n}\r\n\r\nexport function SignupForm({\r\n onSuccess,\r\n onLoginClick,\r\n showOAuth = true,\r\n className = '',\r\n}: SignupFormProps) {\r\n const { signUp, signInWithProvider, isConfigured } = useAuth();\r\n const [name, setName] = useState('');\r\n const [email, setEmail] = useState('');\r\n const [password, setPassword] = useState('');\r\n const [agreed, setAgreed] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState(false);\r\n const [loading, setLoading] = useState(false);\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!agreed) {\r\n setError('Please agree to the Terms of Service');\r\n return;\r\n }\r\n if (password.length < 8) {\r\n setError('Password must be at least 8 characters');\r\n return;\r\n }\r\n\r\n setError(null);\r\n setLoading(true);\r\n\r\n const result = await signUp(email, password, {\r\n metadata: { display_name: name },\r\n });\r\n setLoading(false);\r\n\r\n if (result.error) {\r\n setError(result.error.message);\r\n } else {\r\n setSuccess(true);\r\n onSuccess?.();\r\n }\r\n };\r\n\r\n const handleOAuth = async (provider: string) => {\r\n setError(null);\r\n const result = await signInWithProvider(provider);\r\n if (result.error) {\r\n setError(result.error.message);\r\n }\r\n };\r\n\r\n if (!isConfigured) {\r\n return (\r\n <div style={{ padding: '20px', textAlign: 'center', color: '#6b7280' }}>\r\n Authentication is not configured. Connect a database to enable signup.\r\n </div>\r\n );\r\n }\r\n\r\n if (success) {\r\n return (\r\n <div style={{ padding: '20px', textAlign: 'center' }}>\r\n <h3 style={{ fontSize: '1.25rem', fontWeight: 600, marginBottom: '8px', color: '#059669' }}>Check your email</h3>\r\n <p style={{ color: '#6b7280' }}>We sent a confirmation link to {email}</p>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className={className} style={{ maxWidth: '400px', margin: '0 auto' }}>\r\n <h2 style={{ fontSize: '1.5rem', fontWeight: 600, marginBottom: '24px', textAlign: 'center' }}>\r\n Create Account\r\n </h2>\r\n\r\n {error && (\r\n <div style={{ padding: '12px', marginBottom: '16px', backgroundColor: '#fef2f2', color: '#dc2626', borderRadius: '8px', fontSize: '14px' }}>\r\n {error}\r\n </div>\r\n )}\r\n\r\n <form onSubmit={handleSubmit}>\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '14px', fontWeight: 500 }}>Name</label>\r\n <input type=\"text\" value={name} onChange={(e) => setName(e.target.value)} required\r\n style={{ width: '100%', padding: '8px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }} />\r\n </div>\r\n\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '14px', fontWeight: 500 }}>Email</label>\r\n <input type=\"email\" value={email} onChange={(e) => setEmail(e.target.value)} required\r\n style={{ width: '100%', padding: '8px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }} />\r\n </div>\r\n\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '14px', fontWeight: 500 }}>Password</label>\r\n <input type=\"password\" value={password} onChange={(e) => setPassword(e.target.value)} required minLength={8}\r\n style={{ width: '100%', padding: '8px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }} />\r\n <span style={{ fontSize: '12px', color: '#9ca3af' }}>Minimum 8 characters</span>\r\n </div>\r\n\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'flex', alignItems: 'center', gap: '8px', fontSize: '14px', cursor: 'pointer' }}>\r\n <input type=\"checkbox\" checked={agreed} onChange={(e) => setAgreed(e.target.checked)} />\r\n I agree to the Terms of Service and Privacy Policy\r\n </label>\r\n </div>\r\n\r\n <button type=\"submit\" disabled={loading}\r\n style={{\r\n width: '100%', padding: '10px', backgroundColor: '#3b82f6', color: 'white',\r\n border: 'none', borderRadius: '6px', fontSize: '14px', fontWeight: 500,\r\n cursor: loading ? 'not-allowed' : 'pointer', opacity: loading ? 0.7 : 1,\r\n }}>\r\n {loading ? 'Creating account...' : 'Create Account'}\r\n </button>\r\n </form>\r\n\r\n {showOAuth && (\r\n <div style={{ marginTop: '24px' }}>\r\n <div style={{ textAlign: 'center', color: '#9ca3af', fontSize: '14px', marginBottom: '16px' }}>or continue with</div>\r\n <div style={{ display: 'flex', gap: '12px' }}>\r\n <button onClick={() => handleOAuth('google')}\r\n style={{ flex: 1, padding: '10px', border: '1px solid #d1d5db', borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '14px' }}>\r\n Google\r\n </button>\r\n <button onClick={() => handleOAuth('github')}\r\n style={{ flex: 1, padding: '10px', border: '1px solid #d1d5db', borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '14px' }}>\r\n GitHub\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {onLoginClick && (\r\n <div style={{ marginTop: '24px', textAlign: 'center', fontSize: '14px' }}>\r\n Already have an account?{' '}\r\n <button type=\"button\" onClick={onLoginClick} style={{ background: 'none', border: 'none', color: '#3b82f6', cursor: 'pointer', fontWeight: 500 }}>\r\n Sign in\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState } from 'react';\r\nimport { useAuth } from './AuthProvider';\r\n\r\ninterface ForgotPasswordFormProps {\r\n onBack?: () => void;\r\n className?: string;\r\n}\r\n\r\nexport function ForgotPasswordForm({ onBack, className = '' }: ForgotPasswordFormProps) {\r\n const { resetPassword } = useAuth();\r\n const [email, setEmail] = useState('');\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState(false);\r\n const [loading, setLoading] = useState(false);\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n setLoading(true);\r\n\r\n const result = await resetPassword(email);\r\n setLoading(false);\r\n\r\n if (result.error) {\r\n setError(result.error.message);\r\n } else {\r\n setSuccess(true);\r\n }\r\n };\r\n\r\n if (success) {\r\n return (\r\n <div className={className} style={{ maxWidth: '400px', margin: '0 auto', textAlign: 'center', padding: '20px' }}>\r\n <h3 style={{ fontSize: '1.25rem', fontWeight: 600, marginBottom: '8px', color: '#059669' }}>Check your email</h3>\r\n <p style={{ color: '#6b7280', marginBottom: '16px' }}>We sent a password reset link to {email}</p>\r\n {onBack && (\r\n <button type=\"button\" onClick={onBack} style={{ background: 'none', border: 'none', color: '#3b82f6', cursor: 'pointer', fontSize: '14px' }}>\r\n Back to login\r\n </button>\r\n )}\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className={className} style={{ maxWidth: '400px', margin: '0 auto' }}>\r\n <h2 style={{ fontSize: '1.5rem', fontWeight: 600, marginBottom: '8px', textAlign: 'center' }}>Reset Password</h2>\r\n <p style={{ color: '#6b7280', textAlign: 'center', marginBottom: '24px', fontSize: '14px' }}>\r\n Enter your email and we&apos;ll send you a reset link\r\n </p>\r\n\r\n {error && (\r\n <div style={{ padding: '12px', marginBottom: '16px', backgroundColor: '#fef2f2', color: '#dc2626', borderRadius: '8px', fontSize: '14px' }}>\r\n {error}\r\n </div>\r\n )}\r\n\r\n <form onSubmit={handleSubmit}>\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '14px', fontWeight: 500 }}>Email</label>\r\n <input type=\"email\" value={email} onChange={(e) => setEmail(e.target.value)} required\r\n style={{ width: '100%', padding: '8px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }} />\r\n </div>\r\n\r\n <button type=\"submit\" disabled={loading}\r\n style={{\r\n width: '100%', padding: '10px', backgroundColor: '#3b82f6', color: 'white',\r\n border: 'none', borderRadius: '6px', fontSize: '14px', fontWeight: 500,\r\n cursor: loading ? 'not-allowed' : 'pointer', opacity: loading ? 0.7 : 1,\r\n }}>\r\n {loading ? 'Sending...' : 'Send Reset Link'}\r\n </button>\r\n </form>\r\n\r\n {onBack && (\r\n <div style={{ marginTop: '16px', textAlign: 'center' }}>\r\n <button type=\"button\" onClick={onBack} style={{ background: 'none', border: 'none', color: '#3b82f6', cursor: 'pointer', fontSize: '14px' }}>\r\n Back to login\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useEffect, useState } from 'react';\r\nimport { supabase } from '../core/supabase';\r\n\r\ninterface AuthCallbackProps {\r\n redirectTo?: string;\r\n loadingComponent?: React.ReactNode;\r\n}\r\n\r\nexport function AuthCallback({ redirectTo = '/', loadingComponent }: AuthCallbackProps) {\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n useEffect(() => {\r\n const handleCallback = async () => {\r\n try {\r\n // With detectSessionInUrl + PKCE the client usually auto-exchanges the\r\n // `?code=` before we run, so getSession() already has it. If not (e.g. a\r\n // build with detectSessionInUrl disabled), exchange explicitly.\r\n let session = null;\r\n const got = await supabase.auth.getSession();\r\n if (got.error) { setError(got.error.message); return; }\r\n session = got.data?.session ?? null;\r\n\r\n if (!session && typeof window !== 'undefined' &&\r\n new URLSearchParams(window.location.search).get('code')) {\r\n const ex = await supabase.auth.exchangeCodeForSession(window.location.href);\r\n if (ex.error) { setError(ex.error.message); return; }\r\n session = ex.data?.session ?? null;\r\n }\r\n\r\n // Popup flow (in-editor / framed sign-in): notify the opener and close,\r\n // rather than navigating. The opener (AuthProvider) picks up the session.\r\n if (typeof window !== 'undefined' && window.opener && window.opener !== window) {\r\n try { window.opener.postMessage({ type: 'ezc-auth-complete' }, '*'); } catch { /* cross-origin opener */ }\r\n window.close();\r\n return;\r\n }\r\n\r\n window.location.href = redirectTo;\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : 'Authentication callback failed');\r\n }\r\n };\r\n\r\n handleCallback();\r\n }, [redirectTo]);\r\n\r\n if (error) {\r\n return (\r\n <div style={{ textAlign: 'center', padding: '40px' }}>\r\n <h2 style={{ color: '#dc2626', marginBottom: '8px' }}>Authentication Error</h2>\r\n <p style={{ color: '#6b7280' }}>{error}</p>\r\n <a href=\"/login\" style={{ color: '#3b82f6', marginTop: '16px', display: 'inline-block' }}>\r\n Back to login\r\n </a>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <>\r\n {loadingComponent || (\r\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '200px' }}>\r\n <p style={{ color: '#6b7280' }}>Completing authentication...</p>\r\n </div>\r\n )}\r\n </>\r\n );\r\n}\r\n"],"mappings":";;;;;;;;;;;;AAyBI,SAuBO,UAtBL,KADF;AAXJ,IAAM,cAAsC;AAAA,EAC1C,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS;AAAA,EACT,KAAK;AAAA,EACL,UAAU;AAAA,EACV,YAAY;AACd;AAEA,SAAS,wBAAwB;AAC/B,SACE,qBAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,gBAAgB,UAAU,WAAW,QAAQ,GAChG;AAAA,wBAAC,SAAI,OAAO;AAAA,MACV,OAAO;AAAA,MAAQ,QAAQ;AAAA,MACvB,QAAQ;AAAA,MAAqB,gBAAgB;AAAA,MAC7C,cAAc;AAAA,MACd,WAAW;AAAA,IACb,GAAG;AAAA,IACH,oBAAC,WAAO,mEAAwD;AAAA,KAClE;AAEJ;AAEO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AAAA,EACpB,YAAY;AACd,GAAwB;AACtB,QAAM,EAAE,MAAM,SAAS,SAAS,aAAa,IAAI,QAAQ;AAEzD,MAAI,SAAS;AACX,WAAO,gCAAG,8BAAoB,oBAAC,yBAAsB,GAAG;AAAA,EAC1D;AAEA,MAAI,CAAC,gBAAgB,mBAAmB;AACtC,WAAO,gCAAG,UAAS;AAAA,EACrB;AAEA,MAAI,CAAC,MAAM;AACT,QAAI,SAAU,QAAO,gCAAG,oBAAS;AACjC,QAAI,OAAO,WAAW,aAAa;AACjC,aAAO,SAAS,OAAO;AAAA,IACzB;AACA,WAAO;AAAA,EACT;AAEA,MAAI,cAAc;AAChB,UAAM,WAAW,SAAS,qBAAqB;AAC/C,UAAM,YAAY,YAAY,QAAQ,KAAK;AAC3C,UAAM,gBAAgB,YAAY,YAAY,KAAK;AAEnD,QAAI,YAAY,eAAe;AAC7B,aACE,qBAAC,SAAI,OAAO,EAAE,WAAW,UAAU,SAAS,OAAO,GACjD;AAAA,4BAAC,QAAG,OAAO,EAAE,UAAU,UAAU,YAAY,KAAK,cAAc,MAAM,GAAG,8BAAgB;AAAA,QACzF,qBAAC,OAAE,OAAO,EAAE,OAAO,UAAU,GAAG;AAAA;AAAA,UACH;AAAA,UAAa;AAAA,WAC1C;AAAA,SACF;AAAA,IAEJ;AAAA,EACF;AAEA,SAAO,gCAAG,UAAS;AACrB;;;ACjFA,SAAS,gBAAgB;AAiDnB,gBAAAA,MAmBE,QAAAC,aAnBF;AAtCC,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,YAAY;AACd,GAAmB;AACjB,QAAM,EAAE,QAAQ,oBAAoB,aAAa,IAAI,QAAQ;AAC7D,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,EAAE;AAC3C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAwB,IAAI;AACtD,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,QAAM,eAAe,OAAO,MAAuB;AACjD,MAAE,eAAe;AACjB,aAAS,IAAI;AACb,eAAW,IAAI;AAEf,UAAM,SAAS,MAAM,OAAO,OAAO,QAAQ;AAC3C,eAAW,KAAK;AAEhB,QAAI,OAAO,OAAO;AAChB,eAAS,OAAO,MAAM,OAAO;AAAA,IAC/B,OAAO;AACL,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,cAAc,OAAO,aAAqB;AAC9C,aAAS,IAAI;AACb,UAAM,SAAS,MAAM,mBAAmB,QAAQ;AAChD,QAAI,OAAO,OAAO;AAChB,eAAS,OAAO,MAAM,OAAO;AAAA,IAC/B;AAAA,EACF;AAEA,MAAI,CAAC,cAAc;AACjB,WACE,gBAAAD,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,WAAW,UAAU,OAAO,UAAU,GAAG,mFAExE;AAAA,EAEJ;AAEA,SACE,gBAAAC,MAAC,SAAI,WAAsB,OAAO,EAAE,UAAU,SAAS,QAAQ,SAAS,GACtE;AAAA,oBAAAD,KAAC,QAAG,OAAO,EAAE,UAAU,UAAU,YAAY,KAAK,cAAc,QAAQ,WAAW,SAAS,GAAG,qBAE/F;AAAA,IAEC,SACC,gBAAAA,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,cAAc,QAAQ,iBAAiB,WAAW,OAAO,WAAW,cAAc,OAAO,UAAU,OAAO,GACtI,iBACH;AAAA,IAGF,gBAAAC,MAAC,UAAK,UAAU,cACd;AAAA,sBAAAA,MAAC,SAAI,OAAO,EAAE,cAAc,OAAO,GACjC;AAAA,wBAAAD,KAAC,WAAM,OAAO,EAAE,SAAS,SAAS,cAAc,OAAO,UAAU,QAAQ,YAAY,IAAI,GAAG,mBAAK;AAAA,QACjG,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,YACxC,UAAQ;AAAA,YACR,OAAO,EAAE,OAAO,QAAQ,SAAS,YAAY,QAAQ,qBAAqB,cAAc,OAAO,UAAU,OAAO;AAAA;AAAA,QAClH;AAAA,SACF;AAAA,MAEA,gBAAAC,MAAC,SAAI,OAAO,EAAE,cAAc,OAAO,GACjC;AAAA,wBAAAD,KAAC,WAAM,OAAO,EAAE,SAAS,SAAS,cAAc,OAAO,UAAU,QAAQ,YAAY,IAAI,GAAG,sBAAQ;AAAA,QACpG,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA,YAC3C,UAAQ;AAAA,YACR,OAAO,EAAE,OAAO,QAAQ,SAAS,YAAY,QAAQ,qBAAqB,cAAc,OAAO,UAAU,OAAO;AAAA;AAAA,QAClH;AAAA,SACF;AAAA,MAEC,oBACC,gBAAAA,KAAC,SAAI,OAAO,EAAE,cAAc,QAAQ,WAAW,QAAQ,GACrD,0BAAAA,KAAC,YAAO,MAAK,UAAS,SAAS,kBAAkB,OAAO,EAAE,YAAY,QAAQ,QAAQ,QAAQ,OAAO,WAAW,QAAQ,WAAW,UAAU,OAAO,GAAG,8BAEvJ,GACF;AAAA,MAGF,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU;AAAA,UACV,OAAO;AAAA,YACL,OAAO;AAAA,YAAQ,SAAS;AAAA,YAAQ,iBAAiB;AAAA,YAAW,OAAO;AAAA,YACnE,QAAQ;AAAA,YAAQ,cAAc;AAAA,YAAO,UAAU;AAAA,YAAQ,YAAY;AAAA,YACnE,QAAQ,UAAU,gBAAgB;AAAA,YAAW,SAAS,UAAU,MAAM;AAAA,UACxE;AAAA,UAEC,oBAAU,kBAAkB;AAAA;AAAA,MAC/B;AAAA,OACF;AAAA,IAEC,aACC,gBAAAC,MAAC,SAAI,OAAO,EAAE,WAAW,OAAO,GAC9B;AAAA,sBAAAD,KAAC,SAAI,OAAO,EAAE,WAAW,UAAU,OAAO,WAAW,UAAU,QAAQ,cAAc,OAAO,GAAG,8BAAgB;AAAA,MAC/G,gBAAAC,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,KAAK,OAAO,GACzC;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,MAAM,YAAY,QAAQ;AAAA,YACnC,OAAO,EAAE,MAAM,GAAG,SAAS,QAAQ,QAAQ,qBAAqB,cAAc,OAAO,YAAY,SAAS,QAAQ,WAAW,UAAU,OAAO;AAAA,YAC/I;AAAA;AAAA,QAED;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,MAAM,YAAY,QAAQ;AAAA,YACnC,OAAO,EAAE,MAAM,GAAG,SAAS,QAAQ,QAAQ,qBAAqB,cAAc,OAAO,YAAY,SAAS,QAAQ,WAAW,UAAU,OAAO;AAAA,YAC/I;AAAA;AAAA,QAED;AAAA,SACF;AAAA,OACF;AAAA,IAGD,iBACC,gBAAAC,MAAC,SAAI,OAAO,EAAE,WAAW,QAAQ,WAAW,UAAU,UAAU,OAAO,GAAG;AAAA;AAAA,MAC5C;AAAA,MAC5B,gBAAAD,KAAC,YAAO,MAAK,UAAS,SAAS,eAAe,OAAO,EAAE,YAAY,QAAQ,QAAQ,QAAQ,OAAO,WAAW,QAAQ,WAAW,YAAY,IAAI,GAAG,qBAEnJ;AAAA,OACF;AAAA,KAEJ;AAEJ;;;AC7IA,SAAS,YAAAE,iBAAgB;AA8DnB,gBAAAC,MAUE,QAAAC,aAVF;AApDC,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,YAAY;AACd,GAAoB;AAClB,QAAM,EAAE,QAAQ,oBAAoB,aAAa,IAAI,QAAQ;AAC7D,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAS,EAAE;AACnC,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAS,EAAE;AACrC,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,EAAE;AAC3C,QAAM,CAAC,QAAQ,SAAS,IAAIA,UAAS,KAAK;AAC1C,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AACtD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAC5C,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAE5C,QAAM,eAAe,OAAO,MAAuB;AACjD,MAAE,eAAe;AACjB,QAAI,CAAC,QAAQ;AACX,eAAS,sCAAsC;AAC/C;AAAA,IACF;AACA,QAAI,SAAS,SAAS,GAAG;AACvB,eAAS,wCAAwC;AACjD;AAAA,IACF;AAEA,aAAS,IAAI;AACb,eAAW,IAAI;AAEf,UAAM,SAAS,MAAM,OAAO,OAAO,UAAU;AAAA,MAC3C,UAAU,EAAE,cAAc,KAAK;AAAA,IACjC,CAAC;AACD,eAAW,KAAK;AAEhB,QAAI,OAAO,OAAO;AAChB,eAAS,OAAO,MAAM,OAAO;AAAA,IAC/B,OAAO;AACL,iBAAW,IAAI;AACf,kBAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,cAAc,OAAO,aAAqB;AAC9C,aAAS,IAAI;AACb,UAAM,SAAS,MAAM,mBAAmB,QAAQ;AAChD,QAAI,OAAO,OAAO;AAChB,eAAS,OAAO,MAAM,OAAO;AAAA,IAC/B;AAAA,EACF;AAEA,MAAI,CAAC,cAAc;AACjB,WACE,gBAAAF,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,WAAW,UAAU,OAAO,UAAU,GAAG,oFAExE;AAAA,EAEJ;AAEA,MAAI,SAAS;AACX,WACE,gBAAAC,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,WAAW,SAAS,GACjD;AAAA,sBAAAD,KAAC,QAAG,OAAO,EAAE,UAAU,WAAW,YAAY,KAAK,cAAc,OAAO,OAAO,UAAU,GAAG,8BAAgB;AAAA,MAC5G,gBAAAC,MAAC,OAAE,OAAO,EAAE,OAAO,UAAU,GAAG;AAAA;AAAA,QAAgC;AAAA,SAAM;AAAA,OACxE;AAAA,EAEJ;AAEA,SACE,gBAAAA,MAAC,SAAI,WAAsB,OAAO,EAAE,UAAU,SAAS,QAAQ,SAAS,GACtE;AAAA,oBAAAD,KAAC,QAAG,OAAO,EAAE,UAAU,UAAU,YAAY,KAAK,cAAc,QAAQ,WAAW,SAAS,GAAG,4BAE/F;AAAA,IAEC,SACC,gBAAAA,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,cAAc,QAAQ,iBAAiB,WAAW,OAAO,WAAW,cAAc,OAAO,UAAU,OAAO,GACtI,iBACH;AAAA,IAGF,gBAAAC,MAAC,UAAK,UAAU,cACd;AAAA,sBAAAA,MAAC,SAAI,OAAO,EAAE,cAAc,OAAO,GACjC;AAAA,wBAAAD,KAAC,WAAM,OAAO,EAAE,SAAS,SAAS,cAAc,OAAO,UAAU,QAAQ,YAAY,IAAI,GAAG,kBAAI;AAAA,QAChG,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAAM,MAAK;AAAA,YAAO,OAAO;AAAA,YAAM,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA,YAAG,UAAQ;AAAA,YAChF,OAAO,EAAE,OAAO,QAAQ,SAAS,YAAY,QAAQ,qBAAqB,cAAc,OAAO,UAAU,OAAO;AAAA;AAAA,QAAG;AAAA,SACvH;AAAA,MAEA,gBAAAC,MAAC,SAAI,OAAO,EAAE,cAAc,OAAO,GACjC;AAAA,wBAAAD,KAAC,WAAM,OAAO,EAAE,SAAS,SAAS,cAAc,OAAO,UAAU,QAAQ,YAAY,IAAI,GAAG,mBAAK;AAAA,QACjG,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAAM,MAAK;AAAA,YAAQ,OAAO;AAAA,YAAO,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,YAAG,UAAQ;AAAA,YACnF,OAAO,EAAE,OAAO,QAAQ,SAAS,YAAY,QAAQ,qBAAqB,cAAc,OAAO,UAAU,OAAO;AAAA;AAAA,QAAG;AAAA,SACvH;AAAA,MAEA,gBAAAC,MAAC,SAAI,OAAO,EAAE,cAAc,OAAO,GACjC;AAAA,wBAAAD,KAAC,WAAM,OAAO,EAAE,SAAS,SAAS,cAAc,OAAO,UAAU,QAAQ,YAAY,IAAI,GAAG,sBAAQ;AAAA,QACpG,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAAM,MAAK;AAAA,YAAW,OAAO;AAAA,YAAU,UAAU,CAAC,MAAM,YAAY,EAAE,OAAO,KAAK;AAAA,YAAG,UAAQ;AAAA,YAAC,WAAW;AAAA,YACxG,OAAO,EAAE,OAAO,QAAQ,SAAS,YAAY,QAAQ,qBAAqB,cAAc,OAAO,UAAU,OAAO;AAAA;AAAA,QAAG;AAAA,QACrH,gBAAAA,KAAC,UAAK,OAAO,EAAE,UAAU,QAAQ,OAAO,UAAU,GAAG,kCAAoB;AAAA,SAC3E;AAAA,MAEA,gBAAAA,KAAC,SAAI,OAAO,EAAE,cAAc,OAAO,GACjC,0BAAAC,MAAC,WAAM,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,OAAO,UAAU,QAAQ,QAAQ,UAAU,GACrG;AAAA,wBAAAD,KAAC,WAAM,MAAK,YAAW,SAAS,QAAQ,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,OAAO,GAAG;AAAA,QAAE;AAAA,SAE1F,GACF;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAAO,MAAK;AAAA,UAAS,UAAU;AAAA,UAC9B,OAAO;AAAA,YACL,OAAO;AAAA,YAAQ,SAAS;AAAA,YAAQ,iBAAiB;AAAA,YAAW,OAAO;AAAA,YACnE,QAAQ;AAAA,YAAQ,cAAc;AAAA,YAAO,UAAU;AAAA,YAAQ,YAAY;AAAA,YACnE,QAAQ,UAAU,gBAAgB;AAAA,YAAW,SAAS,UAAU,MAAM;AAAA,UACxE;AAAA,UACC,oBAAU,wBAAwB;AAAA;AAAA,MACrC;AAAA,OACF;AAAA,IAEC,aACC,gBAAAC,MAAC,SAAI,OAAO,EAAE,WAAW,OAAO,GAC9B;AAAA,sBAAAD,KAAC,SAAI,OAAO,EAAE,WAAW,UAAU,OAAO,WAAW,UAAU,QAAQ,cAAc,OAAO,GAAG,8BAAgB;AAAA,MAC/G,gBAAAC,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,KAAK,OAAO,GACzC;AAAA,wBAAAD;AAAA,UAAC;AAAA;AAAA,YAAO,SAAS,MAAM,YAAY,QAAQ;AAAA,YACzC,OAAO,EAAE,MAAM,GAAG,SAAS,QAAQ,QAAQ,qBAAqB,cAAc,OAAO,YAAY,SAAS,QAAQ,WAAW,UAAU,OAAO;AAAA,YAAG;AAAA;AAAA,QAEnJ;AAAA,QACA,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAAO,SAAS,MAAM,YAAY,QAAQ;AAAA,YACzC,OAAO,EAAE,MAAM,GAAG,SAAS,QAAQ,QAAQ,qBAAqB,cAAc,OAAO,YAAY,SAAS,QAAQ,WAAW,UAAU,OAAO;AAAA,YAAG;AAAA;AAAA,QAEnJ;AAAA,SACF;AAAA,OACF;AAAA,IAGD,gBACC,gBAAAC,MAAC,SAAI,OAAO,EAAE,WAAW,QAAQ,WAAW,UAAU,UAAU,OAAO,GAAG;AAAA;AAAA,MAC/C;AAAA,MACzB,gBAAAD,KAAC,YAAO,MAAK,UAAS,SAAS,cAAc,OAAO,EAAE,YAAY,QAAQ,QAAQ,QAAQ,OAAO,WAAW,QAAQ,WAAW,YAAY,IAAI,GAAG,qBAElJ;AAAA,OACF;AAAA,KAEJ;AAEJ;;;ACxJA,SAAS,YAAAG,iBAAgB;AAiCjB,gBAAAC,MACA,QAAAC,aADA;AAzBD,SAAS,mBAAmB,EAAE,QAAQ,YAAY,GAAG,GAA4B;AACtF,QAAM,EAAE,cAAc,IAAI,QAAQ;AAClC,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAS,EAAE;AACrC,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AACtD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAC5C,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,KAAK;AAE5C,QAAM,eAAe,OAAO,MAAuB;AACjD,MAAE,eAAe;AACjB,aAAS,IAAI;AACb,eAAW,IAAI;AAEf,UAAM,SAAS,MAAM,cAAc,KAAK;AACxC,eAAW,KAAK;AAEhB,QAAI,OAAO,OAAO;AAChB,eAAS,OAAO,MAAM,OAAO;AAAA,IAC/B,OAAO;AACL,iBAAW,IAAI;AAAA,IACjB;AAAA,EACF;AAEA,MAAI,SAAS;AACX,WACE,gBAAAD,MAAC,SAAI,WAAsB,OAAO,EAAE,UAAU,SAAS,QAAQ,UAAU,WAAW,UAAU,SAAS,OAAO,GAC5G;AAAA,sBAAAD,KAAC,QAAG,OAAO,EAAE,UAAU,WAAW,YAAY,KAAK,cAAc,OAAO,OAAO,UAAU,GAAG,8BAAgB;AAAA,MAC5G,gBAAAC,MAAC,OAAE,OAAO,EAAE,OAAO,WAAW,cAAc,OAAO,GAAG;AAAA;AAAA,QAAkC;AAAA,SAAM;AAAA,MAC7F,UACC,gBAAAD,KAAC,YAAO,MAAK,UAAS,SAAS,QAAQ,OAAO,EAAE,YAAY,QAAQ,QAAQ,QAAQ,OAAO,WAAW,QAAQ,WAAW,UAAU,OAAO,GAAG,2BAE7I;AAAA,OAEJ;AAAA,EAEJ;AAEA,SACE,gBAAAC,MAAC,SAAI,WAAsB,OAAO,EAAE,UAAU,SAAS,QAAQ,SAAS,GACtE;AAAA,oBAAAD,KAAC,QAAG,OAAO,EAAE,UAAU,UAAU,YAAY,KAAK,cAAc,OAAO,WAAW,SAAS,GAAG,4BAAc;AAAA,IAC5G,gBAAAA,KAAC,OAAE,OAAO,EAAE,OAAO,WAAW,WAAW,UAAU,cAAc,QAAQ,UAAU,OAAO,GAAG,8DAE7F;AAAA,IAEC,SACC,gBAAAA,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,cAAc,QAAQ,iBAAiB,WAAW,OAAO,WAAW,cAAc,OAAO,UAAU,OAAO,GACtI,iBACH;AAAA,IAGF,gBAAAC,MAAC,UAAK,UAAU,cACd;AAAA,sBAAAA,MAAC,SAAI,OAAO,EAAE,cAAc,OAAO,GACjC;AAAA,wBAAAD,KAAC,WAAM,OAAO,EAAE,SAAS,SAAS,cAAc,OAAO,UAAU,QAAQ,YAAY,IAAI,GAAG,mBAAK;AAAA,QACjG,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAAM,MAAK;AAAA,YAAQ,OAAO;AAAA,YAAO,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,YAAG,UAAQ;AAAA,YACnF,OAAO,EAAE,OAAO,QAAQ,SAAS,YAAY,QAAQ,qBAAqB,cAAc,OAAO,UAAU,OAAO;AAAA;AAAA,QAAG;AAAA,SACvH;AAAA,MAEA,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAAO,MAAK;AAAA,UAAS,UAAU;AAAA,UAC9B,OAAO;AAAA,YACL,OAAO;AAAA,YAAQ,SAAS;AAAA,YAAQ,iBAAiB;AAAA,YAAW,OAAO;AAAA,YACnE,QAAQ;AAAA,YAAQ,cAAc;AAAA,YAAO,UAAU;AAAA,YAAQ,YAAY;AAAA,YACnE,QAAQ,UAAU,gBAAgB;AAAA,YAAW,SAAS,UAAU,MAAM;AAAA,UACxE;AAAA,UACC,oBAAU,eAAe;AAAA;AAAA,MAC5B;AAAA,OACF;AAAA,IAEC,UACC,gBAAAA,KAAC,SAAI,OAAO,EAAE,WAAW,QAAQ,WAAW,SAAS,GACnD,0BAAAA,KAAC,YAAO,MAAK,UAAS,SAAS,QAAQ,OAAO,EAAE,YAAY,QAAQ,QAAQ,QAAQ,OAAO,WAAW,QAAQ,WAAW,UAAU,OAAO,GAAG,2BAE7I,GACF;AAAA,KAEJ;AAEJ;;;ACnFA,SAAS,WAAW,YAAAG,iBAAgB;AAgD9B,SAWF,YAAAC,WAVI,OAAAC,MADF,QAAAC,aAAA;AAxCC,SAAS,aAAa,EAAE,aAAa,KAAK,iBAAiB,GAAsB;AACtF,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAwB,IAAI;AAEtD,YAAU,MAAM;AACd,UAAM,iBAAiB,YAAY;AACjC,UAAI;AAIF,YAAI,UAAU;AACd,cAAM,MAAM,MAAM,SAAS,KAAK,WAAW;AAC3C,YAAI,IAAI,OAAO;AAAE,mBAAS,IAAI,MAAM,OAAO;AAAG;AAAA,QAAQ;AACtD,kBAAU,IAAI,MAAM,WAAW;AAE/B,YAAI,CAAC,WAAW,OAAO,WAAW,eAC9B,IAAI,gBAAgB,OAAO,SAAS,MAAM,EAAE,IAAI,MAAM,GAAG;AAC3D,gBAAM,KAAK,MAAM,SAAS,KAAK,uBAAuB,OAAO,SAAS,IAAI;AAC1E,cAAI,GAAG,OAAO;AAAE,qBAAS,GAAG,MAAM,OAAO;AAAG;AAAA,UAAQ;AACpD,oBAAU,GAAG,MAAM,WAAW;AAAA,QAChC;AAIA,YAAI,OAAO,WAAW,eAAe,OAAO,UAAU,OAAO,WAAW,QAAQ;AAC9E,cAAI;AAAE,mBAAO,OAAO,YAAY,EAAE,MAAM,oBAAoB,GAAG,GAAG;AAAA,UAAG,QAAQ;AAAA,UAA4B;AACzG,iBAAO,MAAM;AACb;AAAA,QACF;AAEA,eAAO,SAAS,OAAO;AAAA,MACzB,SAAS,KAAc;AACrB,iBAAS,eAAe,QAAQ,IAAI,UAAU,gCAAgC;AAAA,MAChF;AAAA,IACF;AAEA,mBAAe;AAAA,EACjB,GAAG,CAAC,UAAU,CAAC;AAEf,MAAI,OAAO;AACT,WACE,gBAAAD,MAAC,SAAI,OAAO,EAAE,WAAW,UAAU,SAAS,OAAO,GACjD;AAAA,sBAAAD,KAAC,QAAG,OAAO,EAAE,OAAO,WAAW,cAAc,MAAM,GAAG,kCAAoB;AAAA,MAC1E,gBAAAA,KAAC,OAAE,OAAO,EAAE,OAAO,UAAU,GAAI,iBAAM;AAAA,MACvC,gBAAAA,KAAC,OAAE,MAAK,UAAS,OAAO,EAAE,OAAO,WAAW,WAAW,QAAQ,SAAS,eAAe,GAAG,2BAE1F;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,gBAAAA,KAAAD,WAAA,EACG,8BACC,gBAAAC,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,gBAAgB,UAAU,WAAW,QAAQ,GAChG,0BAAAA,KAAC,OAAE,OAAO,EAAE,OAAO,UAAU,GAAG,0CAA4B,GAC9D,GAEJ;AAEJ;","names":["jsx","jsxs","useState","jsx","jsxs","useState","useState","jsx","jsxs","useState","useState","Fragment","jsx","jsxs","useState"]}
1
+ {"version":3,"sources":["../../src/auth/ProtectedRoute.tsx","../../src/auth/LoginForm.tsx","../../src/auth/SignupForm.tsx","../../src/auth/ForgotPasswordForm.tsx","../../src/auth/AuthCallback.tsx"],"sourcesContent":["import { useAuth } from './AuthProvider';\r\nimport type { SubscriptionTier } from '../core/types';\r\n\r\ninterface ProtectedRouteProps {\r\n children: React.ReactNode;\r\n requiredRoles?: string[];\r\n requiredTier?: SubscriptionTier;\r\n fallback?: React.ReactNode;\r\n unauthorizedFallback?: React.ReactNode;\r\n allowUnconfigured?: boolean;\r\n loadingComponent?: React.ReactNode;\r\n loginPath?: string;\r\n}\r\n\r\nconst TIER_LEVELS: Record<string, number> = {\r\n free: 0,\r\n starter: 1,\r\n creator: 2,\r\n pro: 3,\r\n business: 4,\r\n enterprise: 5,\r\n};\r\n\r\nfunction DefaultLoadingSpinner() {\r\n return (\r\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '200px' }}>\r\n <div style={{\r\n width: '32px', height: '32px',\r\n border: '3px solid #e5e7eb', borderTopColor: '#3b82f6',\r\n borderRadius: '50%',\r\n animation: 'spin 0.6s linear infinite',\r\n }} />\r\n <style>{`@keyframes spin { to { transform: rotate(360deg); } }`}</style>\r\n </div>\r\n );\r\n}\r\n\r\nexport function ProtectedRoute({\r\n children,\r\n requiredTier,\r\n fallback,\r\n loadingComponent,\r\n allowUnconfigured = false,\r\n loginPath = '/login',\r\n}: ProtectedRouteProps) {\r\n const { user, profile, loading, isConfigured } = useAuth();\r\n\r\n if (loading) {\r\n return <>{loadingComponent || <DefaultLoadingSpinner />}</>;\r\n }\r\n\r\n if (!isConfigured && allowUnconfigured) {\r\n return <>{children}</>;\r\n }\r\n\r\n if (!user) {\r\n if (fallback) return <>{fallback}</>;\r\n if (typeof window !== 'undefined') {\r\n window.location.href = loginPath;\r\n }\r\n return null;\r\n }\r\n\r\n if (requiredTier) {\r\n const userTier = profile?.subscription_tier || 'free';\r\n const userLevel = TIER_LEVELS[userTier] ?? 0;\r\n const requiredLevel = TIER_LEVELS[requiredTier] ?? 0;\r\n\r\n if (userLevel < requiredLevel) {\r\n return (\r\n <div style={{ textAlign: 'center', padding: '40px' }}>\r\n <h2 style={{ fontSize: '1.5rem', fontWeight: 600, marginBottom: '8px' }}>Upgrade Required</h2>\r\n <p style={{ color: '#6b7280' }}>\r\n This feature requires the {requiredTier} plan or higher.\r\n </p>\r\n </div>\r\n );\r\n }\r\n }\r\n\r\n return <>{children}</>;\r\n}\r\n","import { useState } from 'react';\r\nimport { useAuth } from './AuthProvider';\r\n\r\ninterface LoginFormProps {\r\n onSuccess?: () => void;\r\n onForgotPassword?: () => void;\r\n onSignupClick?: () => void;\r\n showOAuth?: boolean;\r\n className?: string;\r\n}\r\n\r\nexport function LoginForm({\r\n onSuccess,\r\n onForgotPassword,\r\n onSignupClick,\r\n showOAuth = true,\r\n className = '',\r\n}: LoginFormProps) {\r\n const { signIn, signInWithProvider, isConfigured } = useAuth();\r\n const [email, setEmail] = useState('');\r\n const [password, setPassword] = useState('');\r\n const [error, setError] = useState<string | null>(null);\r\n const [loading, setLoading] = useState(false);\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n setLoading(true);\r\n\r\n const result = await signIn(email, password);\r\n setLoading(false);\r\n\r\n if (result.error) {\r\n setError(result.error.message);\r\n } else {\r\n onSuccess?.();\r\n }\r\n };\r\n\r\n const handleOAuth = async (provider: string) => {\r\n setError(null);\r\n const result = await signInWithProvider(provider);\r\n if (result.error) {\r\n setError(result.error.message);\r\n }\r\n };\r\n\r\n if (!isConfigured) {\r\n return (\r\n <div style={{ padding: '20px', textAlign: 'center', color: '#6b7280' }}>\r\n Authentication is not configured. Connect a database to enable login.\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className={className} style={{ maxWidth: '400px', margin: '0 auto' }}>\r\n <h2 style={{ fontSize: '1.5rem', fontWeight: 600, marginBottom: '24px', textAlign: 'center' }}>\r\n Sign In\r\n </h2>\r\n\r\n {error && (\r\n <div style={{ padding: '12px', marginBottom: '16px', backgroundColor: '#fef2f2', color: '#dc2626', borderRadius: '8px', fontSize: '14px' }}>\r\n {error}\r\n </div>\r\n )}\r\n\r\n <form onSubmit={handleSubmit}>\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '14px', fontWeight: 500 }}>Email</label>\r\n <input\r\n type=\"email\"\r\n value={email}\r\n onChange={(e) => setEmail(e.target.value)}\r\n required\r\n style={{ width: '100%', padding: '8px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }}\r\n />\r\n </div>\r\n\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '14px', fontWeight: 500 }}>Password</label>\r\n <input\r\n type=\"password\"\r\n value={password}\r\n onChange={(e) => setPassword(e.target.value)}\r\n required\r\n style={{ width: '100%', padding: '8px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }}\r\n />\r\n </div>\r\n\r\n {onForgotPassword && (\r\n <div style={{ marginBottom: '16px', textAlign: 'right' }}>\r\n <button type=\"button\" onClick={onForgotPassword} style={{ background: 'none', border: 'none', color: '#3b82f6', cursor: 'pointer', fontSize: '14px' }}>\r\n Forgot password?\r\n </button>\r\n </div>\r\n )}\r\n\r\n <button\r\n type=\"submit\"\r\n disabled={loading}\r\n style={{\r\n width: '100%', padding: '10px', backgroundColor: '#3b82f6', color: 'white',\r\n border: 'none', borderRadius: '6px', fontSize: '14px', fontWeight: 500,\r\n cursor: loading ? 'not-allowed' : 'pointer', opacity: loading ? 0.7 : 1,\r\n }}\r\n >\r\n {loading ? 'Signing in...' : 'Sign In'}\r\n </button>\r\n </form>\r\n\r\n {showOAuth && (\r\n <div style={{ marginTop: '24px' }}>\r\n <div style={{ textAlign: 'center', color: '#9ca3af', fontSize: '14px', marginBottom: '16px' }}>or continue with</div>\r\n <div style={{ display: 'flex', gap: '12px' }}>\r\n <button\r\n onClick={() => handleOAuth('google')}\r\n style={{ flex: 1, padding: '10px', border: '1px solid #d1d5db', borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '14px' }}\r\n >\r\n Google\r\n </button>\r\n <button\r\n onClick={() => handleOAuth('github')}\r\n style={{ flex: 1, padding: '10px', border: '1px solid #d1d5db', borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '14px' }}\r\n >\r\n GitHub\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {onSignupClick && (\r\n <div style={{ marginTop: '24px', textAlign: 'center', fontSize: '14px' }}>\r\n Don&apos;t have an account?{' '}\r\n <button type=\"button\" onClick={onSignupClick} style={{ background: 'none', border: 'none', color: '#3b82f6', cursor: 'pointer', fontWeight: 500 }}>\r\n Sign up\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState } from 'react';\r\nimport { useAuth } from './AuthProvider';\r\n\r\ninterface SignupFormProps {\r\n onSuccess?: () => void;\r\n onLoginClick?: () => void;\r\n showOAuth?: boolean;\r\n className?: string;\r\n}\r\n\r\nexport function SignupForm({\r\n onSuccess,\r\n onLoginClick,\r\n showOAuth = true,\r\n className = '',\r\n}: SignupFormProps) {\r\n const { signUp, signInWithProvider, isConfigured } = useAuth();\r\n const [name, setName] = useState('');\r\n const [email, setEmail] = useState('');\r\n const [password, setPassword] = useState('');\r\n const [agreed, setAgreed] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState(false);\r\n const [loading, setLoading] = useState(false);\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!agreed) {\r\n setError('Please agree to the Terms of Service');\r\n return;\r\n }\r\n if (password.length < 8) {\r\n setError('Password must be at least 8 characters');\r\n return;\r\n }\r\n\r\n setError(null);\r\n setLoading(true);\r\n\r\n const result = await signUp(email, password, {\r\n metadata: { display_name: name },\r\n });\r\n setLoading(false);\r\n\r\n if (result.error) {\r\n setError(result.error.message);\r\n } else {\r\n setSuccess(true);\r\n onSuccess?.();\r\n }\r\n };\r\n\r\n const handleOAuth = async (provider: string) => {\r\n setError(null);\r\n const result = await signInWithProvider(provider);\r\n if (result.error) {\r\n setError(result.error.message);\r\n }\r\n };\r\n\r\n if (!isConfigured) {\r\n return (\r\n <div style={{ padding: '20px', textAlign: 'center', color: '#6b7280' }}>\r\n Authentication is not configured. Connect a database to enable signup.\r\n </div>\r\n );\r\n }\r\n\r\n if (success) {\r\n return (\r\n <div style={{ padding: '20px', textAlign: 'center' }}>\r\n <h3 style={{ fontSize: '1.25rem', fontWeight: 600, marginBottom: '8px', color: '#059669' }}>Check your email</h3>\r\n <p style={{ color: '#6b7280' }}>We sent a confirmation link to {email}</p>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className={className} style={{ maxWidth: '400px', margin: '0 auto' }}>\r\n <h2 style={{ fontSize: '1.5rem', fontWeight: 600, marginBottom: '24px', textAlign: 'center' }}>\r\n Create Account\r\n </h2>\r\n\r\n {error && (\r\n <div style={{ padding: '12px', marginBottom: '16px', backgroundColor: '#fef2f2', color: '#dc2626', borderRadius: '8px', fontSize: '14px' }}>\r\n {error}\r\n </div>\r\n )}\r\n\r\n <form onSubmit={handleSubmit}>\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '14px', fontWeight: 500 }}>Name</label>\r\n <input type=\"text\" value={name} onChange={(e) => setName(e.target.value)} required\r\n style={{ width: '100%', padding: '8px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }} />\r\n </div>\r\n\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '14px', fontWeight: 500 }}>Email</label>\r\n <input type=\"email\" value={email} onChange={(e) => setEmail(e.target.value)} required\r\n style={{ width: '100%', padding: '8px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }} />\r\n </div>\r\n\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '14px', fontWeight: 500 }}>Password</label>\r\n <input type=\"password\" value={password} onChange={(e) => setPassword(e.target.value)} required minLength={8}\r\n style={{ width: '100%', padding: '8px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }} />\r\n <span style={{ fontSize: '12px', color: '#9ca3af' }}>Minimum 8 characters</span>\r\n </div>\r\n\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'flex', alignItems: 'center', gap: '8px', fontSize: '14px', cursor: 'pointer' }}>\r\n <input type=\"checkbox\" checked={agreed} onChange={(e) => setAgreed(e.target.checked)} />\r\n I agree to the Terms of Service and Privacy Policy\r\n </label>\r\n </div>\r\n\r\n <button type=\"submit\" disabled={loading}\r\n style={{\r\n width: '100%', padding: '10px', backgroundColor: '#3b82f6', color: 'white',\r\n border: 'none', borderRadius: '6px', fontSize: '14px', fontWeight: 500,\r\n cursor: loading ? 'not-allowed' : 'pointer', opacity: loading ? 0.7 : 1,\r\n }}>\r\n {loading ? 'Creating account...' : 'Create Account'}\r\n </button>\r\n </form>\r\n\r\n {showOAuth && (\r\n <div style={{ marginTop: '24px' }}>\r\n <div style={{ textAlign: 'center', color: '#9ca3af', fontSize: '14px', marginBottom: '16px' }}>or continue with</div>\r\n <div style={{ display: 'flex', gap: '12px' }}>\r\n <button onClick={() => handleOAuth('google')}\r\n style={{ flex: 1, padding: '10px', border: '1px solid #d1d5db', borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '14px' }}>\r\n Google\r\n </button>\r\n <button onClick={() => handleOAuth('github')}\r\n style={{ flex: 1, padding: '10px', border: '1px solid #d1d5db', borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '14px' }}>\r\n GitHub\r\n </button>\r\n </div>\r\n </div>\r\n )}\r\n\r\n {onLoginClick && (\r\n <div style={{ marginTop: '24px', textAlign: 'center', fontSize: '14px' }}>\r\n Already have an account?{' '}\r\n <button type=\"button\" onClick={onLoginClick} style={{ background: 'none', border: 'none', color: '#3b82f6', cursor: 'pointer', fontWeight: 500 }}>\r\n Sign in\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState } from 'react';\r\nimport { useAuth } from './AuthProvider';\r\n\r\ninterface ForgotPasswordFormProps {\r\n onBack?: () => void;\r\n className?: string;\r\n}\r\n\r\nexport function ForgotPasswordForm({ onBack, className = '' }: ForgotPasswordFormProps) {\r\n const { resetPassword } = useAuth();\r\n const [email, setEmail] = useState('');\r\n const [error, setError] = useState<string | null>(null);\r\n const [success, setSuccess] = useState(false);\r\n const [loading, setLoading] = useState(false);\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n setError(null);\r\n setLoading(true);\r\n\r\n const result = await resetPassword(email);\r\n setLoading(false);\r\n\r\n if (result.error) {\r\n setError(result.error.message);\r\n } else {\r\n setSuccess(true);\r\n }\r\n };\r\n\r\n if (success) {\r\n return (\r\n <div className={className} style={{ maxWidth: '400px', margin: '0 auto', textAlign: 'center', padding: '20px' }}>\r\n <h3 style={{ fontSize: '1.25rem', fontWeight: 600, marginBottom: '8px', color: '#059669' }}>Check your email</h3>\r\n <p style={{ color: '#6b7280', marginBottom: '16px' }}>We sent a password reset link to {email}</p>\r\n {onBack && (\r\n <button type=\"button\" onClick={onBack} style={{ background: 'none', border: 'none', color: '#3b82f6', cursor: 'pointer', fontSize: '14px' }}>\r\n Back to login\r\n </button>\r\n )}\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <div className={className} style={{ maxWidth: '400px', margin: '0 auto' }}>\r\n <h2 style={{ fontSize: '1.5rem', fontWeight: 600, marginBottom: '8px', textAlign: 'center' }}>Reset Password</h2>\r\n <p style={{ color: '#6b7280', textAlign: 'center', marginBottom: '24px', fontSize: '14px' }}>\r\n Enter your email and we&apos;ll send you a reset link\r\n </p>\r\n\r\n {error && (\r\n <div style={{ padding: '12px', marginBottom: '16px', backgroundColor: '#fef2f2', color: '#dc2626', borderRadius: '8px', fontSize: '14px' }}>\r\n {error}\r\n </div>\r\n )}\r\n\r\n <form onSubmit={handleSubmit}>\r\n <div style={{ marginBottom: '16px' }}>\r\n <label style={{ display: 'block', marginBottom: '4px', fontSize: '14px', fontWeight: 500 }}>Email</label>\r\n <input type=\"email\" value={email} onChange={(e) => setEmail(e.target.value)} required\r\n style={{ width: '100%', padding: '8px 12px', border: '1px solid #d1d5db', borderRadius: '6px', fontSize: '14px' }} />\r\n </div>\r\n\r\n <button type=\"submit\" disabled={loading}\r\n style={{\r\n width: '100%', padding: '10px', backgroundColor: '#3b82f6', color: 'white',\r\n border: 'none', borderRadius: '6px', fontSize: '14px', fontWeight: 500,\r\n cursor: loading ? 'not-allowed' : 'pointer', opacity: loading ? 0.7 : 1,\r\n }}>\r\n {loading ? 'Sending...' : 'Send Reset Link'}\r\n </button>\r\n </form>\r\n\r\n {onBack && (\r\n <div style={{ marginTop: '16px', textAlign: 'center' }}>\r\n <button type=\"button\" onClick={onBack} style={{ background: 'none', border: 'none', color: '#3b82f6', cursor: 'pointer', fontSize: '14px' }}>\r\n Back to login\r\n </button>\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useEffect, useState } from 'react';\r\nimport { supabase } from '../core/supabase';\r\nimport { isNeonAuthConfigured } from '../core/config';\r\n\r\ninterface AuthCallbackProps {\r\n redirectTo?: string;\r\n loadingComponent?: React.ReactNode;\r\n}\r\n\r\nexport function AuthCallback({ redirectTo = '/', loadingComponent }: AuthCallbackProps) {\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n useEffect(() => {\r\n const handleCallback = async () => {\r\n try {\r\n // Neon Auth (Better Auth) path: the OAuth flow is completed by the Better\r\n // Auth server, which sets the session cookie and redirects to the app's\r\n // callbackURL. There is no client-side PKCE exchange to perform here.\r\n // Notify any opener (in-editor popup) and either close or land the user.\r\n if (isNeonAuthConfigured) {\r\n if (typeof window !== 'undefined' && window.opener && window.opener !== window) {\r\n try { window.opener.postMessage({ type: 'ezc-auth-complete' }, '*'); } catch { /* cross-origin opener */ }\r\n window.close();\r\n return;\r\n }\r\n if (typeof window !== 'undefined') window.location.href = redirectTo;\r\n return;\r\n }\r\n // With detectSessionInUrl + PKCE the client usually auto-exchanges the\r\n // `?code=` before we run, so getSession() already has it. If not (e.g. a\r\n // build with detectSessionInUrl disabled), exchange explicitly.\r\n let session = null;\r\n const got = await supabase.auth.getSession();\r\n if (got.error) { setError(got.error.message); return; }\r\n session = got.data?.session ?? null;\r\n\r\n if (!session && typeof window !== 'undefined' &&\r\n new URLSearchParams(window.location.search).get('code')) {\r\n const ex = await supabase.auth.exchangeCodeForSession(window.location.href);\r\n if (ex.error) { setError(ex.error.message); return; }\r\n session = ex.data?.session ?? null;\r\n }\r\n\r\n // Popup flow (in-editor / framed sign-in): notify the opener and close,\r\n // rather than navigating. The opener (AuthProvider) picks up the session.\r\n if (typeof window !== 'undefined' && window.opener && window.opener !== window) {\r\n try { window.opener.postMessage({ type: 'ezc-auth-complete' }, '*'); } catch { /* cross-origin opener */ }\r\n window.close();\r\n return;\r\n }\r\n\r\n window.location.href = redirectTo;\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : 'Authentication callback failed');\r\n }\r\n };\r\n\r\n handleCallback();\r\n }, [redirectTo]);\r\n\r\n if (error) {\r\n return (\r\n <div style={{ textAlign: 'center', padding: '40px' }}>\r\n <h2 style={{ color: '#dc2626', marginBottom: '8px' }}>Authentication Error</h2>\r\n <p style={{ color: '#6b7280' }}>{error}</p>\r\n <a href=\"/login\" style={{ color: '#3b82f6', marginTop: '16px', display: 'inline-block' }}>\r\n Back to login\r\n </a>\r\n </div>\r\n );\r\n }\r\n\r\n return (\r\n <>\r\n {loadingComponent || (\r\n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '200px' }}>\r\n <p style={{ color: '#6b7280' }}>Completing authentication...</p>\r\n </div>\r\n )}\r\n </>\r\n );\r\n}\r\n"],"mappings":"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","names":["jsx","jsxs","useState","jsx","jsxs","useState","useState","jsx","jsxs","useState","useState","Fragment","jsx","jsxs","useState"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  env
3
- } from "./chunk-LIUE7M7K.js";
3
+ } from "./chunk-X4JP7DCK.js";
4
4
 
5
5
  // src/core/projectToken.ts
6
6
  function isBrowserRuntime() {
@@ -41,4 +41,4 @@ function warnLegacyOnce() {
41
41
  export {
42
42
  resolveServerToken
43
43
  };
44
- //# sourceMappingURL=chunk-CQKYANAW.js.map
44
+ //# sourceMappingURL=chunk-4WGGFJPE.js.map
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  ezcoder
3
- } from "./chunk-HJ2EIZ4S.js";
3
+ } from "./chunk-DU6N3HVQ.js";
4
4
  import {
5
5
  isSupabaseConfigured,
6
6
  supabase
7
- } from "./chunk-I2YGB7Z6.js";
7
+ } from "./chunk-KKTY5NCR.js";
8
8
  import {
9
9
  env,
10
10
  features
11
- } from "./chunk-LIUE7M7K.js";
11
+ } from "./chunk-X4JP7DCK.js";
12
12
 
13
13
  // src/database/DatabaseProvider.tsx
14
14
  import { createContext, useContext, useEffect, useMemo, useState } from "react";
@@ -623,4 +623,4 @@ export {
623
623
  useIsDatabaseConfigured,
624
624
  useRealtime
625
625
  };
626
- //# sourceMappingURL=chunk-O3GL4ZVC.js.map
626
+ //# sourceMappingURL=chunk-5QYGP7G7.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  env
3
- } from "./chunk-LIUE7M7K.js";
3
+ } from "./chunk-X4JP7DCK.js";
4
4
 
5
5
  // src/core/platform.ts
6
6
  var isConfigured = () => Boolean(env.EZCODER_API_URL && env.EZC_PROJECT_ID);
@@ -386,4 +386,4 @@ export {
386
386
  ezcoder,
387
387
  ezcoderAuthIntegration
388
388
  };
389
- //# sourceMappingURL=chunk-HJ2EIZ4S.js.map
389
+ //# sourceMappingURL=chunk-DU6N3HVQ.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  env
3
- } from "./chunk-LIUE7M7K.js";
3
+ } from "./chunk-X4JP7DCK.js";
4
4
 
5
5
  // src/core/supabase.ts
6
6
  import { createClient } from "@supabase/supabase-js";
@@ -118,4 +118,4 @@ export {
118
118
  supabase,
119
119
  isSupabaseConfigured
120
120
  };
121
- //# sourceMappingURL=chunk-I2YGB7Z6.js.map
121
+ //# sourceMappingURL=chunk-KKTY5NCR.js.map
@@ -1,14 +1,30 @@
1
1
  import {
2
2
  ezcoder,
3
3
  ezcoderAuthIntegration
4
- } from "./chunk-HJ2EIZ4S.js";
4
+ } from "./chunk-DU6N3HVQ.js";
5
5
  import {
6
6
  isSupabaseConfigured,
7
7
  supabase
8
- } from "./chunk-I2YGB7Z6.js";
8
+ } from "./chunk-KKTY5NCR.js";
9
9
  import {
10
- env
11
- } from "./chunk-LIUE7M7K.js";
10
+ env,
11
+ isNeonAuthConfigured
12
+ } from "./chunk-X4JP7DCK.js";
13
+
14
+ // src/auth/neonAuthClient.ts
15
+ import { createAuthClient } from "better-auth/react";
16
+ var cachedClient = null;
17
+ function getNeonAuthClient() {
18
+ if (!isNeonAuthConfigured || !env.NEON_AUTH_URL) {
19
+ return null;
20
+ }
21
+ if (!cachedClient) {
22
+ cachedClient = createAuthClient({
23
+ baseURL: env.NEON_AUTH_URL
24
+ });
25
+ }
26
+ return cachedClient;
27
+ }
12
28
 
13
29
  // src/auth/AuthProvider.tsx
14
30
  import { createContext, useContext, useState, useEffect, useCallback, useRef } from "react";
@@ -33,6 +49,215 @@ var AuthContext = createContext({
33
49
  refetchProfile: async () => null
34
50
  });
35
51
  function AuthProvider({ children }) {
52
+ if (isNeonAuthConfigured) {
53
+ return /* @__PURE__ */ jsx(NeonAuthProvider, { children });
54
+ }
55
+ return /* @__PURE__ */ jsx(SupabaseAuthProvider, { children });
56
+ }
57
+ function mapNeonUser(u) {
58
+ if (!u || !u.id) return null;
59
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
60
+ return {
61
+ id: u.id,
62
+ email: u.email,
63
+ app_metadata: { provider: "neon-auth", ...u.role ? { role: u.role } : {} },
64
+ user_metadata: {
65
+ full_name: u.name,
66
+ name: u.name,
67
+ avatar_url: u.image ?? void 0,
68
+ email_verified: u.emailVerified
69
+ },
70
+ aud: "authenticated",
71
+ created_at: u.createdAt || nowIso,
72
+ updated_at: u.updatedAt || nowIso,
73
+ role: u.role
74
+ };
75
+ }
76
+ function mapNeonSession(rawSession, user) {
77
+ if (!user) return null;
78
+ const s = rawSession || {};
79
+ const token = s.token || s.session?.token || "";
80
+ return {
81
+ access_token: token,
82
+ refresh_token: "",
83
+ token_type: "bearer",
84
+ expires_in: 0,
85
+ expires_at: void 0,
86
+ user
87
+ };
88
+ }
89
+ var NEON_NOT_SUPPORTED = (feature) => new Error(`${feature} is not supported on the Neon Auth path yet.`);
90
+ function NeonAuthProvider({ children }) {
91
+ const authClient = getNeonAuthClient();
92
+ const [user, setUser] = useState(null);
93
+ const [profile, setProfile] = useState(null);
94
+ const [session, setSession] = useState(null);
95
+ const [loading, setLoading] = useState(true);
96
+ const previousUserIdRef = useRef(null);
97
+ const sessionState = authClient?.useSession?.();
98
+ const rawUser = sessionState?.data?.user ?? null;
99
+ const isPending = sessionState?.isPending ?? false;
100
+ useEffect(() => {
101
+ const mappedUser = mapNeonUser(rawUser);
102
+ setUser(mappedUser);
103
+ setSession(mapNeonSession(sessionState?.data?.session ?? sessionState?.data ?? null, mappedUser));
104
+ setLoading(Boolean(isPending));
105
+ const currentId = mappedUser?.id ?? null;
106
+ const prevId = previousUserIdRef.current;
107
+ if (currentId && currentId !== prevId) {
108
+ ezcoderAuthIntegration.onLogin(mappedUser);
109
+ previousUserIdRef.current = currentId;
110
+ } else if (!currentId && prevId) {
111
+ ezcoderAuthIntegration.onLogout(prevId);
112
+ previousUserIdRef.current = null;
113
+ setProfile(null);
114
+ }
115
+ }, [rawUser, isPending]);
116
+ const signUp = useCallback(async (email, password, options = {}) => {
117
+ if (!authClient) return { data: null, error: notConfiguredError() };
118
+ const { metadata = {} } = options;
119
+ const name = metadata.display_name || metadata.name || email;
120
+ try {
121
+ const result = await authClient.signUp.email({ email, password, name });
122
+ const error = result?.error;
123
+ if (error) {
124
+ return { data: null, error: toError(error, "Sign up failed") };
125
+ }
126
+ const data = result?.data ?? result;
127
+ const newUser = data?.user;
128
+ if (newUser?.id) {
129
+ ezcoderAuthIntegration.onSignup({ id: newUser.id, email: newUser.email });
130
+ }
131
+ return { data, error: null };
132
+ } catch (err) {
133
+ return { data: null, error: err instanceof Error ? err : new Error("Sign up failed") };
134
+ }
135
+ }, [authClient]);
136
+ const signIn = useCallback(async (email, password) => {
137
+ if (!authClient) return { data: null, error: notConfiguredError() };
138
+ try {
139
+ const result = await authClient.signIn.email({ email, password });
140
+ const error = result?.error;
141
+ if (error) {
142
+ return { data: null, error: toError(error, "Sign in failed") };
143
+ }
144
+ const data = result?.data ?? result;
145
+ return { data, error: null };
146
+ } catch (err) {
147
+ return { data: null, error: err instanceof Error ? err : new Error("Sign in failed") };
148
+ }
149
+ }, [authClient]);
150
+ const signInWithProvider = useCallback(async (provider, options = {}) => {
151
+ if (!authClient) return { data: null, error: notConfiguredError() };
152
+ try {
153
+ const origin = typeof window !== "undefined" ? window.location.origin : "";
154
+ const callbackURL = options.redirectTo || origin;
155
+ const framed = typeof window !== "undefined" && window.self !== window.top;
156
+ const social = provider;
157
+ if (framed && typeof window !== "undefined") {
158
+ const result2 = await authClient.signIn.social({
159
+ provider: social,
160
+ callbackURL,
161
+ disableRedirect: true
162
+ });
163
+ const error2 = result2?.error;
164
+ if (error2) return { data: null, error: toError(error2, "OAuth sign in failed") };
165
+ const data2 = result2?.data ?? null;
166
+ const url = data2?.url;
167
+ if (url) window.open(url, "ezc-auth", "popup,width=500,height=680");
168
+ return { data: data2, error: null };
169
+ }
170
+ const result = await authClient.signIn.social({ provider: social, callbackURL });
171
+ const error = result?.error;
172
+ if (error) return { data: null, error: toError(error, "OAuth sign in failed") };
173
+ const data = result?.data ?? null;
174
+ return { data, error: null };
175
+ } catch (err) {
176
+ return { data: null, error: err instanceof Error ? err : new Error("OAuth sign in failed") };
177
+ }
178
+ }, [authClient]);
179
+ const signOut = useCallback(async () => {
180
+ if (!authClient) return { error: notConfiguredError() };
181
+ const userId = user?.id;
182
+ try {
183
+ const result = await authClient.signOut();
184
+ const error = result?.error;
185
+ if (error) return { error: toError(error, "Sign out failed") };
186
+ if (userId) ezcoder.users.trackLogout(userId);
187
+ return { error: null };
188
+ } catch (err) {
189
+ return { error: err instanceof Error ? err : new Error("Sign out failed") };
190
+ }
191
+ }, [authClient, user]);
192
+ const resetPassword = useCallback(async (email) => {
193
+ if (!authClient) return { data: null, error: notConfiguredError() };
194
+ const client = authClient;
195
+ const redirectTo = `${typeof window !== "undefined" ? window.location.origin : ""}/auth/reset-password`;
196
+ const fn = client.requestPasswordReset || client.forgetPassword;
197
+ if (!fn) {
198
+ return { data: null, error: NEON_NOT_SUPPORTED("Password reset") };
199
+ }
200
+ try {
201
+ const result = await fn({ email, redirectTo });
202
+ const error = result?.error;
203
+ if (error) return { data: null, error: toError(error, "Password reset failed") };
204
+ const data = result?.data ?? result;
205
+ return { data, error: null };
206
+ } catch (err) {
207
+ return { data: null, error: err instanceof Error ? err : new Error("Password reset failed") };
208
+ }
209
+ }, [authClient]);
210
+ const updatePassword = useCallback(async (newPassword) => {
211
+ if (!authClient) return { data: null, error: notConfiguredError() };
212
+ const token = typeof window !== "undefined" ? new URLSearchParams(window.location.search).get("token") || new URLSearchParams(window.location.search).get("reset_token") : null;
213
+ const client = authClient;
214
+ if (token && client.resetPassword) {
215
+ try {
216
+ const result = await client.resetPassword({ newPassword, token });
217
+ const error = result?.error;
218
+ if (error) return { data: null, error: toError(error, "Password update failed") };
219
+ const data = result?.data ?? result;
220
+ return { data, error: null };
221
+ } catch (err) {
222
+ return { data: null, error: err instanceof Error ? err : new Error("Password update failed") };
223
+ }
224
+ }
225
+ return { data: null, error: NEON_NOT_SUPPORTED("Updating the password without a reset token") };
226
+ }, [authClient]);
227
+ const fetchProfile = useCallback(async (_userId) => {
228
+ return null;
229
+ }, []);
230
+ const updateProfile = useCallback(async (_updates) => {
231
+ if (!user) return { data: null, error: new Error("Not authenticated") };
232
+ return { data: null, error: NEON_NOT_SUPPORTED("Updating the profile") };
233
+ }, [user]);
234
+ const value = {
235
+ user,
236
+ profile,
237
+ session,
238
+ loading,
239
+ isConfigured: Boolean(authClient),
240
+ signUp,
241
+ signIn,
242
+ signInWithProvider,
243
+ signOut,
244
+ resetPassword,
245
+ updatePassword,
246
+ updateProfile,
247
+ refetchProfile: fetchProfile
248
+ };
249
+ return /* @__PURE__ */ jsx(AuthContext.Provider, { value, children });
250
+ }
251
+ function toError(error, fallback) {
252
+ if (error instanceof Error) return error;
253
+ if (error && typeof error === "object") {
254
+ const msg = error.message || error.statusText;
255
+ if (msg) return new Error(msg);
256
+ }
257
+ if (typeof error === "string") return new Error(error);
258
+ return new Error(fallback);
259
+ }
260
+ function SupabaseAuthProvider({ children }) {
36
261
  const [user, setUser] = useState(null);
37
262
  const [profile, setProfile] = useState(null);
38
263
  const [session, setSession] = useState(null);
@@ -312,8 +537,9 @@ function useAuth() {
312
537
  }
313
538
 
314
539
  export {
540
+ getNeonAuthClient,
315
541
  AuthContext,
316
542
  AuthProvider,
317
543
  useAuth
318
544
  };
319
- //# sourceMappingURL=chunk-QHB7LGCA.js.map
545
+ //# sourceMappingURL=chunk-NTA3RMYR.js.map