/* =========================================================== Forja 3D — Camada de nuvem (Supabase) Auth por e-mail/senha + workspace compartilhado (1 linha JSONB) + sincronização em tempo real. Exposto em window.cloud / Login. =========================================================== */ const SUPABASE_URL = 'https://gfmroinpwvvmzgsmgsri.supabase.co'; const SUPABASE_ANON = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImdmbXJvaW5wd3Z2bXpnc21nc3JpIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODEwNTA2MDYsImV4cCI6MjA5NjYyNjYwNn0.jzt-D6FRdgmqM73OUHwTWvpIEcT24uoyja1g5_MvQo8'; const WORKSPACE_ID = 'forja'; const _db = (window.supabase && window.supabase.createClient) ? window.supabase.createClient(SUPABASE_URL, SUPABASE_ANON, { auth: { persistSession: true, autoRefreshToken: true } }) : null; let _saveTimer = null; let _lastPushed = null; const cloud = { ok: !!_db, client: _db, async getSession() { if (!_db) return null; const { data } = await _db.auth.getSession(); return data.session; }, onAuth(cb) { if (!_db) return { unsubscribe() {} }; const { data } = _db.auth.onAuthStateChange((_e, session) => cb(session)); return data.subscription; }, signIn(email, password) { return _db.auth.signInWithPassword({ email, password }); }, async signOut() { if (_db) await _db.auth.signOut(); }, async loadWorkspace() { if (!_db) return { error: { message: 'Supabase não carregou' } }; const { data, error } = await _db.from('workspace').select('data').eq('id', WORKSPACE_ID).maybeSingle(); if (error) return { error }; return { data: data ? data.data : null }; }, saveWorkspace(stateObj) { if (!_db) return; clearTimeout(_saveTimer); _saveTimer = setTimeout(async () => { _lastPushed = JSON.stringify(stateObj); const { error } = await _db.from('workspace') .update({ data: stateObj, updated_at: new Date().toISOString() }) .eq('id', WORKSPACE_ID); if (error) console.warn('[cloud] save error', error.message); }, 600); }, subscribe(onRemote) { if (!_db) return null; return _db.channel('ws-' + WORKSPACE_ID) .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'workspace', filter: 'id=eq.' + WORKSPACE_ID }, (payload) => { const s = JSON.stringify(payload.new.data); if (s === _lastPushed) return; // ignora o eco da própria escrita onRemote(payload.new.data); }) .subscribe(); }, removeChannel(ch) { if (_db && ch) _db.removeChannel(ch); }, }; window.cloud = cloud; /* ---------------- Tela de Login ---------------- */ function Login() { const [email, setEmail] = useState(''); const [pw, setPw] = useState(''); const [busy, setBusy] = useState(false); const [err, setErr] = useState(''); async function submit(e) { e.preventDefault(); setErr(''); setBusy(true); try { const { error } = await cloud.signIn(email.trim(), pw); if (error) setErr(traduzErro(error.message)); } catch (ex) { setErr('Não consegui conectar. Verifique a internet.'); } setBusy(false); } return (
Os acessos são criados no painel do Supabase.
Não existe cadastro aberto.