Spaces:
Running
Running
| import {initializeApp} from "https://www.gstatic.com/firebasejs/11.6.1/firebase-app.js"; | |
| import {getAuth, onAuthStateChanged, signInAnonymously, signOut as fbSignOut} from "https://www.gstatic.com/firebasejs/11.6.1/firebase-auth.js"; | |
| import {getFirestore, doc, setDoc, getDoc, serverTimestamp} from "https://www.gstatic.com/firebasejs/11.6.1/firebase-firestore.js"; | |
| import {firebaseConfig, appId} from './config.js'; | |
| import {autoUsername} from './utils.js'; | |
| let app, db, auth, userId=null, username=null, ready=false; | |
| function genId(){ try{ if (crypto && crypto.randomUUID) return crypto.randomUUID(); }catch{} return 'u_'+Math.random().toString(36).slice(2,10)+'_'+Date.now().toString(36); } | |
| let profilesCache={}; | |
| async function fetchIP(){try{const r=await fetch('https://api.ipify.org?format=json');if(!r.ok)throw 0;const j=await r.json();return j.ip||'';}catch{return''}} | |
| export async function initFirebase(){ | |
| try{ | |
| app=initializeApp(firebaseConfig); db=getFirestore(app); auth=getAuth(app); | |
| }catch{ | |
| db=undefined; auth=undefined; | |
| } | |
| const ip=await fetchIP(); const last=localStorage.getItem('last_ip')||''; | |
| if(ip&&ip!==last){ localStorage.removeItem('local_username'); localStorage.setItem('last_ip',ip); } | |
| let resolved=false; | |
| function resolveReady(){ if(!resolved){ resolved=true; ready=true; }} | |
| if (auth){ | |
| onAuthStateChanged(auth,async u=>{ | |
| if(u){ userId=u.uid; const p=await ensureProfile(userId); username=p.username; renderAuthUI(true); resolveReady(); } | |
| else{ | |
| try{ await signInAnonymously(auth); } | |
| catch{ | |
| userId=localStorage.getItem('local_uid')||genId(); localStorage.setItem('local_uid',userId); | |
| let uname=localStorage.getItem('local_username'); if(!uname){ uname=autoUsername(); localStorage.setItem('local_username',uname); } | |
| username=uname; renderAuthUI(false); resolveReady(); | |
| } | |
| } | |
| }); | |
| } else { | |
| userId=localStorage.getItem('local_uid')||genId(); localStorage.setItem('local_uid',userId); | |
| let uname=localStorage.getItem('local_username'); if(!uname){ uname=autoUsername(); localStorage.setItem('local_username',uname); } | |
| username=uname; renderAuthUI(false); resolveReady(); | |
| } | |
| return new Promise(res=>{ | |
| const start=Date.now(); | |
| const t=setInterval(()=>{ if(ready){ clearInterval(t); res(); } else if(Date.now()-start>2500){ resolveReady(); clearInterval(t); res(); } }, 50); | |
| }); | |
| } | |
| export function getDB(){return db;} | |
| export function getAuthState(){return{userId,username,ready}}; | |
| export async function ensureProfile(uid){if(profilesCache[uid])return profilesCache[uid];try{const ref=doc(db,'artifacts',appId,'users',uid,'user_data','profile');const s=await getDoc(ref);if(s.exists()){const p=s.data();profilesCache[uid]=p;return p;}const uname=localStorage.getItem('local_username')||autoUsername();const p={username:uname,createdAt:serverTimestamp()};await setDoc(ref,p);profilesCache[uid]=p;return p;}catch{const uname=localStorage.getItem('local_username')||autoUsername();const p={username:uname};profilesCache[uid]=p;return p;}} | |
| export function getProfile(uid){return profilesCache[uid]||null} | |
| export async function signOut(){try{await fbSignOut(auth);}catch{} localStorage.removeItem('local_username');} | |
| function renderAuthUI(logged){const pill=document.getElementById('statusPill');const lo=document.getElementById('logoutBtn');const ul=document.getElementById('usernameLabel');if(logged){pill.classList.remove('hidden');lo.classList.remove('hidden');}else{pill.classList.remove('hidden');lo.classList.remove('hidden');}ul.textContent=username||'-';} | |