@ezcoder.dev/sdk 1.0.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.
Files changed (53) hide show
  1. package/dist/DatabaseProvider-DalP-KHC.d.ts +167 -0
  2. package/dist/analytics/index.d.ts +22 -1
  3. package/dist/analytics/index.js +79 -4
  4. package/dist/analytics/index.js.map +1 -1
  5. package/dist/animation/index.js.map +1 -1
  6. package/dist/auth/index.d.ts +2 -1
  7. package/dist/auth/index.js +25 -6
  8. package/dist/auth/index.js.map +1 -1
  9. package/dist/chunk-CQKYANAW.js +44 -0
  10. package/dist/chunk-CQKYANAW.js.map +1 -0
  11. package/dist/{chunk-5XIZHBKE.js → chunk-HJ2EIZ4S.js} +23 -6
  12. package/dist/chunk-HJ2EIZ4S.js.map +1 -0
  13. package/dist/{chunk-G7XDUN3Z.js → chunk-I2YGB7Z6.js} +24 -44
  14. package/dist/chunk-I2YGB7Z6.js.map +1 -0
  15. package/dist/chunk-LIUE7M7K.js +72 -0
  16. package/dist/chunk-LIUE7M7K.js.map +1 -0
  17. package/dist/{chunk-YNDCD53D.js → chunk-QHB7LGCA.js} +123 -16
  18. package/dist/chunk-QHB7LGCA.js.map +1 -0
  19. package/dist/chunk-R4MDAYFO.js +642 -0
  20. package/dist/chunk-R4MDAYFO.js.map +1 -0
  21. package/dist/cms/index.js +4 -2
  22. package/dist/cms/index.js.map +1 -1
  23. package/dist/cron/index.d.ts +32 -0
  24. package/dist/cron/index.js +63 -0
  25. package/dist/cron/index.js.map +1 -0
  26. package/dist/database/index.d.ts +37 -0
  27. package/dist/database/index.js +32 -0
  28. package/dist/database/index.js.map +1 -0
  29. package/dist/email/index.d.ts +29 -0
  30. package/dist/email/index.js +60 -0
  31. package/dist/email/index.js.map +1 -0
  32. package/dist/errors/index.js.map +1 -1
  33. package/dist/index.d.ts +176 -3
  34. package/dist/index.js +270 -6
  35. package/dist/index.js.map +1 -1
  36. package/dist/notifications/index.d.ts +35 -1
  37. package/dist/notifications/index.js +61 -4
  38. package/dist/notifications/index.js.map +1 -1
  39. package/dist/payments/index.d.ts +11 -3
  40. package/dist/payments/index.js +101 -7
  41. package/dist/payments/index.js.map +1 -1
  42. package/dist/roles/index.js +6 -4
  43. package/dist/roles/index.js.map +1 -1
  44. package/dist/seo/index.js.map +1 -1
  45. package/dist/server/index.js.map +1 -1
  46. package/dist/storage/index.d.ts +1 -1
  47. package/dist/storage/index.js +18 -9
  48. package/dist/storage/index.js.map +1 -1
  49. package/dist/{types-DtY5lp3P.d.ts → types-1uP3V_pe.d.ts} +5 -0
  50. package/package.json +120 -105
  51. package/dist/chunk-5XIZHBKE.js.map +0 -1
  52. package/dist/chunk-G7XDUN3Z.js.map +0 -1
  53. package/dist/chunk-YNDCD53D.js.map +0 -1
@@ -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-G7XDUN3Z.js";
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);
@@ -76,11 +76,17 @@ var stripePost = async (endpoint, body) => {
76
76
  if (!env.EZCODER_API_URL) {
77
77
  return { success: false, error: "Platform not configured" };
78
78
  }
79
+ if (!env.EZC_SECRET_KEY) {
80
+ return {
81
+ success: false,
82
+ error: "Payment configuration incomplete. The site owner needs to redeploy from EzCoder to enable checkout."
83
+ };
84
+ }
79
85
  try {
80
- const headers = { "Content-Type": "application/json" };
81
- if (env.EZC_SECRET_KEY) {
82
- headers["Authorization"] = `Bearer ${env.EZC_SECRET_KEY}`;
83
- }
86
+ const headers = {
87
+ "Content-Type": "application/json",
88
+ "Authorization": `Bearer ${env.EZC_SECRET_KEY}`
89
+ };
84
90
  const response = await fetch(`${env.EZCODER_API_URL}${endpoint}`, {
85
91
  method: "POST",
86
92
  headers,
@@ -214,6 +220,12 @@ var ezcoder = {
214
220
  window.location.href = result.url;
215
221
  }
216
222
  return result;
223
+ },
224
+ getInvoices: async (customerId, options = {}) => {
225
+ const params = new URLSearchParams();
226
+ params.set("customer_id", customerId);
227
+ if (options.limit) params.set("limit", String(options.limit));
228
+ return stripeGet(`/api/stripe/invoices?${params.toString()}`);
217
229
  }
218
230
  },
219
231
  users: {
@@ -363,10 +375,15 @@ if (typeof window !== "undefined") {
363
375
  setupErrorTracking();
364
376
  }, 100);
365
377
  }
378
+ if (env.EZCODER_API_URL && !env.EZC_SECRET_KEY) {
379
+ console.warn(
380
+ "[EzCoder SDK] EZCODER_SECRET_KEY is not set \u2014 Stripe checkout and authenticated API calls will fail. Redeploy your project from the EzCoder editor to auto-provision keys."
381
+ );
382
+ }
366
383
  }
367
384
 
368
385
  export {
369
386
  ezcoder,
370
387
  ezcoderAuthIntegration
371
388
  };
