Files
AtreidesAssetsFree/shared/zap.js
T
2026-10-29 11:57:29 +01:00

88 lines
3.1 KiB
JavaScript

// Generated, do not edit. sha256:e8c40c7f89911d6db87ea8c48a3cd675bb64d66a36f01a1148bfcf8fc28f29e5
export const MEMO_MAX = 2000;
const HEX64 = /^[0-9a-f]{64}$/;
const tag = (tags, name) => (Array.isArray(tags) ? tags.find(t => Array.isArray(t) && t[0] === name)?.[1] : undefined);
function zapRequest(memo) {
let ev = memo;
if (typeof memo === 'string') {
const s = memo.trim();
if (!s.startsWith('{')) return null;
try { ev = JSON.parse(s); } catch { return null; }
}
if (!ev || typeof ev !== 'object' || Number(ev.kind) !== 9734) return null;
return ev;
}
export function zapContext(memo) {
const ev = zapRequest(memo);
if (!ev) return null;
const hex = v => (typeof v === 'string' && HEX64.test(v.toLowerCase()) ? v.toLowerCase() : null);
const message = typeof ev.content === 'string' ? ev.content.trim() : '';
return { sender: hex(ev.pubkey), recipient: hex(tag(ev.tags, 'p')), message, note: hex(tag(ev.tags, 'e')) };
}
export function compactMemo(memo) {
const ev = zapRequest(memo);
if (ev) {
const tags = (Array.isArray(ev.tags) ? ev.tags : []).filter(t => Array.isArray(t) && (t[0] === 'p' || t[0] === 'e'))
.map(t => [t[0], String(t[1] ?? '')]);
const klein = { kind: 9734, pubkey: String(ev.pubkey ?? ''), content: String(ev.content ?? '').slice(0, 1000), tags };
return JSON.stringify(klein).slice(0, MEMO_MAX);
}
if (typeof memo !== 'string') return null;
const s = memo.trim();
return s ? s.slice(0, MEMO_MAX) : null;
}
const CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';
function polymod(values) {
const GEN = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
let chk = 1;
for (const v of values) {
const top = chk >> 25;
chk = ((chk & 0x1ffffff) << 5) ^ v;
for (let i = 0; i < 5; i++) if ((top >> i) & 1) chk ^= GEN[i];
}
return chk;
}
function toWords(bytes) {
const out = [];
let acc = 0, bits = 0;
for (const b of bytes) {
acc = (acc << 8) | b;
bits += 8;
while (bits >= 5) { bits -= 5; out.push((acc >> bits) & 31); }
}
if (bits > 0) out.push((acc << (5 - bits)) & 31);
return out;
}
export function npub(hex) {
if (typeof hex !== 'string' || !HEX64.test(hex)) return null;
const bytes = hex.match(/../g).map(h => parseInt(h, 16));
const hrp = 'npub';
const data = toWords(bytes);
const expand = [...[...hrp].map(c => c.charCodeAt(0) >> 5), 0, ...[...hrp].map(c => c.charCodeAt(0) & 31)];
const mod = polymod([...expand, ...data, 0, 0, 0, 0, 0, 0]) ^ 1;
const checksum = Array.from({ length: 6 }, (_, i) => (mod >> (5 * (5 - i))) & 31);
return `${hrp}1${[...data, ...checksum].map(w => CHARSET[w]).join('')}`;
}
export function npubShort(hex) {
const n = npub(hex);
return n ? `${n.slice(0, 9)}…${n.slice(-4)}` : null;
}
export function memoNote(memo, direction) {
const z = zapContext(memo);
if (z) {
const wie = npubShort(direction === 'in' ? z.sender : z.recipient);
const kop = `zap ${direction === 'in' ? 'from' : 'to'}${wie ? ` ${wie}` : ''}`;
return z.message ? `${kop}: "${z.message}"` : kop;
}
const s = compactMemo(memo);
return s ? s.slice(0, 200) : null;
}