// Generated, do not edit. sha256:867f87b26d0b27fe51f4a0cb77d5196bad8cd8b58a6856168c9cad25f5776d99 import { t, localeTag } from '../i18n/index.js'; import { CONFIG } from '../../shared/config.js'; import { esc } from '../ui/escape.js'; import { licenseSnapshot, loadLicense, markLicenseSeen } from '../license.js'; import { installLicense } from '../data/license-install.js'; import { refreshAttention } from '../ui/attention.js'; import { npubFromHex, shortKey, secretFromText, publicKeyOf, nsecFromSecret, newSecret } from '../nostr/keys.js'; import { keySigner, extensionSigner, nip98Header } from '../nostr/nip98.js'; import { qrSvg, invoiceQrText } from '../ui/qr.js'; import { CHECK, CHEVRON, IMAGE } from '../ui/icons.js'; import { setPageHint } from '../ui/page-hint.js'; import { splashMarkHtml } from '../ui/splash.js'; import { expanders } from '../ui/expand.js'; import { supportInfo, supportMessages, sendSupport, supportAttachment } from '../data/support.js'; import { licenseShop, buyerLicenses, saleInfo, placeOrder, orderStatus } from '../data/license-buyer.js'; const BROKEN = new Set(['invalid', 'unreadable']); function buyerOf(s) { const npub = npubFromHex(s.buyer); return { text: shortKey(npub ?? s.buyer, 10), title: npub ?? s.buyer ?? '' }; } function standHtml(s) { const out = []; if (s.installed) { const buyer = buyerOf(s); const range = t('license.cardFacts', { issued: s.issued ?? '', from: s.installed.majorFrom, to: s.installed.majorTo === 'unlimited' ? t('license.unlimited') : s.installed.majorTo, }); const [before, after] = t('license.cardFor', { npub: '§' }).split('§'); out.push(`
${esc(before)}${esc(buyer.text)}${esc(after)}
`); } else { out.push(`${esc(t(s.level === 'full' ? 'license.cardFull' : 'license.cardFree'))}
`); } if (BROKEN.has(s.why)) out.push(`${esc(`${t('license.cardProblem')} ${t(`license.why_${s.why}`)}.`)}
`); return out.join(''); } async function installAndReload(text, message) { message.className = 't-body-sm'; message.textContent = ''; try { const result = await installLicense(text); message.classList.add('t-pos'); message.textContent = result.covers ? t('license.installOk') : t('license.installOkFuture'); setTimeout(() => location.reload(), 1200); } catch (err) { message.classList.add('t-neg'); message.textContent = err.message; } } const INFO = ['Nostr', 'Why', 'SignIn', 'Zap', 'Privacy']; const link = (url, html) => `${html}`; const legendRows = () => [ say('license.payIntro'), ...['easy', 'other'].flatMap(group => [{ heading: say(`license.payGroup_${group}`) }, ...CONFIG.LICENSE.PAY_APPS.filter(a => a.group === group) .map(a => `${link(a.url, `${esc(a.name)}`)} ${say(`license.payApp_${a.id}`)}`)]), say('license.payNote'), { heading: say('license.nostrMore') }, ...INFO.map(k => `${say(`license.info${k}Head`)} ${say(`license.info${k}`)}`), ...CONFIG.LICENSE.INFO_LINKS.map(l => link(l.url, say(`license.link_${l.id}`))), ]; let signer = null; let newKey = null; const npubText = (hex) => { const npub = npubFromHex(hex) ?? hex; return `${esc(shortKey(npub, 10))}`; }; const say = (key, params) => esc(t(key, params)); async function drawSignIn(box, s) { let shop = { serviceUrl: null, buyer: null }; try { shop = await licenseShop(); } catch { } serviceUrl = shop.serviceUrl; drawBuy(); drawSupport(); const head = `${say('license.otherBuyer')}
` : ''} `; box.querySelector('[data-signout]').onclick = () => { signer = null; drawSignIn(box, s); }; await drawLicenses(box.querySelector('[data-licenses]'), box.querySelector('[data-signin-msg]'), shop); return; } if (newKey) { const nsec = nsecFromSecret(newKey.secret); box.innerHTML = `${head}${say('license.newKeyIntro')}
${say('license.newKeyPublic', { npub: npubFromHex(publicKeyOf(newKey.secret)) })}
${say('license.signInIntro')}
${known ? `${esc(t(known.key, { npub: '§' })).replace('§', npubText(known.hex))}
` : ''}${say('license.signInExtensionNone')}
`} `; const msg = box.querySelector('[data-signin-msg]'); const fault = (text) => { msg.className = 't-body-sm mt-sm t-neg'; msg.textContent = text; }; box.querySelector('[data-ext]').onclick = async () => { try { signer = await extensionSigner(); drawSignIn(box, s); } catch (err) { fault(err.message); } }; const form = box.querySelector('[data-key-form]'); box.querySelector('[data-key]').onclick = () => { form.hidden = false; form.querySelector('input').focus(); }; form.onsubmit = (e) => { e.preventDefault(); const input = form.querySelector('input'); const { secret, error } = secretFromText(input.value); input.value = ''; if (error) { fault(t(error === 'npub' ? 'license.signInNpub' : 'license.signInBadKey')); return; } signer = keySigner(secret); drawSignIn(box, s); }; box.querySelector('[data-new]').onclick = () => { newKey = { secret: newSecret(), copied: false }; drawSignIn(box, s); }; } const BUY_POLL_MS = 3000; let buyBox = null; let serviceUrl = null; let purchase = null; let pollTimer = null; const sats = (n) => Number(n).toLocaleString(localeTag()); const clock = (ms) => new Date(ms).toLocaleTimeString(localeTag(), { hour: '2-digit', minute: '2-digit' }); const FINAL = { expired: 'license.buyExpired', canceled: 'license.buyCanceled', underpaid: 'license.buyUnderpaid' }; const AWAY = new Set(['marketService.unreachable', 'marketService.timeout', 'marketService.unavailable']); async function drawBuy() { const box = buyBox; if (!box) return; box.hidden = !signer && !purchase; if (box.hidden) return; const head = `${say('license.buyInvoice', { time: clock(o.expiresAt) })}
${state}
${purchase.note ? esc(purchase.note) : ''}
${final ? `` : ''}`; const copy = box.querySelector('[data-invoice-copy]'); if (copy) copy.onclick = (e) => copyText(o.paymentRequest, box.querySelector('[data-invoice]')).then((ok) => { if (ok) e.target.textContent = t('license.buyCopied'); }); const again = box.querySelector('[data-buy-again]'); if (again) again.onclick = () => { purchase = null; drawBuy(); }; return; } let sale = null; let problem = null; try { sale = await saleInfo(); } catch (err) { problem = AWAY.has(err.key) ? t('license.buyAway') : err.message; } const price = sale?.open ? say('license.buyPrice', { major: sale.major, sats: sats(sale.priceSat) }) : sale ? say('license.buyClosed') : esc(problem ?? ''); box.innerHTML = `${head}${price}
`; box.querySelector('[data-buy-go]').onclick = async (e) => { const msg = box.querySelector('[data-buy-msg]'); e.target.disabled = true; try { const body = '{}'; const header = await nip98Header(signer, { url: `${serviceUrl}/v1/orders`, method: 'POST', body }); const { order, readKey } = await placeOrder(header, body); purchase = { order, readKey, note: '' }; drawBuy(); schedulePoll(); } catch (err) { e.target.disabled = false; msg.className = 't-body-sm mt-sm t-neg'; msg.textContent = err.message; } }; } function schedulePoll() { clearTimeout(pollTimer); pollTimer = setTimeout(pollOnce, BUY_POLL_MS); } async function pollOnce() { if (!purchase?.readKey) return; try { const { order, license } = await orderStatus(purchase.order.id, purchase.readKey); purchase.order = order; purchase.note = ''; if (license) { drawBuy(); const msg = buyBox?.querySelector('[data-buy-msg]'); if (!license.valid) { purchase.note = t('license.buyNotValid'); drawBuy(); return; } if (msg && buyBox.isConnected) await installAndReload(license.file, msg); else await installLicense(license.file).then(() => location.reload()); return; } drawBuy(); if (FINAL[order.status]) return; } catch (err) { purchase.note = err.message; drawBuy(); } schedulePoll(); } const SUPPORT_POLL_MS = 30_000; let supportBox = null; let supportDraft = ''; let supportFile = null; let supportTimer = null; const shots = new Map(); const supportUrl = (info, path) => `${info.serviceUrl}/v1/support/${path}`; async function drawSupport() { const box = supportBox; if (!box) return; clearInterval(supportTimer); box.hidden = !signer; if (!signer) return; let info = null; try { info = await supportInfo(); } catch { info = null; } const head = `${esc(t('license.supportNostr', { name: '§' })).replace('§', `${esc(info.nostr.name)} (${npubText(info.nostr.pubkey)})`)}
` : ''; if (!info?.serviceUrl) { box.innerHTML = `${head}${say('license.supportIntro')}
${nostr}`; return; } const mb = info.maxAttachmentBytes / 1024 / 1024; box.innerHTML = `${head}${say('license.supportIntro')}
${say('license.supportThreadLoading')}
`; let list; try { const header = await nip98Header(signer, { url: supportUrl(info, 'messages'), method: 'GET' }); list = await supportMessages(header); } catch (err) { if (quiet) return; area.innerHTML = `${esc(AWAY.has(err.key) ? t('license.supportAway') : err.message)}
`; return; } if (!list.length) { area.innerHTML = `${say('license.supportThreadEmpty')}
`; return; } const when = (ms) => new Date(ms).toLocaleString(localeTag(), { dateStyle: 'short', timeStyle: 'short' }); const who = (m) => t(m.from === 'buyer' ? 'license.supportYou' : m.ai ? 'license.supportAi' : 'license.supportSeller'); const shot = (a) => (shots.has(a.id) ? `${esc(m.text)}
` : ''}${m.attachments.map(shot).join('')}${say('license.licensesLoading')}
`; let list; try { const header = await nip98Header(signer, { url: `${shop.serviceUrl}/v1/license`, method: 'GET' }); list = await buyerLicenses(header); } catch (err) { area.innerHTML = ''; msg.className = 't-body-sm t-neg'; msg.textContent = err.message; return; } if (!list.length) { area.innerHTML = `${say('license.licensesNone')}
`; return; } area.innerHTML = list.map((l, i) => { if (l.unreadable) return `${say('license.licenseNotValid')}
`; const text = say('license.licenseLine', { level: t(`license.level_${l.level}`), from: l.majorFrom, to: l.majorTo === 'unlimited' ? t('license.unlimited') : l.majorTo, issued: l.issued, }); const state = !l.valid ? say('license.licenseNotValid') : l.installed ? `${say('license.licenseInstalled')}` : `` + (l.covers ? '' : ` ${say('license.licenseNotCovered')}`); return `${esc(t('license.featNoShot'))}
`; }; img.src = `${CONFIG.LICENSE.FEATURE_IMAGES}/${id}.webp`; }; const hide = () => { on = null; shot.hidden = true; root.querySelectorAll('.is-on').forEach(r => r.classList.remove('is-on')); }; const over = (e) => { if (!root.isConnected) { stop(); return; } const mark = e.target.closest?.(MARKS); const row = mark?.closest('[data-feature]'); if (row && root.contains(row)) show(row, mark); else hide(); }; const stop = () => { shot.remove(); document.removeEventListener('pointerover', over); window.removeEventListener('scroll', hide, true); window.removeEventListener('hashchange', stop); }; document.addEventListener('pointerover', over); window.addEventListener('scroll', hide, { capture: true, passive: true }); window.addEventListener('hashchange', stop); root.addEventListener('focusin', (e) => { const row = e.target.closest('[data-feature]'); if (row) show(row); }); root.addEventListener('focusout', hide); root.querySelectorAll('.lic-group').forEach(d => d.addEventListener('toggle', hide)); } export async function render(el) { const s = licenseSnapshot() ?? await loadLicense(); const expand = await expanders('license', Object.fromEntries(CONFIG.LICENSE.FEATURE_GROUPS.map(g => [groupKey(g), false]))); el.innerHTML = `