372
- //# sourceMappingURL=chunk-5XIZHBKE.js.map
389
+ //# sourceMappingURL=chunk-HJ2EIZ4S.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/platform.ts"],"sourcesContent":["import { env } from './config';\r\nimport type { AnalyticsResult, CheckoutOptions, EzcoderClient, AuthIntegration, AuthUser } from './types';\r\n\r\nconst isConfigured = (): boolean => Boolean(env.EZCODER_API_URL && env.EZC_PROJECT_ID);\r\n\r\nfunction getSessionId(): string {\r\n if (typeof sessionStorage === 'undefined') return 'server';\r\n let sessionId = sessionStorage.getItem('ezcoder_session_id');\r\n if (!sessionId) {\r\n sessionId = `sess_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\r\n sessionStorage.setItem('ezcoder_session_id', sessionId);\r\n }\r\n return sessionId;\r\n}\r\n\r\nfunction getVisitorId(): string {\r\n if (typeof localStorage === 'undefined') return 'server';\r\n let visitorId = localStorage.getItem('ezcoder_visitor_id');\r\n if (!visitorId) {\r\n visitorId = `vis_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\r\n localStorage.setItem('ezcoder_visitor_id', visitorId);\r\n }\r\n return visitorId;\r\n}\r\n\r\nlet pageEntryTime: number = typeof window !== 'undefined' ? Date.now() : 0;\r\nlet currentPath: string = typeof window !== 'undefined' ? window.location.pathname : '/';\r\nlet maxScrollDepth: number = 0;\r\n\r\nconst trackPageEntry = (): void => {\r\n pageEntryTime = Date.now();\r\n currentPath = window.location.pathname;\r\n maxScrollDepth = 0;\r\n};\r\n\r\nconst getTimeOnPage = (): number => Date.now() - pageEntryTime;\r\n\r\nconst throttle = <T extends (...args: never[]) => void>(fn: T, wait: number): ((...args: Parameters<T>) => void) => {\r\n let lastTime = 0;\r\n return (...args: Parameters<T>) => {\r\n const now = Date.now();\r\n if (now - lastTime >= wait) {\r\n lastTime = now;\r\n fn(...args);\r\n }\r\n };\r\n};\r\n\r\nconst trackScrollDepth = (): void => {\r\n if (typeof window === 'undefined') return;\r\n const scrollTop = window.scrollY;\r\n const docHeight = document.documentElement.scrollHeight - window.innerHeight;\r\n if (docHeight > 0) {\r\n const scrollPercent = Math.round((scrollTop / docHeight) * 100);\r\n if (scrollPercent > maxScrollDepth) {\r\n maxScrollDepth = Math.min(scrollPercent, 100);\r\n }\r\n }\r\n};\r\n\r\nconst analyticsPost = async (endpoint: string, body: Record<string, unknown>): Promise<AnalyticsResult> => {\r\n if (!isConfigured()) {\r\n return { success: false, error: 'Platform not configured' };\r\n }\r\n\r\n try {\r\n const response = await fetch(`${env.EZCODER_API_URL}${endpoint}`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.text();\r\n return { success: false, error };\r\n }\r\n\r\n return await response.json();\r\n } catch (error: unknown) {\r\n const message = error instanceof Error ? error.message : 'Unknown error';\r\n return { success: false, error: message };\r\n }\r\n};\r\n\r\nconst stripePost = async (endpoint: string, body: Record<string, unknown>): Promise<AnalyticsResult & Record<string, unknown>> => {\r\n if (!env.EZCODER_API_URL) {\r\n return { success: false, error: 'Platform not configured' };\r\n }\r\n\r\n if (!env.EZC_SECRET_KEY) {\r\n return {\r\n success: false,\r\n error: 'Payment configuration incomplete. The site owner needs to redeploy from EzCoder to enable checkout.',\r\n };\r\n }\r\n\r\n try {\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${env.EZC_SECRET_KEY}`,\r\n };\r\n\r\n const response = await fetch(`${env.EZCODER_API_URL}${endpoint}`, {\r\n method: 'POST',\r\n headers,\r\n body: JSON.stringify(body),\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.text();\r\n return { success: false, error };\r\n }\r\n\r\n return await response.json();\r\n } catch (error: unknown) {\r\n const message = error instanceof Error ? error.message : 'Unknown error';\r\n return { success: false, error: message };\r\n }\r\n};\r\n\r\nconst stripeGet = async (endpoint: string): Promise<AnalyticsResult & Record<string, unknown>> => {\r\n if (!env.EZCODER_API_URL) {\r\n return { success: false, error: 'Platform not configured' };\r\n }\r\n\r\n try {\r\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\r\n if (env.EZC_SECRET_KEY) {\r\n headers['Authorization'] = `Bearer ${env.EZC_SECRET_KEY}`;\r\n }\r\n\r\n const response = await fetch(`${env.EZCODER_API_URL}${endpoint}`, {\r\n method: 'GET',\r\n headers,\r\n });\r\n\r\n if (!response.ok) {\r\n const error = await response.text();\r\n return { success: false, error };\r\n }\r\n\r\n return await response.json();\r\n } catch (error: unknown) {\r\n const message = error instanceof Error ? error.message : 'Unknown error';\r\n return { success: false, error: message };\r\n }\r\n};\r\n\r\nconst sendPageExit = (): void => {\r\n if (!isConfigured() || typeof navigator === 'undefined') return;\r\n\r\n const payload = JSON.stringify({\r\n type: 'page_exit',\r\n projectId: env.EZC_PROJECT_ID,\r\n sessionId: getSessionId(),\r\n visitorId: getVisitorId(),\r\n pathname: currentPath,\r\n timeOnPage: getTimeOnPage(),\r\n scrollDepth: maxScrollDepth,\r\n timestamp: new Date().toISOString(),\r\n });\r\n\r\n if (navigator.sendBeacon) {\r\n navigator.sendBeacon(`${env.EZCODER_API_URL}/api/analytics/collect`, payload);\r\n }\r\n};\r\n\r\nexport const ezcoder: EzcoderClient = {\r\n isConfigured,\r\n\r\n analytics: {\r\n track: (eventType: string, properties: Record<string, unknown> = {}) => {\r\n return analyticsPost('/api/analytics/collect', {\r\n type: eventType,\r\n projectId: env.EZC_PROJECT_ID,\r\n sessionId: getSessionId(),\r\n visitorId: getVisitorId(),\r\n url: typeof window !== 'undefined' ? window.location.href : '',\r\n pathname: typeof window !== 'undefined' ? window.location.pathname : '/',\r\n referrer: typeof document !== 'undefined' ? document.referrer : '',\r\n userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : '',\r\n screenResolution: typeof window !== 'undefined'\r\n ? `${window.screen.width}x${window.screen.height}`\r\n : '',\r\n viewport: typeof window !== 'undefined'\r\n ? `${window.innerWidth}x${window.innerHeight}`\r\n : '',\r\n timestamp: new Date().toISOString(),\r\n metadata: properties,\r\n });\r\n },\r\n\r\n pageView: (path?: string) => {\r\n trackPageEntry();\r\n return ezcoder.analytics.track('page_view', {\r\n path: path || (typeof window !== 'undefined' ? window.location.pathname : '/'),\r\n title: typeof document !== 'undefined' ? document.title : '',\r\n });\r\n },\r\n\r\n identify: (userId: string, traits: Record<string, unknown> = {}) => {\r\n return ezcoder.analytics.track('identify', { userId, ...traits });\r\n },\r\n\r\n error: (message: string, context: Record<string, unknown> = {}) => {\r\n return ezcoder.analytics.track('error', {\r\n message,\r\n ...context,\r\n stack: (context.stack as string) || new Error().stack,\r\n });\r\n },\r\n },\r\n\r\n stripe: {\r\n createCheckout: async (priceId: string, options: CheckoutOptions = {}) => {\r\n const result = await stripePost('/api/stripe/create-checkout', {\r\n priceId,\r\n projectId: env.EZC_PROJECT_ID,\r\n successUrl: options.successUrl || `${typeof window !== 'undefined' ? window.location.origin : ''}/payment/success`,\r\n cancelUrl: options.cancelUrl || `${typeof window !== 'undefined' ? window.location.origin : ''}/payment/cancel`,\r\n customerEmail: options.customerEmail,\r\n quantity: options.quantity || 1,\r\n });\r\n\r\n if (result.url && options.redirect !== false && typeof window !== 'undefined') {\r\n window.location.href = result.url as string;\r\n }\r\n\r\n return result;\r\n },\r\n\r\n getProducts: async () => {\r\n return { products: [], message: 'Products managed via EzCoder dashboard' };\r\n },\r\n\r\n verifySession: async (sessionId: string) => {\r\n if (!sessionId) {\r\n return { success: false, error: 'Session ID is required' };\r\n }\r\n return stripeGet(`/api/stripe/verify-session?session_id=${encodeURIComponent(sessionId)}`);\r\n },\r\n\r\n getCustomerStatus: async (options: { customerId?: string; email?: string } = {}) => {\r\n const params = new URLSearchParams();\r\n if (options.customerId) params.set('customer_id', options.customerId);\r\n if (options.email) params.set('email', options.email);\r\n\r\n if (!options.customerId && !options.email) {\r\n return { success: false, error: 'Either customerId or email is required' };\r\n }\r\n\r\n return stripeGet(`/api/stripe/customer-status?${params.toString()}`);\r\n },\r\n\r\n createPortalSession: async (customerId: string, options: { returnUrl?: string; redirect?: boolean } = {}) => {\r\n const result = await stripePost('/api/stripe/customer-portal', {\r\n customerId,\r\n returnUrl: options.returnUrl || window.location.href,\r\n });\r\n\r\n if (result.url && options.redirect !== false && typeof window !== 'undefined') {\r\n window.location.href = result.url as string;\r\n }\r\n\r\n return result;\r\n },\r\n\r\n getInvoices: async (customerId: string, options: { limit?: number } = {}) => {\r\n const params = new URLSearchParams();\r\n params.set('customer_id', customerId);\r\n if (options.limit) params.set('limit', String(options.limit));\r\n return stripeGet(`/api/stripe/invoices?${params.toString()}`);\r\n },\r\n },\r\n\r\n users: {\r\n trackSignup: (userId: string, email: string, role: string | null = null) => {\r\n return ezcoder.analytics.track('user_signup', { userId, email, role, signupMethod: 'email' });\r\n },\r\n\r\n trackLogin: (userId: string) => {\r\n return ezcoder.analytics.track('user_login', { userId });\r\n },\r\n\r\n trackLogout: (userId: string) => {\r\n return ezcoder.analytics.track('user_logout', { userId });\r\n },\r\n\r\n trackRoleChange: (userId: string, oldRole: string, newRole: string) => {\r\n return ezcoder.analytics.track('role_change', { userId, oldRole, newRole });\r\n },\r\n },\r\n};\r\n\r\nexport const ezcoderAuthIntegration: AuthIntegration = {\r\n onLogin: (user: AuthUser) => {\r\n if (user?.id) {\r\n ezcoder.analytics.identify(user.id, {\r\n email: user.email,\r\n name: user.user_metadata?.full_name,\r\n });\r\n ezcoder.users.trackLogin(user.id);\r\n }\r\n },\r\n onSignup: (user: AuthUser) => {\r\n if (user?.id) {\r\n ezcoder.analytics.identify(user.id, { email: user.email });\r\n ezcoder.users.trackSignup(user.id, user.email || '');\r\n }\r\n },\r\n onLogout: (userId: string) => {\r\n if (userId) {\r\n ezcoder.users.trackLogout(userId);\r\n }\r\n },\r\n};\r\n\r\ninterface LayoutShift extends PerformanceEntry {\r\n hadRecentInput: boolean;\r\n value: number;\r\n}\r\n\r\ninterface PerformanceEventTiming extends PerformanceEntry {\r\n processingStart: number;\r\n}\r\n\r\nconst trackWebVitals = (): void => {\r\n if (typeof window === 'undefined' || !('PerformanceObserver' in window)) return;\r\n\r\n try {\r\n new PerformanceObserver((list) => {\r\n const entries = list.getEntries();\r\n const lastEntry = entries[entries.length - 1];\r\n if (lastEntry) {\r\n ezcoder.analytics.track('web_vital', {\r\n metric: 'LCP',\r\n value: Math.round(lastEntry.startTime),\r\n pathname: window.location.pathname,\r\n });\r\n }\r\n }).observe({ type: 'largest-contentful-paint', buffered: true });\r\n } catch { /* LCP not supported */ }\r\n\r\n try {\r\n new PerformanceObserver((list) => {\r\n const entry = list.getEntries()[0] as PerformanceEventTiming;\r\n if (entry) {\r\n ezcoder.analytics.track('web_vital', {\r\n metric: 'FID',\r\n value: Math.round(entry.processingStart - entry.startTime),\r\n pathname: window.location.pathname,\r\n });\r\n }\r\n }).observe({ type: 'first-input', buffered: true });\r\n } catch { /* FID not supported */ }\r\n\r\n try {\r\n let clsValue = 0;\r\n new PerformanceObserver((list) => {\r\n for (const entry of list.getEntries()) {\r\n if (!(entry as LayoutShift).hadRecentInput) {\r\n clsValue += (entry as LayoutShift).value;\r\n }\r\n }\r\n }).observe({ type: 'layout-shift', buffered: true });\r\n\r\n document.addEventListener('visibilitychange', () => {\r\n if (document.hidden && clsValue > 0) {\r\n ezcoder.analytics.track('web_vital', {\r\n metric: 'CLS',\r\n value: Math.round(clsValue * 1000) / 1000,\r\n pathname: window.location.pathname,\r\n });\r\n }\r\n });\r\n } catch { /* CLS not supported */ }\r\n};\r\n\r\nconst setupErrorTracking = (): void => {\r\n if (typeof window === 'undefined') return;\r\n\r\n window.onerror = (message, source, lineno, colno, error) => {\r\n ezcoder.analytics.track('js_error', {\r\n message: String(message),\r\n source,\r\n lineno,\r\n colno,\r\n stack: error?.stack,\r\n pathname: window.location.pathname,\r\n });\r\n return false;\r\n };\r\n\r\n window.addEventListener('unhandledrejection', (event: PromiseRejectionEvent) => {\r\n ezcoder.analytics.track('promise_rejection', {\r\n reason: event.reason?.message || String(event.reason),\r\n stack: event.reason?.stack,\r\n pathname: window.location.pathname,\r\n });\r\n });\r\n};\r\n\r\nif (typeof window !== 'undefined') {\r\n window.addEventListener('scroll', throttle(trackScrollDepth, 500), { passive: true });\r\n window.addEventListener('beforeunload', sendPageExit);\r\n\r\n document.addEventListener('visibilitychange', () => {\r\n if (!isConfigured()) return;\r\n if (document.hidden) {\r\n ezcoder.analytics.track('page_blur', {\r\n timeOnPage: getTimeOnPage(),\r\n scrollDepth: maxScrollDepth,\r\n pathname: currentPath,\r\n });\r\n } else {\r\n ezcoder.analytics.track('page_focus', { pathname: window.location.pathname });\r\n }\r\n });\r\n\r\n const originalPushState = history.pushState;\r\n history.pushState = function (...args: Parameters<typeof history.pushState>) {\r\n sendPageExit();\r\n originalPushState.apply(this, args);\r\n trackPageEntry();\r\n if (isConfigured()) ezcoder.analytics.pageView();\r\n };\r\n\r\n const originalReplaceState = history.replaceState;\r\n history.replaceState = function (...args: Parameters<typeof history.replaceState>) {\r\n originalReplaceState.apply(this, args);\r\n trackPageEntry();\r\n };\r\n\r\n window.addEventListener('popstate', () => {\r\n sendPageExit();\r\n trackPageEntry();\r\n if (isConfigured()) ezcoder.analytics.pageView();\r\n });\r\n\r\n if (isConfigured()) {\r\n setTimeout(() => {\r\n ezcoder.analytics.pageView();\r\n trackWebVitals();\r\n setupErrorTracking();\r\n }, 100);\r\n }\r\n\r\n if (env.EZCODER_API_URL && !env.EZC_SECRET_KEY) {\r\n console.warn(\r\n '[EzCoder SDK] EZCODER_SECRET_KEY is not set — Stripe checkout and authenticated API calls will fail. ' +\r\n 'Redeploy your project from the EzCoder editor to auto-provision keys.'\r\n );\r\n }\r\n}\r\n"],"mappings":"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","names":[]}
@@ -1,39 +1,6 @@
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
- STRIPE_PUBLISHABLE_KEY: getEnv("VITE_STRIPE_PUBLISHABLE_KEY", "NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY"),
21
- EZC_PROJECT_ID: getEnv("VITE_EZC_PROJECT_ID", "NEXT_PUBLIC_EZC_PROJECT_ID"),
22
- EZCODER_API_URL: getEnv("VITE_EZCODER_API_URL", "NEXT_PUBLIC_EZCODER_API_URL"),
23
- EZC_SECRET_KEY: getEnv("VITE_EZC_SECRET_KEY", "EZC_SECRET_KEY"),
24
- S3_BUCKET: getEnv("VITE_S3_BUCKET", "S3_BUCKET"),
25
- CLOUDINARY_URL: getEnv("VITE_CLOUDINARY_URL", "CLOUDINARY_URL")
26
- };
27
- var features = {
28
- auth: Boolean(env.SUPABASE_URL && env.SUPABASE_ANON_KEY),
29
- payments: Boolean(env.STRIPE_PUBLISHABLE_KEY),
30
- analytics: Boolean(env.EZCODER_API_URL && env.EZC_PROJECT_ID),
31
- storage: Boolean(env.SUPABASE_URL || env.S3_BUCKET || env.CLOUDINARY_URL),
32
- database: Boolean(env.SUPABASE_URL)
33
- };
34
- function isFeatureConfigured(feature) {
35
- return features[feature];
36
- }
1
+ import {
2
+ env
3
+ } from "./chunk-LIUE7M7K.js";
37
4
 
