@ezcoder.dev/sdk 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/{DatabaseProvider-BtYMJRqh.d.ts → DatabaseProvider-DRnx_V_u.d.ts} +7 -0
  2. package/dist/analytics/index.js +4 -4
  3. package/dist/auth/index.d.ts +2 -2
  4. package/dist/auth/index.js +94 -4
  5. package/dist/auth/index.js.map +1 -1
  6. package/dist/{chunk-4WGGFJPE.js → chunk-FFMYVTI2.js} +2 -2
  7. package/dist/{chunk-KKTY5NCR.js → chunk-FPSSXTQG.js} +2 -2
  8. package/dist/{chunk-X4JP7DCK.js → chunk-KWR4PA5I.js} +13 -2
  9. package/dist/{chunk-X4JP7DCK.js.map → chunk-KWR4PA5I.js.map} +1 -1
  10. package/dist/{chunk-NTA3RMYR.js → chunk-L326T7UV.js} +48 -7
  11. package/dist/chunk-L326T7UV.js.map +1 -0
  12. package/dist/chunk-VHKTBOFU.js +124 -0
  13. package/dist/chunk-VHKTBOFU.js.map +1 -0
  14. package/dist/{chunk-5QYGP7G7.js → chunk-WFDQ4YUZ.js} +448 -125
  15. package/dist/chunk-WFDQ4YUZ.js.map +1 -0
  16. package/dist/cms/index.js +2 -2
  17. package/dist/{config-D5ajnLCe.d.ts → config-Cb4MMhGa.d.ts} +1 -0
  18. package/dist/cron/index.js +2 -2
  19. package/dist/database/index.d.ts +1 -1
  20. package/dist/database/index.js +11 -10
  21. package/dist/email/index.js +2 -2
  22. package/dist/index.d.ts +4 -4
  23. package/dist/index.js +9 -9
  24. package/dist/notifications/index.js +5 -5
  25. package/dist/payments/index.d.ts +1 -1
  26. package/dist/payments/index.js +4 -4
  27. package/dist/roles/index.js +36 -13
  28. package/dist/roles/index.js.map +1 -1
  29. package/dist/storage/index.d.ts +1 -1
  30. package/dist/storage/index.js +4 -4
  31. package/dist/{types-1uP3V_pe.d.ts → types-BET19sj2.d.ts} +1 -0
  32. package/package.json +1 -1
  33. package/dist/chunk-5QYGP7G7.js.map +0 -1
  34. package/dist/chunk-DU6N3HVQ.js +0 -389
  35. package/dist/chunk-DU6N3HVQ.js.map +0 -1
  36. package/dist/chunk-NTA3RMYR.js.map +0 -1
  37. /package/dist/{chunk-4WGGFJPE.js.map → chunk-FFMYVTI2.js.map} +0 -0
  38. /package/dist/{chunk-KKTY5NCR.js.map → chunk-FPSSXTQG.js.map} +0 -0
@@ -168,6 +168,13 @@ declare class DatabaseClient {
168
168
  * server key → end-user session JWT → public/legacy token → none (origin).
169
169
  */
170
170
  private _authHeaders;
171
+ /**
172
+ * Return a fresh Neon Better Auth session JWT (cached in-memory until ~30s
173
+ * before its exp), or '' when logged out / unavailable. NEVER throws — a
174
+ * failure falls through to the anonymous data path. Browser-only by nature
175
+ * (relies on the HttpOnly session cookie via credentials:'include').
176
+ */
177
+ private _neonSessionJwt;
171
178
  /** Platform API base — runtime bootstrap wins over the baked value so an
172
179
  * env-less build still reaches the right host. */
173
180
  private baseUrl;
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  AuthContext
3
- } from "../chunk-NTA3RMYR.js";
3
+ } from "../chunk-L326T7UV.js";
4
4
  import {
5
5
  ezcoder,
6
6
  ezcoderAuthIntegration
7
- } from "../chunk-DU6N3HVQ.js";
7
+ } from "../chunk-WFDQ4YUZ.js";
8
8
  import {
9
9
  isSupabaseConfigured,
10
10
  supabase
11
- } from "../chunk-KKTY5NCR.js";
11
+ } from "../chunk-FPSSXTQG.js";
12
12
  import {
13
13
  env,
14
14
  features
15
- } from "../chunk-X4JP7DCK.js";
15
+ } from "../chunk-KWR4PA5I.js";
16
16
 
17
17
  // src/analytics/useAnalytics.ts
18
18
  import { useEffect, useRef, useCallback, useContext } from "react";
@@ -1,9 +1,9 @@
1
1
  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
- import { U as UserProfile, e as SubscriptionTier } from '../types-1uP3V_pe.js';
4
+ import { U as UserProfile, e as SubscriptionTier } from '../types-BET19sj2.js';
5
5
  import { createAuthClient } from 'better-auth/react';
6
- export { a as isNeonAuthConfigured } from '../config-D5ajnLCe.js';
6
+ export { a as isNeonAuthConfigured } from '../config-Cb4MMhGa.js';
7
7
 
8
8
  interface AuthResult<T = unknown> {
9
9
  data: T | null;
@@ -3,14 +3,15 @@ import {
3
3
  AuthProvider,
4
4
  getNeonAuthClient,
5
5
  useAuth
6
- } from "../chunk-NTA3RMYR.js";
7
- import "../chunk-DU6N3HVQ.js";
6
+ } from "../chunk-L326T7UV.js";
7
+ import "../chunk-WFDQ4YUZ.js";
8
8
  import {
9
9
  supabase
10
- } from "../chunk-KKTY5NCR.js";
10
+ } from "../chunk-FPSSXTQG.js";
11
11
  import {
12
+ env,
12
13
  isNeonAuthConfigured
13
- } from "../chunk-X4JP7DCK.js";
14
+ } from "../chunk-KWR4PA5I.js";
14
15
 
