import asset from "./persona-resource-manifest.json"; const source = `${asset.path}?v=${asset.sha256}`; const cacheName = "tjwater-agent-persona-v1"; let pending: Promise | undefined; async function readResource(response: Response): Promise { if (!response.ok) throw new Error(`Obsidian resource: ${response.status}`); const bytes = await response.arrayBuffer(); const header = new Uint8Array(bytes, 0, Math.min(bytes.byteLength, 4)); if (bytes.byteLength !== asset.byteLength || String.fromCharCode(...header) !== "RIVE") { throw new Error("Obsidian resource: invalid animation data"); } if (globalThis.crypto?.subtle) { const digest = await crypto.subtle.digest("SHA-256", bytes); const hash = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join(""); if (hash !== asset.sha256) throw new Error("Obsidian resource: version mismatch"); } return bytes; } async function loadBytes(): Promise { let cache: Cache | undefined; try { cache = await globalThis.caches?.open(cacheName); const cached = await cache?.match(source); if (cached) return await readResource(cached); } catch { // Storage can be denied or contain incomplete data. Retry through the network. } const response = await fetch(source, { signal: AbortSignal.timeout(15_000) }); const bytes = await readResource(response); if (cache) { try { await cache.put(source, new Response(bytes, { headers: { "Content-Type": "application/octet-stream" } })); const current = new URL(source, window.location.href); for (const request of await cache.keys()) { const url = new URL(request.url); if (url.origin === current.origin && url.pathname === asset.path && url.href !== current.href) { await cache.delete(request); } } } catch { // Quota or storage failures must not prevent the downloaded animation playing. } } return bytes; } // Share the immutable bytes, never a live renderer or View Model instance. export function loadPersonaResource() { pending ??= loadBytes().catch((error: unknown) => { pending = undefined; throw error; }); return pending; }