38
5
  // src/core/supabase.ts
39
6
  import { createClient } from "@supabase/supabase-js";
@@ -122,20 +89,33 @@ function createStubClient() {
122
89
  }
123
90
  };
124
91
  }
125
- var supabase = features.auth ? createClient(env.SUPABASE_URL, env.SUPABASE_ANON_KEY, {
92
+ var authUrl = env.EZCODER_AUTH_URL || env.SUPABASE_URL;
93
+ var authKey = env.EZCODER_AUTH_ANON_KEY || env.SUPABASE_ANON_KEY;
94
+ var isConfigured = Boolean(authUrl && authKey);
95
+ if (!isConfigured && typeof window !== "undefined") {
96
+ console.warn(
97
+ "[EzCoder SDK] Supabase not configured \u2014 auth, database, and storage features are disabled. Set VITE_EZCODER_AUTH_URL and VITE_EZCODER_AUTH_ANON_KEY (or NEXT_PUBLIC_ equivalents) to enable."
98
+ );
99
+ }
100
+ var supabase = isConfigured ? createClient(authUrl, authKey, {
126
101
  auth: {
127
102
  autoRefreshToken: true,
128
103
  persistSession: true,
129
- detectSessionInUrl: true
130
- }
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 } } } : {}
131
114
  }) : createStubClient();
