import React from 'react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { OpenCodeIcon } from '@/components/ui/OpenCodeIcon'; import { isDesktopRuntime, isVSCodeRuntime } from '@/lib/desktop'; import { syncDesktopSettings, initializeAppearancePreferences } from '@/lib/persistence'; import { applyPersistedDirectoryPreferences } from '@/lib/directoryPersistence'; const STATUS_CHECK_ENDPOINT = '/auth/session'; const fetchSessionStatus = async (): Promise => { return fetch(STATUS_CHECK_ENDPOINT, { method: 'GET', credentials: 'include', headers: { Accept: 'application/json', }, }); }; const submitPassword = async (password: string): Promise => { return fetch(STATUS_CHECK_ENDPOINT, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, body: JSON.stringify({ password }), }); }; const AuthShell: React.FC<{ children: React.ReactNode }> = ({ children }) => (
{children}
); const LoadingScreen: React.FC<{ message?: string }> = ({ message = 'Preparing workspace…' }) => (

{message}

); const ErrorScreen: React.FC<{ onRetry: () => void }> = ({ onRetry }) => (

Unable to reach server

We couldn't verify the UI session. Check that the service is running and try again.

); interface SessionAuthGateProps { children: React.ReactNode; } type GateState = 'pending' | 'authenticated' | 'locked' | 'error'; export const SessionAuthGate: React.FC = ({ children }) => { const desktopRuntime = React.useMemo(() => isDesktopRuntime(), []); const vscodeRuntime = React.useMemo(() => isVSCodeRuntime(), []); const skipAuth = desktopRuntime || vscodeRuntime; const [state, setState] = React.useState(() => (skipAuth ? 'authenticated' : 'pending')); const [password, setPassword] = React.useState(''); const [isSubmitting, setIsSubmitting] = React.useState(false); const [errorMessage, setErrorMessage] = React.useState(''); const passwordInputRef = React.useRef(null); const hasResyncedRef = React.useRef(skipAuth); const checkStatus = React.useCallback(async () => { if (skipAuth) { setState('authenticated'); return; } setState((prev) => (prev === 'authenticated' ? prev : 'pending')); try { const response = await fetchSessionStatus(); if (response.ok) { setState('authenticated'); setErrorMessage(''); return; } if (response.status === 401) { setState('locked'); return; } setState('error'); } catch (error) { console.warn('Failed to check session status:', error); setState('error'); } }, [skipAuth]); React.useEffect(() => { if (skipAuth) { return; } void checkStatus(); }, [checkStatus, skipAuth]); React.useEffect(() => { if (!skipAuth && state === 'locked') { hasResyncedRef.current = false; } }, [skipAuth, state]); React.useEffect(() => { if (state === 'locked' && passwordInputRef.current) { passwordInputRef.current.focus(); passwordInputRef.current.select(); } }, [state]); React.useEffect(() => { if (skipAuth) { return; } if (state === 'authenticated' && !hasResyncedRef.current) { hasResyncedRef.current = true; void (async () => { await syncDesktopSettings(); await initializeAppearancePreferences(); await applyPersistedDirectoryPreferences(); })(); } }, [skipAuth, state]); const handleSubmit = async (event: React.FormEvent) => { event.preventDefault(); if (!password || isSubmitting) { return; } setIsSubmitting(true); setErrorMessage(''); try { const response = await submitPassword(password); if (response.ok) { setPassword(''); setState('authenticated'); return; } if (response.status === 401) { setErrorMessage('Incorrect password. Try again.'); setState('locked'); return; } setErrorMessage('Unexpected response from server.'); setState('error'); } catch (error) { console.warn('Failed to submit UI password:', error); setErrorMessage('Network error. Check connection and retry.'); setState('error'); } finally { setIsSubmitting(false); } }; if (state === 'pending') { return ; } if (state === 'error') { return void checkStatus()} />; } if (state === 'locked') { return (

Unlock OpenChamber

Enter the password configured for this web session.

{ setPassword(event.target.value); if (errorMessage) { setErrorMessage(''); } }} aria-invalid={Boolean(errorMessage) || undefined} aria-describedby={errorMessage ? 'oc-ui-auth-error' : undefined} disabled={isSubmitting} /> {errorMessage && (

{errorMessage}

)}
); } return <>{children}; };