(() => { "use strict"; const embedded = JSON.parse(document.getElementById("docslib-manifest").textContent); const config = JSON.parse(document.getElementById("docslib-config").textContent); const loading = document.getElementById("docslib-loading"); const loaderStyle = document.getElementById("docslib-loader-style"); function isManifest(value) { return Boolean( value && value.schema_version >= 2 && Array.isArray(value.pages) && value.client && value.client.css && typeof value.client.css.system === "string" && value.client.js && typeof value.client.js.system === "string" ); } const dbPromise = new Promise((resolve, reject) => { if (!window.indexedDB) return reject(new Error("IndexedDB")); const request = indexedDB.open("docslib-cache", 1); request.onupgradeneeded = () => { if (!request.result.objectStoreNames.contains("manifests")) { request.result.createObjectStore("manifests"); } }; request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); async function cacheGet() { const db = await dbPromise; return new Promise((resolve, reject) => { const request = db.transaction("manifests", "readonly").objectStore("manifests").get(config.cacheKey); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); } async function cachePut(value) { const db = await dbPromise; return new Promise((resolve, reject) => { const transaction = db.transaction("manifests", "readwrite"); transaction.objectStore("manifests").put(value, config.cacheKey); transaction.oncomplete = resolve; transaction.onerror = () => reject(transaction.error); }); } async function selectManifest() { let selected = embedded; try { const cached = await cacheGet(); if ( isManifest(cached) && cached.schema_version === embedded.schema_version && String(cached.updated_at || "") >= String(embedded.updated_at || "") ) selected = cached; else await cachePut(embedded); } catch (_) { /* embedded manifest remains available */ } const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 4000); try { const response = await fetch(config.manifestUrl, { cache: "no-store", signal: controller.signal }); if (!response.ok) throw new Error(String(response.status)); const remote = await response.json(); if (!isManifest(remote) || remote.schema_version !== embedded.schema_version) { throw new Error("manifest"); } selected = remote; await cachePut(remote).catch(() => {}); } catch (_) { /* cached or embedded manifest remains available */ } finally { clearTimeout(timeout); } return selected; } function applyRuntime(manifest) { const style = document.createElement("style"); style.id = "docslib-runtime-style"; style.textContent = [manifest.client.css.system, manifest.client.css.custom || ""].join("\n"); document.head.append(style); window.__DOCSLIB_MANIFEST__ = manifest; window.__DOCSLIB_CONFIG__ = config; const script = document.createElement("script"); script.id = "docslib-runtime-script"; script.textContent = `${manifest.client.js.system}\n//# sourceURL=docslib-client.js`; document.body.append(script); } document.addEventListener("docslib:rendered", () => { loading?.remove(); loaderStyle?.remove(); }, { once: true }); selectManifest() .then((manifest) => { if (!isManifest(manifest)) throw new Error("manifest"); applyRuntime(manifest); }) .catch((error) => console.error("SharedDocsLib", error)); })();