132
- var isSupabaseConfigured = features.auth;
115
+ var isSupabaseConfigured = isConfigured;
133
116
 
134
117
  export {
135
- env,
136
- features,
137
- isFeatureConfigured,
138
118
  supabase,
139
119
  isSupabaseConfigured
140
120
  };
141
- //# sourceMappingURL=chunk-G7XDUN3Z.js.map
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":[]}
@@ -1,16 +1,19 @@
1
1
  import {
2
2
  ezcoder,
3
3
  ezcoderAuthIntegration
4
- } from "./chunk-5XIZHBKE.js";
4
+ } from "./chunk-HJ2EIZ4S.js";
5
5
  import {
6
6
  isSupabaseConfigured,
7
7
  supabase
8
- } from "./chunk-G7XDUN3Z.js";
8
+ } from "./chunk-I2YGB7Z6.js";
9
+ import {
10
+ env
11
+ } from "./chunk-LIUE7M7K.js";
9
12
 
10
13
  // src/auth/AuthProvider.tsx
11
14
  import { createContext, useContext, useState, useEffect, useCallback, useRef } from "react";
12
15
  import { jsx } from "react/jsx-runtime";
13
- var NOT_CONFIGURED_MSG = "Authentication is not configured. Connect a Supabase database in Settings \u2192 Databases to enable login and signup.";
16
+ var NOT_CONFIGURED_MSG = "Authentication is not configured. Ensure EzCoder platform credentials are injected, or connect your own Supabase database in Settings \u2192 Databases.";
14
17
  function notConfiguredError() {
15
18
  return new Error(NOT_CONFIGURED_MSG);
16
19
  }