15
16
  // src/auth/ProtectedRoute.tsx
16
17
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -428,11 +429,100 @@ function ForgotPasswordForm({ onBack, className = "" }) {
428
429
  // src/auth/AuthCallback.tsx
429
430
  import { useEffect, useState as useState4 } from "react";
430
431
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
432
+ function generateRandomPassword() {
433
+ const bytes = new Uint8Array(32);
434
+ crypto.getRandomValues(bytes);
435
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
436
+ }
431
437
  function AuthCallback({ redirectTo = "/", loadingComponent }) {
432
438
  const [error, setError] = useState4(null);
433
439
  useEffect(() => {
434
440
  const handleCallback = async () => {
435
441
  try {
442
+ if (isNeonAuthConfigured && typeof window !== "undefined") {
443
+ const hash = window.location.hash;
444
+ const hashParams = new URLSearchParams(hash.startsWith("#") ? hash.slice(1) : hash);
445
+ const proxyCode = hashParams.get("code");
446
+ const proxyError = hashParams.get("error");
447
+ if (proxyError) {
448
+ window.history.replaceState(null, "", window.location.pathname + window.location.search);
449
+ setError(
450
+ proxyError === "email_exists" ? "An account with this email already exists. Please sign in with your original method." : "Sign-in could not be completed. Please try again."
451
+ );
452
+ return;
453
+ }
454
+ if (proxyCode) {
455
+ window.history.replaceState(
456
+ null,
457
+ "",
458
+ window.location.pathname + window.location.search
459
+ );
460
+ const authClient = getNeonAuthClient();
461
+ if (!authClient || !env.EZCODER_API_URL) {
462
+ setError("Auth client not available for proxy exchange");
463
+ return;
464
+ }
465
+ const exchangeRes = await fetch(
466
+ `${env.EZCODER_API_URL.replace(/\/$/, "")}/api/app-auth/exchange`,
467
+ {
468
+ method: "POST",
469
+ headers: { "content-type": "application/json" },
470
+ mode: "cors",
471
+ body: JSON.stringify({ code: proxyCode })
472
+ }
473
+ );
474
+ if (!exchangeRes.ok) {
475
+ const msg = await exchangeRes.text().catch(() => exchangeRes.statusText);
476
+ setError(`Auth exchange failed: ${msg}`);
477
+ return;
478
+ }
479
+ const { email, password, finalizeToken } = await exchangeRes.json();
480
+ const signInResult = await authClient.signIn.email({ email, password });
481
+ const signInError = signInResult?.error;
482
+ if (signInError) {
483
+ const errObj = signInError instanceof Error ? signInError : new Error(
484
+ typeof signInError?.message === "string" ? signInError.message : "Sign in failed after proxy exchange"
485
+ );
486
+ setError(errObj.message);
487
+ return;
488
+ }
489
+ try {
490
+ const changePasswordFn = authClient.changePassword;
491
+ if (changePasswordFn) {
492
+ await changePasswordFn({
493
+ currentPassword: password,
494
+ newPassword: generateRandomPassword(),
495
+ revokeOtherSessions: true
496
+ });
497
+ }
498
+ } catch {
499
+ }
500
+ if (finalizeToken && env.EZCODER_API_URL) {
501
+ try {
502
+ await fetch(
503
+ `${env.EZCODER_API_URL.replace(/\/$/, "")}/api/app-auth/finalize`,
504
+ {
505
+ method: "POST",
506
+ headers: { "content-type": "application/json" },
507
+ mode: "cors",
508
+ body: JSON.stringify({ finalizeToken })
509
+ }
510
+ );
511
+ } catch {
512
+ }
513
+ }
514
+ if (window.opener && window.opener !== window) {
515
+ try {
516
+ window.opener.postMessage({ type: "ezc-auth-complete" }, "*");
517
+ } catch {
518
+ }
519
+ window.close();
520
+ return;
521
+ }
522
+ window.location.href = redirectTo;
523
+ return;
524
+ }
525
+ }
436
526
  if (isNeonAuthConfigured) {
437
527
  if (typeof window !== "undefined" && window.opener && window.opener !== window) {
438
528
  try {
@@ -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\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":";;;;;;;;;;;;;;;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;AA8D9B,SAWF,YAAAC,WAVI,OAAAC,MADF,QAAAC,aAAA;AArDC,SAAS,aAAa,EAAE,aAAa,KAAK,iBAAiB,GAAsB;AACtF,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAwB,IAAI;AAEtD,YAAU,MAAM;AACd,UAAM,iBAAiB,YAAY;AACjC,UAAI;AAKF,YAAI,sBAAsB;AACxB,cAAI,OAAO,WAAW,eAAe,OAAO,UAAU,OAAO,WAAW,QAAQ;AAC9E,gBAAI;AAAE,qBAAO,OAAO,YAAY,EAAE,MAAM,oBAAoB,GAAG,GAAG;AAAA,YAAG,QAAQ;AAAA,YAA4B;AACzG,mBAAO,MAAM;AACb;AAAA,UACF;AACA,cAAI,OAAO,WAAW,YAAa,QAAO,SAAS,OAAO;AAC1D;AAAA,QACF;AAIA,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 { env, isNeonAuthConfigured } from '../core/config';\r\nimport { getNeonAuthClient } from './neonAuthClient';\r\n\r\ninterface AuthCallbackProps {\r\n redirectTo?: string;\r\n loadingComponent?: React.ReactNode;\r\n}\r\n\r\n/** Generate a cryptographically-random password of at least 32 characters. */\r\nfunction generateRandomPassword(): string {\r\n const bytes = new Uint8Array(32);\r\n crypto.getRandomValues(bytes);\r\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\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 // ── Proxy handoff branch (Neon path only) ────────────────────────────\r\n // The central EzCoder auth proxy appended `#code=<singleUse>` to the\r\n // callback URL. We must exchange it before doing anything else, including\r\n // notifying openers, so that the session cookie is established first.\r\n if (isNeonAuthConfigured && typeof window !== 'undefined') {\r\n const hash = window.location.hash;\r\n // Only treat it as a proxy code when the fragment starts with `#code=`\r\n // (or contains `code=` after `#`).\r\n const hashParams = new URLSearchParams(hash.startsWith('#') ? hash.slice(1) : hash);\r\n const proxyCode = hashParams.get('code');\r\n const proxyError = hashParams.get('error');\r\n\r\n // The proxy reports a failed sign-in via `#error=<reason>`. Surface it\r\n // (don't fall through to the success redirect, which would look \"logged in\").\r\n if (proxyError) {\r\n window.history.replaceState(null, '', window.location.pathname + window.location.search);\r\n setError(\r\n proxyError === 'email_exists'\r\n ? 'An account with this email already exists. Please sign in with your original method.'\r\n : 'Sign-in could not be completed. Please try again.'\r\n );\r\n return;\r\n }\r\n\r\n if (proxyCode) {\r\n // Scrub the code from the URL immediately before any async work so it\r\n // cannot be captured by third-party scripts or browser history.\r\n window.history.replaceState(\r\n null,\r\n '',\r\n window.location.pathname + window.location.search\r\n );\r\n\r\n const authClient = getNeonAuthClient();\r\n if (!authClient || !env.EZCODER_API_URL) {\r\n setError('Auth client not available for proxy exchange');\r\n return;\r\n }\r\n\r\n // Exchange the single-use code for ephemeral credentials.\r\n const exchangeRes = await fetch(\r\n `${env.EZCODER_API_URL.replace(/\\/$/, '')}/api/app-auth/exchange`,\r\n {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n mode: 'cors',\r\n body: JSON.stringify({ code: proxyCode }),\r\n }\r\n );\r\n\r\n if (!exchangeRes.ok) {\r\n const msg = await exchangeRes.text().catch(() => exchangeRes.statusText);\r\n setError(`Auth exchange failed: ${msg}`);\r\n return;\r\n }\r\n\r\n const { email, password, finalizeToken } = (await exchangeRes.json()) as {\r\n email: string;\r\n password: string;\r\n finalizeToken?: string;\r\n };\r\n\r\n // Sign in directly against the per-project Neon Auth server so the\r\n // browser gets the native SameSite=None;Partitioned session cookie.\r\n const signInResult = await authClient.signIn.email({ email, password });\r\n const signInError = (signInResult as { error?: unknown })?.error;\r\n if (signInError) {\r\n const errObj =\r\n signInError instanceof Error\r\n ? signInError\r\n : new Error(\r\n typeof (signInError as { message?: string })?.message === 'string'\r\n ? (signInError as { message: string }).message\r\n : 'Sign in failed after proxy exchange'\r\n );\r\n setError(errObj.message);\r\n return;\r\n }\r\n\r\n // Kill the briefly-exposed ephemeral credential via TWO independent paths so a\r\n // same-origin XSS cannot keep a durable password:\r\n // (1) client-side changePassword with revokeOtherSessions:true — also kills any\r\n // session an attacker minted with the captured password;\r\n // (2) server-side finalize — the AUTHORITATIVE rotation; runs even if (1) fails.\r\n // Both are best-effort w.r.t. blocking login (the user is already signed in), but\r\n // (2) is reliable server-side, closing the swallowed-failure gap.\r\n try {\r\n const changePasswordFn = (\r\n authClient as unknown as {\r\n changePassword?: (args: {\r\n currentPassword: string;\r\n newPassword: string;\r\n revokeOtherSessions: boolean;\r\n }) => Promise<unknown>;\r\n }\r\n ).changePassword;\r\n if (changePasswordFn) {\r\n await changePasswordFn({\r\n currentPassword: password,\r\n newPassword: generateRandomPassword(),\r\n revokeOtherSessions: true,\r\n });\r\n }\r\n } catch {\r\n // Client rotation failed — the server-side finalize below is the safety net.\r\n }\r\n\r\n if (finalizeToken && env.EZCODER_API_URL) {\r\n try {\r\n await fetch(\r\n `${env.EZCODER_API_URL.replace(/\\/$/, '')}/api/app-auth/finalize`,\r\n {\r\n method: 'POST',\r\n headers: { 'content-type': 'application/json' },\r\n mode: 'cors',\r\n body: JSON.stringify({ finalizeToken }),\r\n }\r\n );\r\n } catch {\r\n // Server rotation network failure — non-fatal; the short-TTL token expires.\r\n }\r\n }\r\n\r\n // Notify any opener (in-editor popup flow) and finish.\r\n if (window.opener && window.opener !== window) {\r\n try {\r\n window.opener.postMessage({ type: 'ezc-auth-complete' }, '*');\r\n } catch {\r\n /* cross-origin opener */\r\n }\r\n window.close();\r\n return;\r\n }\r\n window.location.href = redirectTo;\r\n return;\r\n }\r\n }\r\n\r\n // ── Neon Auth (Better Auth) direct path ───────────────────────────────\r\n // The OAuth flow was completed by the Better Auth server (no proxy), which\r\n // sets the session cookie and redirects to the app's callbackURL. There is\r\n // no client-side PKCE exchange to perform here. Notify any opener\r\n // (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-X4JP7DCK.js";
3
+ } from "./chunk-KWR4PA5I.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-4WGGFJPE.js.map
44
+ //# sourceMappingURL=chunk-FFMYVTI2.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  env
3
- } from "./chunk-X4JP7DCK.js";
3
+ } from "./chunk-KWR4PA5I.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-KKTY5NCR.js.map
121
+ //# sourceMappingURL=chunk-FPSSXTQG.js.map
@@ -54,7 +54,18 @@ var env = {
54
54
  S3_BUCKET: getEnv("VITE_S3_BUCKET", "S3_BUCKET"),
55
55
  CLOUDINARY_URL: getEnv("VITE_CLOUDINARY_URL", "CLOUDINARY_URL"),
56
56
  STORAGE_BUCKET_PUBLIC: getEnv("VITE_STORAGE_BUCKET_PUBLIC", "NEXT_PUBLIC_STORAGE_BUCKET_PUBLIC"),
57
- STORAGE_BUCKET_PRIVATE: getEnv("VITE_STORAGE_BUCKET_PRIVATE", "NEXT_PUBLIC_STORAGE_BUCKET_PRIVATE")
57
+ STORAGE_BUCKET_PRIVATE: getEnv("VITE_STORAGE_BUCKET_PRIVATE", "NEXT_PUBLIC_STORAGE_BUCKET_PRIVATE"),
58
+ // When true, social login in the Neon Auth path is handled via the central
59
+ // EzCoder auth proxy instead of calling the per-project Better Auth server
60
+ // directly. The proxy redirects back to <app>/auth/callback#code=<singleUse>;
61
+ // AuthCallback exchanges the code for an ephemeral credential, calls
62
+ // authClient.signIn.email directly (so Neon sets the native session cookie),
63
+ // then rotates the password to kill the exposed credential.
64
+ // Set VITE_APP_AUTH_PROXY=1 (Vite) or NEXT_PUBLIC_APP_AUTH_PROXY=1 (Next).
65
+ APP_AUTH_PROXY: (() => {
66
+ const v = getEnv("VITE_APP_AUTH_PROXY", "NEXT_PUBLIC_APP_AUTH_PROXY");
67
+ return v === "1" || v === "true";
68
+ })()
58
69
  };
59
70
  var isNeonAuthConfigured = Boolean(env.NEON_AUTH_URL);
60
71
  var features = {
@@ -78,4 +89,4 @@ export {
78
89
  features,
79
90
  isFeatureConfigured
80
91
  };
81
- //# sourceMappingURL=chunk-X4JP7DCK.js.map
92
+ //# sourceMappingURL=chunk-KWR4PA5I.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/config.ts"],"sourcesContent":["const getEnv = (viteKey: string, nextKey?: string): string => {\r\n try {\r\n if (typeof import.meta !== 'undefined' && import.meta.env) {\r\n return (import.meta.env[viteKey] as string) || '';\r\n }\r\n } catch {\r\n // import.meta not available\r\n }\r\n try {\r\n if (typeof process !== 'undefined' && process.env) {\r\n return process.env[nextKey || viteKey] || '';\r\n }\r\n } catch {\r\n // process not available\r\n }\r\n return '';\r\n};\r\n\r\nexport const env = {\r\n SUPABASE_URL: getEnv('VITE_SUPABASE_URL', 'NEXT_PUBLIC_SUPABASE_URL'),\r\n SUPABASE_ANON_KEY: getEnv('VITE_SUPABASE_ANON_KEY', 'NEXT_PUBLIC_SUPABASE_ANON_KEY'),\r\n EZCODER_AUTH_URL: getEnv('VITE_EZCODER_AUTH_URL', 'NEXT_PUBLIC_EZCODER_AUTH_URL'),\r\n EZCODER_AUTH_ANON_KEY: getEnv('VITE_EZCODER_AUTH_ANON_KEY', 'NEXT_PUBLIC_EZCODER_AUTH_ANON_KEY'),\r\n // Per-project Neon Auth (Better Auth) server base URL. When present, the app\r\n // authenticates against its OWN isolated Neon Auth server (e.g.\r\n // https://ep-xxx.neonauth.<region>.aws.neon.tech/neondb/auth) instead of the\r\n // shared tenant Supabase. Injected at provision time as VITE_NEON_AUTH_URL;\r\n // NEON_AUTH_BASE_URL is the server/Next fallback name. Presence of this value\r\n // is the sole trigger for the Better Auth code path in AuthProvider.\r\n NEON_AUTH_URL: getEnv('VITE_NEON_AUTH_URL', 'NEON_AUTH_BASE_URL'),\r\n STRIPE_PUBLISHABLE_KEY: getEnv('VITE_STRIPE_PUBLISHABLE_KEY', 'NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY'),\r\n EZC_PROJECT_ID: getEnv('VITE_EZC_PROJECT_ID', 'NEXT_PUBLIC_EZC_PROJECT_ID'),\r\n EZCODER_API_URL: getEnv('VITE_EZCODER_API_URL', 'NEXT_PUBLIC_EZCODER_API_URL'),\r\n // Server-only secret for Stripe + authenticated platform API calls. Deployment\r\n // injects this as `EZCODER_SECRET_KEY` (see lib/deployment/fetch-project-env-vars.js);\r\n // resolve that name first, then fall back to the legacy `EZC_SECRET_KEY` so older\r\n // deploys keep working. Both are non-VITE/non-NEXT_PUBLIC (never exposed to the browser).\r\n EZC_SECRET_KEY: getEnv('EZCODER_SECRET_KEY', 'EZCODER_SECRET_KEY') || getEnv('EZC_SECRET_KEY', 'EZC_SECRET_KEY'),\r\n // B1: two-class project token model.\r\n //\r\n // EZC_PROJECT_TOKEN_PUBLIC — browser-safe. Read-only endpoints (manifest,\r\n // list, etc). Available in both server and\r\n // browser bundles via NEXT_PUBLIC_/VITE_\r\n // prefixes.\r\n // EZC_PROJECT_TOKEN_SERVER — server-only. Authenticates write APIs\r\n // (email send, cron register, notifications\r\n // send). NEVER prefixed with NEXT_PUBLIC_ or\r\n // VITE_; accessing it from a browser bundle\r\n // returns '' and the calling SDK function\r\n // must error out with a clear message.\r\n EZC_PROJECT_TOKEN_PUBLIC: getEnv('VITE_EZC_PROJECT_TOKEN_PUBLIC', 'NEXT_PUBLIC_EZC_PROJECT_TOKEN_PUBLIC'),\r\n EZC_PROJECT_TOKEN_SERVER: getEnv('EZC_PROJECT_TOKEN_SERVER', 'EZC_PROJECT_TOKEN_SERVER'),\r\n // Legacy single-class token. Deprecated, kept for backwards compat during\r\n // Phase 1 of the rollout. New code MUST use the split pair above.\r\n EZC_PROJECT_TOKEN_LEGACY: getEnv('VITE_EZC_PROJECT_TOKEN', 'NEXT_PUBLIC_EZC_PROJECT_TOKEN'),\r\n S3_BUCKET: getEnv('VITE_S3_BUCKET', 'S3_BUCKET'),\r\n CLOUDINARY_URL: getEnv('VITE_CLOUDINARY_URL', 'CLOUDINARY_URL'),\r\n STORAGE_BUCKET_PUBLIC: getEnv('VITE_STORAGE_BUCKET_PUBLIC', 'NEXT_PUBLIC_STORAGE_BUCKET_PUBLIC'),\r\n STORAGE_BUCKET_PRIVATE: getEnv('VITE_STORAGE_BUCKET_PRIVATE', 'NEXT_PUBLIC_STORAGE_BUCKET_PRIVATE'),\r\n};\r\n\r\n// True when the project ships its own per-project Neon Auth (Better Auth)\r\n// server. This is authoritative for which auth backend AuthProvider uses.\r\nexport const isNeonAuthConfigured: boolean = Boolean(env.NEON_AUTH_URL);\r\n\r\nexport const features = {\r\n auth: Boolean(\r\n isNeonAuthConfigured ||\r\n (env.SUPABASE_URL && env.SUPABASE_ANON_KEY) ||\r\n (env.EZCODER_AUTH_URL && env.EZCODER_AUTH_ANON_KEY)\r\n ),\r\n payments: Boolean(env.STRIPE_PUBLISHABLE_KEY),\r\n analytics: Boolean(env.EZCODER_API_URL && env.EZC_PROJECT_ID),\r\n storage: Boolean(env.SUPABASE_URL || env.EZCODER_AUTH_URL || env.S3_BUCKET || env.CLOUDINARY_URL),\r\n database: Boolean(\r\n (env.EZCODER_AUTH_URL || env.SUPABASE_URL) && env.EZC_PROJECT_ID\r\n ),\r\n};\r\n\r\nexport function isFeatureConfigured(feature: keyof typeof features): boolean {\r\n return features[feature];\r\n}\r\n"],"mappings":";AAAA,IAAM,SAAS,CAAC,SAAiB,YAA6B;AAC5D,MAAI;AACF,QAAI,OAAO,gBAAgB,eAAe,YAAY,KAAK;AACzD,aAAQ,YAAY,IAAI,OAAO,KAAgB;AAAA,IACjD;AAAA,EACF,QAAQ;AAAA,EAER;AACA,MAAI;AACF,QAAI,OAAO,YAAY,eAAe,QAAQ,KAAK;AACjD,aAAO,QAAQ,IAAI,WAAW,OAAO,KAAK;AAAA,IAC5C;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEO,IAAM,MAAM;AAAA,EACjB,cAAc,OAAO,qBAAqB,0BAA0B;AAAA,EACpE,mBAAmB,OAAO,0BAA0B,+BAA+B;AAAA,EACnF,kBAAkB,OAAO,yBAAyB,8BAA8B;AAAA,EAChF,uBAAuB,OAAO,8BAA8B,mCAAmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO/F,eAAe,OAAO,sBAAsB,oBAAoB;AAAA,EAChE,wBAAwB,OAAO,+BAA+B,oCAAoC;AAAA,EAClG,gBAAgB,OAAO,uBAAuB,4BAA4B;AAAA,EAC1E,iBAAiB,OAAO,wBAAwB,6BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA,EAK7E,gBAAgB,OAAO,sBAAsB,oBAAoB,KAAK,OAAO,kBAAkB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAa/G,0BAA0B,OAAO,iCAAiC,sCAAsC;AAAA,EACxG,0BAA0B,OAAO,4BAA4B,0BAA0B;AAAA;AAAA;AAAA,EAGvF,0BAA0B,OAAO,0BAA0B,+BAA+B;AAAA,EAC1F,WAAW,OAAO,kBAAkB,WAAW;AAAA,EAC/C,gBAAgB,OAAO,uBAAuB,gBAAgB;AAAA,EAC9D,uBAAuB,OAAO,8BAA8B,mCAAmC;AAAA,EAC/F,wBAAwB,OAAO,+BAA+B,oCAAoC;AACpG;AAIO,IAAM,uBAAgC,QAAQ,IAAI,aAAa;AAE/D,IAAM,WAAW;AAAA,EACtB,MAAM;AAAA,IACJ,wBACC,IAAI,gBAAgB,IAAI,qBACxB,IAAI,oBAAoB,IAAI;AAAA,EAC/B;AAAA,EACA,UAAU,QAAQ,IAAI,sBAAsB;AAAA,EAC5C,WAAW,QAAQ,IAAI,mBAAmB,IAAI,cAAc;AAAA,EAC5D,SAAS,QAAQ,IAAI,gBAAgB,IAAI,oBAAoB,IAAI,aAAa,IAAI,cAAc;AAAA,EAChG,UAAU;AAAA,KACP,IAAI,oBAAoB,IAAI,iBAAiB,IAAI;AAAA,EACpD;AACF;AAEO,SAAS,oBAAoB,SAAyC;AAC3E,SAAO,SAAS,OAAO;AACzB;","names":[]}
1
+ {"version":3,"sources":["../src/core/config.ts"],"sourcesContent":["const getEnv = (viteKey: string, nextKey?: string): string => {\r\n try {\r\n if (typeof import.meta !== 'undefined' && import.meta.env) {\r\n return (import.meta.env[viteKey] as string) || '';\r\n }\r\n } catch {\r\n // import.meta not available\r\n }\r\n try {\r\n if (typeof process !== 'undefined' && process.env) {\r\n return process.env[nextKey || viteKey] || '';\r\n }\r\n } catch {\r\n // process not available\r\n }\r\n return '';\r\n};\r\n\r\nexport const env = {\r\n SUPABASE_URL: getEnv('VITE_SUPABASE_URL', 'NEXT_PUBLIC_SUPABASE_URL'),\r\n SUPABASE_ANON_KEY: getEnv('VITE_SUPABASE_ANON_KEY', 'NEXT_PUBLIC_SUPABASE_ANON_KEY'),\r\n EZCODER_AUTH_URL: getEnv('VITE_EZCODER_AUTH_URL', 'NEXT_PUBLIC_EZCODER_AUTH_URL'),\r\n EZCODER_AUTH_ANON_KEY: getEnv('VITE_EZCODER_AUTH_ANON_KEY', 'NEXT_PUBLIC_EZCODER_AUTH_ANON_KEY'),\r\n // Per-project Neon Auth (Better Auth) server base URL. When present, the app\r\n // authenticates against its OWN isolated Neon Auth server (e.g.\r\n // https://ep-xxx.neonauth.<region>.aws.neon.tech/neondb/auth) instead of the\r\n // shared tenant Supabase. Injected at provision time as VITE_NEON_AUTH_URL;\r\n // NEON_AUTH_BASE_URL is the server/Next fallback name. Presence of this value\r\n // is the sole trigger for the Better Auth code path in AuthProvider.\r\n NEON_AUTH_URL: getEnv('VITE_NEON_AUTH_URL', 'NEON_AUTH_BASE_URL'),\r\n STRIPE_PUBLISHABLE_KEY: getEnv('VITE_STRIPE_PUBLISHABLE_KEY', 'NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY'),\r\n EZC_PROJECT_ID: getEnv('VITE_EZC_PROJECT_ID', 'NEXT_PUBLIC_EZC_PROJECT_ID'),\r\n EZCODER_API_URL: getEnv('VITE_EZCODER_API_URL', 'NEXT_PUBLIC_EZCODER_API_URL'),\r\n // Server-only secret for Stripe + authenticated platform API calls. Deployment\r\n // injects this as `EZCODER_SECRET_KEY` (see lib/deployment/fetch-project-env-vars.js);\r\n // resolve that name first, then fall back to the legacy `EZC_SECRET_KEY` so older\r\n // deploys keep working. Both are non-VITE/non-NEXT_PUBLIC (never exposed to the browser).\r\n EZC_SECRET_KEY: getEnv('EZCODER_SECRET_KEY', 'EZCODER_SECRET_KEY') || getEnv('EZC_SECRET_KEY', 'EZC_SECRET_KEY'),\r\n // B1: two-class project token model.\r\n //\r\n // EZC_PROJECT_TOKEN_PUBLIC — browser-safe. Read-only endpoints (manifest,\r\n // list, etc). Available in both server and\r\n // browser bundles via NEXT_PUBLIC_/VITE_\r\n // prefixes.\r\n // EZC_PROJECT_TOKEN_SERVER — server-only. Authenticates write APIs\r\n // (email send, cron register, notifications\r\n // send). NEVER prefixed with NEXT_PUBLIC_ or\r\n // VITE_; accessing it from a browser bundle\r\n // returns '' and the calling SDK function\r\n // must error out with a clear message.\r\n EZC_PROJECT_TOKEN_PUBLIC: getEnv('VITE_EZC_PROJECT_TOKEN_PUBLIC', 'NEXT_PUBLIC_EZC_PROJECT_TOKEN_PUBLIC'),\r\n EZC_PROJECT_TOKEN_SERVER: getEnv('EZC_PROJECT_TOKEN_SERVER', 'EZC_PROJECT_TOKEN_SERVER'),\r\n // Legacy single-class token. Deprecated, kept for backwards compat during\r\n // Phase 1 of the rollout. New code MUST use the split pair above.\r\n EZC_PROJECT_TOKEN_LEGACY: getEnv('VITE_EZC_PROJECT_TOKEN', 'NEXT_PUBLIC_EZC_PROJECT_TOKEN'),\r\n S3_BUCKET: getEnv('VITE_S3_BUCKET', 'S3_BUCKET'),\r\n CLOUDINARY_URL: getEnv('VITE_CLOUDINARY_URL', 'CLOUDINARY_URL'),\r\n STORAGE_BUCKET_PUBLIC: getEnv('VITE_STORAGE_BUCKET_PUBLIC', 'NEXT_PUBLIC_STORAGE_BUCKET_PUBLIC'),\r\n STORAGE_BUCKET_PRIVATE: getEnv('VITE_STORAGE_BUCKET_PRIVATE', 'NEXT_PUBLIC_STORAGE_BUCKET_PRIVATE'),\r\n // When true, social login in the Neon Auth path is handled via the central\r\n // EzCoder auth proxy instead of calling the per-project Better Auth server\r\n // directly. The proxy redirects back to <app>/auth/callback#code=<singleUse>;\r\n // AuthCallback exchanges the code for an ephemeral credential, calls\r\n // authClient.signIn.email directly (so Neon sets the native session cookie),\r\n // then rotates the password to kill the exposed credential.\r\n // Set VITE_APP_AUTH_PROXY=1 (Vite) or NEXT_PUBLIC_APP_AUTH_PROXY=1 (Next).\r\n APP_AUTH_PROXY: ((): boolean => {\r\n const v = getEnv('VITE_APP_AUTH_PROXY', 'NEXT_PUBLIC_APP_AUTH_PROXY');\r\n return v === '1' || v === 'true';\r\n })(),\r\n};\r\n\r\n// True when the project ships its own per-project Neon Auth (Better Auth)\r\n// server. This is authoritative for which auth backend AuthProvider uses.\r\nexport const isNeonAuthConfigured: boolean = Boolean(env.NEON_AUTH_URL);\r\n\r\nexport const features = {\r\n auth: Boolean(\r\n isNeonAuthConfigured ||\r\n (env.SUPABASE_URL && env.SUPABASE_ANON_KEY) ||\r\n (env.EZCODER_AUTH_URL && env.EZCODER_AUTH_ANON_KEY)\r\n ),\r\n payments: Boolean(env.STRIPE_PUBLISHABLE_KEY),\r\n analytics: Boolean(env.EZCODER_API_URL && env.EZC_PROJECT_ID),\r\n storage: Boolean(env.SUPABASE_URL || env.EZCODER_AUTH_URL || env.S3_BUCKET || env.CLOUDINARY_URL),\r\n database: Boolean(\r\n (env.EZCODER_AUTH_URL || env.SUPABASE_URL) && env.EZC_PROJECT_ID\r\n ),\r\n};\r\n\r\nexport function isFeatureConfigured(feature: keyof typeof features): boolean {\r\n return features[feature];\r\n}\r\n"],"mappings":";AAAA,IAAM,SAAS,CAAC,SAAiB,YAA6B;AAC5D,MAAI;AACF,QAAI,OAAO,gBAAgB,eAAe,YAAY,KAAK;AACzD,aAAQ,YAAY,IAAI,OAAO,KAAgB;AAAA,IACjD;AAAA,EACF,QAAQ;AAAA,EAER;AACA,MAAI;AACF,QAAI,OAAO,YAAY,eAAe,QAAQ,KAAK;AACjD,aAAO,QAAQ,IAAI,WAAW,OAAO,KAAK;AAAA,IAC5C;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEO,IAAM,MAAM;AAAA,EACjB,cAAc,OAAO,qBAAqB,0BAA0B;AAAA,EACpE,mBAAmB,OAAO,0BAA0B,+BAA+B;AAAA,EACnF,kBAAkB,OAAO,yBAAyB,8BAA8B;AAAA,EAChF,uBAAuB,OAAO,8BAA8B,mCAAmC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO/F,eAAe,OAAO,sBAAsB,oBAAoB;AAAA,EAChE,wBAAwB,OAAO,+BAA+B,oCAAoC;AAAA,EAClG,gBAAgB,OAAO,uBAAuB,4BAA4B;AAAA,EAC1E,iBAAiB,OAAO,wBAAwB,6BAA6B;AAAA;AAAA;AAAA;AAAA;AAAA,EAK7E,gBAAgB,OAAO,sBAAsB,oBAAoB,KAAK,OAAO,kBAAkB,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAa/G,0BAA0B,OAAO,iCAAiC,sCAAsC;AAAA,EACxG,0BAA0B,OAAO,4BAA4B,0BAA0B;AAAA;AAAA;AAAA,EAGvF,0BAA0B,OAAO,0BAA0B,+BAA+B;AAAA,EAC1F,WAAW,OAAO,kBAAkB,WAAW;AAAA,EAC/C,gBAAgB,OAAO,uBAAuB,gBAAgB;AAAA,EAC9D,uBAAuB,OAAO,8BAA8B,mCAAmC;AAAA,EAC/F,wBAAwB,OAAO,+BAA+B,oCAAoC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQlG,iBAAiB,MAAe;AAC9B,UAAM,IAAI,OAAO,uBAAuB,4BAA4B;AACpE,WAAO,MAAM,OAAO,MAAM;AAAA,EAC5B,GAAG;AACL;AAIO,IAAM,uBAAgC,QAAQ,IAAI,aAAa;AAE/D,IAAM,WAAW;AAAA,EACtB,MAAM;AAAA,IACJ,wBACC,IAAI,gBAAgB,IAAI,qBACxB,IAAI,oBAAoB,IAAI;AAAA,EAC/B;AAAA,EACA,UAAU,QAAQ,IAAI,sBAAsB;AAAA,EAC5C,WAAW,QAAQ,IAAI,mBAAmB,IAAI,cAAc;AAAA,EAC5D,SAAS,QAAQ,IAAI,gBAAgB,IAAI,oBAAoB,IAAI,aAAa,IAAI,cAAc;AAAA,EAChG,UAAU;AAAA,KACP,IAAI,oBAAoB,IAAI,iBAAiB,IAAI;AAAA,EACpD;AACF;AAEO,SAAS,oBAAoB,SAAyC;AAC3E,SAAO,SAAS,OAAO;AACzB;","names":[]}
@@ -1,15 +1,17 @@
1
1
  import {
2
+ DatabaseClient,
2
3
  ezcoder,
3
- ezcoderAuthIntegration
4
- } from "./chunk-DU6N3HVQ.js";
4
+ ezcoderAuthIntegration,
5
+ getRuntimeConfig
6
+ } from "./chunk-WFDQ4YUZ.js";
5
7
  import {
6
8
  isSupabaseConfigured,
7
9
  supabase
8
- } from "./chunk-KKTY5NCR.js";
10
+ } from "./chunk-FPSSXTQG.js";
9
11
  import {
10
12
  env,
11
13
  isNeonAuthConfigured
12
- } from "./chunk-X4JP7DCK.js";
14
+ } from "./chunk-KWR4PA5I.js";
13
15
 
14
16
  // src/auth/neonAuthClient.ts
15
17
  import { createAuthClient } from "better-auth/react";
@@ -29,6 +31,7 @@ function getNeonAuthClient() {
29
31
  // src/auth/AuthProvider.tsx
30
32
  import { createContext, useContext, useState, useEffect, useCallback, useRef } from "react";
31
33
  import { jsx } from "react/jsx-runtime";
34
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
32
35
  var NOT_CONFIGURED_MSG = "Authentication is not configured. Ensure EzCoder platform credentials are injected, or connect your own Supabase database in Settings \u2192 Databases.";
33
36
  function notConfiguredError() {
34
37
  return new Error(NOT_CONFIGURED_MSG);
@@ -107,6 +110,7 @@ function NeonAuthProvider({ children }) {
107
110
  if (currentId && currentId !== prevId) {
108
111
  ezcoderAuthIntegration.onLogin(mappedUser);
109
112
  previousUserIdRef.current = currentId;
113
+ void fetchProfile(currentId);
110
114
  } else if (!currentId && prevId) {
111
115
  ezcoderAuthIntegration.onLogout(prevId);
112
116
  previousUserIdRef.current = null;
@@ -154,6 +158,17 @@ function NeonAuthProvider({ children }) {
154
158
  const callbackURL = options.redirectTo || origin;
155
159
  const framed = typeof window !== "undefined" && window.self !== window.top;
156
160
  const social = provider;
161
+ if (env.APP_AUTH_PROXY && env.EZCODER_API_URL && env.EZC_PROJECT_ID) {
162
+ const proxyStartUrl = `${env.EZCODER_API_URL.replace(/\/$/, "")}/api/app-auth/start?provider=${encodeURIComponent(provider)}&projectId=${encodeURIComponent(env.EZC_PROJECT_ID)}&returnUrl=${encodeURIComponent(origin + "/auth/callback")}`;
163
+ if (framed && typeof window !== "undefined") {
164
+ window.open(proxyStartUrl, "ezc-auth", "popup,width=500,height=680");
165
+ return { data: null, error: null };
166
+ }
167
+ if (typeof window !== "undefined") {
168
+ window.location.href = proxyStartUrl;
169
+ }
170
+ return { data: null, error: null };
171
+ }
157
172
  if (framed && typeof window !== "undefined") {
158
173
  const result2 = await authClient.signIn.social({
159
174
  provider: social,
@@ -224,8 +239,34 @@ function NeonAuthProvider({ children }) {
224
239
  }
225
240
  return { data: null, error: NEON_NOT_SUPPORTED("Updating the password without a reset token") };
226
241
  }, [authClient]);
227
- const fetchProfile = useCallback(async (_userId) => {
228
- return null;
242
+ const fetchProfile = useCallback(async (userId) => {
243
+ if (!userId || !UUID_RE.test(userId)) return null;
244
+ const projectId = env.EZC_PROJECT_ID || getRuntimeConfig()?.projectId || "";
245
+ if (!projectId) return null;
246
+ try {
247
+ const db = new DatabaseClient(supabase, projectId);
248
+ const result = await db.sql(
249
+ "SELECT * FROM ezc_ensure_user_setup()"
250
+ );
251
+ const row = result?.data?.[0];
252
+ if (!row) return null;
253
+ const mapped = {
254
+ id: String(row.id ?? userId),
255
+ user_id: row.user_id ?? userId,
256
+ email: row.email ?? void 0,
257
+ display_name: row.display_name ?? void 0,
258
+ avatar_url: row.avatar_url ?? void 0,
259
+ stripe_customer_id: row.stripe_customer_id ?? void 0,
260
+ subscription_tier: row.subscription_tier ?? void 0,
261
+ subscription_status: row.subscription_status ?? void 0,
262
+ subscription_period_end: row.subscription_period_end ?? void 0
263
+ };
264
+ setProfile(mapped);
265
+ return mapped;
266
+ } catch (err) {
267
+ console.warn("[EzCoder SDK] Neon profile fetch failed:", err instanceof Error ? err.message : err);
268
+ return null;
269
+ }
229
270
  }, []);
230
271
  const updateProfile = useCallback(async (_updates) => {
231
272
  if (!user) return { data: null, error: new Error("Not authenticated") };
@@ -542,4 +583,4 @@ export {
542
583
  AuthProvider,
543
584
  useAuth
544
585
  };
545
- //# sourceMappingURL=chunk-NTA3RMYR.js.map
586
+ //# sourceMappingURL=chunk-L326T7UV.js.map