// nip19.ts import { bytesToHex as bytesToHex2, concatBytes, hexToBytes as hexToBytes2 } from "@noble/hashes/utils"; import { bech32 } from "@scure/base"; // utils.ts import { bytesToHex, hexToBytes } from "@noble/hashes/utils"; var utf8Decoder = new TextDecoder("utf-8"); var utf8Encoder = new TextEncoder(); // nip19.ts var NostrTypeGuard = { isNProfile: (value) => /^nprofile1[a-z\d]+$/.test(value || ""), isNEvent: (value) => /^nevent1[a-z\d]+$/.test(value || ""), isNAddr: (value) => /^naddr1[a-z\d]+$/.test(value || ""), isNSec: (value) => /^nsec1[a-z\d]{58}$/.test(value || ""), isNPub: (value) => /^npub1[a-z\d]{58}$/.test(value || ""), isNote: (value) => /^note1[a-z\d]+$/.test(value || ""), isNcryptsec: (value) => /^ncryptsec1[a-z\d]+$/.test(value || "") }; 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 decodeNostrURI(nip19code) { try { if (nip19code.startsWith("nostr:")) nip19code = nip19code.substring(6); return decode(nip19code); } catch (_err) { return { type: "invalid", data: null }; } } function decode(code) { let { prefix, words } = bech32.decode(code, 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: bytesToHex2(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: bytesToHex2(tlv[0][0]), relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [], author: tlv[2]?.[0] ? bytesToHex2(tlv[2][0]) : void 0, kind: tlv[3]?.[0] ? parseInt(bytesToHex2(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: bytesToHex2(tlv[2][0]), kind: parseInt(bytesToHex2(tlv[3][0]), 16), relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [] } }; } case "nsec": return { type: prefix, data }; case "npub": case "note": return { type: prefix, data: bytesToHex2(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]; 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(key) { return encodeBytes("nsec", key); } function npubEncode(hex) { return encodeBytes("npub", hexToBytes2(hex)); } function noteEncode(hex) { return encodeBytes("note", hexToBytes2(hex)); } function encodeBech32(prefix, data) { let words = bech32.toWords(data); return bech32.encode(prefix, words, Bech32MaxSize); } function encodeBytes(prefix, bytes) { return encodeBech32(prefix, bytes); } function nprofileEncode(profile) { let data = encodeTLV({ 0: [hexToBytes2(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: [hexToBytes2(event.id)], 1: (event.relays || []).map((url) => utf8Encoder.encode(url)), 2: event.author ? [hexToBytes2(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: [hexToBytes2(addr.pubkey)], 3: [new Uint8Array(kind)] }); return encodeBech32("naddr", data); } function encodeTLV(tlv) { let entries = []; Object.entries(tlv).reverse().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, Bech32MaxSize, NostrTypeGuard, decode, decodeNostrURI, encodeBytes, naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nsecEncode };