const API = (() => { const ENDPOINTS = { owner: "sh.tangled.owner", list: "sh.tangled.repo.list", tree: "sh.tangled.repo.tree", blob: "sh.tangled.repo.blob", branches: "sh.tangled.repo.branches", tags: "sh.tangled.repo.tags", defaultBranch: "sh.tangled.repo.getDefaultBranch", archive: "sh.tangled.repo.archive", }; let baseUrl = ""; function setBaseUrl(url) { baseUrl = url.replace(/\/+$/, ""); } function getBaseUrl() { return baseUrl; } async function fetchWithRetry(url, options = {}, retries = 3) { let lastError; for (let attempt = 1; attempt <= retries; attempt++) { try { const response = await fetch(url, options); if (response.ok) return response; lastError = new Error(`HTTP ${response.status}`); if (attempt < retries) { await new Promise((resolve) => setTimeout(resolve, 1000)); } } catch (err) { lastError = err; if (attempt < retries) { await new Promise((resolve) => setTimeout(resolve, 1000)); } } } throw lastError; } async function getOwner() { const url = `${baseUrl}/xrpc/${ENDPOINTS.owner}`; const response = await fetchWithRetry(url); return response.json(); } async function listRepos() { const url = `${baseUrl}/xrpc/${ENDPOINTS.list}`; const response = await fetch(url); if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); } async function getDefaultBranch(repo) { const url = `${baseUrl}/xrpc/${ENDPOINTS.defaultBranch}?repo=${encodeURIComponent(repo)}`; const response = await fetch(url); if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); } async function getBranches(repo) { const url = `${baseUrl}/xrpc/${ENDPOINTS.branches}?repo=${encodeURIComponent(repo)}`; const response = await fetch(url); if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); } async function getTree(repo, branch, path = "") { const url = `${baseUrl}/xrpc/${ENDPOINTS.tree}?repo=${encodeURIComponent(repo)}&branch=${encodeURIComponent(branch)}&path=${encodeURIComponent(path)}`; const response = await fetchWithRetry(url); return response.json(); } async function getBlob(repo, branch, path) { const url = `${baseUrl}/xrpc/${ENDPOINTS.blob}?repo=${encodeURIComponent(repo)}&branch=${encodeURIComponent(branch)}&path=${encodeURIComponent(path)}`; const response = await fetchWithRetry(url); return response.json(); } function getArchiveUrl(repo, branch) { return `${baseUrl}/xrpc/${ENDPOINTS.archive}?repo=${encodeURIComponent(repo)}&branch=${encodeURIComponent(branch)}`; } async function resolveDID(did) { try { const url = `https://plc.directory/${encodeURIComponent(did)}`; const response = await fetch(url); if (!response.ok) return null; const didDocument = await response.json(); // Extract handle from alsoKnownAs field if (didDocument.alsoKnownAs && didDocument.alsoKnownAs.length > 0) { const handle = didDocument.alsoKnownAs[0].replace(/^at:\/\//, ""); return handle; } return null; } catch (error) { console.error("Failed to resolve DID:", error); return null; } } return { setBaseUrl, getBaseUrl, getOwner, listRepos, getDefaultBranch, getBranches, getTree, getBlob, getArchiveUrl, resolveDID, }; })();