import { accounts } from "$lib/stores/accounts.svelte"; import { auth } from "$lib/stores/auth.svelte"; const BASE = import.meta.env.VITE_API_BASE ?? "/api"; const RETRY_DELAY = 2500; export interface CustomEmojiAsset { mime: string; url: string; } const ready = new Map(); const missing = new Set(); const inflight = new Map>(); function authHeaders(): Record { return auth.token ? { Authorization: `Bearer ${auth.token}` } : {}; } function delay(ms: number): Promise { return new Promise((resolve) => { setTimeout(resolve, ms); }); } async function fetchEmoji( account: number, id: string, key: string, retry: boolean ): Promise { const url = `${BASE}/custom-emoji/${id}?account_id=${account}`; const response = await fetch(url, { headers: authHeaders() }); if (response.ok) { const blob = await response.blob(); const asset = { url: URL.createObjectURL(blob), mime: blob.type }; ready.set(key, asset); return asset; } if (response.status === 409 && retry) { await delay(RETRY_DELAY); return fetchEmoji(account, id, key, false); } missing.add(key); return null; } export function loadCustomEmoji(id: string): Promise { const account = accounts.selectedId; if (account === null) { return Promise.resolve(null); } const key = `${account}:${id}`; const cached = ready.get(key); if (cached) { return Promise.resolve(cached); } if (missing.has(key)) { return Promise.resolve(null); } const existing = inflight.get(key); if (existing) { return existing; } const promise = fetchEmoji(account, id, key, true).finally(() => { inflight.delete(key); }); inflight.set(key, promise); return promise; }