@ezcoder.dev/sdk 1.1.0 → 1.2.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.
- package/dist/analytics/index.js +7 -5
- package/dist/analytics/index.js.map +1 -1
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.js +25 -6
- package/dist/auth/index.js.map +1 -1
- package/dist/chunk-CQKYANAW.js +44 -0
- package/dist/chunk-CQKYANAW.js.map +1 -0
- package/dist/{chunk-GPF4AYNG.js → chunk-HJ2EIZ4S.js} +2 -2
- package/dist/{chunk-2WG4O4J2.js → chunk-I2YGB7Z6.js} +14 -50
- package/dist/chunk-I2YGB7Z6.js.map +1 -0
- package/dist/chunk-LIUE7M7K.js +72 -0
- package/dist/chunk-LIUE7M7K.js.map +1 -0
- package/dist/{chunk-AWU47M6N.js → chunk-QHB7LGCA.js} +91 -8
- package/dist/chunk-QHB7LGCA.js.map +1 -0
- package/dist/{chunk-7VGYFCQC.js → chunk-R4MDAYFO.js} +7 -5
- package/dist/{chunk-7VGYFCQC.js.map → chunk-R4MDAYFO.js.map} +1 -1
- package/dist/cms/index.js +4 -2
- package/dist/cms/index.js.map +1 -1
- package/dist/cron/index.d.ts +17 -0
- package/dist/cron/index.js +26 -12
- package/dist/cron/index.js.map +1 -1
- package/dist/database/index.js +4 -3
- package/dist/email/index.d.ts +18 -0
- package/dist/email/index.js +27 -12
- package/dist/email/index.js.map +1 -1
- package/dist/index.d.ts +167 -1
- package/dist/index.js +263 -7
- package/dist/index.js.map +1 -1
- package/dist/notifications/index.d.ts +27 -2
- package/dist/notifications/index.js +53 -18
- package/dist/notifications/index.js.map +1 -1
- package/dist/payments/index.js +6 -4
- package/dist/payments/index.js.map +1 -1
- package/dist/roles/index.js +6 -4
- package/dist/roles/index.js.map +1 -1
- package/dist/storage/index.js +7 -5
- package/dist/storage/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-2WG4O4J2.js.map +0 -1
- package/dist/chunk-AWU47M6N.js.map +0 -1
- /package/dist/{chunk-GPF4AYNG.js.map → chunk-HJ2EIZ4S.js.map} +0 -0
package/dist/analytics/index.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AuthContext
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-QHB7LGCA.js";
|
|
4
4
|
import {
|
|
5
5
|
ezcoder,
|
|
6
6
|
ezcoderAuthIntegration
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-HJ2EIZ4S.js";
|
|
8
8
|
import {
|
|
9
|
-
env,
|
|
10
|
-
features,
|
|
11
9
|
isSupabaseConfigured,
|
|
12
10
|
supabase
|
|
13
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-I2YGB7Z6.js";
|
|
12
|
+
import {
|
|
13
|
+
env,
|
|
14
|
+
features
|
|
15
|
+
} from "../chunk-LIUE7M7K.js";
|
|
14
16
|
|
|
15
17
|
// src/analytics/useAnalytics.ts
|
|
16
18
|
import { useEffect, useRef, useCallback, useContext } from "react";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/analytics/useAnalytics.ts","../../src/analytics/useMetrics.ts"],"sourcesContent":["import { useEffect, useRef, useCallback, useContext } from 'react';\r\nimport { ezcoder, ezcoderAuthIntegration } from '../core/platform';\r\nimport { features } from '../core/config';\r\nimport { AuthContext } from '../auth/AuthProvider';\r\n\r\ninterface UseAnalyticsReturn {\r\n trackEvent: (eventName: string, properties?: Record<string, unknown>) => void;\r\n trackPageView: (pathname?: string) => void;\r\n trackError: (message: string, context?: Record<string, unknown>) => void;\r\n identify: (userId: string, traits?: Record<string, unknown>) => void;\r\n trackSignup: (user: { id?: string; email?: string }) => void;\r\n trackLogin: (user: { id?: string }) => void;\r\n trackLogout: (userId: string) => void;\r\n isConfigured: boolean;\r\n}\r\n\r\nexport function useAnalytics(): UseAnalyticsReturn {\r\n const auth = useContext(AuthContext);\r\n const lastPageViewRef = useRef<string>('');\r\n\r\n const enrichProperties = useCallback((properties: Record<string, unknown> = {}): Record<string, unknown> => {\r\n const enriched = { ...properties };\r\n if (auth?.user?.id) {\r\n enriched.userId = auth.user.id;\r\n enriched.userEmail = auth.user.email;\r\n }\r\n if (auth?.profile) {\r\n const profile = auth.profile as unknown as Record<string, unknown>;\r\n enriched.userTier = profile.subscription_tier || 'free';\r\n enriched.userName = profile.display_name;\r\n }\r\n return enriched;\r\n }, [auth?.user, auth?.profile]);\r\n\r\n const trackEvent = useCallback((eventName: string, properties: Record<string, unknown> = {}) => {\r\n if (!features.analytics) return;\r\n ezcoder.analytics.track(eventName, enrichProperties(properties));\r\n }, [enrichProperties]);\r\n\r\n const trackPageView = useCallback((pathname?: string) => {\r\n if (!features.analytics) return;\r\n const path = pathname || (typeof window !== 'undefined' ? window.location.pathname : '/');\r\n if (path === lastPageViewRef.current) return;\r\n lastPageViewRef.current = path;\r\n ezcoder.analytics.pageView(path);\r\n }, []);\r\n\r\n const trackError = useCallback((message: string, context: Record<string, unknown> = {}) => {\r\n if (!features.analytics) return;\r\n ezcoder.analytics.error(message, enrichProperties(context));\r\n }, [enrichProperties]);\r\n\r\n const identify = useCallback((userId: string, traits: Record<string, unknown> = {}) => {\r\n if (!features.analytics) return;\r\n ezcoder.analytics.identify(userId, traits);\r\n }, []);\r\n\r\n const trackSignup = useCallback((user: { id?: string; email?: string }) => {\r\n ezcoderAuthIntegration.onSignup(user);\r\n }, []);\r\n\r\n const trackLogin = useCallback((user: { id?: string }) => {\r\n ezcoderAuthIntegration.onLogin(user);\r\n }, []);\r\n\r\n const trackLogout = useCallback((userId: string) => {\r\n ezcoderAuthIntegration.onLogout(userId);\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (!features.analytics) return;\r\n trackPageView();\r\n }, [trackPageView]);\r\n\r\n return {\r\n trackEvent,\r\n trackPageView,\r\n trackError,\r\n identify,\r\n trackSignup,\r\n trackLogin,\r\n trackLogout,\r\n isConfigured: features.analytics,\r\n };\r\n}\r\n","import { useCallback, useMemo } from 'react';\r\nimport { supabase, isSupabaseConfigured } from '../core/supabase';\r\nimport { env } from '../core/config';\r\n\r\ninterface MetricResult<T = Record<string, unknown>> {\r\n data: T | null;\r\n error: string | null;\r\n}\r\n\r\ninterface UseMetricsReturn {\r\n getTotalUsers: () => Promise<MetricResult<{ count: number }>>;\r\n getUserGrowth: (days?: number) => Promise<MetricResult<Array<{ date: string; count: number }>>>;\r\n getActiveUsers: (days?: number) => Promise<MetricResult<{ count: number }>>;\r\n getRecentActivity: (limit?: number) => Promise<MetricResult<Array<Record<string, unknown>>>>;\r\n runQuery: <T = Record<string, unknown>>(sql: string) => Promise<MetricResult<T>>;\r\n isConfigured: boolean;\r\n}\r\n\r\nasync function queryRpc<T>(sql: string, projectId: string): Promise<MetricResult<T>> {\r\n const { data, error } = await supabase.rpc('sdk_query_project', {\r\n p_project_id: projectId,\r\n p_sql: sql,\r\n });\r\n\r\n if (error) {\r\n return { data: null, error: error.message };\r\n }\r\n\r\n const result = data as { success: boolean; data: T; error?: string };\r\n if (!result?.success) {\r\n return { data: null, error: result?.error || 'Query failed' };\r\n }\r\n\r\n return { data: result.data, error: null };\r\n}\r\n\r\nexport function useMetrics(): UseMetricsReturn {\r\n const projectId = env.EZC_PROJECT_ID;\r\n const configured = isSupabaseConfigured && Boolean(projectId);\r\n\r\n const getTotalUsers = useCallback(async () => {\r\n if (!configured || !projectId) return { data: null, error: 'Not configured' };\r\n const result = await queryRpc<Array<{ count: number }>>(\r\n 'SELECT COUNT(*)::integer as count FROM user_profiles',\r\n projectId,\r\n );\r\n return {\r\n data: result.data?.[0] ?? null,\r\n error: result.error,\r\n };\r\n }, [configured, projectId]);\r\n\r\n const getUserGrowth = useCallback(async (days = 30) => {\r\n if (!configured || !projectId) return { data: null, error: 'Not configured' };\r\n return queryRpc<Array<{ date: string; count: number }>>(\r\n `SELECT date_trunc('day', created_at)::date::text as date, COUNT(*)::integer as count FROM user_profiles WHERE created_at > NOW() - INTERVAL '${days} days' GROUP BY 1 ORDER BY 1`,\r\n projectId,\r\n );\r\n }, [configured, projectId]);\r\n\r\n const getActiveUsers = useCallback(async (days = 7) => {\r\n if (!configured || !projectId) return { data: null, error: 'Not configured' };\r\n const result = await queryRpc<Array<{ count: number }>>(\r\n `SELECT COUNT(DISTINCT user_id)::integer as count FROM activity_log WHERE created_at > NOW() - INTERVAL '${days} days'`,\r\n projectId,\r\n );\r\n return {\r\n data: result.data?.[0] ?? null,\r\n error: result.error,\r\n };\r\n }, [configured, projectId]);\r\n\r\n const getRecentActivity = useCallback(async (limit = 20) => {\r\n if (!configured || !projectId) return { data: null, error: 'Not configured' };\r\n return queryRpc<Array<Record<string, unknown>>>(\r\n `SELECT * FROM activity_log ORDER BY created_at DESC LIMIT ${limit}`,\r\n projectId,\r\n );\r\n }, [configured, projectId]);\r\n\r\n const runQuery = useCallback(async <T = Record<string, unknown>>(sql: string) => {\r\n if (!configured || !projectId) return { data: null, error: 'Not configured' } as MetricResult<T>;\r\n return queryRpc<T>(sql, projectId);\r\n }, [configured, projectId]);\r\n\r\n return useMemo(() => ({\r\n getTotalUsers,\r\n getUserGrowth,\r\n getActiveUsers,\r\n getRecentActivity,\r\n runQuery,\r\n isConfigured: configured,\r\n }), [getTotalUsers, getUserGrowth, getActiveUsers, getRecentActivity, runQuery, configured]);\r\n}\r\n"],"mappings":"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","names":["useCallback","useCallback"]}
|
|
1
|
+
{"version":3,"sources":["../../src/analytics/useAnalytics.ts","../../src/analytics/useMetrics.ts"],"sourcesContent":["import { useEffect, useRef, useCallback, useContext } from 'react';\r\nimport { ezcoder, ezcoderAuthIntegration } from '../core/platform';\r\nimport { features } from '../core/config';\r\nimport { AuthContext } from '../auth/AuthProvider';\r\n\r\ninterface UseAnalyticsReturn {\r\n trackEvent: (eventName: string, properties?: Record<string, unknown>) => void;\r\n trackPageView: (pathname?: string) => void;\r\n trackError: (message: string, context?: Record<string, unknown>) => void;\r\n identify: (userId: string, traits?: Record<string, unknown>) => void;\r\n trackSignup: (user: { id?: string; email?: string }) => void;\r\n trackLogin: (user: { id?: string }) => void;\r\n trackLogout: (userId: string) => void;\r\n isConfigured: boolean;\r\n}\r\n\r\nexport function useAnalytics(): UseAnalyticsReturn {\r\n const auth = useContext(AuthContext);\r\n const lastPageViewRef = useRef<string>('');\r\n\r\n const enrichProperties = useCallback((properties: Record<string, unknown> = {}): Record<string, unknown> => {\r\n const enriched = { ...properties };\r\n if (auth?.user?.id) {\r\n enriched.userId = auth.user.id;\r\n enriched.userEmail = auth.user.email;\r\n }\r\n if (auth?.profile) {\r\n const profile = auth.profile as unknown as Record<string, unknown>;\r\n enriched.userTier = profile.subscription_tier || 'free';\r\n enriched.userName = profile.display_name;\r\n }\r\n return enriched;\r\n }, [auth?.user, auth?.profile]);\r\n\r\n const trackEvent = useCallback((eventName: string, properties: Record<string, unknown> = {}) => {\r\n if (!features.analytics) return;\r\n ezcoder.analytics.track(eventName, enrichProperties(properties));\r\n }, [enrichProperties]);\r\n\r\n const trackPageView = useCallback((pathname?: string) => {\r\n if (!features.analytics) return;\r\n const path = pathname || (typeof window !== 'undefined' ? window.location.pathname : '/');\r\n if (path === lastPageViewRef.current) return;\r\n lastPageViewRef.current = path;\r\n ezcoder.analytics.pageView(path);\r\n }, []);\r\n\r\n const trackError = useCallback((message: string, context: Record<string, unknown> = {}) => {\r\n if (!features.analytics) return;\r\n ezcoder.analytics.error(message, enrichProperties(context));\r\n }, [enrichProperties]);\r\n\r\n const identify = useCallback((userId: string, traits: Record<string, unknown> = {}) => {\r\n if (!features.analytics) return;\r\n ezcoder.analytics.identify(userId, traits);\r\n }, []);\r\n\r\n const trackSignup = useCallback((user: { id?: string; email?: string }) => {\r\n ezcoderAuthIntegration.onSignup(user);\r\n }, []);\r\n\r\n const trackLogin = useCallback((user: { id?: string }) => {\r\n ezcoderAuthIntegration.onLogin(user);\r\n }, []);\r\n\r\n const trackLogout = useCallback((userId: string) => {\r\n ezcoderAuthIntegration.onLogout(userId);\r\n }, []);\r\n\r\n useEffect(() => {\r\n if (!features.analytics) return;\r\n trackPageView();\r\n }, [trackPageView]);\r\n\r\n return {\r\n trackEvent,\r\n trackPageView,\r\n trackError,\r\n identify,\r\n trackSignup,\r\n trackLogin,\r\n trackLogout,\r\n isConfigured: features.analytics,\r\n };\r\n}\r\n","import { useCallback, useMemo } from 'react';\r\nimport { supabase, isSupabaseConfigured } from '../core/supabase';\r\nimport { env } from '../core/config';\r\n\r\ninterface MetricResult<T = Record<string, unknown>> {\r\n data: T | null;\r\n error: string | null;\r\n}\r\n\r\ninterface UseMetricsReturn {\r\n getTotalUsers: () => Promise<MetricResult<{ count: number }>>;\r\n getUserGrowth: (days?: number) => Promise<MetricResult<Array<{ date: string; count: number }>>>;\r\n getActiveUsers: (days?: number) => Promise<MetricResult<{ count: number }>>;\r\n getRecentActivity: (limit?: number) => Promise<MetricResult<Array<Record<string, unknown>>>>;\r\n runQuery: <T = Record<string, unknown>>(sql: string) => Promise<MetricResult<T>>;\r\n isConfigured: boolean;\r\n}\r\n\r\nasync function queryRpc<T>(sql: string, projectId: string): Promise<MetricResult<T>> {\r\n const { data, error } = await supabase.rpc('sdk_query_project', {\r\n p_project_id: projectId,\r\n p_sql: sql,\r\n });\r\n\r\n if (error) {\r\n return { data: null, error: error.message };\r\n }\r\n\r\n const result = data as { success: boolean; data: T; error?: string };\r\n if (!result?.success) {\r\n return { data: null, error: result?.error || 'Query failed' };\r\n }\r\n\r\n return { data: result.data, error: null };\r\n}\r\n\r\nexport function useMetrics(): UseMetricsReturn {\r\n const projectId = env.EZC_PROJECT_ID;\r\n const configured = isSupabaseConfigured && Boolean(projectId);\r\n\r\n const getTotalUsers = useCallback(async () => {\r\n if (!configured || !projectId) return { data: null, error: 'Not configured' };\r\n const result = await queryRpc<Array<{ count: number }>>(\r\n 'SELECT COUNT(*)::integer as count FROM user_profiles',\r\n projectId,\r\n );\r\n return {\r\n data: result.data?.[0] ?? null,\r\n error: result.error,\r\n };\r\n }, [configured, projectId]);\r\n\r\n const getUserGrowth = useCallback(async (days = 30) => {\r\n if (!configured || !projectId) return { data: null, error: 'Not configured' };\r\n return queryRpc<Array<{ date: string; count: number }>>(\r\n `SELECT date_trunc('day', created_at)::date::text as date, COUNT(*)::integer as count FROM user_profiles WHERE created_at > NOW() - INTERVAL '${days} days' GROUP BY 1 ORDER BY 1`,\r\n projectId,\r\n );\r\n }, [configured, projectId]);\r\n\r\n const getActiveUsers = useCallback(async (days = 7) => {\r\n if (!configured || !projectId) return { data: null, error: 'Not configured' };\r\n const result = await queryRpc<Array<{ count: number }>>(\r\n `SELECT COUNT(DISTINCT user_id)::integer as count FROM activity_log WHERE created_at > NOW() - INTERVAL '${days} days'`,\r\n projectId,\r\n );\r\n return {\r\n data: result.data?.[0] ?? null,\r\n error: result.error,\r\n };\r\n }, [configured, projectId]);\r\n\r\n const getRecentActivity = useCallback(async (limit = 20) => {\r\n if (!configured || !projectId) return { data: null, error: 'Not configured' };\r\n return queryRpc<Array<Record<string, unknown>>>(\r\n `SELECT * FROM activity_log ORDER BY created_at DESC LIMIT ${limit}`,\r\n projectId,\r\n );\r\n }, [configured, projectId]);\r\n\r\n const runQuery = useCallback(async <T = Record<string, unknown>>(sql: string) => {\r\n if (!configured || !projectId) return { data: null, error: 'Not configured' } as MetricResult<T>;\r\n return queryRpc<T>(sql, projectId);\r\n }, [configured, projectId]);\r\n\r\n return useMemo(() => ({\r\n getTotalUsers,\r\n getUserGrowth,\r\n getActiveUsers,\r\n getRecentActivity,\r\n runQuery,\r\n isConfigured: configured,\r\n }), [getTotalUsers, getUserGrowth, getActiveUsers, getRecentActivity, runQuery, configured]);\r\n}\r\n"],"mappings":"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","names":["useCallback","useCallback"]}
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ interface AuthContextType {
|
|
|
27
27
|
error: Error | null;
|
|
28
28
|
}>;
|
|
29
29
|
resetPassword: (email: string) => Promise<AuthResult>;
|
|
30
|
+
updatePassword: (newPassword: string) => Promise<AuthResult>;
|
|
30
31
|
updateProfile: (updates: Partial<UserProfile>) => Promise<AuthResult>;
|
|
31
32
|
refetchProfile: (userId: string) => Promise<UserProfile | null>;
|
|
32
33
|
}
|
package/dist/auth/index.js
CHANGED
|
@@ -2,11 +2,12 @@ import {
|
|
|
2
2
|
AuthContext,
|
|
3
3
|
AuthProvider,
|
|
4
4
|
useAuth
|
|
5
|
-
} from "../chunk-
|
|
6
|
-
import "../chunk-
|
|
5
|
+
} from "../chunk-QHB7LGCA.js";
|
|
6
|
+
import "../chunk-HJ2EIZ4S.js";
|
|
7
7
|
import {
|
|
8
8
|
supabase
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-I2YGB7Z6.js";
|
|
10
|
+
import "../chunk-LIUE7M7K.js";
|
|
10
11
|
|
|
11
12
|
// src/auth/ProtectedRoute.tsx
|
|
12
13
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -429,9 +430,27 @@ function AuthCallback({ redirectTo = "/", loadingComponent }) {
|
|
|
429
430
|
useEffect(() => {
|
|
430
431
|
const handleCallback = async () => {
|
|
431
432
|
try {
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
433
|
+
let session = null;
|
|
434
|
+
const got = await supabase.auth.getSession();
|
|
435
|
+
if (got.error) {
|
|
436
|
+
setError(got.error.message);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
session = got.data?.session ?? null;
|
|
440
|
+
if (!session && typeof window !== "undefined" && new URLSearchParams(window.location.search).get("code")) {
|
|
441
|
+
const ex = await supabase.auth.exchangeCodeForSession(window.location.href);
|
|
442
|
+
if (ex.error) {
|
|
443
|
+
setError(ex.error.message);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
session = ex.data?.session ?? null;
|
|
447
|
+
}
|
|
448
|
+
if (typeof window !== "undefined" && window.opener && window.opener !== window) {
|
|
449
|
+
try {
|
|
450
|
+
window.opener.postMessage({ type: "ezc-auth-complete" }, "*");
|
|
451
|
+
} catch {
|
|
452
|
+
}
|
|
453
|
+
window.close();
|
|
435
454
|
return;
|
|
436
455
|
}
|
|
437
456
|
window.location.href = redirectTo;
|
package/dist/auth/index.js.map
CHANGED
|
@@ -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'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'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 const { error } = await supabase.auth.getSession();\r\n if (error) {\r\n setError(error.message);\r\n return;\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;AA8B9B,SAWF,YAAAC,WAVI,OAAAC,MADF,QAAAC,aAAA;AAtBC,SAAS,aAAa,EAAE,aAAa,KAAK,iBAAiB,GAAsB;AACtF,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAwB,IAAI;AAEtD,YAAU,MAAM;AACd,UAAM,iBAAiB,YAAY;AACjC,UAAI;AACF,cAAM,EAAE,OAAAC,OAAM,IAAI,MAAM,SAAS,KAAK,WAAW;AACjD,YAAIA,QAAO;AACT,mBAASA,OAAM,OAAO;AACtB;AAAA,QACF;AACA,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,gBAAAF,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","error"]}
|
|
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'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'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":"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","names":["jsx","jsxs","useState","jsx","jsxs","useState","useState","jsx","jsxs","useState","useState","Fragment","jsx","jsxs","useState"]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import {
|
|
2
|
+
env
|
|
3
|
+
} from "./chunk-LIUE7M7K.js";
|
|
4
|
+
|
|
5
|
+
// src/core/projectToken.ts
|
|
6
|
+
function isBrowserRuntime() {
|
|
7
|
+
return typeof window !== "undefined" && typeof window.document !== "undefined";
|
|
8
|
+
}
|
|
9
|
+
function resolveServerToken() {
|
|
10
|
+
const serverToken = env.EZC_PROJECT_TOKEN_SERVER;
|
|
11
|
+
if (typeof serverToken === "string" && serverToken.length > 0) {
|
|
12
|
+
return { ok: true, token: serverToken, source: "server-class" };
|
|
13
|
+
}
|
|
14
|
+
const legacyToken = env.EZC_PROJECT_TOKEN_LEGACY;
|
|
15
|
+
if (typeof legacyToken === "string" && legacyToken.length > 0) {
|
|
16
|
+
warnLegacyOnce();
|
|
17
|
+
return { ok: true, token: legacyToken, source: "legacy" };
|
|
18
|
+
}
|
|
19
|
+
if (isBrowserRuntime()) {
|
|
20
|
+
return {
|
|
21
|
+
ok: false,
|
|
22
|
+
reason: "This SDK function must be called from server-side code; EZC_PROJECT_TOKEN_SERVER is not available in browser bundles. Move the call to a Next.js API route, server action, or Node script."
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
ok: false,
|
|
27
|
+
reason: "EZC_PROJECT_TOKEN_SERVER is not configured. Set it in your server environment (e.g. via fly.io secrets, .env.local, or your deploy provider)."
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
var legacyWarnIssued = false;
|
|
31
|
+
function warnLegacyOnce() {
|
|
32
|
+
if (legacyWarnIssued) return;
|
|
33
|
+
legacyWarnIssued = true;
|
|
34
|
+
if (typeof console !== "undefined" && typeof console.warn === "function") {
|
|
35
|
+
console.warn(
|
|
36
|
+
"[ezcoder-sdk] EZC_PROJECT_TOKEN is deprecated. Migrate to the two-class pair (EZC_PROJECT_TOKEN_PUBLIC + EZC_PROJECT_TOKEN_SERVER); the legacy single-token will be removed in Phase 2 of the B1 rollout."
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
resolveServerToken
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=chunk-CQKYANAW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/projectToken.ts"],"sourcesContent":["/**\r\n * Project token helpers (B1).\r\n *\r\n * The SDK uses two token classes:\r\n * - PUBLIC (ezc_pub_*) browser-safe, read-only APIs.\r\n * - SERVER (ezc_srv_*) server-only, write APIs.\r\n *\r\n * This module centralizes the resolution + the \"you called this from the\r\n * browser\" error path so every SDK write function (sendEmail, registerCronJob,\r\n * sendNotification, ...) returns the same diagnostic when the server token\r\n * is unreachable.\r\n */\r\n\r\nimport { env } from './config';\r\n\r\n/**\r\n * True when running in a browser-like JavaScript environment (a `window`\r\n * object exists). Server-only env vars are unreachable here.\r\n */\r\nexport function isBrowserRuntime(): boolean {\r\n return typeof window !== 'undefined' && typeof window.document !== 'undefined';\r\n}\r\n\r\nexport type ServerTokenResolution =\r\n | { ok: true; token: string; source: 'server-class' | 'legacy' }\r\n | { ok: false; reason: string };\r\n\r\n/**\r\n * Resolves the SERVER-class project token for an SDK write call.\r\n *\r\n * Resolution order:\r\n * 1. EZC_PROJECT_TOKEN_SERVER (B1 server-class token, preferred)\r\n * 2. EZC_PROJECT_TOKEN_LEGACY (deprecated single-class token, warn once)\r\n * 3. Fail with a precise diagnostic.\r\n *\r\n * Browser-runtime calls fail fast in (1) because the env var is unset; we\r\n * surface a clear error message so the SDK consumer doesn't waste time\r\n * looking for a 401.\r\n */\r\nexport function resolveServerToken(): ServerTokenResolution {\r\n const serverToken = env.EZC_PROJECT_TOKEN_SERVER;\r\n if (typeof serverToken === 'string' && serverToken.length > 0) {\r\n return { ok: true, token: serverToken, source: 'server-class' };\r\n }\r\n\r\n const legacyToken = env.EZC_PROJECT_TOKEN_LEGACY;\r\n if (typeof legacyToken === 'string' && legacyToken.length > 0) {\r\n warnLegacyOnce();\r\n return { ok: true, token: legacyToken, source: 'legacy' };\r\n }\r\n\r\n if (isBrowserRuntime()) {\r\n return {\r\n ok: false,\r\n reason:\r\n 'This SDK function must be called from server-side code; ' +\r\n 'EZC_PROJECT_TOKEN_SERVER is not available in browser bundles. ' +\r\n 'Move the call to a Next.js API route, server action, or Node script.',\r\n };\r\n }\r\n\r\n return {\r\n ok: false,\r\n reason:\r\n 'EZC_PROJECT_TOKEN_SERVER is not configured. ' +\r\n 'Set it in your server environment (e.g. via fly.io secrets, .env.local, or your deploy provider).',\r\n };\r\n}\r\n\r\n/**\r\n * Returns the PUBLIC-class project token, with fallback to the legacy\r\n * single-class token during Phase 1. Browser-safe.\r\n */\r\nexport function resolvePublicToken(): string | null {\r\n if (typeof env.EZC_PROJECT_TOKEN_PUBLIC === 'string' && env.EZC_PROJECT_TOKEN_PUBLIC.length > 0) {\r\n return env.EZC_PROJECT_TOKEN_PUBLIC;\r\n }\r\n if (typeof env.EZC_PROJECT_TOKEN_LEGACY === 'string' && env.EZC_PROJECT_TOKEN_LEGACY.length > 0) {\r\n warnLegacyOnce();\r\n return env.EZC_PROJECT_TOKEN_LEGACY;\r\n }\r\n return null;\r\n}\r\n\r\nlet legacyWarnIssued = false;\r\n\r\nfunction warnLegacyOnce(): void {\r\n if (legacyWarnIssued) return;\r\n legacyWarnIssued = true;\r\n if (typeof console !== 'undefined' && typeof console.warn === 'function') {\r\n console.warn(\r\n '[ezcoder-sdk] EZC_PROJECT_TOKEN is deprecated. ' +\r\n 'Migrate to the two-class pair (EZC_PROJECT_TOKEN_PUBLIC + EZC_PROJECT_TOKEN_SERVER); ' +\r\n 'the legacy single-token will be removed in Phase 2 of the B1 rollout.'\r\n );\r\n }\r\n}\r\n\r\n/** Test-only escape hatch. Resets the once-flag so multiple calls log again. */\r\nexport const __testing = {\r\n resetLegacyWarning(): void {\r\n legacyWarnIssued = false;\r\n },\r\n};\r\n"],"mappings":";;;;;AAmBO,SAAS,mBAA4B;AAC1C,SAAO,OAAO,WAAW,eAAe,OAAO,OAAO,aAAa;AACrE;AAkBO,SAAS,qBAA4C;AAC1D,QAAM,cAAc,IAAI;AACxB,MAAI,OAAO,gBAAgB,YAAY,YAAY,SAAS,GAAG;AAC7D,WAAO,EAAE,IAAI,MAAM,OAAO,aAAa,QAAQ,eAAe;AAAA,EAChE;AAEA,QAAM,cAAc,IAAI;AACxB,MAAI,OAAO,gBAAgB,YAAY,YAAY,SAAS,GAAG;AAC7D,mBAAe;AACf,WAAO,EAAE,IAAI,MAAM,OAAO,aAAa,QAAQ,SAAS;AAAA,EAC1D;AAEA,MAAI,iBAAiB,GAAG;AACtB,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,QACE;AAAA,IAGJ;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,QACE;AAAA,EAEJ;AACF;AAiBA,IAAI,mBAAmB;AAEvB,SAAS,iBAAuB;AAC9B,MAAI,iBAAkB;AACtB,qBAAmB;AACnB,MAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,SAAS,YAAY;AACxE,YAAQ;AAAA,MACN;AAAA,IAGF;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
env
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LIUE7M7K.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-
|
|
389
|
+
//# sourceMappingURL=chunk-HJ2EIZ4S.js.map
|
|
@@ -1,47 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
if (typeof import.meta !== "undefined" && import.meta.env) {
|
|
5
|
-
return import.meta.env[viteKey] || "";
|
|
6
|
-
}
|
|
7
|
-
} catch {
|
|
8
|
-
}
|
|
9
|
-
try {
|
|
10
|
-
if (typeof process !== "undefined" && process.env) {
|
|
11
|
-
return process.env[nextKey || viteKey] || "";
|
|
12
|
-
}
|
|
13
|
-
} catch {
|
|
14
|
-
}
|
|
15
|
-
return "";
|
|
16
|
-
};
|
|
17
|
-
var env = {
|
|
18
|
-
SUPABASE_URL: getEnv("VITE_SUPABASE_URL", "NEXT_PUBLIC_SUPABASE_URL"),
|
|
19
|
-
SUPABASE_ANON_KEY: getEnv("VITE_SUPABASE_ANON_KEY", "NEXT_PUBLIC_SUPABASE_ANON_KEY"),
|
|
20
|
-
EZCODER_AUTH_URL: getEnv("VITE_EZCODER_AUTH_URL", "NEXT_PUBLIC_EZCODER_AUTH_URL"),
|
|
21
|
-
EZCODER_AUTH_ANON_KEY: getEnv("VITE_EZCODER_AUTH_ANON_KEY", "NEXT_PUBLIC_EZCODER_AUTH_ANON_KEY"),
|
|
22
|
-
STRIPE_PUBLISHABLE_KEY: getEnv("VITE_STRIPE_PUBLISHABLE_KEY", "NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY"),
|
|
23
|
-
EZC_PROJECT_ID: getEnv("VITE_EZC_PROJECT_ID", "NEXT_PUBLIC_EZC_PROJECT_ID"),
|
|
24
|
-
EZCODER_API_URL: getEnv("VITE_EZCODER_API_URL", "NEXT_PUBLIC_EZCODER_API_URL"),
|
|
25
|
-
EZC_SECRET_KEY: getEnv("EZC_SECRET_KEY", "EZC_SECRET_KEY"),
|
|
26
|
-
S3_BUCKET: getEnv("VITE_S3_BUCKET", "S3_BUCKET"),
|
|
27
|
-
CLOUDINARY_URL: getEnv("VITE_CLOUDINARY_URL", "CLOUDINARY_URL"),
|
|
28
|
-
STORAGE_BUCKET_PUBLIC: getEnv("VITE_STORAGE_BUCKET_PUBLIC", "NEXT_PUBLIC_STORAGE_BUCKET_PUBLIC"),
|
|
29
|
-
STORAGE_BUCKET_PRIVATE: getEnv("VITE_STORAGE_BUCKET_PRIVATE", "NEXT_PUBLIC_STORAGE_BUCKET_PRIVATE")
|
|
30
|
-
};
|
|
31
|
-
var features = {
|
|
32
|
-
auth: Boolean(
|
|
33
|
-
env.SUPABASE_URL && env.SUPABASE_ANON_KEY || env.EZCODER_AUTH_URL && env.EZCODER_AUTH_ANON_KEY
|
|
34
|
-
),
|
|
35
|
-
payments: Boolean(env.STRIPE_PUBLISHABLE_KEY),
|
|
36
|
-
analytics: Boolean(env.EZCODER_API_URL && env.EZC_PROJECT_ID),
|
|
37
|
-
storage: Boolean(env.SUPABASE_URL || env.EZCODER_AUTH_URL || env.S3_BUCKET || env.CLOUDINARY_URL),
|
|
38
|
-
database: Boolean(
|
|
39
|
-
(env.EZCODER_AUTH_URL || env.SUPABASE_URL) && env.EZC_PROJECT_ID
|
|
40
|
-
)
|
|
41
|
-
};
|
|
42
|
-
function isFeatureConfigured(feature) {
|
|
43
|
-
return features[feature];
|
|
44
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
env
|
|
3
|
+
} from "./chunk-LIUE7M7K.js";
|
|
45
4
|
|
|
46
5
|
// src/core/supabase.ts
|
|
47
6
|
import { createClient } from "@supabase/supabase-js";
|
|
@@ -142,16 +101,21 @@ var supabase = isConfigured ? createClient(authUrl, authKey, {
|
|
|
142
101
|
auth: {
|
|
143
102
|
autoRefreshToken: true,
|
|
144
103
|
persistSession: true,
|
|
145
|
-
detectSessionInUrl: true
|
|
146
|
-
|
|
104
|
+
detectSessionInUrl: true,
|
|
105
|
+
// PKCE: no access token in the URL (the secure SPA default). With
|
|
106
|
+
// detectSessionInUrl:true the client auto-exchanges the `?code=` on load,
|
|
107
|
+
// so OAuth still completes on the landing page for apps without a dedicated
|
|
108
|
+
// callback route; AuthCallback adds an explicit exchange as a safety net.
|
|
109
|
+
flowType: "pkce"
|
|
110
|
+
},
|
|
111
|
+
// Tag every request with the project id so the auth-proxy edge (auth.ezcoder.app)
|
|
112
|
+
// can attribute + rate-limit per app on the shared tenant. Advisory only.
|
|
113
|
+
...env.EZC_PROJECT_ID ? { global: { headers: { "x-ezc-project": env.EZC_PROJECT_ID } } } : {}
|
|
147
114
|
}) : createStubClient();
|
|
148
115
|
var isSupabaseConfigured = isConfigured;
|
|
149
116
|
|
|
150
117
|
export {
|
|
151
|
-
env,
|
|
152
|
-
features,
|
|
153
|
-
isFeatureConfigured,
|
|
154
118
|
supabase,
|
|
155
119
|
isSupabaseConfigured
|
|
156
120
|
};
|
|
157
|
-
//# sourceMappingURL=chunk-
|
|
121
|
+
//# sourceMappingURL=chunk-I2YGB7Z6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/supabase.ts"],"sourcesContent":["import { createClient, SupabaseClient } from '@supabase/supabase-js';\r\nimport { env, features } from './config';\r\n\r\nfunction createStubClient(): SupabaseClient {\r\n const notConfiguredError = new Error('Supabase not configured');\r\n\r\n function createQueryBuilder() {\r\n const builder: Record<string, unknown> = {\r\n select: () => builder,\r\n insert: () => builder,\r\n update: () => builder,\r\n upsert: () => builder,\r\n delete: () => builder,\r\n eq: () => builder,\r\n neq: () => builder,\r\n gt: () => builder,\r\n gte: () => builder,\r\n lt: () => builder,\r\n lte: () => builder,\r\n like: () => builder,\r\n ilike: () => builder,\r\n is: () => builder,\r\n in: () => builder,\r\n contains: () => builder,\r\n containedBy: () => builder,\r\n match: () => builder,\r\n not: () => builder,\r\n or: () => builder,\r\n filter: () => builder,\r\n order: () => builder,\r\n limit: () => builder,\r\n range: () => builder,\r\n textSearch: () => builder,\r\n csv: () => builder,\r\n single: () => Promise.resolve({ data: null, error: null }),\r\n maybeSingle: () => Promise.resolve({ data: null, error: null }),\r\n then: (resolve: (value: unknown) => void, reject?: (reason: unknown) => void) =>\r\n Promise.resolve({ data: [], error: null }).then(resolve, reject),\r\n catch: (fn: (reason: unknown) => void) =>\r\n Promise.resolve({ data: [], error: null }).catch(fn),\r\n };\r\n return builder;\r\n }\r\n\r\n return {\r\n auth: {\r\n getSession: async () => ({ data: { session: null }, error: null }),\r\n getUser: async () => ({ data: { user: null }, error: null }),\r\n signUp: async () => ({ data: null, error: notConfiguredError }),\r\n signInWithPassword: async () => ({ data: null, error: notConfiguredError }),\r\n signInWithOAuth: async () => ({ data: null, error: notConfiguredError }),\r\n signOut: async () => ({ error: null }),\r\n resetPasswordForEmail: async () => ({ data: null, error: notConfiguredError }),\r\n updateUser: async () => ({ data: null, error: notConfiguredError }),\r\n onAuthStateChange: (callback: (event: string, session: null) => void) => {\r\n if (typeof window !== 'undefined') {\r\n setTimeout(() => callback('INITIAL_SESSION', null), 0);\r\n }\r\n return { data: { subscription: { unsubscribe: () => {} } } };\r\n },\r\n },\r\n from: () => createQueryBuilder(),\r\n rpc: async () => ({ data: null, error: notConfiguredError }),\r\n channel: (_name: string) => ({\r\n on: (_event: string, _filter: unknown, _callback: unknown) => ({\r\n subscribe: (cb?: (status: string) => void) => {\r\n if (cb) cb('SUBSCRIBED');\r\n return { unsubscribe: () => {} };\r\n },\r\n }),\r\n subscribe: (cb?: (status: string) => void) => {\r\n if (cb) cb('SUBSCRIBED');\r\n return { unsubscribe: () => {} };\r\n },\r\n }),\r\n removeChannel: () => Promise.resolve('ok'),\r\n removeAllChannels: () => Promise.resolve([]),\r\n storage: {\r\n from: () => ({\r\n upload: async () => ({ data: null, error: notConfiguredError }),\r\n download: async () => ({ data: null, error: notConfiguredError }),\r\n getPublicUrl: () => ({ data: { publicUrl: '' } }),\r\n createSignedUrl: async () => ({ data: null, error: notConfiguredError }),\r\n list: async () => ({ data: [], error: null }),\r\n remove: async () => ({ data: [], error: null }),\r\n }),\r\n },\r\n } as unknown as SupabaseClient;\r\n}\r\n\r\nconst authUrl = env.EZCODER_AUTH_URL || env.SUPABASE_URL;\r\nconst authKey = env.EZCODER_AUTH_ANON_KEY || env.SUPABASE_ANON_KEY;\r\n\r\nconst isConfigured = Boolean(authUrl && authKey);\r\n\r\nif (!isConfigured && typeof window !== 'undefined') {\r\n console.warn(\r\n '[EzCoder SDK] Supabase not configured — auth, database, and storage features are disabled. ' +\r\n 'Set VITE_EZCODER_AUTH_URL and VITE_EZCODER_AUTH_ANON_KEY (or NEXT_PUBLIC_ equivalents) to enable.'\r\n );\r\n}\r\n\r\nexport const supabase: SupabaseClient = isConfigured\r\n ? createClient(authUrl!, authKey!, {\r\n auth: {\r\n autoRefreshToken: true,\r\n persistSession: true,\r\n detectSessionInUrl: true,\r\n // PKCE: no access token in the URL (the secure SPA default). With\r\n // detectSessionInUrl:true the client auto-exchanges the `?code=` on load,\r\n // so OAuth still completes on the landing page for apps without a dedicated\r\n // callback route; AuthCallback adds an explicit exchange as a safety net.\r\n flowType: 'pkce',\r\n },\r\n // Tag every request with the project id so the auth-proxy edge (auth.ezcoder.app)\r\n // can attribute + rate-limit per app on the shared tenant. Advisory only.\r\n ...(env.EZC_PROJECT_ID ? { global: { headers: { 'x-ezc-project': env.EZC_PROJECT_ID } } } : {}),\r\n })\r\n : createStubClient();\r\n\r\nexport const isSupabaseConfigured: boolean = isConfigured;\r\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// src/core/config.ts
|
|
2
|
+
var getEnv = (viteKey, nextKey) => {
|
|
3
|
+
try {
|
|
4
|
+
if (typeof import.meta !== "undefined" && import.meta.env) {
|
|
5
|
+
return import.meta.env[viteKey] || "";
|
|
6
|
+
}
|
|
7
|
+
} catch {
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
if (typeof process !== "undefined" && process.env) {
|
|
11
|
+
return process.env[nextKey || viteKey] || "";
|
|
12
|
+
}
|
|
13
|
+
} catch {
|
|
14
|
+
}
|
|
15
|
+
return "";
|
|
16
|
+
};
|
|
17
|
+
var env = {
|
|
18
|
+
SUPABASE_URL: getEnv("VITE_SUPABASE_URL", "NEXT_PUBLIC_SUPABASE_URL"),
|
|
19
|
+
SUPABASE_ANON_KEY: getEnv("VITE_SUPABASE_ANON_KEY", "NEXT_PUBLIC_SUPABASE_ANON_KEY"),
|
|
20
|
+
EZCODER_AUTH_URL: getEnv("VITE_EZCODER_AUTH_URL", "NEXT_PUBLIC_EZCODER_AUTH_URL"),
|
|
21
|
+
EZCODER_AUTH_ANON_KEY: getEnv("VITE_EZCODER_AUTH_ANON_KEY", "NEXT_PUBLIC_EZCODER_AUTH_ANON_KEY"),
|
|
22
|
+
STRIPE_PUBLISHABLE_KEY: getEnv("VITE_STRIPE_PUBLISHABLE_KEY", "NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY"),
|
|
23
|
+
EZC_PROJECT_ID: getEnv("VITE_EZC_PROJECT_ID", "NEXT_PUBLIC_EZC_PROJECT_ID"),
|
|
24
|
+
EZCODER_API_URL: getEnv("VITE_EZCODER_API_URL", "NEXT_PUBLIC_EZCODER_API_URL"),
|
|
25
|
+
// Server-only secret for Stripe + authenticated platform API calls. Deployment
|
|
26
|
+
// injects this as `EZCODER_SECRET_KEY` (see lib/deployment/fetch-project-env-vars.js);
|
|
27
|
+
// resolve that name first, then fall back to the legacy `EZC_SECRET_KEY` so older
|
|
28
|
+
// deploys keep working. Both are non-VITE/non-NEXT_PUBLIC (never exposed to the browser).
|
|
29
|
+
EZC_SECRET_KEY: getEnv("EZCODER_SECRET_KEY", "EZCODER_SECRET_KEY") || getEnv("EZC_SECRET_KEY", "EZC_SECRET_KEY"),
|
|
30
|
+
// B1: two-class project token model.
|
|
31
|
+
//
|
|
32
|
+
// EZC_PROJECT_TOKEN_PUBLIC — browser-safe. Read-only endpoints (manifest,
|
|
33
|
+
// list, etc). Available in both server and
|
|
34
|
+
// browser bundles via NEXT_PUBLIC_/VITE_
|
|
35
|
+
// prefixes.
|
|
36
|
+
// EZC_PROJECT_TOKEN_SERVER — server-only. Authenticates write APIs
|
|
37
|
+
// (email send, cron register, notifications
|
|
38
|
+
// send). NEVER prefixed with NEXT_PUBLIC_ or
|
|
39
|
+
// VITE_; accessing it from a browser bundle
|
|
40
|
+
// returns '' and the calling SDK function
|
|
41
|
+
// must error out with a clear message.
|
|
42
|
+
EZC_PROJECT_TOKEN_PUBLIC: getEnv("VITE_EZC_PROJECT_TOKEN_PUBLIC", "NEXT_PUBLIC_EZC_PROJECT_TOKEN_PUBLIC"),
|
|
43
|
+
EZC_PROJECT_TOKEN_SERVER: getEnv("EZC_PROJECT_TOKEN_SERVER", "EZC_PROJECT_TOKEN_SERVER"),
|
|
44
|
+
// Legacy single-class token. Deprecated, kept for backwards compat during
|
|
45
|
+
// Phase 1 of the rollout. New code MUST use the split pair above.
|
|
46
|
+
EZC_PROJECT_TOKEN_LEGACY: getEnv("VITE_EZC_PROJECT_TOKEN", "NEXT_PUBLIC_EZC_PROJECT_TOKEN"),
|
|
47
|
+
S3_BUCKET: getEnv("VITE_S3_BUCKET", "S3_BUCKET"),
|
|
48
|
+
CLOUDINARY_URL: getEnv("VITE_CLOUDINARY_URL", "CLOUDINARY_URL"),
|
|
49
|
+
STORAGE_BUCKET_PUBLIC: getEnv("VITE_STORAGE_BUCKET_PUBLIC", "NEXT_PUBLIC_STORAGE_BUCKET_PUBLIC"),
|
|
50
|
+
STORAGE_BUCKET_PRIVATE: getEnv("VITE_STORAGE_BUCKET_PRIVATE", "NEXT_PUBLIC_STORAGE_BUCKET_PRIVATE")
|
|
51
|
+
};
|
|
52
|
+
var features = {
|
|
53
|
+
auth: Boolean(
|
|
54
|
+
env.SUPABASE_URL && env.SUPABASE_ANON_KEY || env.EZCODER_AUTH_URL && env.EZCODER_AUTH_ANON_KEY
|
|
55
|
+
),
|
|
56
|
+
payments: Boolean(env.STRIPE_PUBLISHABLE_KEY),
|
|
57
|
+
analytics: Boolean(env.EZCODER_API_URL && env.EZC_PROJECT_ID),
|
|
58
|
+
storage: Boolean(env.SUPABASE_URL || env.EZCODER_AUTH_URL || env.S3_BUCKET || env.CLOUDINARY_URL),
|
|
59
|
+
database: Boolean(
|
|
60
|
+
(env.EZCODER_AUTH_URL || env.SUPABASE_URL) && env.EZC_PROJECT_ID
|
|
61
|
+
)
|
|
62
|
+
};
|
|
63
|
+
function isFeatureConfigured(feature) {
|
|
64
|
+
return features[feature];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export {
|
|
68
|
+
env,
|
|
69
|
+
features,
|
|
70
|
+
isFeatureConfigured
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=chunk-LIUE7M7K.js.map
|
|
@@ -0,0 +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 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\nexport const features = {\r\n auth: Boolean(\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,EAC/F,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;AAEO,IAAM,WAAW;AAAA,EACtB,MAAM;AAAA,IACH,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":[]}
|