import { createTopBar } from '../components/topbar.js'; import { authService, state } from '../state.js'; export const pageMeta = { id: 'blockchain-archive-view', title: 'Архив блокчейна' }; function text(value) { return String(value == null ? '' : value).trim(); } function buildViewerUrl(location, blockchainName, channelName, messageNumber) { const url = new URL('/Blockchain-Viewer.html', window.location.origin); url.searchParams.set('tx', text(location.arweaveTxId)); url.searchParams.set('offset', String(location.chunkOffset)); url.searchParams.set('size', String(location.chunkSize)); url.searchParams.set('blockchain', blockchainName); const channel = text(channelName); if (channel) url.searchParams.set('channel', channel); const message = text(messageNumber); if (message) url.searchParams.set('message', message); return url.toString(); } async function copyText(value) { if (navigator.clipboard?.writeText) { await navigator.clipboard.writeText(value); return; } const area = document.createElement('textarea'); area.value = value; document.body.appendChild(area); area.select(); document.execCommand('copy'); area.remove(); } export function render({ navigate, chrome }) { const screen = document.createElement('section'); screen.className = 'stack'; chrome?.setTopbar(createTopBar({ title: 'Архив блокчейна', back: { label: '←', onClick: () => navigate('settings-view') }, })); const card = document.createElement('div'); card.className = 'card stack'; card.innerHTML = `
Последний архивный блок
Загружаю...
Технические данные

    
`; screen.appendChild(card); const status = card.querySelector('#archive-status'); const blockchainInput = card.querySelector('#archive-blockchain'); const channelInput = card.querySelector('#archive-channel'); const messageInput = card.querySelector('#archive-message'); const linkInput = card.querySelector('#archive-link'); const copyButton = card.querySelector('#archive-copy'); const openButton = card.querySelector('#archive-open'); const tech = card.querySelector('#archive-tech'); let location = null; let blockchainName = ''; function refreshLink() { if (!location || !blockchainName) { linkInput.value = ''; copyButton.disabled = true; openButton.disabled = true; return; } linkInput.value = buildViewerUrl(location, blockchainName, channelInput.value, messageInput.value); copyButton.disabled = false; openButton.disabled = false; } channelInput.addEventListener('input', refreshLink); messageInput.addEventListener('input', refreshLink); copyButton.addEventListener('click', async () => { if (!linkInput.value) return; await copyText(linkInput.value); status.textContent = 'Ссылка скопирована.'; }); openButton.addEventListener('click', () => { if (linkInput.value) window.open(linkInput.value, '_blank', 'noopener,noreferrer'); }); void (async () => { try { const login = text(state.session.login); if (!login) throw new Error('Нет активного пользователя'); const user = await authService.getUser(login); blockchainName = text(user.blockchainName); if (!blockchainName) throw new Error('У пользователя не найден blockchainName'); blockchainInput.value = blockchainName; location = await authService.getArchiveBlockchainLocation(blockchainName); if (!text(location.arweaveTxId) || !Number.isFinite(Number(location.chunkOffset)) || !Number.isFinite(Number(location.chunkSize))) { throw new Error('Сервер вернул неполную архивную ссылку'); } status.textContent = `Известна архивная история до блока ${location.sourceLastBlockNumber ?? '—'}.`; tech.textContent = [ `publisher: ${text(location.publisherLogin) || '—'}`, `archive big block: ${location.bigBlockNumber ?? '—'}`, `Arweave TX: ${text(location.arweaveTxId)}`, `archive hash: ${text(location.archiveHash) || '—'}`, `chunk offset: ${location.chunkOffset}`, `chunk size: ${location.chunkSize}`, `source last block: ${location.sourceLastBlockNumber ?? '—'}`, ].join('\n'); refreshLink(); } catch (error) { status.textContent = `Архивная ссылка пока недоступна: ${error?.message || error}`; tech.textContent = ''; refreshLink(); } })(); return screen; }