@@ -25,6 +28,7 @@ var AuthContext = createContext({
25
28
  signInWithProvider: async () => ({ data: null, error: null }),
26
29
  signOut: async () => ({ error: null }),
27
30
  resetPassword: async () => ({ data: null, error: null }),
31
+ updatePassword: async () => ({ data: null, error: null }),
28
32
  updateProfile: async () => ({ data: null, error: null }),
29
33
  refetchProfile: async () => null
30
34
  });
@@ -37,7 +41,11 @@ function AuthProvider({ children }) {
37
41
  const fetchProfile = useCallback(async (userId) => {
38
42
  if (!userId) return null;
39
43
  try {
40
- const result = await supabase.from("user_profiles").select("*").eq("id", userId).single();
44
+ let query = supabase.from("user_profiles").select("*").eq("id", userId);
45
+ if (env.EZC_PROJECT_ID) {
46
+ query = query.eq("project_id", env.EZC_PROJECT_ID);
47
+ }
48
+ const result = await query.single();
41
49
  const { data, error } = result || { data: null, error: null };
42
50
  if (error) {
43
51
  return null;
@@ -48,12 +56,37 @@ function AuthProvider({ children }) {
48
56
  return null;
49
57
  }
50
58
  }, []);
59
+ const bindProjectIfNeeded = useCallback(async (currentUser) => {
60
+ if (!currentUser || !env.EZC_PROJECT_ID || !env.EZCODER_API_URL) return;
61
+ const appMeta = currentUser.app_metadata;
62
+ if (appMeta?.bound_project_id) return;
63
+ try {
64
+ const { data } = await supabase.auth.getSession();
65
+ const token = data?.session?.access_token;
66
+ if (!token) return;
67
+ const res = await fetch(`${env.EZCODER_API_URL.replace(/\/$/, "")}/api/managed-auth/bind`, {
68
+ method: "POST",
69
+ headers: {
70
+ "Content-Type": "application/json",
71
+ ...env.EZC_PROJECT_TOKEN_PUBLIC ? { Authorization: `Bearer ${env.EZC_PROJECT_TOKEN_PUBLIC}` } : {},
72
+ "X-EZC-User-Token": token
73
+ },
74
+ body: JSON.stringify({ projectId: env.EZC_PROJECT_ID })
75
+ });
76
+ const j = await res.json().catch(() => ({}));
77
+ if (j?.changed) {
78
+ await supabase.auth.refreshSession();
79
+ }
80
+ } catch {
81
+ }
82
+ }, []);
51
83
  useEffect(() => {
52
84
  supabase.auth.getSession().then(async ({ data: { session: initialSession } }) => {
53
85
  setSession(initialSession);
54
86
  setUser(initialSession?.user ?? null);
55
87
  if (initialSession?.user) {
56
88
  await fetchProfile(initialSession.user.id);
89
+ bindProjectIfNeeded(initialSession.user);
57
90
  }
58
91
  setLoading(false);
59
92
  });
@@ -64,6 +97,7 @@ function AuthProvider({ children }) {
64
97
  setUser(currentSession?.user ?? null);
65
98
  if (event === "SIGNED_IN" && currentSession?.user) {
66
99
  await fetchProfile(currentSession.user.id);
100
+ bindProjectIfNeeded(currentSession.user);
67
101
  ezcoderAuthIntegration.onLogin(currentSession.user);
68
102
  previousUserIdRef.current = currentSession.user.id;
69
103
  } else if (event === "SIGNED_OUT") {
@@ -79,30 +113,72 @@ function AuthProvider({ children }) {
79
113
  });
80
114
  }
81
115
  });
82
- return () => subscription.unsubscribe();
83
- }, [fetchProfile]);
116
+ const refreshFromExternal = () => {
117
+ supabase.auth.getSession().then(({ data }) => {
118
+ const s = data?.session ?? null;
119
+ setSession(s);
120
+ setUser(s?.user ?? null);
121
+ if (s?.user) {
122
+ fetchProfile(s.user.id);
123
+ bindProjectIfNeeded(s.user);
124
+ }
125
+ });
126
+ };
127
+ const onMsg = (e) => {
128
+ if (e?.data?.type === "ezc-auth-complete") refreshFromExternal();
129
+ };
130
+ const onStorage = (e) => {
131
+ if (e.key && /auth-token/.test(e.key)) refreshFromExternal();
132
+ };
133
+ if (typeof window !== "undefined") {
134
+ window.addEventListener("message", onMsg);
135
+ window.addEventListener("storage", onStorage);
136
+ }
137
+ return () => {
138
+ subscription.unsubscribe();
139
+ if (typeof window !== "undefined") {
140
+ window.removeEventListener("message", onMsg);
141
+ window.removeEventListener("storage", onStorage);
142
+ }
143
+ };
144
+ }, [fetchProfile, bindProjectIfNeeded]);
84
145
  const signUp = useCallback(async (email, password, options = {}) => {
85
146
  if (!isSupabaseConfigured) {
86
147
  return { data: null, error: notConfiguredError() };
87
148
  }
88
149
  const { metadata = {} } = options;
89
150
  try {
151
+ const signUpMetadata = { ...metadata };
152
+ if (env.EZC_PROJECT_ID) {
153
+ signUpMetadata.project_id = env.EZC_PROJECT_ID;
154
+ signUpMetadata.bound_project_id = env.EZC_PROJECT_ID;
155
+ }
90
156
  const result = await supabase.auth.signUp({
91
157
  email,
92
158
  password,
93
- options: { data: metadata }
159
+ options: { data: signUpMetadata }
94
160
  });
95
161
  const { data, error } = result || { data: null, error: new Error("Sign up failed") };
96
162
  if (error) {
97
163
  return { data: null, error };
98
164
  }
99
165
  if (data?.user) {
166
+ const profileData = {
167
+ id: data.user.id,
168
+ email
169
+ };
100
170
  if (metadata.display_name) {
101
- await supabase.from("user_profiles").upsert({
102
- id: data.user.id,
103
- email,
104
- display_name: metadata.display_name
105
- });
171
+ profileData.display_name = metadata.display_name;
172
+ }
173
+ if (env.EZC_PROJECT_ID) {
174
+ profileData.project_id = env.EZC_PROJECT_ID;
175
+ }
176
+ if (metadata.display_name || env.EZC_PROJECT_ID) {
177
+ await supabase.from("user_profiles").upsert(profileData);
178
+ }
179
+ try {
180
+ await supabase.rpc("assign_default_role", { user_uuid: data.user.id });
181
+ } catch {
106
182
  }
107
183
  ezcoderAuthIntegration.onSignup(data.user);
108
184
  }
@@ -128,10 +204,24 @@ function AuthProvider({ children }) {
128
204
  return { data: null, error: notConfiguredError() };
129
205
  }
130
206
  try {
207
+ const provider2 = provider;
208
+ const origin = typeof window !== "undefined" ? window.location.origin : "";
209
+ const framed = typeof window !== "undefined" && window.self !== window.top;
210
+ if (framed && typeof window !== "undefined") {
211
+ const redirectTo = options.redirectTo || (origin ? `${origin}/auth/callback` : "");
212
+ const result2 = await supabase.auth.signInWithOAuth({
213
+ provider: provider2,
214
+ options: { redirectTo, skipBrowserRedirect: true, ...options }
215
+ });
216
+ if (result2?.error) return { data: null, error: result2.error };
217
+ const url = result2?.data?.url;
218
+ if (url) window.open(url, "ezc-auth", "popup,width=500,height=680");
219
+ return { data: result2?.data ?? null, error: null };
220
+ }
131
221
  const result = await supabase.auth.signInWithOAuth({
132
- provider,
222
+ provider: provider2,
133
223
  options: {
134
- redirectTo: options.redirectTo || (typeof window !== "undefined" ? window.location.origin : ""),
224
+ redirectTo: options.redirectTo || origin,
135
225
  ...options
136
226
  }
137
227
  });
@@ -165,13 +255,29 @@ function AuthProvider({ children }) {
165
255
  return { data: null, error: err instanceof Error ? err : new Error("Password reset failed") };
166
256
  }
167
257
  }, []);
258
+ const updatePassword = useCallback(async (newPassword) => {
259
+ if (!isSupabaseConfigured) {
260
+ return { data: null, error: notConfiguredError() };
261
+ }
262
+ try {
263
+ const result = await supabase.auth.updateUser({ password: newPassword });
264
+ const { data, error } = result || { data: null, error: new Error("Password update failed") };
265
+ return { data, error };
266
+ } catch (err) {
267
+ return { data: null, error: err instanceof Error ? err : new Error("Password update failed") };
268
+ }
269
+ }, []);
168
270
  const updateProfile = useCallback(
169
271
  async (updates) => {
170
272
  if (!user) {
171
273
  return { data: null, error: new Error("Not authenticated") };
172
274
  }
173
275
  try {
174
- const result = await supabase.from("user_profiles").update(updates).eq("id", user.id).select().single();
276
+ let query = supabase.from("user_profiles").update(updates).eq("id", user.id);
277
+ if (env.EZC_PROJECT_ID) {
278
+ query = query.eq("project_id", env.EZC_PROJECT_ID);
279
+ }
280
+ const result = await query.select().single();
175
281
  const { data, error } = result || { data: null, error: null };
176
282
  return { data, error };
177
283
  } catch (err) {
@@ -191,6 +297,7 @@ function AuthProvider({ children }) {
191
297
  signInWithProvider,
192
298
  signOut,
193
299
  resetPassword,
300
+ updatePassword,
194
301
  updateProfile,
195
302
  refetchProfile: fetchProfile
196
303
  };
@@ -209,4 +316,4 @@ export {
209
316
  AuthProvider,
210
317
  useAuth
211
318
  };
212
- //# sourceMappingURL=chunk-YNDCD53D.js.map
319
+ //# sourceMappingURL=chunk-QHB7LGCA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/auth/AuthProvider.tsx"],"sourcesContent":["import { createContext, useContext, useState, useEffect, useCallback, useRef } from 'react';\r\nimport type { User, Session } from '@supabase/supabase-js';\r\nimport { supabase, isSupabaseConfigured } from '../core/supabase';\r\nimport { env } from '../core/config';\r\nimport { ezcoder, ezcoderAuthIntegration } from '../core/platform';\r\nimport type { UserProfile } from '../core/types';\r\n\r\ninterface AuthResult<T = unknown> {\r\n data: T | null;\r\n error: Error | null;\r\n}\r\n\r\ninterface SignUpOptions {\r\n metadata?: Record<string, unknown>;\r\n}\r\n\r\ninterface SignInWithProviderOptions {\r\n redirectTo?: string;\r\n [key: string]: unknown;\r\n}\r\n\r\nexport interface AuthContextType {\r\n user: User | null;\r\n profile: UserProfile | null;\r\n session: Session | null;\r\n loading: boolean;\r\n isConfigured: boolean;\r\n signUp: (email: string, password: string, options?: SignUpOptions) => Promise<AuthResult>;\r\n signIn: (email: string, password: string) => Promise<AuthResult>;\r\n signInWithProvider: (provider: string, options?: SignInWithProviderOptions) => Promise<AuthResult>;\r\n signOut: () => Promise<{ error: Error | null }>;\r\n resetPassword: (email: string) => Promise<AuthResult>;\r\n updatePassword: (newPassword: string) => Promise<AuthResult>;\r\n updateProfile: (updates: Partial<UserProfile>) => Promise<AuthResult>;\r\n refetchProfile: (userId: string) => Promise<UserProfile | null>;\r\n}\r\n\r\nconst NOT_CONFIGURED_MSG = 'Authentication is not configured. Ensure EzCoder platform credentials are injected, or connect your own Supabase database in Settings → Databases.';\r\nfunction notConfiguredError() {\r\n return new Error(NOT_CONFIGURED_MSG);\r\n}\r\n\r\nexport const AuthContext = createContext<AuthContextType>({\r\n user: null,\r\n profile: null,\r\n session: null,\r\n loading: true,\r\n isConfigured: false,\r\n signUp: async () => ({ data: null, error: null }),\r\n signIn: async () => ({ data: null, error: null }),\r\n signInWithProvider: async () => ({ data: null, error: null }),\r\n signOut: async () => ({ error: null }),\r\n resetPassword: async () => ({ data: null, error: null }),\r\n updatePassword: async () => ({ data: null, error: null }),\r\n updateProfile: async () => ({ data: null, error: null }),\r\n refetchProfile: async () => null,\r\n});\r\n\r\nexport function AuthProvider({ children }: { children: React.ReactNode }) {\r\n const [user, setUser] = useState<User | null>(null);\r\n const [profile, setProfile] = useState<UserProfile | null>(null);\r\n const [session, setSession] = useState<Session | null>(null);\r\n const [loading, setLoading] = useState<boolean>(true);\r\n const previousUserIdRef = useRef<string | null>(null);\r\n\r\n const fetchProfile = useCallback(async (userId: string): Promise<UserProfile | null> => {\r\n if (!userId) return null;\r\n\r\n try {\r\n let query = supabase\r\n .from('user_profiles')\r\n .select('*')\r\n .eq('id', userId);\r\n\r\n if (env.EZC_PROJECT_ID) {\r\n query = query.eq('project_id', env.EZC_PROJECT_ID);\r\n }\r\n\r\n const result = await query.single();\r\n\r\n const { data, error } = result || { data: null, error: null };\r\n\r\n if (error) {\r\n return null;\r\n }\r\n\r\n setProfile(data as UserProfile);\r\n return data as UserProfile;\r\n } catch {\r\n return null;\r\n }\r\n }, []);\r\n\r\n // SEC-1: bind the end-user to THIS project server-side (authoritative; app_metadata\r\n // is service-role-only). OAuth users have no signup metadata so the migration-226\r\n // trigger can't bind them — this is what stops migration 227 from locking them out.\r\n // No-ops if already bound. Non-blocking.\r\n const bindProjectIfNeeded = useCallback(async (currentUser: User | null): Promise<void> => {\r\n if (!currentUser || !env.EZC_PROJECT_ID || !env.EZCODER_API_URL) return;\r\n const appMeta = currentUser.app_metadata as Record<string, unknown> | undefined;\r\n if (appMeta?.bound_project_id) return;\r\n try {\r\n const { data } = await supabase.auth.getSession();\r\n const token = data?.session?.access_token;\r\n if (!token) return;\r\n const res = await fetch(`${env.EZCODER_API_URL.replace(/\\/$/, '')}/api/managed-auth/bind`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n ...(env.EZC_PROJECT_TOKEN_PUBLIC ? { Authorization: `Bearer ${env.EZC_PROJECT_TOKEN_PUBLIC}` } : {}),\r\n 'X-EZC-User-Token': token,\r\n },\r\n body: JSON.stringify({ projectId: env.EZC_PROJECT_ID }),\r\n });\r\n const j = await res.json().catch(() => ({}));\r\n if (j?.changed) {\r\n // The new bound_project_id claim only appears after a token refresh.\r\n await supabase.auth.refreshSession();\r\n }\r\n } catch {\r\n // non-blocking — login still works; binding reconciles on next load / via backfill\r\n }\r\n }, []);\r\n\r\n useEffect(() => {\r\n supabase.auth.getSession().then(async ({ data: { session: initialSession } }) => {\r\n setSession(initialSession);\r\n setUser(initialSession?.user ?? null);\r\n\r\n if (initialSession?.user) {\r\n await fetchProfile(initialSession.user.id);\r\n bindProjectIfNeeded(initialSession.user);\r\n }\r\n\r\n setLoading(false);\r\n });\r\n\r\n const {\r\n data: { subscription },\r\n } = supabase.auth.onAuthStateChange(async (event, currentSession) => {\r\n setSession(currentSession);\r\n setUser(currentSession?.user ?? null);\r\n\r\n if (event === 'SIGNED_IN' && currentSession?.user) {\r\n await fetchProfile(currentSession.user.id);\r\n bindProjectIfNeeded(currentSession.user);\r\n ezcoderAuthIntegration.onLogin(currentSession.user);\r\n previousUserIdRef.current = currentSession.user.id;\r\n } else if (event === 'SIGNED_OUT') {\r\n setProfile(null);\r\n if (previousUserIdRef.current) {\r\n ezcoderAuthIntegration.onLogout(previousUserIdRef.current);\r\n previousUserIdRef.current = null;\r\n }\r\n } else if (event === 'USER_UPDATED' && currentSession?.user) {\r\n ezcoder.analytics.identify(currentSession.user.id, {\r\n email: currentSession.user.email,\r\n name: currentSession.user.user_metadata?.full_name,\r\n });\r\n }\r\n });\r\n\r\n // In-editor popup sign-in: the /auth/callback popup postMessages on completion;\r\n // the storage event is a same-origin fallback for the popup's localStorage write.\r\n const refreshFromExternal = () => {\r\n supabase.auth.getSession().then(({ data }) => {\r\n const s = data?.session ?? null;\r\n setSession(s);\r\n setUser(s?.user ?? null);\r\n if (s?.user) { fetchProfile(s.user.id); bindProjectIfNeeded(s.user); }\r\n });\r\n };\r\n const onMsg = (e: MessageEvent) => { if (e?.data?.type === 'ezc-auth-complete') refreshFromExternal(); };\r\n const onStorage = (e: StorageEvent) => { if (e.key && /auth-token/.test(e.key)) refreshFromExternal(); };\r\n if (typeof window !== 'undefined') {\r\n window.addEventListener('message', onMsg);\r\n window.addEventListener('storage', onStorage);\r\n }\r\n\r\n return () => {\r\n subscription.unsubscribe();\r\n if (typeof window !== 'undefined') {\r\n window.removeEventListener('message', onMsg);\r\n window.removeEventListener('storage', onStorage);\r\n }\r\n };\r\n }, [fetchProfile, bindProjectIfNeeded]);\r\n\r\n const signUp = useCallback(async (email: string, password: string, options: SignUpOptions = {}): Promise<AuthResult> => {\r\n if (!isSupabaseConfigured) {\r\n return { data: null, error: notConfiguredError() };\r\n }\r\n const { metadata = {} } = options;\r\n\r\n try {\r\n const signUpMetadata = { ...metadata };\r\n if (env.EZC_PROJECT_ID) {\r\n signUpMetadata.project_id = env.EZC_PROJECT_ID;\r\n signUpMetadata.bound_project_id = env.EZC_PROJECT_ID;\r\n }\r\n\r\n const result = await supabase.auth.signUp({\r\n email,\r\n password,\r\n options: { data: signUpMetadata },\r\n });\r\n\r\n const { data, error } = result || { data: null, error: new Error('Sign up failed') };\r\n\r\n if (error) {\r\n return { data: null, error };\r\n }\r\n\r\n if (data?.user) {\r\n const profileData: Record<string, unknown> = {\r\n id: data.user.id,\r\n email,\r\n };\r\n if (metadata.display_name) {\r\n profileData.display_name = metadata.display_name;\r\n }\r\n if (env.EZC_PROJECT_ID) {\r\n profileData.project_id = env.EZC_PROJECT_ID;\r\n }\r\n if (metadata.display_name || env.EZC_PROJECT_ID) {\r\n await supabase.from('user_profiles').upsert(profileData);\r\n }\r\n try {\r\n await supabase.rpc('assign_default_role', { user_uuid: data.user.id });\r\n } catch {\r\n // Non-blocking — role tables may not exist in all projects\r\n }\r\n ezcoderAuthIntegration.onSignup(data.user);\r\n }\r\n\r\n return { data, error: null };\r\n } catch (err: unknown) {\r\n return { data: null, error: err instanceof Error ? err : new Error('Sign up failed') };\r\n }\r\n }, []);\r\n\r\n const signIn = useCallback(async (email: string, password: string): Promise<AuthResult> => {\r\n if (!isSupabaseConfigured) {\r\n return { data: null, error: notConfiguredError() };\r\n }\r\n try {\r\n const result = await supabase.auth.signInWithPassword({ email, password });\r\n const { data, error } = result || { data: null, error: new Error('Sign in failed') };\r\n return { data, error };\r\n } catch (err: unknown) {\r\n return { data: null, error: err instanceof Error ? err : new Error('Sign in failed') };\r\n }\r\n }, []);\r\n\r\n const signInWithProvider = useCallback(async (provider: string, options: SignInWithProviderOptions = {}): Promise<AuthResult> => {\r\n if (!isSupabaseConfigured) {\r\n return { data: null, error: notConfiguredError() };\r\n }\r\n try {\r\n const provider2 = provider as 'google' | 'github' | 'facebook' | 'apple' | 'twitter';\r\n const origin = typeof window !== 'undefined' ? window.location.origin : '';\r\n const framed = typeof window !== 'undefined' && window.self !== window.top;\r\n\r\n if (framed && typeof window !== 'undefined') {\r\n // Provider login pages refuse to render inside an iframe (X-Frame-Options /\r\n // frame-ancestors), so we cannot do a full-page redirect in the editor preview.\r\n // Open the flow in a popup; the /auth/callback page completes PKCE and\r\n // postMessages back (storage event is the fallback). Land on the callback route.\r\n const redirectTo = options.redirectTo || (origin ? `${origin}/auth/callback` : '');\r\n const result = await supabase.auth.signInWithOAuth({\r\n provider: provider2,\r\n options: { redirectTo, skipBrowserRedirect: true, ...options },\r\n });\r\n if (result?.error) return { data: null, error: result.error };\r\n const url = (result?.data as { url?: string } | null)?.url;\r\n if (url) window.open(url, 'ezc-auth', 'popup,width=500,height=680');\r\n return { data: result?.data ?? null, error: null };\r\n }\r\n\r\n // Standalone (deployed app / own tab): full-page redirect. Default to the app\r\n // origin (root) so apps without a scaffolded callback route still complete via\r\n // detectSessionInUrl; new apps pass /auth/callback explicitly.\r\n const result = await supabase.auth.signInWithOAuth({\r\n provider: provider2,\r\n options: {\r\n redirectTo: options.redirectTo || origin,\r\n ...options,\r\n },\r\n });\r\n const { data, error } = result || { data: null, error: new Error('OAuth sign in failed') };\r\n return { data, error };\r\n } catch (err: unknown) {\r\n return { data: null, error: err instanceof Error ? err : new Error('OAuth sign in failed') };\r\n }\r\n }, []);\r\n\r\n const signOut = useCallback(async (): Promise<{ error: Error | null }> => {\r\n const userId = user?.id;\r\n try {\r\n const result = await supabase.auth.signOut();\r\n const { error } = result || { error: null };\r\n if (!error && userId) {\r\n ezcoder.users.trackLogout(userId);\r\n }\r\n return { error };\r\n } catch (err: unknown) {\r\n return { error: err instanceof Error ? err : new Error('Sign out failed') };\r\n }\r\n }, [user]);\r\n\r\n const resetPassword = useCallback(async (email: string): Promise<AuthResult> => {\r\n try {\r\n const result = await supabase.auth.resetPasswordForEmail(email, {\r\n redirectTo: `${typeof window !== 'undefined' ? window.location.origin : ''}/auth/reset-password`,\r\n });\r\n const { data, error } = result || { data: null, error: new Error('Password reset failed') };\r\n return { data, error };\r\n } catch (err: unknown) {\r\n return { data: null, error: err instanceof Error ? err : new Error('Password reset failed') };\r\n }\r\n }, []);\r\n\r\n // Set a new password. Used on the /auth/reset-password landing page, where the\r\n // recovery link has already established a (recovery) session via detectSessionInUrl.\r\n const updatePassword = useCallback(async (newPassword: string): Promise<AuthResult> => {\r\n if (!isSupabaseConfigured) {\r\n return { data: null, error: notConfiguredError() };\r\n }\r\n try {\r\n const result = await supabase.auth.updateUser({ password: newPassword });\r\n const { data, error } = result || { data: null, error: new Error('Password update failed') };\r\n return { data, error };\r\n } catch (err: unknown) {\r\n return { data: null, error: err instanceof Error ? err : new Error('Password update failed') };\r\n }\r\n }, []);\r\n\r\n const updateProfile = useCallback(\r\n async (updates: Partial<UserProfile>): Promise<AuthResult> => {\r\n if (!user) {\r\n return { data: null, error: new Error('Not authenticated') };\r\n }\r\n try {\r\n let query = supabase\r\n .from('user_profiles')\r\n .update(updates)\r\n .eq('id', user.id);\r\n\r\n if (env.EZC_PROJECT_ID) {\r\n query = query.eq('project_id', env.EZC_PROJECT_ID);\r\n }\r\n\r\n const result = await query.select().single();\r\n const { data, error } = result || { data: null, error: null };\r\n return { data, error };\r\n } catch (err: unknown) {\r\n return { data: null, error: err instanceof Error ? err : new Error('Update failed') };\r\n }\r\n },\r\n [user]\r\n );\r\n\r\n const value: AuthContextType = {\r\n user,\r\n profile,\r\n session,\r\n loading,\r\n isConfigured: isSupabaseConfigured,\r\n signUp,\r\n signIn,\r\n signInWithProvider,\r\n signOut,\r\n resetPassword,\r\n updatePassword,\r\n updateProfile,\r\n refetchProfile: fetchProfile,\r\n };\r\n\r\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;\r\n}\r\n\r\nexport function useAuth(): AuthContextType {\r\n const context = useContext(AuthContext);\r\n if (context === undefined) {\r\n throw new Error('useAuth must be used within an AuthProvider');\r\n }\r\n return context;\r\n}\r\n\r\nexport type { AuthResult, SignUpOptions, SignInWithProviderOptions };\r\n"],"mappings":"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","names":["result"]}