import sodium from 'libsodium-wrappers-sumo' import {initUpload} from './upload.js' import {initDownload} from './download.js' import {t} from './i18n.js' function getAppElement(): HTMLElement | null { return (document.querySelector('[data-xftp-app]') as HTMLElement | null) ?? document.getElementById('app') } const wasmReady = sodium.ready async function main() { // Render UI immediately — no WASM needed for HTML + event listeners. // WASM is only used later when user triggers upload/download. const app = getAppElement() if (!app?.hasAttribute('data-defer-init')) { initApp() } if (!app?.hasAttribute('data-no-hashchange')) { window.addEventListener('hashchange', () => { const hash = window.location.hash.slice(1) if (!hash || looksLikeXFTPHash(hash)) initApp() }) } await wasmReady app?.dispatchEvent(new CustomEvent('xftp:ready', {bubbles: true})) } // XFTP hashes are base64url-encoded DEFLATE data, always long. // Matches the index.html inline script heuristic (length > 50). function looksLikeXFTPHash(hash: string): boolean { return hash.length > 50 && /^[A-Za-z0-9_=-]+$/.test(hash) } function initApp() { const app = getAppElement()! const hash = window.location.hash.slice(1) if (hash && looksLikeXFTPHash(hash)) { initDownload(app, hash) } else { initUpload(app) } } ;(window as any).__xftp_initApp = async () => { await wasmReady; initApp() } main().catch(err => { const app = getAppElement() if (app) { app.innerHTML = `
${t('initError', 'Failed to initialize: %error%').replace('%error%', err.message)}