import { describeRepo, listRecordsRaw, getRecordRaw, fetchLexicon, resolveHandle, getServiceInfo } from '../lib/api.js' import { deleteRecord } from '../lib/auth.js' function extractRkey(uri: string): string { const parts = uri.split('/') return parts[parts.length - 1] } function formatDate(dateStr: string): string { const date = new Date(dateStr) return date.toLocaleDateString('ja-JP', { year: 'numeric', month: '2-digit', day: '2-digit', }) } function escapeHtml(str: string): string { return str .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') } async function renderServices(did: string, handle: string): Promise { const collections = await describeRepo(did) if (collections.length === 0) { return '

No collections found

' } // Group by service domain const serviceMap = new Map() for (const col of collections) { const info = getServiceInfo(col) if (info) { const key = info.domain if (!serviceMap.has(key)) { serviceMap.set(key, { name: info.name, favicon: info.favicon, count: 0 }) } serviceMap.get(key)!.count++ } } const items = Array.from(serviceMap.entries()).map(([domain, info]) => { return `
  • ${info.name} ${info.count}
  • ` }).join('') return `

    Services

      ${items}
    ` } async function renderCollections(did: string, handle: string, serviceDomain: string): Promise { const collections = await describeRepo(did) // Filter by service domain const filtered = collections.filter(col => { const info = getServiceInfo(col) return info && info.domain === serviceDomain }) if (filtered.length === 0) { return '

    No collections found

    ' } // Get favicon from first collection const firstInfo = getServiceInfo(filtered[0]) const favicon = firstInfo ? `` : '' const items = filtered.map(col => { return `
  • ${col}
  • ` }).join('') return `

    ${favicon}${serviceDomain}

      ${items}
    ` } async function renderRecordList(did: string, handle: string, collection: string): Promise { const records = await listRecordsRaw(did, collection) if (records.length === 0) { return '

    No records found

    ' } const items = records.map(rec => { const rkey = extractRkey(rec.uri) const preview = rec.value.title || rec.value.text?.slice(0, 50) || rkey return `
  • ${rkey} ${preview}
  • ` }).join('') return `

    ${collection}

    ${records.length} records

      ${items}
    ` } async function renderRecordDetail(did: string, handle: string, collection: string, rkey: string, canDelete: boolean): Promise { const record = await getRecordRaw(did, collection, rkey) if (!record) { return '

    Record not found

    ' } const lexicon = await fetchLexicon(collection) const schemaStatus = lexicon ? 'verified' : 'none' const schemaLabel = lexicon ? '✓ Schema' : '○ No schema' const json = JSON.stringify(record, null, 2) const deleteBtn = canDelete ? `` : '' return `

    ${collection}

    ${record.uri}

    CID: ${record.cid}

    ${schemaLabel} ${deleteBtn}
    ${escapeHtml(json)}
    ` } export async function mountAtBrowser( container: HTMLElement, handle: string, collection: string | null, rkey: string | null, service: string | null = null, loginDid: string | null = null ): Promise { container.innerHTML = '
    ' try { const did = handle.startsWith('did:') ? handle : await resolveHandle(handle) const canDelete = loginDid !== null && loginDid === did let content: string let nav = '' if (collection && rkey) { nav = `← Back` content = await renderRecordDetail(did, handle, collection, rkey, canDelete) } else if (collection) { // Get service from collection for back link const info = getServiceInfo(collection) const backService = info ? info.domain : '' nav = `← ${info?.name || 'Back'}` content = await renderRecordList(did, handle, collection) } else if (service) { nav = `← Services` content = await renderCollections(did, handle, service) } else { content = await renderServices(did, handle) } container.innerHTML = nav + content // Add delete button handler const deleteBtn = container.querySelector('.delete-btn') if (deleteBtn) { deleteBtn.addEventListener('click', async (e) => { e.preventDefault() const btn = e.target as HTMLButtonElement const col = btn.dataset.collection const rk = btn.dataset.rkey if (!col || !rk) return if (!confirm('Delete this record?')) return try { btn.disabled = true btn.textContent = 'Deleting...' await deleteRecord(col, rk) // Go back to collection window.location.href = `/at/${handle}/${col}` } catch (err) { alert('Delete failed: ' + err) btn.disabled = false btn.textContent = 'Delete' } }) } } catch (err) { container.innerHTML = `

    Failed to load: ${err}

    ` } }