CompactAI's picture
Upload 126 files
f6b8770 verified
Raw
History Blame Contribute Delete
1.8 kB
// fetch helpers + session state + toasts
export const state = {
me: null,
catalog: [],
};
export async function api(path, opts = {}) {
const res = await fetch('/api' + path, {
headers: opts.body ? { 'Content-Type': 'application/json' } : {},
method: opts.method || (opts.body ? 'POST' : 'GET'),
body: opts.body ? JSON.stringify(opts.body) : undefined,
});
let data = {};
try { data = await res.json(); } catch (e) { /* non-JSON */ }
if (!res.ok) {
const err = new Error(data.error || `Request failed (${res.status})`);
err.status = res.status;
throw err;
}
return data;
}
export async function refreshMe() {
const data = await api('/me');
state.me = data.user;
if (data.dailyBonus) toast(`Daily bonus: +${data.dailyBonus} ◈ Glimmers!`, 'gold');
return state.me;
}
export async function loadCatalog() {
if (!state.catalog.length) {
const data = await api('/catalog');
state.catalog = data.items;
}
return state.catalog;
}
export function catalogItem(id) {
return state.catalog.find((i) => i.id === id) || null;
}
export function toast(text, kind = '') {
const el = document.createElement('div');
el.className = 'toast ' + kind;
el.textContent = text;
document.getElementById('toasts').appendChild(el);
setTimeout(() => el.remove(), 3500);
}
export function esc(s) {
return String(s ?? '').replace(/[&<>"']/g, (c) => (
{ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]
));
}
export function fmtNum(n) {
if (n >= 1e6) return (n / 1e6).toFixed(1) + 'M';
if (n >= 1e3) return (n / 1e3).toFixed(1) + 'K';
return String(n);
}
export function openWS() {
const proto = location.protocol === 'https:' ? 'wss' : 'ws';
return new WebSocket(`${proto}://${location.host}/ws`);
}