// nip19.ts import { bytesToHex, concatBytes, hexToBytes } from "@noble/hashes/utils"; import { bech32 } from "@scure/base"; // utils.ts var utf8Decoder = new TextDecoder("utf-8"); var utf8Encoder = new TextEncoder(); // nip19.ts var Bech32MaxSize = 5e3; var BECH32_REGEX = /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/; function integerToUint8Array(number) { const uint8Array = new Uint8Array(4); uint8Array[0] = number >> 24 & 255; uint8Array[1] = number >> 16 & 255; uint8Array[2] = number >> 8 & 255; uint8Array[3] = number & 255; return uint8Array; } function decode(nip19) { let { prefix, words } = bech32.decode(nip19, Bech32MaxSize); let data = new Uint8Array(bech32.fromWords(words)); switch (prefix) { case "nprofile": { let tlv = parseTLV(data); if (!tlv[0]?.[0]) throw new Error("missing TLV 0 for nprofile"); if (tlv[0][0].length !== 32) throw new Error("TLV 0 should be 32 bytes"); return { type: "nprofile", data: { pubkey: bytesToHex(tlv[0][0]), relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [] } }; } case "nevent": { let tlv = parseTLV(data); if (!tlv[0]?.[0]) throw new Error("missing TLV 0 for nevent"); if (tlv[0][0].length !== 32) throw new Error("TLV 0 should be 32 bytes"); if (tlv[2] && tlv[2][0].length !== 32) throw new Error("TLV 2 should be 32 bytes"); if (tlv[3] && tlv[3][0].length !== 4) throw new Error("TLV 3 should be 4 bytes"); return { type: "nevent", data: { id: bytesToHex(tlv[0][0]), relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [], author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : void 0, kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : void 0 } }; } case "naddr": { let tlv = parseTLV(data); if (!tlv[0]?.[0]) throw new Error("missing TLV 0 for naddr"); if (!tlv[2]?.[0]) throw new Error("missing TLV 2 for naddr"); if (tlv[2][0].length !== 32) throw new Error("TLV 2 should be 32 bytes"); if (!tlv[3]?.[0]) throw new Error("missing TLV 3 for naddr"); if (tlv[3][0].length !== 4) throw new Error("TLV 3 should be 4 bytes"); return { type: "naddr", data: { identifier: utf8Decoder.decode(tlv[0][0]), pubkey: bytesToHex(tlv[2][0]), kind: parseInt(bytesToHex(tlv[3][0]), 16), relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [] } }; } case "nrelay": { let tlv = parseTLV(data); if (!tlv[0]?.[0]) throw new Error("missing TLV 0 for nrelay"); return { type: "nrelay", data: utf8Decoder.decode(tlv[0][0]) }; } case "nsec": case "npub": case "note": return { type: prefix, data: bytesToHex(data) }; default: throw new Error(`unknown prefix ${prefix}`); } } function parseTLV(data) { let result = {}; let rest = data; while (rest.length > 0) { let t = rest[0]; let l = rest[1]; if (!l) throw new Error(`malformed TLV ${t}`); let v = rest.slice(2, 2 + l); rest = rest.slice(2 + l); if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`); result[t] = result[t] || []; result[t].push(v); } return result; } function nsecEncode(hex) { return encodeBytes("nsec", hex); } function npubEncode(hex) { return encodeBytes("npub", hex); } function noteEncode(hex) { return encodeBytes("note", hex); } function encodeBech32(prefix, data) { let words = bech32.toWords(data); return bech32.encode(prefix, words, Bech32MaxSize); } function encodeBytes(prefix, hex) { let data = hexToBytes(hex); return encodeBech32(prefix, data); } function nprofileEncode(profile) { let data = encodeTLV({ 0: [hexToBytes(profile.pubkey)], 1: (profile.relays || []).map((url) => utf8Encoder.encode(url)) }); return encodeBech32("nprofile", data); } function neventEncode(event) { let kindArray; if (event.kind != void 0) { kindArray = integerToUint8Array(event.kind); } let data = encodeTLV({ 0: [hexToBytes(event.id)], 1: (event.relays || []).map((url) => utf8Encoder.encode(url)), 2: event.author ? [hexToBytes(event.author)] : [], 3: kindArray ? [new Uint8Array(kindArray)] : [] }); return encodeBech32("nevent", data); } function naddrEncode(addr) { let kind = new ArrayBuffer(4); new DataView(kind).setUint32(0, addr.kind, false); let data = encodeTLV({ 0: [utf8Encoder.encode(addr.identifier)], 1: (addr.relays || []).map((url) => utf8Encoder.encode(url)), 2: [hexToBytes(addr.pubkey)], 3: [new Uint8Array(kind)] }); return encodeBech32("naddr", data); } function nrelayEncode(url) { let data = encodeTLV({ 0: [utf8Encoder.encode(url)] }); return encodeBech32("nrelay", data); } function encodeTLV(tlv) { let entries = []; Object.entries(tlv).forEach(([t, vs]) => { vs.forEach((v) => { let entry = new Uint8Array(v.length + 2); entry.set([parseInt(t)], 0); entry.set([v.length], 1); entry.set(v, 2); entries.push(entry); }); }); return concatBytes(...entries); } export { BECH32_REGEX, decode, naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nrelayEncode, nsecEncode };