import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import App from './App.tsx'; import './index.css'; import { supabase, INITIAL_URL_HASH, INITIAL_URL_SEARCH } from './services/supabase.ts'; const rawHash = INITIAL_URL_HASH || (typeof window !== 'undefined' ? window.location.hash : ''); const rawSearch = INITIAL_URL_SEARCH || (typeof window !== 'undefined' ? window.location.search : ''); const cleanHash = rawHash.startsWith('#') ? rawHash.substring(1) : rawHash; const hashParams = new URLSearchParams(cleanHash); const searchParams = new URLSearchParams(rawSearch); const authType = searchParams.get('type') || hashParams.get('type') || ''; const isEmailFlow = authType === 'recovery' || authType === 'signup' || authType === 'email' || authType === 'invite' || authType === 'magiclink'; const hasAuthParams = typeof window !== 'undefined' && !isEmailFlow && (hashParams.has('access_token') || searchParams.has('code') || searchParams.has('error') || hashParams.has('error') || searchParams.has('error_description') || hashParams.has('error_description')); const isSameTabRedirect = (() => { try { if (typeof window !== 'undefined' && sessionStorage.getItem('supabase_oauth_same_tab') === '1') { sessionStorage.removeItem('supabase_oauth_same_tab'); return true; } } catch (e) {} return false; })(); // Check if this window was opened as a Supabase OAuth popup callback // Note: Navigating through accounts.google.com sends Cross-Origin-Opener-Policy headers // which can set window.opener = null and clear window.name = '' in modern browsers. const isPopup = typeof window !== 'undefined' && hasAuthParams && !isSameTabRedirect && ((window.opener && window.opener !== window) || window.name === 'supabase_google_oauth' || window.self === window.top); if (isPopup && hasAuthParams) { // Render a minimal loader in the popup instead of mounting the entire application UI const rootEl = document.getElementById('root'); if (rootEl) { rootEl.innerHTML = `

تمت المصادقة بنجاح

جاري تحديث الجلسة والعودة للتطبيق...

`; } const notifyOpenerAndClose = async (payload: { type: string; code?: string | null; session?: any; error?: string }) => { // 1. Direct postMessage to opener (if not severed by COOP) try { if (window.opener && !window.opener.closed) { window.opener.postMessage(payload, '*'); } } catch (e) { console.warn('postMessage to opener error:', e); } // 2. BroadcastChannel (for same-partition contexts) try { if (typeof BroadcastChannel !== 'undefined') { const bc = new BroadcastChannel('supabase_google_oauth_channel'); bc.postMessage(payload); setTimeout(() => { try { bc.close(); } catch (e) {} }, 300); } } catch (e) {} // 3. localStorage event bridge (for same-partition contexts) try { localStorage.setItem( 'supabase_google_oauth_result', JSON.stringify({ ...payload, ts: Date.now() }) ); } catch (e) {} // 4. Server-side relay (bridges cross-origin iframe storage partitioning & COOP severed opener) try { if ( payload.type === 'SUPABASE_AUTH_SUCCESS' && (payload.code || (payload.session?.access_token && payload.session?.refresh_token)) ) { await fetch('/api/oauth-relay', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'complete', code: payload.code || null, session: payload.session?.access_token && payload.session?.refresh_token ? { access_token: payload.session.access_token, refresh_token: payload.session.refresh_token, } : null, }), }); } else if (payload.type === 'SUPABASE_AUTH_ERROR') { await fetch('/api/oauth-relay', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ action: 'error', error: payload.error || 'Authentication failed', }), }); } } catch (e) { console.warn('Server oauth-relay error:', e); } setTimeout(() => { try { window.close(); } catch (e) {} // Fallback UI if browser prevents closing a COOP-severed window automatically setTimeout(() => { if (rootEl) { rootEl.innerHTML = `
✓

تم تسجيل الدخول بنجاح

تم ربط جلستك في نافذة التطبيق بنجاح. يمكنك إغلاق هذه النافذة الآن.

`; } }, 600); }, 250); }; // 1. Direct extraction for PKCE code or implicit tokens const code = searchParams.get('code'); const accessToken = hashParams.get('access_token'); const refreshToken = hashParams.get('refresh_token'); const errorDescription = searchParams.get('error_description') || hashParams.get('error_description') || searchParams.get('error') || hashParams.get('error'); if (errorDescription) { notifyOpenerAndClose({ type: 'SUPABASE_AUTH_ERROR', error: errorDescription }); } else if (code) { notifyOpenerAndClose({ type: 'SUPABASE_AUTH_SUCCESS', code, }); } else if (accessToken && refreshToken) { notifyOpenerAndClose({ type: 'SUPABASE_AUTH_SUCCESS', session: { access_token: accessToken, refresh_token: refreshToken, }, }); } else { supabase.auth .getSession() .then(({ data, error }) => { if (data?.session) { notifyOpenerAndClose({ type: 'SUPABASE_AUTH_SUCCESS', session: data.session }); } else if (error) { notifyOpenerAndClose({ type: 'SUPABASE_AUTH_ERROR', error: error.message }); } else { notifyOpenerAndClose({ type: 'SUPABASE_AUTH_SUCCESS' }); } }) .catch(() => { notifyOpenerAndClose({ type: 'SUPABASE_AUTH_SUCCESS' }); }); } } else { // Main app window: render normal React application createRoot(document.getElementById('root')!).render( , ); }