@qntx/nostr 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{abort-Ba8tDrOI.mjs → abort-DBq2STPj.mjs} +13 -6
- package/dist/abort-DBq2STPj.mjs.map +1 -0
- package/dist/{builder-sSflu6nB.d.mts → builder-CTwkB2zM.d.mts} +14 -15
- package/dist/{builder-9tjI6WQ3.mjs → builder-aNU2gGFP.mjs} +11 -17
- package/dist/builder-aNU2gGFP.mjs.map +1 -0
- package/dist/{client-CadO5fAX.mjs → client-Cj2lUaVh.mjs} +141 -353
- package/dist/client-Cj2lUaVh.mjs.map +1 -0
- package/dist/client.d.mts +2 -2
- package/dist/client.mjs +2 -2
- package/dist/collections-DtwMc1NU.mjs +33 -0
- package/dist/collections-DtwMc1NU.mjs.map +1 -0
- package/dist/core.d.mts +9 -8
- package/dist/core.mjs +7 -7
- package/dist/emitter-DkCY6NkU.mjs +32 -0
- package/dist/emitter-DkCY6NkU.mjs.map +1 -0
- package/dist/{error-BW7re1UN.d.mts → error-BD_0QFKT.d.mts} +2 -2
- package/dist/{error-DrEIM7FO.mjs → error-BILMe3Gr.mjs} +2 -2
- package/dist/{error-DrEIM7FO.mjs.map → error-BILMe3Gr.mjs.map} +1 -1
- package/dist/{error-CR8Urc84.d.mts → error-BquXDmIN.d.mts} +4 -4
- package/dist/{error-B__OMBRY.mjs → error-DlhGW4mJ.mjs} +2 -2
- package/dist/{error-B__OMBRY.mjs.map → error-DlhGW4mJ.mjs.map} +1 -1
- package/dist/{event-D8Nfoh4K.mjs → event-CHf47dPM.mjs} +16 -10
- package/dist/event-CHf47dPM.mjs.map +1 -0
- package/dist/{event-fU3Y01PR.d.mts → event-DJeb_DIL.d.mts} +4 -2
- package/dist/{filter-C0IMByE3.d.mts → filter-jI_9htF7.d.mts} +2 -2
- package/dist/{gossip-oloDMWEj.mjs → gossip-DFxIBlsr.mjs} +23 -33
- package/dist/gossip-DFxIBlsr.mjs.map +1 -0
- package/dist/{gossip-DpIvkBuj.d.mts → gossip-OOeeFzG5.d.mts} +37 -28
- package/dist/gossip.d.mts +1 -1
- package/dist/gossip.mjs +1 -1
- package/dist/{index-D1bqFHKB.d.mts → index-BxCBX-8R.d.mts} +18 -18
- package/dist/{index-lvXeER5t.d.mts → index-CPVEyzNX.d.mts} +32 -50
- package/dist/{index-MxC28S4P.d.mts → index-C_w2WfVz.d.mts} +27 -29
- package/dist/{index-CNl2q67H.d.mts → index-Cl_1XdYP.d.mts} +111 -180
- package/dist/{index-CvkvqB16.d.mts → index-DU9tRFTZ.d.mts} +7 -20
- package/dist/{index-q4MDce_r.d.mts → index-DyKwQnbt.d.mts} +6 -8
- package/dist/index.d.mts +23 -21
- package/dist/index.mjs +21 -19
- package/dist/{instance-DQE8BoWt.mjs → instance-C62w3cEt.mjs} +26 -27
- package/dist/instance-C62w3cEt.mjs.map +1 -0
- package/dist/{instance-CIca-ynn.d.mts → instance-DjsL8h84.d.mts} +5 -5
- package/dist/{key-Cv4_pN3x.d.mts → key-D_5OgGT7.d.mts} +11 -7
- package/dist/{key-Bps-LqX7.mjs → key-DnVpchl6.mjs} +13 -9
- package/dist/key-DnVpchl6.mjs.map +1 -0
- package/dist/{loaders-o6YXB_Ri.mjs → loaders-BmPkQfzI.mjs} +73 -82
- package/dist/loaders-BmPkQfzI.mjs.map +1 -0
- package/dist/loaders.d.mts +3 -3
- package/dist/loaders.mjs +2 -2
- package/dist/{memory-C2EVx0_O.mjs → memory-CdJ07kub.mjs} +2 -2
- package/dist/memory-CdJ07kub.mjs.map +1 -0
- package/dist/{memory-index-Do1mz0WF.mjs → memory-index-Cbc83vOZ.mjs} +30 -247
- package/dist/memory-index-Cbc83vOZ.mjs.map +1 -0
- package/dist/message-oNr7t0SJ.mjs +194 -0
- package/dist/message-oNr7t0SJ.mjs.map +1 -0
- package/dist/{message-iGPIqnn0.d.mts → message-tclYCVNc.d.mts} +6 -6
- package/dist/{nip17-CKIufV98.d.mts → nip17-B5WgW4C4.d.mts} +6 -7
- package/dist/{nip19-BevCJZsp.d.mts → nip19-DpPN17bY.d.mts} +25 -31
- package/dist/{nip46-DDV4dC56.d.mts → nip46-BHaxC9TZ.d.mts} +19 -21
- package/dist/nip51-CR0Q8eym.d.mts +87 -0
- package/dist/{nip59-zQgdLcEr.d.mts → nip59-C-RWFQIv.d.mts} +11 -5
- package/dist/nip65-D1fbmhOg.d.mts +23 -0
- package/dist/{nip77-DH4RhS5r.d.mts → nip77-DzUwUxHq.d.mts} +8 -9
- package/dist/nips/blossom.d.mts +17 -13
- package/dist/nips/blossom.mjs +30 -9
- package/dist/nips/blossom.mjs.map +1 -1
- package/dist/nips/nip04.mjs +17 -7
- package/dist/nips/nip04.mjs.map +1 -1
- package/dist/nips/nip05.d.mts +9 -10
- package/dist/nips/nip05.mjs +1 -4
- package/dist/nips/nip05.mjs.map +1 -1
- package/dist/nips/nip10.d.mts +8 -8
- package/dist/nips/nip10.mjs +34 -32
- package/dist/nips/nip10.mjs.map +1 -1
- package/dist/nips/nip11.d.mts +28 -28
- package/dist/nips/nip11.mjs +4 -4
- package/dist/nips/nip11.mjs.map +1 -1
- package/dist/nips/nip13.d.mts +7 -7
- package/dist/nips/nip13.mjs +32 -10
- package/dist/nips/nip13.mjs.map +1 -1
- package/dist/nips/nip17.d.mts +1 -1
- package/dist/nips/nip17.mjs +16 -34
- package/dist/nips/nip17.mjs.map +1 -1
- package/dist/nips/nip19.d.mts +2 -2
- package/dist/nips/nip19.mjs +16 -28
- package/dist/nips/nip19.mjs.map +1 -1
- package/dist/nips/nip21.d.mts +9 -4
- package/dist/nips/nip21.mjs +15 -5
- package/dist/nips/nip21.mjs.map +1 -1
- package/dist/nips/nip27.d.mts +22 -22
- package/dist/nips/nip27.mjs +2 -2
- package/dist/nips/nip27.mjs.map +1 -1
- package/dist/nips/nip42.d.mts +1 -1
- package/dist/nips/nip42.mjs +2 -1
- package/dist/nips/nip42.mjs.map +1 -1
- package/dist/nips/nip44.mjs +2 -2
- package/dist/nips/nip44.mjs.map +1 -1
- package/dist/nips/nip46.d.mts +2 -2
- package/dist/nips/nip46.mjs +15 -19
- package/dist/nips/nip46.mjs.map +1 -1
- package/dist/nips/nip49.d.mts +9 -9
- package/dist/nips/nip49.mjs +4 -4
- package/dist/nips/nip49.mjs.map +1 -1
- package/dist/nips/nip51.d.mts +2 -86
- package/dist/nips/nip51.mjs +7 -23
- package/dist/nips/nip51.mjs.map +1 -1
- package/dist/nips/nip57.d.mts +25 -23
- package/dist/nips/nip57.mjs +12 -17
- package/dist/nips/nip57.mjs.map +1 -1
- package/dist/nips/nip59.d.mts +1 -1
- package/dist/nips/nip59.mjs +27 -19
- package/dist/nips/nip59.mjs.map +1 -1
- package/dist/nips/nip65.d.mts +2 -2
- package/dist/nips/nip65.mjs +14 -37
- package/dist/nips/nip65.mjs.map +1 -1
- package/dist/nips/nip77.d.mts +1 -1
- package/dist/nips/nip77.mjs +33 -32
- package/dist/nips/nip77.mjs.map +1 -1
- package/dist/nips/nip98.d.mts +5 -5
- package/dist/nips/nip98.mjs +8 -8
- package/dist/nips/nip98.mjs.map +1 -1
- package/dist/{pool-DBIYMtwy.d.mts → pool-CqQvUnsq.d.mts} +132 -108
- package/dist/pool-vlw74C4t.mjs +606 -0
- package/dist/pool-vlw74C4t.mjs.map +1 -0
- package/dist/put-w13ci3sC.mjs +187 -0
- package/dist/put-w13ci3sC.mjs.map +1 -0
- package/dist/{reactive-BfhPp9a3.mjs → reactive-Tz0otDIP.mjs} +125 -88
- package/dist/reactive-Tz0otDIP.mjs.map +1 -0
- package/dist/{reactive-7aqeip4A.d.mts → reactive-gGqUrzW8.d.mts} +20 -26
- package/dist/relay-quCs7MHD.mjs +1811 -0
- package/dist/relay-quCs7MHD.mjs.map +1 -0
- package/dist/relay.d.mts +4 -4
- package/dist/relay.mjs +3 -2
- package/dist/serial-Bzpw-xz3.mjs +21 -0
- package/dist/serial-Bzpw-xz3.mjs.map +1 -0
- package/dist/{signer-CYQutDzD.mjs → signer-poTGe6Er.mjs} +12 -14
- package/dist/signer-poTGe6Er.mjs.map +1 -0
- package/dist/signer.d.mts +2 -2
- package/dist/signer.mjs +2 -2
- package/dist/{storage-Dky3wuoH.mjs → storage-B5IXTVuS.mjs} +28 -51
- package/dist/storage-B5IXTVuS.mjs.map +1 -0
- package/dist/storage.d.mts +3 -3
- package/dist/storage.mjs +4 -4
- package/dist/store.d.mts +2 -2
- package/dist/store.mjs +1 -1
- package/dist/testing.d.mts +19 -19
- package/dist/testing.mjs +9 -9
- package/dist/testing.mjs.map +1 -1
- package/dist/{types-2pCUprRU.d.mts → types-BacwnDtU.d.mts} +10 -10
- package/dist/{types-CRQEk0Oi.d.mts → types-DNmiscfd.d.mts} +2 -2
- package/dist/{util-LfQirgDk.mjs → util-DMF9AIO0.mjs} +33 -7
- package/dist/util-DMF9AIO0.mjs.map +1 -0
- package/dist/{verifier-t5WoWbtY.mjs → verifier-B51Wkt5H.mjs} +3 -3
- package/dist/verifier-B51Wkt5H.mjs.map +1 -0
- package/dist/verifier-CgTFpgsC.d.mts +22 -0
- package/dist/wasm.browser.d.mts +3 -3
- package/dist/wasm.browser.mjs +3 -3
- package/dist/wasm.d.mts +3 -3
- package/dist/wasm.mjs +3 -3
- package/dist/wasm.mjs.map +1 -1
- package/package.json +5 -9
- package/dist/abort-Ba8tDrOI.mjs.map +0 -1
- package/dist/builder-9tjI6WQ3.mjs.map +0 -1
- package/dist/client-CadO5fAX.mjs.map +0 -1
- package/dist/event-D8Nfoh4K.mjs.map +0 -1
- package/dist/gossip-oloDMWEj.mjs.map +0 -1
- package/dist/instance-DQE8BoWt.mjs.map +0 -1
- package/dist/key-Bps-LqX7.mjs.map +0 -1
- package/dist/loaders-o6YXB_Ri.mjs.map +0 -1
- package/dist/memory-C2EVx0_O.mjs.map +0 -1
- package/dist/memory-index-Do1mz0WF.mjs.map +0 -1
- package/dist/message-DcY6Fi9o.mjs +0 -193
- package/dist/message-DcY6Fi9o.mjs.map +0 -1
- package/dist/nip65-CjgmdpPB.d.mts +0 -26
- package/dist/nips/nip96.d.mts +0 -40
- package/dist/nips/nip96.mjs +0 -118
- package/dist/nips/nip96.mjs.map +0 -1
- package/dist/pool-As20OGxB.mjs +0 -2166
- package/dist/pool-As20OGxB.mjs.map +0 -1
- package/dist/reactive-BfhPp9a3.mjs.map +0 -1
- package/dist/signer-CYQutDzD.mjs.map +0 -1
- package/dist/storage-Dky3wuoH.mjs.map +0 -1
- package/dist/util-LfQirgDk.mjs.map +0 -1
- package/dist/verifier-t5WoWbtY.mjs.map +0 -1
package/dist/nips/nip19.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nip19.mjs","names":[],"sources":["../../src/nips/nip19.ts"],"sourcesContent":["import { bech32 } from \"@scure/base\";\n\nimport { NostrError } from \"../core/error.ts\";\nimport {\n assertByteLength,\n assertHex32,\n bytesToHex,\n hexToBytes,\n utf8Decoder,\n utf8Encoder,\n} from \"../core/util.ts\";\n\n/** Bech32 `nprofile1…` string (TLV profile pointer). */\nexport type NProfile = `nprofile1${string}`;\n/** Bech32 `nevent1…` string (TLV event pointer). */\nexport type NEvent = `nevent1${string}`;\n/** Bech32 `naddr1…` string (TLV address pointer). */\nexport type NAddr = `naddr1${string}`;\n/** Bech32 `nsec1…` string (32-byte secret key). */\nexport type NSec = `nsec1${string}`;\n/** Bech32 `npub1…` string (32-byte public key). */\nexport type NPub = `npub1${string}`;\n/** Bech32 `note1…` string (32-byte event id). */\nexport type Note = `note1${string}`;\n\n/** Maximum bech32 string length accepted by {@link decode} (NIP-19). */\nexport const Bech32MaxSize = 5000;\n\n/** Decoded `nprofile` payload: a pubkey plus optional relay hints. */\nexport type ProfilePointer = {\n pubkey: string;\n relays?: string[];\n};\n\n/** Decoded `nevent` payload: an event id plus optional relay/author/kind hints. */\nexport type EventPointer = {\n id: string;\n relays?: string[];\n author?: string;\n kind?: number;\n};\n\n/** Decoded `naddr` payload: a replaceable-event coordinate plus optional relay hints. */\nexport type AddressPointer = {\n identifier: string;\n pubkey: string;\n kind: number;\n relays?: string[];\n};\n\n/** Result of {@link decode}: the bech32 prefix and its decoded payload. */\nexport type DecodedResult =\n | { type: \"nprofile\"; data: ProfilePointer }\n | { type: \"nevent\"; data: EventPointer }\n | { type: \"naddr\"; data: AddressPointer }\n | { type: \"nsec\"; data: Uint8Array }\n | { type: \"npub\"; data: string }\n | { type: \"note\"; data: string };\n\n/** Error thrown by NIP-19 encoding/decoding failures. */\nexport class Nip19Error extends NostrError {\n override name = \"Nip19Error\";\n constructor(message: string) {\n super(message);\n }\n}\n\ntype TLV = Record<number, Uint8Array[]>;\n\nfunction integerToUint8Array(number: number): Uint8Array {\n const out = new Uint8Array(4);\n new DataView(out.buffer).setUint32(0, number);\n return out;\n}\n\nfunction parseTLV(data: Uint8Array): TLV {\n const result: TLV = {};\n let rest = data;\n while (rest.length > 0) {\n if (rest.length < 2) {\n throw new Nip19Error(\"not enough data to read TLV\");\n }\n const t = rest.at(0);\n const l = rest.at(1);\n if (t === undefined || l === undefined) {\n throw new Nip19Error(\"not enough data to read TLV\");\n }\n const v = rest.slice(2, 2 + l);\n rest = rest.slice(2 + l);\n if (v.length < l) {\n throw new Nip19Error(`not enough data to read on TLV ${t}`);\n }\n result[t] = result[t] ?? [];\n result[t].push(v);\n }\n return result;\n}\n\nfunction assertNip19Kind(kind: number): void {\n if (!Number.isInteger(kind) || kind < 0 || kind > 0xffffffff) {\n throw new Nip19Error(`invalid kind: ${kind}`);\n }\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n const entries: Uint8Array[] = [];\n for (const [t, vs] of Object.entries(tlv).reverse()) {\n for (const v of vs) {\n if (v.length > 255) {\n throw new Nip19Error(\"TLV value exceeds 255 bytes\");\n }\n const entry = new Uint8Array(v.length + 2);\n entry[0] = Math.trunc(Number(t));\n entry[1] = v.length;\n entry.set(v, 2);\n entries.push(entry);\n }\n }\n let total = 0;\n for (const e of entries) {\n total += e.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const e of entries) {\n out.set(e, offset);\n offset += e.length;\n }\n return out;\n}\n\nfunction encodeBech32<Prefix extends string>(\n prefix: Prefix,\n data: Uint8Array,\n): `${Prefix}1${string}` {\n const words = bech32.toWords(data);\n // oxlint-disable-next-line no-unsafe-type-assertion -- bech32 output is `${prefix}1…` by construction\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`;\n}\n\nexport function encodeBytes<Prefix extends string>(\n prefix: Prefix,\n bytes: Uint8Array,\n): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes);\n}\n\n/** Encode a 32-byte secret key as `nsec1…`; throws {@link Nip19Error} on wrong length. */\nexport function nsecEncode(key: Uint8Array): NSec {\n assertByteLength(key, 32, \"secret key\");\n return encodeBytes(\"nsec\", key);\n}\n\n/** Encode a hex public key as `npub1…`; throws {@link HexError} on bad hex. */\nexport function npubEncode(hex: string): NPub {\n return encodeBytes(\"npub\", hexToBytes(assertHex32(hex, \"pubkey\")));\n}\n\n/** Encode a hex event id as `note1…`; throws {@link HexError} on bad hex. */\nexport function noteEncode(hex: string): Note {\n return encodeBytes(\"note\", hexToBytes(assertHex32(hex, \"event id\")));\n}\n\n/** Encode a profile pointer as `nprofile1…`. */\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n const data = encodeTLV({\n 0: [hexToBytes(assertHex32(profile.pubkey, \"pubkey\"))],\n 1: (profile.relays ?? []).map((url) => utf8Encoder.encode(url)),\n });\n return encodeBech32(\"nprofile\", data);\n}\n\n/** Encode an event pointer as `nevent1…`. */\nexport function neventEncode(event: EventPointer): NEvent {\n if (event.kind !== undefined) {\n assertNip19Kind(event.kind);\n }\n const kindArray = event.kind === undefined ? undefined : integerToUint8Array(event.kind);\n const data = encodeTLV({\n 0: [hexToBytes(assertHex32(event.id, \"event id\"))],\n 1: (event.relays ?? []).map((url) => utf8Encoder.encode(url)),\n 2:\n event.author !== undefined && event.author !== \"\"\n ? [hexToBytes(assertHex32(event.author, \"author\"))]\n : [],\n 3: kindArray ? [kindArray] : [],\n });\n return encodeBech32(\"nevent\", data);\n}\n\n/** Encode an address pointer as `naddr1…`. */\nexport function naddrEncode(addr: AddressPointer): NAddr {\n assertNip19Kind(addr.kind);\n const kind = integerToUint8Array(addr.kind);\n const data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays ?? []).map((url) => utf8Encoder.encode(url)),\n 2: [hexToBytes(assertHex32(addr.pubkey, \"pubkey\"))],\n 3: [kind],\n });\n return encodeBech32(\"naddr\", data);\n}\n\n/** Decode a NIP-19 bech32 entity; throws {@link Nip19Error} on bad input or unknown prefix. */\nexport function decode(code: string): DecodedResult {\n const { prefix, words } = bech32.decode(code, Bech32MaxSize);\n const data = new Uint8Array(bech32.fromWords(words));\n\n switch (prefix) {\n case \"nprofile\": {\n const tlv = parseTLV(data);\n if (!tlv[0]?.[0]) {\n throw new Nip19Error(\"missing TLV 0 for nprofile\");\n }\n if (tlv[0][0].length !== 32) {\n throw new Nip19Error(\"TLV 0 should be 32 bytes\");\n }\n return {\n type: \"nprofile\",\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],\n },\n };\n }\n case \"nevent\": {\n const tlv = parseTLV(data);\n if (!tlv[0]?.[0]) {\n throw new Nip19Error(\"missing TLV 0 for nevent\");\n }\n if (tlv[0][0].length !== 32) {\n throw new Nip19Error(\"TLV 0 should be 32 bytes\");\n }\n if (tlv[2]?.[0] && tlv[2][0].length !== 32) {\n throw new Nip19Error(\"TLV 2 should be 32 bytes\");\n }\n if (tlv[3]?.[0] && tlv[3][0].length !== 4) {\n throw new Nip19Error(\"TLV 3 should be 4 bytes\");\n }\n const pointer: EventPointer = {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],\n };\n const author = tlv[2]?.[0];\n if (author !== undefined) {\n pointer.author = bytesToHex(author);\n }\n const kind = tlv[3]?.[0];\n if (kind !== undefined) {\n pointer.kind = Number.parseInt(bytesToHex(kind), 16);\n }\n return { type: \"nevent\", data: pointer };\n }\n case \"naddr\": {\n const tlv = parseTLV(data);\n if (!tlv[0]?.[0]) {\n throw new Nip19Error(\"missing TLV 0 for naddr\");\n }\n if (!tlv[2]?.[0]) {\n throw new Nip19Error(\"missing TLV 2 for naddr\");\n }\n if (tlv[2][0].length !== 32) {\n throw new Nip19Error(\"TLV 2 should be 32 bytes\");\n }\n if (!tlv[3]?.[0]) {\n throw new Nip19Error(\"missing TLV 3 for naddr\");\n }\n if (tlv[3][0].length !== 4) {\n throw new Nip19Error(\"TLV 3 should be 4 bytes\");\n }\n return {\n type: \"naddr\",\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: Number.parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],\n },\n };\n }\n case \"nsec\":\n if (data.length !== 32) {\n throw new Nip19Error(\"nsec must be 32 bytes\");\n }\n return { type: \"nsec\", data };\n case \"npub\":\n case \"note\":\n if (data.length !== 32) {\n throw new Nip19Error(`${prefix} must be 32 bytes`);\n }\n return { type: prefix, data: bytesToHex(data) };\n default:\n throw new Nip19Error(`unknown prefix ${prefix}`);\n }\n}\n\n/** Decode `nostr:` URI or bare bech32; returns invalid sentinel instead of throwing. */\nexport function decodeNostrURI(\n nip19code: string,\n): DecodedResult | { type: \"invalid\"; data: undefined } {\n try {\n let code = nip19code;\n if (code.startsWith(\"nostr:\")) {\n code = code.slice(6);\n // NIP-21 excludes nsec from nostr: identifiers.\n if (code.startsWith(\"nsec1\")) {\n return { type: \"invalid\", data: undefined };\n }\n }\n return decode(code);\n } catch {\n return { type: \"invalid\", data: undefined };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nip19.mjs","names":[],"sources":["../../src/nips/nip19.ts"],"sourcesContent":["import { bech32 } from \"@scure/base\";\n\nimport { NostrError, errorMessage } from \"../core/error.ts\";\nimport type { Mutable } from \"../core/util.ts\";\nimport {\n assertByteLength,\n assertHex32,\n bytesToHex,\n hexToBytes,\n utf8Decoder,\n utf8Encoder,\n} from \"../core/util.ts\";\n\n/** Bech32 `nprofile1…` string (TLV profile pointer). */\nexport type NProfile = `nprofile1${string}`;\n/** Bech32 `nevent1…` string (TLV event pointer). */\nexport type NEvent = `nevent1${string}`;\n/** Bech32 `naddr1…` string (TLV address pointer). */\nexport type NAddr = `naddr1${string}`;\n/** Bech32 `nsec1…` string (32-byte secret key). */\nexport type NSec = `nsec1${string}`;\n/** Bech32 `npub1…` string (32-byte public key). */\nexport type NPub = `npub1${string}`;\n/** Bech32 `note1…` string (32-byte event id). */\nexport type Note = `note1${string}`;\n\n/** Maximum bech32 string length accepted by {@link decode} (NIP-19). */\nexport const Bech32MaxSize = 5000;\n\n/** Decoded `nprofile` payload: a pubkey plus optional relay hints. */\nexport type ProfilePointer = {\n readonly pubkey: string;\n readonly relays?: ReadonlyArray<string> | undefined;\n};\n\n/** Decoded `nevent` payload: an event id plus optional relay/author/kind hints. */\nexport type EventPointer = {\n readonly id: string;\n readonly relays?: ReadonlyArray<string> | undefined;\n readonly author?: string | undefined;\n readonly kind?: number | undefined;\n};\n\n/** Decoded `naddr` payload: a replaceable-event coordinate plus optional relay hints. */\nexport type AddressPointer = {\n readonly identifier: string;\n readonly pubkey: string;\n readonly kind: number;\n readonly relays?: ReadonlyArray<string> | undefined;\n};\n\n/** Result of {@link decode}: the bech32 prefix and its decoded payload. */\nexport type DecodedResult =\n | { readonly type: \"nprofile\"; readonly data: ProfilePointer }\n | { readonly type: \"nevent\"; readonly data: EventPointer }\n | { readonly type: \"naddr\"; readonly data: AddressPointer }\n | { readonly type: \"nsec\"; readonly data: Uint8Array }\n | { readonly type: \"npub\"; readonly data: string }\n | { readonly type: \"note\"; readonly data: string };\n\n/** Error thrown by NIP-19 encoding/decoding failures. */\nexport class Nip19Error extends NostrError {\n override name = \"Nip19Error\";\n}\n\ntype TLV = Record<number, Uint8Array[]>;\n\nfunction integerToUint8Array(number: number): Uint8Array {\n const out = new Uint8Array(4);\n new DataView(out.buffer).setUint32(0, number);\n return out;\n}\n\nfunction parseTLV(data: Uint8Array): TLV {\n const result: TLV = {};\n let rest = data;\n while (rest.length > 0) {\n if (rest.length < 2) {\n throw new Nip19Error(\"not enough data to read TLV\");\n }\n const t = rest.at(0);\n const l = rest.at(1);\n if (t === undefined || l === undefined) {\n throw new Nip19Error(\"not enough data to read TLV\");\n }\n const v = rest.slice(2, 2 + l);\n rest = rest.slice(2 + l);\n if (v.length < l) {\n throw new Nip19Error(`not enough data to read on TLV ${t}`);\n }\n result[t] = result[t] ?? [];\n result[t].push(v);\n }\n return result;\n}\n\nfunction assertNip19Kind(kind: number): void {\n if (!Number.isInteger(kind) || kind < 0 || kind > 0xffffffff) {\n throw new Nip19Error(`invalid kind: ${kind}`);\n }\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n const entries: Uint8Array[] = [];\n for (const [t, vs] of Object.entries(tlv).reverse()) {\n for (const v of vs) {\n if (v.length > 255) {\n throw new Nip19Error(\"TLV value exceeds 255 bytes\");\n }\n const entry = new Uint8Array(v.length + 2);\n entry[0] = Math.trunc(Number(t));\n entry[1] = v.length;\n entry.set(v, 2);\n entries.push(entry);\n }\n }\n let total = 0;\n for (const e of entries) {\n total += e.length;\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const e of entries) {\n out.set(e, offset);\n offset += e.length;\n }\n return out;\n}\n\nfunction encodeBech32<Prefix extends string>(\n prefix: Prefix,\n data: Uint8Array,\n): `${Prefix}1${string}` {\n const words = bech32.toWords(data);\n // oxlint-disable-next-line no-unsafe-type-assertion -- bech32 output is `${prefix}1…` by construction\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`;\n}\n\nexport function encodeBytes<Prefix extends string>(\n prefix: Prefix,\n bytes: Uint8Array,\n): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes);\n}\n\n/** Encode a 32-byte secret key as `nsec1…`; throws {@link Nip19Error} on wrong length. */\nexport function nsecEncode(key: Uint8Array): NSec {\n assertByteLength(key, 32, \"secret key\");\n return encodeBytes(\"nsec\", key);\n}\n\n/** Encode a hex public key as `npub1…`; throws {@link HexError} on bad hex. */\nexport function npubEncode(hex: string): NPub {\n return encodeBytes(\"npub\", hexToBytes(assertHex32(hex, \"pubkey\")));\n}\n\n/** Encode a hex event id as `note1…`; throws {@link HexError} on bad hex. */\nexport function noteEncode(hex: string): Note {\n return encodeBytes(\"note\", hexToBytes(assertHex32(hex, \"event id\")));\n}\n\n/** Encode a profile pointer as `nprofile1…`. */\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n const data = encodeTLV({\n 0: [hexToBytes(assertHex32(profile.pubkey, \"pubkey\"))],\n 1: (profile.relays ?? []).map((url) => utf8Encoder.encode(url)),\n });\n return encodeBech32(\"nprofile\", data);\n}\n\n/** Encode an event pointer as `nevent1…`. */\nexport function neventEncode(event: EventPointer): NEvent {\n if (event.kind !== undefined) {\n assertNip19Kind(event.kind);\n }\n const kindArray = event.kind === undefined ? undefined : integerToUint8Array(event.kind);\n const data = encodeTLV({\n 0: [hexToBytes(assertHex32(event.id, \"event id\"))],\n 1: (event.relays ?? []).map((url) => utf8Encoder.encode(url)),\n 2:\n event.author !== undefined && event.author !== \"\"\n ? [hexToBytes(assertHex32(event.author, \"author\"))]\n : [],\n 3: kindArray ? [kindArray] : [],\n });\n return encodeBech32(\"nevent\", data);\n}\n\n/** Encode an address pointer as `naddr1…`. */\nexport function naddrEncode(addr: AddressPointer): NAddr {\n assertNip19Kind(addr.kind);\n const kind = integerToUint8Array(addr.kind);\n const data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays ?? []).map((url) => utf8Encoder.encode(url)),\n 2: [hexToBytes(assertHex32(addr.pubkey, \"pubkey\"))],\n 3: [kind],\n });\n return encodeBech32(\"naddr\", data);\n}\n\nfunction readUint32(bytes: Uint8Array): number {\n return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0);\n}\n\n/** Decode a NIP-19 bech32 entity; throws {@link Nip19Error} on bad input or unknown prefix. */\nexport function decode(code: string): DecodedResult {\n let prefix: string;\n let data: Uint8Array;\n try {\n const { prefix: hrp, words } = bech32.decode(code, Bech32MaxSize);\n prefix = hrp;\n data = new Uint8Array(bech32.fromWords(words));\n } catch (error) {\n throw new Nip19Error(`invalid bech32: ${errorMessage(error)}`, { cause: error });\n }\n\n switch (prefix) {\n case \"nprofile\": {\n const tlv = parseTLV(data);\n if (!tlv[0]?.[0]) {\n throw new Nip19Error(\"missing TLV 0 for nprofile\");\n }\n if (tlv[0][0].length !== 32) {\n throw new Nip19Error(\"TLV 0 should be 32 bytes\");\n }\n return {\n type: \"nprofile\",\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],\n },\n };\n }\n case \"nevent\": {\n const tlv = parseTLV(data);\n if (!tlv[0]?.[0]) {\n throw new Nip19Error(\"missing TLV 0 for nevent\");\n }\n if (tlv[0][0].length !== 32) {\n throw new Nip19Error(\"TLV 0 should be 32 bytes\");\n }\n if (tlv[2]?.[0] && tlv[2][0].length !== 32) {\n throw new Nip19Error(\"TLV 2 should be 32 bytes\");\n }\n if (tlv[3]?.[0] && tlv[3][0].length !== 4) {\n throw new Nip19Error(\"TLV 3 should be 4 bytes\");\n }\n const pointer: Mutable<EventPointer> = {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],\n };\n const author = tlv[2]?.[0];\n if (author !== undefined) {\n pointer.author = bytesToHex(author);\n }\n const kind = tlv[3]?.[0];\n if (kind !== undefined) {\n pointer.kind = readUint32(kind);\n }\n return { type: \"nevent\", data: pointer };\n }\n case \"naddr\": {\n const tlv = parseTLV(data);\n if (!tlv[0]?.[0]) {\n throw new Nip19Error(\"missing TLV 0 for naddr\");\n }\n if (!tlv[2]?.[0]) {\n throw new Nip19Error(\"missing TLV 2 for naddr\");\n }\n if (tlv[2][0].length !== 32) {\n throw new Nip19Error(\"TLV 2 should be 32 bytes\");\n }\n if (!tlv[3]?.[0]) {\n throw new Nip19Error(\"missing TLV 3 for naddr\");\n }\n if (tlv[3][0].length !== 4) {\n throw new Nip19Error(\"TLV 3 should be 4 bytes\");\n }\n return {\n type: \"naddr\",\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: readUint32(tlv[3][0]),\n relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],\n },\n };\n }\n case \"nsec\":\n if (data.length !== 32) {\n throw new Nip19Error(\"nsec must be 32 bytes\");\n }\n return { type: \"nsec\", data };\n case \"npub\":\n case \"note\":\n if (data.length !== 32) {\n throw new Nip19Error(`${prefix} must be 32 bytes`);\n }\n return { type: prefix, data: bytesToHex(data) };\n default:\n throw new Nip19Error(`unknown prefix ${prefix}`);\n }\n}\n"],"mappings":"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"}
|
package/dist/nips/nip21.d.mts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as NostrError } from "../error-BquXDmIN.mjs";
|
|
2
|
+
import { r as DecodedResult } from "../nip19-DpPN17bY.mjs";
|
|
2
3
|
//#region src/nips/nip21.d.ts
|
|
4
|
+
/** Error thrown by {@link parseNostrURI} on malformed or non-decodable URIs. */
|
|
5
|
+
export declare class Nip21Error extends NostrError {
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
3
8
|
/** Matches `nostr:<bech32>` (not anchored). */
|
|
4
9
|
export declare const NOSTR_URI_REGEX: RegExp;
|
|
5
10
|
export type NostrURI = {
|
|
6
11
|
/** Full URI including `nostr:` */
|
|
7
|
-
uri: `nostr:${string}`;
|
|
12
|
+
readonly uri: `nostr:${string}`;
|
|
8
13
|
/** Bech32 entity without prefix */
|
|
9
|
-
value: string;
|
|
10
|
-
decoded: DecodedResult;
|
|
14
|
+
readonly value: string;
|
|
15
|
+
readonly decoded: DecodedResult;
|
|
11
16
|
};
|
|
12
17
|
export declare function isNostrURI(value: unknown): value is `nostr:${string}`;
|
|
13
18
|
/** Parse and decode a full `nostr:…` URI. NIP-21 excludes `nsec`. */
|
package/dist/nips/nip21.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { v as NostrError } from "../util-DMF9AIO0.mjs";
|
|
2
2
|
import { decode } from "./nip19.mjs";
|
|
3
3
|
//#region src/nips/nip21.ts
|
|
4
4
|
/**
|
|
@@ -6,6 +6,10 @@ import { decode } from "./nip19.mjs";
|
|
|
6
6
|
*
|
|
7
7
|
* @see https://github.com/nostr-protocol/nips/blob/master/21.md
|
|
8
8
|
*/
|
|
9
|
+
/** Error thrown by {@link parseNostrURI} on malformed or non-decodable URIs. */
|
|
10
|
+
var Nip21Error = class extends NostrError {
|
|
11
|
+
name = "Nip21Error";
|
|
12
|
+
};
|
|
9
13
|
/** Matches `nostr:<bech32>` (not anchored). */
|
|
10
14
|
const NOSTR_URI_REGEX = /nostr:([a-z0-9]+1[02-9ac-hj-np-z]+)/i;
|
|
11
15
|
function isNostrURI(value) {
|
|
@@ -16,15 +20,21 @@ function isNostrURI(value) {
|
|
|
16
20
|
/** Parse and decode a full `nostr:…` URI. NIP-21 excludes `nsec`. */
|
|
17
21
|
function parseNostrURI(uri) {
|
|
18
22
|
const entity = /^nostr:([a-z0-9]+1[02-9ac-hj-np-z]+)$/i.exec(uri)?.at(1);
|
|
19
|
-
if (entity === void 0) throw new
|
|
20
|
-
if (entity.toLowerCase().startsWith("nsec1")) throw new
|
|
23
|
+
if (entity === void 0) throw new Nip21Error(`invalid Nostr URI: ${uri}`);
|
|
24
|
+
if (entity.toLowerCase().startsWith("nsec1")) throw new Nip21Error("NIP-21 identifiers exclude nsec");
|
|
25
|
+
let decoded;
|
|
26
|
+
try {
|
|
27
|
+
decoded = decode(entity);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
throw new Nip21Error(`invalid Nostr URI: ${uri}`, { cause: error });
|
|
30
|
+
}
|
|
21
31
|
return {
|
|
22
32
|
uri: `nostr:${entity}`,
|
|
23
33
|
value: entity,
|
|
24
|
-
decoded
|
|
34
|
+
decoded
|
|
25
35
|
};
|
|
26
36
|
}
|
|
27
37
|
//#endregion
|
|
28
|
-
export { NOSTR_URI_REGEX, isNostrURI, parseNostrURI };
|
|
38
|
+
export { NOSTR_URI_REGEX, Nip21Error, isNostrURI, parseNostrURI };
|
|
29
39
|
|
|
30
40
|
//# sourceMappingURL=nip21.mjs.map
|
package/dist/nips/nip21.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nip21.mjs","names":[],"sources":["../../src/nips/nip21.ts"],"sourcesContent":["/**\n * NIP-21: `nostr:` URI scheme\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/21.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport { decode } from \"./nip19.ts\";\nimport type { DecodedResult } from \"./nip19.ts\";\n\n/** Matches `nostr:<bech32>` (not anchored). */\n// oxlint-disable-next-line no-inferrable-types -- isolatedDeclarations requires the annotation for dts emit\nexport const NOSTR_URI_REGEX: RegExp = /nostr:([a-z0-9]+1[02-9ac-hj-np-z]+)/i;\n\nexport type NostrURI = {\n /** Full URI including `nostr:` */\n uri: `nostr:${string}`;\n /** Bech32 entity without prefix */\n value: string;\n decoded: DecodedResult;\n};\n\nexport function isNostrURI(value: unknown): value is `nostr:${string}` {\n if (typeof value !== \"string\") {\n return false;\n }\n if (!/^nostr:[a-z0-9]+1[02-9ac-hj-np-z]+$/i.test(value)) {\n return false;\n }\n return !value.toLowerCase().startsWith(\"nostr:nsec1\");\n}\n\n/** Parse and decode a full `nostr:…` URI. NIP-21 excludes `nsec`. */\nexport function parseNostrURI(uri: string): NostrURI {\n const match = /^nostr:([a-z0-9]+1[02-9ac-hj-np-z]+)$/i.exec(uri);\n const entity = match?.at(1);\n if (entity === undefined) {\n throw new
|
|
1
|
+
{"version":3,"file":"nip21.mjs","names":[],"sources":["../../src/nips/nip21.ts"],"sourcesContent":["/**\n * NIP-21: `nostr:` URI scheme\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/21.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport { decode } from \"./nip19.ts\";\nimport type { DecodedResult } from \"./nip19.ts\";\n\n/** Error thrown by {@link parseNostrURI} on malformed or non-decodable URIs. */\nexport class Nip21Error extends NostrError {\n override name = \"Nip21Error\";\n}\n\n/** Matches `nostr:<bech32>` (not anchored). */\n// oxlint-disable-next-line no-inferrable-types -- isolatedDeclarations requires the annotation for dts emit\nexport const NOSTR_URI_REGEX: RegExp = /nostr:([a-z0-9]+1[02-9ac-hj-np-z]+)/i;\n\nexport type NostrURI = {\n /** Full URI including `nostr:` */\n readonly uri: `nostr:${string}`;\n /** Bech32 entity without prefix */\n readonly value: string;\n readonly decoded: DecodedResult;\n};\n\nexport function isNostrURI(value: unknown): value is `nostr:${string}` {\n if (typeof value !== \"string\") {\n return false;\n }\n if (!/^nostr:[a-z0-9]+1[02-9ac-hj-np-z]+$/i.test(value)) {\n return false;\n }\n return !value.toLowerCase().startsWith(\"nostr:nsec1\");\n}\n\n/** Parse and decode a full `nostr:…` URI. NIP-21 excludes `nsec`. */\nexport function parseNostrURI(uri: string): NostrURI {\n const match = /^nostr:([a-z0-9]+1[02-9ac-hj-np-z]+)$/i.exec(uri);\n const entity = match?.at(1);\n if (entity === undefined) {\n throw new Nip21Error(`invalid Nostr URI: ${uri}`);\n }\n if (entity.toLowerCase().startsWith(\"nsec1\")) {\n throw new Nip21Error(\"NIP-21 identifiers exclude nsec\");\n }\n let decoded: DecodedResult;\n try {\n decoded = decode(entity);\n } catch (error) {\n throw new Nip21Error(`invalid Nostr URI: ${uri}`, { cause: error });\n }\n return {\n uri: `nostr:${entity}`,\n value: entity,\n decoded,\n };\n}\n"],"mappings":";;;;;;;;;AAUA,IAAa,aAAb,cAAgC,WAAW;CACzC,OAAgB;AAClB;;AAIA,MAAa,kBAA0B;AAUvC,SAAgB,WAAW,OAA4C;CACrE,IAAI,OAAO,UAAU,UACnB,OAAO;CAET,IAAI,CAAC,uCAAuC,KAAK,KAAK,GACpD,OAAO;CAET,OAAO,CAAC,MAAM,YAAY,CAAC,CAAC,WAAW,aAAa;AACtD;;AAGA,SAAgB,cAAc,KAAuB;CAEnD,MAAM,SADQ,yCAAyC,KAAK,GACzC,CAAC,EAAE,GAAG,CAAC;CAC1B,IAAI,WAAW,KAAA,GACb,MAAM,IAAI,WAAW,sBAAsB,KAAK;CAElD,IAAI,OAAO,YAAY,CAAC,CAAC,WAAW,OAAO,GACzC,MAAM,IAAI,WAAW,iCAAiC;CAExD,IAAI;CACJ,IAAI;EACF,UAAU,OAAO,MAAM;CACzB,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,sBAAsB,OAAO,EAAE,OAAO,MAAM,CAAC;CACpE;CACA,OAAO;EACL,KAAK,SAAS;EACd,OAAO;EACP;CACF;AACF"}
|
package/dist/nips/nip27.d.mts
CHANGED
|
@@ -1,48 +1,48 @@
|
|
|
1
|
-
import { t as Event } from "../event-
|
|
2
|
-
import { f as ProfilePointer, i as EventPointer, t as AddressPointer } from "../nip19-
|
|
1
|
+
import { t as Event } from "../event-DJeb_DIL.mjs";
|
|
2
|
+
import { f as ProfilePointer, i as EventPointer, t as AddressPointer } from "../nip19-DpPN17bY.mjs";
|
|
3
3
|
//#region src/nips/nip27.d.ts
|
|
4
4
|
export type ContentBlock = {
|
|
5
|
-
type: "text";
|
|
6
|
-
text: string;
|
|
5
|
+
readonly type: "text";
|
|
6
|
+
readonly text: string;
|
|
7
7
|
} | {
|
|
8
|
-
type: "reference";
|
|
9
|
-
pointer: ProfilePointer | EventPointer | AddressPointer;
|
|
8
|
+
readonly type: "reference";
|
|
9
|
+
readonly pointer: ProfilePointer | EventPointer | AddressPointer;
|
|
10
10
|
/**
|
|
11
11
|
* `true` when the reference had no `nostr:` prefix (see
|
|
12
12
|
* {@link ParseContentOptions.legacyBech32}).
|
|
13
13
|
*/
|
|
14
|
-
bare: boolean;
|
|
14
|
+
readonly bare: boolean;
|
|
15
15
|
} | {
|
|
16
|
-
type: "url";
|
|
17
|
-
url: string;
|
|
16
|
+
readonly type: "url";
|
|
17
|
+
readonly url: string;
|
|
18
18
|
} | {
|
|
19
|
-
type: "image" | "video" | "audio";
|
|
20
|
-
url: string;
|
|
19
|
+
readonly type: "image" | "video" | "audio";
|
|
20
|
+
readonly url: string;
|
|
21
21
|
} | {
|
|
22
|
-
type: "relay";
|
|
23
|
-
url: string;
|
|
22
|
+
readonly type: "relay";
|
|
23
|
+
readonly url: string;
|
|
24
24
|
} | {
|
|
25
|
-
type: "hashtag";
|
|
26
|
-
value: string;
|
|
25
|
+
readonly type: "hashtag";
|
|
26
|
+
readonly value: string;
|
|
27
27
|
} | {
|
|
28
|
-
type: "emoji";
|
|
29
|
-
shortcode: string;
|
|
30
|
-
url: string;
|
|
28
|
+
readonly type: "emoji";
|
|
29
|
+
readonly shortcode: string;
|
|
30
|
+
readonly url: string;
|
|
31
31
|
} | {
|
|
32
|
-
type: "invoice";
|
|
33
|
-
bolt11: string;
|
|
32
|
+
readonly type: "invoice";
|
|
33
|
+
readonly bolt11: string;
|
|
34
34
|
};
|
|
35
35
|
export type ParseContentOptions = {
|
|
36
36
|
/**
|
|
37
37
|
* Recognize bare `npub`, `nprofile`, `note`, `nevent`, `naddr` without the `nostr:` prefix.
|
|
38
38
|
* Default `false`.
|
|
39
39
|
*/
|
|
40
|
-
legacyBech32?: boolean;
|
|
40
|
+
legacyBech32?: boolean | undefined;
|
|
41
41
|
/**
|
|
42
42
|
* URL → MIME type (the `m` field of NIP-92 `imeta` tags); takes precedence over extension
|
|
43
43
|
* classification.
|
|
44
44
|
*/
|
|
45
|
-
imeta?: ReadonlyMap<string, string
|
|
45
|
+
imeta?: ReadonlyMap<string, string> | undefined;
|
|
46
46
|
};
|
|
47
47
|
/**
|
|
48
48
|
* Parse note content (or a full event, to pick up `emoji` tags) into ordered blocks. One
|
package/dist/nips/nip27.mjs
CHANGED
|
@@ -10,7 +10,7 @@ const SCAN_BODY = [
|
|
|
10
10
|
`(?<relay>wss?://${URL_RUN})`,
|
|
11
11
|
`(?<invoice>(?:lightning:)?ln(?:bcrt|tbs|bc|tb)(?:\\d+[munp]?)?1[${BECH32_CHARS}]+)`,
|
|
12
12
|
`(?<hashtag>#[\\p{L}\\p{M}\\p{N}_]{1,42})`,
|
|
13
|
-
`(?<emoji>:[A-Za-z0-9_]+:)`
|
|
13
|
+
`(?<emoji>:[A-Za-z0-9_-]+:)`
|
|
14
14
|
].join("|");
|
|
15
15
|
const SCAN = new RegExp(SCAN_BODY, "giu");
|
|
16
16
|
const SCAN_LEGACY = new RegExp(`${SCAN_BODY}|(?<bare>${NIP19_BARE_PREFIX}[${BECH32_CHARS}]+)`, "giu");
|
|
@@ -178,7 +178,7 @@ function parseContent(content, opts) {
|
|
|
178
178
|
bolt11: (token.toLowerCase().startsWith("lightning:") ? token.slice(10) : token).toLowerCase()
|
|
179
179
|
};
|
|
180
180
|
} else if (g?.["hashtag"] !== void 0) {
|
|
181
|
-
if (!isChar(start === 0 ? void 0 : text.codePointAt(start - 1), TAG_CHAR)) block = {
|
|
181
|
+
if (!isChar(start === 0 ? void 0 : text.codePointAt(start - 1), TAG_CHAR) && !isChar(text.codePointAt(end), TAG_CHAR)) block = {
|
|
182
182
|
type: "hashtag",
|
|
183
183
|
value: token.slice(1)
|
|
184
184
|
};
|
package/dist/nips/nip27.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nip27.mjs","names":[],"sources":["../../src/nips/nip27.ts"],"sourcesContent":["/**\n * NIP-27: Text Note References. Tokenizes note content into text, `nostr:` references, URLs, media,\n * relays, hashtags, custom emoji, and Lightning invoices.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/27.md\n */\nimport type { Event } from \"../core/event.ts\";\nimport { decode } from \"./nip19.ts\";\nimport type { AddressPointer, EventPointer, ProfilePointer } from \"./nip19.ts\";\n\nexport type ContentBlock =\n | { type: \"text\"; text: string }\n | {\n type: \"reference\";\n pointer: ProfilePointer | EventPointer | AddressPointer;\n /**\n * `true` when the reference had no `nostr:` prefix (see\n * {@link ParseContentOptions.legacyBech32}).\n */\n bare: boolean;\n }\n | { type: \"url\"; url: string }\n | { type: \"image\" | \"video\" | \"audio\"; url: string }\n | { type: \"relay\"; url: string }\n | { type: \"hashtag\"; value: string }\n | { type: \"emoji\"; shortcode: string; url: string }\n | { type: \"invoice\"; bolt11: string };\n\nexport type ParseContentOptions = {\n /**\n * Recognize bare `npub`, `nprofile`, `note`, `nevent`, `naddr` without the `nostr:` prefix.\n * Default `false`.\n */\n legacyBech32?: boolean;\n /**\n * URL → MIME type (the `m` field of NIP-92 `imeta` tags); takes precedence over extension\n * classification.\n */\n imeta?: ReadonlyMap<string, string>;\n};\n\n// Bech32 data charset ([02-9ac-hj-np-z], case-insensitive) and the NIP-19 entity prefixes.\nconst BECH32_CHARS = \"02-9ac-hj-np-z\";\nconst NIP19_PREFIX = \"(?:npub|nprofile|note|nevent|naddr|nsec)1\";\nconst NIP19_BARE_PREFIX = \"(?:npub|nprofile|note|nevent|naddr)1\";\n\n// A URL run ends at whitespace, angle brackets, double quotes, CJK punctuation\n// (U+3000–U+303F), or full-width forms (U+FF00–U+FFEF).\nconst URL_RUN = `[^\\\\s<>\"\\\\u3000-\\\\u303f\\\\uff00-\\\\uffef]+`;\n\n// Rule order matters: at every position the first matching alternative wins.\nconst SCAN_BODY = [\n // 1. nostr: URIs carry a NIP-19 entity.\n `(?<nostr>nostr:${NIP19_PREFIX}[${BECH32_CHARS}]+)`,\n // 2./3. http(s) and ws(s) URLs share the same boundary rules.\n `(?<url>https?://${URL_RUN})`,\n `(?<relay>wss?://${URL_RUN})`,\n // 4. BOLT11 invoices, with an optional lightning: URI prefix. The HRP may carry an amount\n // (`lnbc10u1…` = ln + currency + amount + multiplier + the `1` separator).\n `(?<invoice>(?:lightning:)?ln(?:bcrt|tbs|bc|tb)(?:\\\\d+[munp]?)?1[${BECH32_CHARS}]+)`,\n // 5. Hashtags: Unicode letters/marks/numbers and underscore, at most 42 code points.\n `(?<hashtag>#[\\\\p{L}\\\\p{M}\\\\p{N}_]{1,42})`,\n // 6. Custom emoji shortcodes (validated against the event's emoji tags).\n `(?<emoji>:[A-Za-z0-9_]+:)`,\n].join(\"|\");\n\nconst SCAN = new RegExp(SCAN_BODY, \"giu\");\n// 7. Bare NIP-19 entities — legacy rendering support, opt-in only.\nconst SCAN_LEGACY = new RegExp(\n `${SCAN_BODY}|(?<bare>${NIP19_BARE_PREFIX}[${BECH32_CHARS}]+)`,\n \"giu\",\n);\n\n// The character before `#` must be absent or a non-tag character.\nconst TAG_CHAR = /[\\p{L}\\p{M}\\p{N}_]/u;\n// Invoice and bare-bech32 tokens must not be glued to a letter or digit.\nconst WORD_CHAR = /[\\p{L}\\p{N}]/u;\n\nconst TRAILING_URL_CHARS = new Set([\".\", \",\", \";\", \":\", \"!\", \"?\", \"'\"]);\n\nconst IMAGE_EXT = new Set([\"jpg\", \"jpeg\", \"png\", \"gif\", \"webp\", \"avif\", \"svg\"]);\nconst VIDEO_EXT = new Set([\"mp4\", \"webm\", \"mov\", \"m4v\", \"m3u8\"]);\nconst AUDIO_EXT = new Set([\"mp3\", \"m4a\", \"ogg\", \"oga\", \"opus\", \"wav\", \"flac\", \"aac\"]);\n\nfunction isChar(cp: number | undefined, re: RegExp): boolean {\n return cp !== undefined && re.test(String.fromCodePoint(cp));\n}\n\n/** Drop trailing sentence punctuation and closers that have no opener inside the URL. */\nfunction trimUrlTail(raw: string): string {\n let url = raw;\n for (;;) {\n const last = url.at(-1);\n if (last !== undefined && TRAILING_URL_CHARS.has(last)) {\n url = url.slice(0, -1);\n continue;\n }\n if (last === \")\" || last === \"]\") {\n const open = last === \")\" ? \"(\" : \"[\";\n let opens = 0;\n let closes = 0;\n for (const c of url) {\n if (c === open) {\n opens++;\n } else if (c === last) {\n closes++;\n }\n }\n if (closes > opens) {\n url = url.slice(0, -1);\n continue;\n }\n }\n return url;\n }\n}\n\ntype MediaType = \"image\" | \"video\" | \"audio\";\n\nfunction mimeMedia(mime: string | undefined): MediaType | undefined {\n if (mime === undefined) {\n return undefined;\n }\n const slash = mime.indexOf(\"/\");\n const base = slash === -1 ? mime : mime.slice(0, slash);\n return base === \"image\" || base === \"video\" || base === \"audio\" ? base : undefined;\n}\n\nfunction extMedia(pathname: string): MediaType | undefined {\n const dot = pathname.lastIndexOf(\".\");\n if (dot === -1) {\n return undefined;\n }\n const ext = pathname.slice(dot + 1).toLowerCase();\n if (IMAGE_EXT.has(ext)) {\n return \"image\";\n }\n if (VIDEO_EXT.has(ext)) {\n return \"video\";\n }\n return AUDIO_EXT.has(ext) ? \"audio\" : undefined;\n}\n\nfunction urlBlock(\n raw: string,\n relay: boolean,\n imeta: ReadonlyMap<string, string> | undefined,\n): ContentBlock | undefined {\n const url = trimUrlTail(raw);\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return undefined;\n }\n if (!parsed.hostname.includes(\".\")) {\n return undefined;\n }\n if (relay) {\n return { type: \"relay\", url };\n }\n const media = mimeMedia(imeta?.get(url)) ?? extMedia(parsed.pathname);\n return media === undefined ? { type: \"url\", url } : { type: media, url };\n}\n\nfunction referenceFor(code: string, bare: boolean): ContentBlock | undefined {\n let pointer: ProfilePointer | EventPointer | AddressPointer;\n try {\n const decoded = decode(code);\n switch (decoded.type) {\n case \"npub\":\n pointer = { pubkey: decoded.data };\n break;\n case \"note\":\n pointer = { id: decoded.data };\n break;\n case \"nprofile\":\n case \"nevent\":\n case \"naddr\":\n pointer = decoded.data;\n break;\n case \"nsec\":\n return undefined;\n }\n } catch {\n return undefined;\n }\n return { type: \"reference\", pointer, bare };\n}\n\n/**\n * Parse note content (or a full event, to pick up `emoji` tags) into ordered blocks. One\n * left-to-right scan; at every position the rules fire in the alternation order above. Adjacent\n * text merges and no empty text blocks are emitted.\n */\nexport function parseContent(\n content: string | Pick<Event, \"content\" | \"tags\">,\n opts?: ParseContentOptions,\n): ContentBlock[] {\n const emojis = new Map<string, string>();\n let text: string;\n if (typeof content === \"string\") {\n text = content;\n } else {\n for (const tag of content.tags) {\n if (\n tag[0] === \"emoji\" &&\n tag[1] !== undefined &&\n tag[1] !== \"\" &&\n tag[2] !== undefined &&\n tag[2] !== \"\"\n ) {\n emojis.set(tag[1], tag[2]);\n }\n }\n text = content.content;\n }\n\n const scan = opts?.legacyBech32 === true ? SCAN_LEGACY : SCAN;\n scan.lastIndex = 0;\n\n const blocks: ContentBlock[] = [];\n let textStart = 0;\n const flushText = (end: number): void => {\n if (end > textStart) {\n blocks.push({ type: \"text\", text: text.slice(textStart, end) });\n }\n };\n\n for (let m = scan.exec(text); m !== null; m = scan.exec(text)) {\n const start = m.index;\n const [token] = m;\n const end = start + token.length;\n const g = m.groups;\n let block: ContentBlock | undefined;\n\n if (g?.[\"nostr\"] !== undefined) {\n block = referenceFor(token.slice(\"nostr:\".length), false);\n } else if (g?.[\"url\"] !== undefined) {\n block = urlBlock(token, false, opts?.imeta);\n } else if (g?.[\"relay\"] !== undefined) {\n block = urlBlock(token, true, undefined);\n } else if (g?.[\"invoice\"] !== undefined) {\n const prev = start === 0 ? undefined : text.codePointAt(start - 1);\n if (!isChar(prev, WORD_CHAR) && !isChar(text.codePointAt(end), WORD_CHAR)) {\n const invoice = token.toLowerCase().startsWith(\"lightning:\")\n ? token.slice(\"lightning:\".length)\n : token;\n block = { type: \"invoice\", bolt11: invoice.toLowerCase() };\n }\n } else if (g?.[\"hashtag\"] !== undefined) {\n const prev = start === 0 ? undefined : text.codePointAt(start - 1);\n if (!isChar(prev, TAG_CHAR)) {\n block = { type: \"hashtag\", value: token.slice(1) };\n }\n } else if (g?.[\"emoji\"] !== undefined) {\n const url = emojis.get(token.slice(1, -1));\n if (url !== undefined) {\n block = { type: \"emoji\", shortcode: token.slice(1, -1), url };\n }\n } else if (g?.[\"bare\"] !== undefined) {\n const prev = start === 0 ? undefined : text.codePointAt(start - 1);\n if (!isChar(prev, WORD_CHAR) && !isChar(text.codePointAt(end), WORD_CHAR)) {\n block = referenceFor(token, true);\n }\n }\n\n if (block === undefined) {\n // The candidate is plain text; resume scanning one code unit later so any token inside\n // its span can still match.\n scan.lastIndex = start + 1;\n continue;\n }\n flushText(start);\n blocks.push(block);\n // URL-family blocks may end before the regex run once trailing punctuation is trimmed.\n textStart =\n block.type === \"url\" ||\n block.type === \"relay\" ||\n block.type === \"image\" ||\n block.type === \"video\" ||\n block.type === \"audio\"\n ? start + block.url.length\n : end;\n }\n\n flushText(text.length);\n return blocks;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nip27.mjs","names":[],"sources":["../../src/nips/nip27.ts"],"sourcesContent":["/**\n * NIP-27: Text Note References. Tokenizes note content into text, `nostr:` references, URLs, media,\n * relays, hashtags, custom emoji, and Lightning invoices.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/27.md\n */\nimport type { Event } from \"../core/event.ts\";\nimport { decode } from \"./nip19.ts\";\nimport type { AddressPointer, EventPointer, ProfilePointer } from \"./nip19.ts\";\n\nexport type ContentBlock =\n | { readonly type: \"text\"; readonly text: string }\n | {\n readonly type: \"reference\";\n readonly pointer: ProfilePointer | EventPointer | AddressPointer;\n /**\n * `true` when the reference had no `nostr:` prefix (see\n * {@link ParseContentOptions.legacyBech32}).\n */\n readonly bare: boolean;\n }\n | { readonly type: \"url\"; readonly url: string }\n | { readonly type: \"image\" | \"video\" | \"audio\"; readonly url: string }\n | { readonly type: \"relay\"; readonly url: string }\n | { readonly type: \"hashtag\"; readonly value: string }\n | { readonly type: \"emoji\"; readonly shortcode: string; readonly url: string }\n | { readonly type: \"invoice\"; readonly bolt11: string };\n\nexport type ParseContentOptions = {\n /**\n * Recognize bare `npub`, `nprofile`, `note`, `nevent`, `naddr` without the `nostr:` prefix.\n * Default `false`.\n */\n legacyBech32?: boolean | undefined;\n /**\n * URL → MIME type (the `m` field of NIP-92 `imeta` tags); takes precedence over extension\n * classification.\n */\n imeta?: ReadonlyMap<string, string> | undefined;\n};\n\n// Bech32 data charset ([02-9ac-hj-np-z], case-insensitive) and the NIP-19 entity prefixes.\nconst BECH32_CHARS = \"02-9ac-hj-np-z\";\nconst NIP19_PREFIX = \"(?:npub|nprofile|note|nevent|naddr|nsec)1\";\nconst NIP19_BARE_PREFIX = \"(?:npub|nprofile|note|nevent|naddr)1\";\n\n// A URL run ends at whitespace, angle brackets, double quotes, CJK punctuation\n// (U+3000–U+303F), or full-width forms (U+FF00–U+FFEF).\nconst URL_RUN = `[^\\\\s<>\"\\\\u3000-\\\\u303f\\\\uff00-\\\\uffef]+`;\n\n// Rule order matters: at every position the first matching alternative wins.\nconst SCAN_BODY = [\n // 1. nostr: URIs carry a NIP-19 entity.\n `(?<nostr>nostr:${NIP19_PREFIX}[${BECH32_CHARS}]+)`,\n // 2./3. http(s) and ws(s) URLs share the same boundary rules.\n `(?<url>https?://${URL_RUN})`,\n `(?<relay>wss?://${URL_RUN})`,\n // 4. BOLT11 invoices, with an optional lightning: URI prefix. The HRP may carry an amount\n // (`lnbc10u1…` = ln + currency + amount + multiplier + the `1` separator).\n `(?<invoice>(?:lightning:)?ln(?:bcrt|tbs|bc|tb)(?:\\\\d+[munp]?)?1[${BECH32_CHARS}]+)`,\n // 5. Hashtags: Unicode letters/marks/numbers and underscore, at most 42 code points.\n `(?<hashtag>#[\\\\p{L}\\\\p{M}\\\\p{N}_]{1,42})`,\n // 6. Custom emoji shortcodes (validated against the event's emoji tags). NIP-30 allows\n // alphanumerics, hyphens, and underscores.\n `(?<emoji>:[A-Za-z0-9_-]+:)`,\n].join(\"|\");\n\nconst SCAN = new RegExp(SCAN_BODY, \"giu\");\n// 7. Bare NIP-19 entities — legacy rendering support, opt-in only.\nconst SCAN_LEGACY = new RegExp(\n `${SCAN_BODY}|(?<bare>${NIP19_BARE_PREFIX}[${BECH32_CHARS}]+)`,\n \"giu\",\n);\n\n// The character before `#` must be absent or a non-tag character.\nconst TAG_CHAR = /[\\p{L}\\p{M}\\p{N}_]/u;\n// Invoice and bare-bech32 tokens must not be glued to a letter or digit.\nconst WORD_CHAR = /[\\p{L}\\p{N}]/u;\n\nconst TRAILING_URL_CHARS = new Set([\".\", \",\", \";\", \":\", \"!\", \"?\", \"'\"]);\n\nconst IMAGE_EXT = new Set([\"jpg\", \"jpeg\", \"png\", \"gif\", \"webp\", \"avif\", \"svg\"]);\nconst VIDEO_EXT = new Set([\"mp4\", \"webm\", \"mov\", \"m4v\", \"m3u8\"]);\nconst AUDIO_EXT = new Set([\"mp3\", \"m4a\", \"ogg\", \"oga\", \"opus\", \"wav\", \"flac\", \"aac\"]);\n\nfunction isChar(cp: number | undefined, re: RegExp): boolean {\n return cp !== undefined && re.test(String.fromCodePoint(cp));\n}\n\n/** Drop trailing sentence punctuation and closers that have no opener inside the URL. */\nfunction trimUrlTail(raw: string): string {\n let url = raw;\n for (;;) {\n const last = url.at(-1);\n if (last !== undefined && TRAILING_URL_CHARS.has(last)) {\n url = url.slice(0, -1);\n continue;\n }\n if (last === \")\" || last === \"]\") {\n const open = last === \")\" ? \"(\" : \"[\";\n let opens = 0;\n let closes = 0;\n for (const c of url) {\n if (c === open) {\n opens++;\n } else if (c === last) {\n closes++;\n }\n }\n if (closes > opens) {\n url = url.slice(0, -1);\n continue;\n }\n }\n return url;\n }\n}\n\ntype MediaType = \"image\" | \"video\" | \"audio\";\n\nfunction mimeMedia(mime: string | undefined): MediaType | undefined {\n if (mime === undefined) {\n return undefined;\n }\n const slash = mime.indexOf(\"/\");\n const base = slash === -1 ? mime : mime.slice(0, slash);\n return base === \"image\" || base === \"video\" || base === \"audio\" ? base : undefined;\n}\n\nfunction extMedia(pathname: string): MediaType | undefined {\n const dot = pathname.lastIndexOf(\".\");\n if (dot === -1) {\n return undefined;\n }\n const ext = pathname.slice(dot + 1).toLowerCase();\n if (IMAGE_EXT.has(ext)) {\n return \"image\";\n }\n if (VIDEO_EXT.has(ext)) {\n return \"video\";\n }\n return AUDIO_EXT.has(ext) ? \"audio\" : undefined;\n}\n\nfunction urlBlock(\n raw: string,\n relay: boolean,\n imeta: ReadonlyMap<string, string> | undefined,\n): ContentBlock | undefined {\n const url = trimUrlTail(raw);\n let parsed: URL;\n try {\n parsed = new URL(url);\n } catch {\n return undefined;\n }\n if (!parsed.hostname.includes(\".\")) {\n return undefined;\n }\n if (relay) {\n return { type: \"relay\", url };\n }\n const media = mimeMedia(imeta?.get(url)) ?? extMedia(parsed.pathname);\n return media === undefined ? { type: \"url\", url } : { type: media, url };\n}\n\nfunction referenceFor(code: string, bare: boolean): ContentBlock | undefined {\n let pointer: ProfilePointer | EventPointer | AddressPointer;\n try {\n const decoded = decode(code);\n switch (decoded.type) {\n case \"npub\":\n pointer = { pubkey: decoded.data };\n break;\n case \"note\":\n pointer = { id: decoded.data };\n break;\n case \"nprofile\":\n case \"nevent\":\n case \"naddr\":\n pointer = decoded.data;\n break;\n case \"nsec\":\n return undefined;\n }\n } catch {\n return undefined;\n }\n return { type: \"reference\", pointer, bare };\n}\n\n/**\n * Parse note content (or a full event, to pick up `emoji` tags) into ordered blocks. One\n * left-to-right scan; at every position the rules fire in the alternation order above. Adjacent\n * text merges and no empty text blocks are emitted.\n */\nexport function parseContent(\n content: string | Pick<Event, \"content\" | \"tags\">,\n opts?: ParseContentOptions,\n): ContentBlock[] {\n const emojis = new Map<string, string>();\n let text: string;\n if (typeof content === \"string\") {\n text = content;\n } else {\n for (const tag of content.tags) {\n if (\n tag[0] === \"emoji\" &&\n tag[1] !== undefined &&\n tag[1] !== \"\" &&\n tag[2] !== undefined &&\n tag[2] !== \"\"\n ) {\n emojis.set(tag[1], tag[2]);\n }\n }\n text = content.content;\n }\n\n const scan = opts?.legacyBech32 === true ? SCAN_LEGACY : SCAN;\n scan.lastIndex = 0;\n\n const blocks: ContentBlock[] = [];\n let textStart = 0;\n const flushText = (end: number): void => {\n if (end > textStart) {\n blocks.push({ type: \"text\", text: text.slice(textStart, end) });\n }\n };\n\n for (let m = scan.exec(text); m !== null; m = scan.exec(text)) {\n const start = m.index;\n const [token] = m;\n const end = start + token.length;\n const g = m.groups;\n let block: ContentBlock | undefined;\n\n if (g?.[\"nostr\"] !== undefined) {\n block = referenceFor(token.slice(\"nostr:\".length), false);\n } else if (g?.[\"url\"] !== undefined) {\n block = urlBlock(token, false, opts?.imeta);\n } else if (g?.[\"relay\"] !== undefined) {\n block = urlBlock(token, true, undefined);\n } else if (g?.[\"invoice\"] !== undefined) {\n const prev = start === 0 ? undefined : text.codePointAt(start - 1);\n if (!isChar(prev, WORD_CHAR) && !isChar(text.codePointAt(end), WORD_CHAR)) {\n const invoice = token.toLowerCase().startsWith(\"lightning:\")\n ? token.slice(\"lightning:\".length)\n : token;\n block = { type: \"invoice\", bolt11: invoice.toLowerCase() };\n }\n } else if (g?.[\"hashtag\"] !== undefined) {\n const prev = start === 0 ? undefined : text.codePointAt(start - 1);\n // A tag char right after the match means the {1,42} cap truncated a longer\n // run; the whole run is text, not a hashtag plus remainder.\n if (!isChar(prev, TAG_CHAR) && !isChar(text.codePointAt(end), TAG_CHAR)) {\n block = { type: \"hashtag\", value: token.slice(1) };\n }\n } else if (g?.[\"emoji\"] !== undefined) {\n const url = emojis.get(token.slice(1, -1));\n if (url !== undefined) {\n block = { type: \"emoji\", shortcode: token.slice(1, -1), url };\n }\n } else if (g?.[\"bare\"] !== undefined) {\n const prev = start === 0 ? undefined : text.codePointAt(start - 1);\n if (!isChar(prev, WORD_CHAR) && !isChar(text.codePointAt(end), WORD_CHAR)) {\n block = referenceFor(token, true);\n }\n }\n\n if (block === undefined) {\n // The candidate is plain text; resume scanning one code unit later so any token inside\n // its span can still match.\n scan.lastIndex = start + 1;\n continue;\n }\n flushText(start);\n blocks.push(block);\n // URL-family blocks may end before the regex run once trailing punctuation is trimmed.\n textStart =\n block.type === \"url\" ||\n block.type === \"relay\" ||\n block.type === \"image\" ||\n block.type === \"video\" ||\n block.type === \"audio\"\n ? start + block.url.length\n : end;\n }\n\n flushText(text.length);\n return blocks;\n}\n"],"mappings":"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"}
|
package/dist/nips/nip42.d.mts
CHANGED
package/dist/nips/nip42.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { d as nowSeconds } from "../util-DMF9AIO0.mjs";
|
|
1
2
|
import { t as Kind } from "../kind-Cxwhhkx8.mjs";
|
|
2
3
|
//#region src/nips/nip42.ts
|
|
3
4
|
/**
|
|
@@ -7,7 +8,7 @@ import { t as Kind } from "../kind-Cxwhhkx8.mjs";
|
|
|
7
8
|
function makeAuthEvent(relayURL, challenge) {
|
|
8
9
|
return {
|
|
9
10
|
kind: Kind.ClientAuth,
|
|
10
|
-
created_at:
|
|
11
|
+
created_at: nowSeconds(),
|
|
11
12
|
tags: [["relay", relayURL], ["challenge", challenge]],
|
|
12
13
|
content: ""
|
|
13
14
|
};
|
package/dist/nips/nip42.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nip42.mjs","names":[],"sources":["../../src/nips/nip42.ts"],"sourcesContent":["import type { EventTemplate } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\n\n/**\n * Build an unsigned NIP-42 AUTH event template for the given relay challenge. Caller must sign with\n * their `NostrSigner` / keys.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: Kind.ClientAuth,\n created_at:
|
|
1
|
+
{"version":3,"file":"nip42.mjs","names":[],"sources":["../../src/nips/nip42.ts"],"sourcesContent":["import type { EventTemplate } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { nowSeconds } from \"../core/util.ts\";\n\n/**\n * Build an unsigned NIP-42 AUTH event template for the given relay challenge. Caller must sign with\n * their `NostrSigner` / keys.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: Kind.ClientAuth,\n created_at: nowSeconds(),\n tags: [\n [\"relay\", relayURL],\n [\"challenge\", challenge],\n ],\n content: \"\",\n };\n}\n\n/** True when a CLOSED reason requests NIP-42 authentication. */\nexport function isAuthRequired(reason: string): boolean {\n return reason.startsWith(\"auth-required:\");\n}\n"],"mappings":";;;;;;;AAQA,SAAgB,cAAc,UAAkB,WAAkC;CAChF,OAAO;EACL,MAAM,KAAK;EACX,YAAY,WAAW;EACvB,MAAM,CACJ,CAAC,SAAS,QAAQ,GAClB,CAAC,aAAa,SAAS,CACzB;EACA,SAAS;CACX;AACF;;AAGA,SAAgB,eAAe,QAAyB;CACtD,OAAO,OAAO,WAAW,gBAAgB;AAC3C"}
|
package/dist/nips/nip44.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as hexToBytes$1,
|
|
1
|
+
import { a as hexToBytes$1, f as utf8Decoder, m as CryptoError, n as assertHex32, p as utf8Encoder, r as assertSecretKeyBytes } from "../util-DMF9AIO0.mjs";
|
|
2
2
|
import { concatBytes, randomBytes } from "@noble/hashes/utils.js";
|
|
3
3
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
4
4
|
import { secp256k1 } from "@noble/curves/secp256k1.js";
|
|
@@ -95,7 +95,7 @@ function decodePayload(payload, maxPayloadChars) {
|
|
|
95
95
|
try {
|
|
96
96
|
data = base64.decode(payload);
|
|
97
97
|
} catch (error) {
|
|
98
|
-
throw new CryptoError(
|
|
98
|
+
throw new CryptoError("invalid base64", { cause: error });
|
|
99
99
|
}
|
|
100
100
|
if (data.length < 99) throw new CryptoError(`invalid data length: ${data.length}`);
|
|
101
101
|
const version = data.at(0);
|
package/dist/nips/nip44.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nip44.mjs","names":["hexToBytes","hkdf_extract","hkdf_expand"],"sources":["../../src/nips/nip44.ts"],"sourcesContent":["import { chacha20 } from \"@noble/ciphers/chacha.js\";\nimport { equalBytes } from \"@noble/ciphers/utils.js\";\nimport { secp256k1 } from \"@noble/curves/secp256k1.js\";\nimport { extract as hkdf_extract, expand as hkdf_expand } from \"@noble/hashes/hkdf.js\";\nimport { hmac } from \"@noble/hashes/hmac.js\";\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport { concatBytes, randomBytes } from \"@noble/hashes/utils.js\";\nimport { base64 } from \"@scure/base\";\n\nimport { CryptoError } from \"../core/error.ts\";\nimport {\n assertHex32,\n assertSecretKeyBytes,\n hexToBytes,\n utf8Decoder,\n utf8Encoder,\n} from \"../core/util.ts\";\n\nconst minPlaintextSize = 0x0001;\nconst maxPlaintextSize = 0xffffffff;\nconst extendedPrefixThreshold = 0x10000;\n\n/**\n * Default decode-side payload cap: the base64 length of a payload carrying exactly 1 MiB (0x100000\n * bytes) of plaintext — version(1) + nonce(32) + extended prefix(6) + calcPaddedLen(1 MiB) +\n * mac(32) bytes. NIP-44 asks implementations to enforce their own maximum payload size; relays cap\n * events far below this. Raise it via `opts.maxPayloadChars` in `decrypt`/ `decryptFromPubkey` for\n * large local payloads.\n */\nexport const DEFAULT_MAX_PAYLOAD_CHARS: number = Math.ceil((71 + calcPaddedLen(0x100000)) / 3) * 4;\n\nfunction assert32(bytes: Uint8Array, label: string): void {\n if (bytes.length !== 32) {\n throw new CryptoError(`${label} must be 32 bytes`);\n }\n}\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n assertSecretKeyBytes(privkeyA);\n assertHex32(pubkeyB, \"public key\");\n const sharedX = secp256k1\n .getSharedSecret(privkeyA, hexToBytes(`02${pubkeyB.toLowerCase()}`))\n .subarray(1, 33);\n return hkdf_extract(sha256, sharedX, utf8Encoder.encode(\"nip44-v2\"));\n}\n\n/** NIP-44 `get_message_keys`: HKDF-expand the 76-byte key material. */\nexport function getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n assert32(conversationKey, \"conversation_key\");\n assert32(nonce, \"nonce\");\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76);\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n };\n}\n\nexport function calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) {\n throw new CryptoError(\"expected positive integer\");\n }\n if (len <= 32) {\n return 32;\n }\n const nextPower = 2 ** (Math.floor(Math.log2(len - 1)) + 1);\n const chunk = nextPower <= 256 ? 32 : nextPower / 8;\n return chunk * (Math.floor((len - 1) / chunk) + 1);\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > 0xffff) {\n throw new CryptoError(\"invalid plaintext size: must be between 1 and 65535 bytes\");\n }\n const arr = new Uint8Array(2);\n new DataView(arr.buffer).setUint16(0, num, false);\n return arr;\n}\n\nfunction writeU32BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < extendedPrefixThreshold || num > maxPlaintextSize) {\n throw new CryptoError(\"invalid plaintext size: must be between 65536 and 4294967295 bytes\");\n }\n const arr = new Uint8Array(4);\n new DataView(arr.buffer).setUint32(0, num, false);\n return arr;\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext);\n const unpaddedLen = unpadded.length;\n if (unpaddedLen < minPlaintextSize || unpaddedLen > maxPlaintextSize) {\n throw new CryptoError(\"invalid plaintext size: must be between 1 and 4294967295 bytes\");\n }\n const prefix =\n unpaddedLen >= extendedPrefixThreshold\n ? concatBytes(new Uint8Array([0, 0]), writeU32BE(unpaddedLen))\n : writeU16BE(unpaddedLen);\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen);\n return concatBytes(prefix, unpadded, suffix);\n}\n\nfunction unpad(padded: Uint8Array): string {\n const dv = new DataView(padded.buffer, padded.byteOffset, padded.byteLength);\n const firstTwo = dv.getUint16(0);\n let unpaddedLen: number;\n let prefixLen: number;\n if (firstTwo === 0) {\n unpaddedLen = dv.getUint32(2);\n if (unpaddedLen < extendedPrefixThreshold) {\n throw new CryptoError(\"invalid padding\");\n }\n prefixLen = 6;\n } else {\n unpaddedLen = firstTwo;\n prefixLen = 2;\n }\n const unpadded = padded.subarray(prefixLen, prefixLen + unpaddedLen);\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== prefixLen + calcPaddedLen(unpaddedLen)\n ) {\n throw new CryptoError(\"invalid padding\");\n }\n return utf8Decoder.decode(unpadded);\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) {\n throw new CryptoError(\"AAD associated data must be 32 bytes\");\n }\n return hmac(sha256, key, concatBytes(aad, message));\n}\n\nfunction decodePayload(\n payload: string,\n maxPayloadChars: number,\n): {\n nonce: Uint8Array;\n ciphertext: Uint8Array;\n mac: Uint8Array;\n} {\n if (typeof payload !== \"string\") {\n throw new CryptoError(\"payload must be a valid string\");\n }\n if (payload.startsWith(\"#\")) {\n throw new CryptoError(\"unknown encryption version\");\n }\n if (payload.length < 132 || payload.length > maxPayloadChars) {\n throw new CryptoError(`invalid payload length: ${payload.length}`);\n }\n let data: Uint8Array;\n try {\n data = base64.decode(payload);\n } catch (error) {\n throw new CryptoError(\n `invalid base64: ${error instanceof Error ? error.message : \"decode failed\"}`,\n );\n }\n if (data.length < 99) {\n throw new CryptoError(`invalid data length: ${data.length}`);\n }\n const version = data.at(0);\n if (version === undefined) {\n throw new CryptoError(\"invalid data length\");\n }\n if (version !== 2) {\n throw new CryptoError(`unknown encryption version ${version}`);\n }\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n };\n}\n\nexport function encrypt(\n plaintext: string,\n conversationKey: Uint8Array,\n nonce: Uint8Array = randomBytes(32),\n): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce);\n const padded = pad(plaintext);\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded);\n const mac = hmacAad(hmac_key, ciphertext, nonce);\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac));\n}\n\nexport function decrypt(\n payload: string,\n conversationKey: Uint8Array,\n opts?: { maxPayloadChars?: number },\n): string {\n const { nonce, ciphertext, mac } = decodePayload(\n payload,\n opts?.maxPayloadChars ?? DEFAULT_MAX_PAYLOAD_CHARS,\n );\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce);\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce);\n if (!equalBytes(calculatedMac, mac)) {\n throw new CryptoError(\"invalid MAC\");\n }\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext);\n return unpad(padded);\n}\n\n/** Convenience: derive conversation key from secret/public pair and encrypt. */\nexport function encryptToPubkey(\n plaintext: string,\n secretKey: Uint8Array,\n peerPubkey: string,\n): string {\n return encrypt(plaintext, getConversationKey(secretKey, peerPubkey));\n}\n\n/** Convenience: decrypt a payload from a peer pubkey. */\nexport function decryptFromPubkey(\n payload: string,\n secretKey: Uint8Array,\n peerPubkey: string,\n opts?: { maxPayloadChars?: number },\n): string {\n return decrypt(payload, getConversationKey(secretKey, peerPubkey), opts);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nip44.mjs","names":["hexToBytes","hkdf_extract","hkdf_expand"],"sources":["../../src/nips/nip44.ts"],"sourcesContent":["import { chacha20 } from \"@noble/ciphers/chacha.js\";\nimport { equalBytes } from \"@noble/ciphers/utils.js\";\nimport { secp256k1 } from \"@noble/curves/secp256k1.js\";\nimport { extract as hkdf_extract, expand as hkdf_expand } from \"@noble/hashes/hkdf.js\";\nimport { hmac } from \"@noble/hashes/hmac.js\";\nimport { sha256 } from \"@noble/hashes/sha2.js\";\nimport { concatBytes, randomBytes } from \"@noble/hashes/utils.js\";\nimport { base64 } from \"@scure/base\";\n\nimport { CryptoError } from \"../core/error.ts\";\nimport {\n assertHex32,\n assertSecretKeyBytes,\n hexToBytes,\n utf8Decoder,\n utf8Encoder,\n} from \"../core/util.ts\";\n\nconst minPlaintextSize = 0x0001;\nconst maxPlaintextSize = 0xffffffff;\nconst extendedPrefixThreshold = 0x10000;\n\n/**\n * Default decode-side payload cap: the base64 length of a payload carrying exactly 1 MiB (0x100000\n * bytes) of plaintext — version(1) + nonce(32) + extended prefix(6) + calcPaddedLen(1 MiB) +\n * mac(32) bytes. NIP-44 asks implementations to enforce their own maximum payload size; relays cap\n * events far below this. Raise it via `opts.maxPayloadChars` in `decrypt`/ `decryptFromPubkey` for\n * large local payloads.\n */\nexport const DEFAULT_MAX_PAYLOAD_CHARS: number = Math.ceil((71 + calcPaddedLen(0x100000)) / 3) * 4;\n\nfunction assert32(bytes: Uint8Array, label: string): void {\n if (bytes.length !== 32) {\n throw new CryptoError(`${label} must be 32 bytes`);\n }\n}\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n assertSecretKeyBytes(privkeyA);\n assertHex32(pubkeyB, \"public key\");\n const sharedX = secp256k1\n .getSharedSecret(privkeyA, hexToBytes(`02${pubkeyB.toLowerCase()}`))\n .subarray(1, 33);\n return hkdf_extract(sha256, sharedX, utf8Encoder.encode(\"nip44-v2\"));\n}\n\n/** NIP-44 `get_message_keys`: HKDF-expand the 76-byte key material. */\nexport function getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n assert32(conversationKey, \"conversation_key\");\n assert32(nonce, \"nonce\");\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76);\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n };\n}\n\nexport function calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) {\n throw new CryptoError(\"expected positive integer\");\n }\n if (len <= 32) {\n return 32;\n }\n const nextPower = 2 ** (Math.floor(Math.log2(len - 1)) + 1);\n const chunk = nextPower <= 256 ? 32 : nextPower / 8;\n return chunk * (Math.floor((len - 1) / chunk) + 1);\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > 0xffff) {\n throw new CryptoError(\"invalid plaintext size: must be between 1 and 65535 bytes\");\n }\n const arr = new Uint8Array(2);\n new DataView(arr.buffer).setUint16(0, num, false);\n return arr;\n}\n\nfunction writeU32BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < extendedPrefixThreshold || num > maxPlaintextSize) {\n throw new CryptoError(\"invalid plaintext size: must be between 65536 and 4294967295 bytes\");\n }\n const arr = new Uint8Array(4);\n new DataView(arr.buffer).setUint32(0, num, false);\n return arr;\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext);\n const unpaddedLen = unpadded.length;\n if (unpaddedLen < minPlaintextSize || unpaddedLen > maxPlaintextSize) {\n throw new CryptoError(\"invalid plaintext size: must be between 1 and 4294967295 bytes\");\n }\n const prefix =\n unpaddedLen >= extendedPrefixThreshold\n ? concatBytes(new Uint8Array([0, 0]), writeU32BE(unpaddedLen))\n : writeU16BE(unpaddedLen);\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen);\n return concatBytes(prefix, unpadded, suffix);\n}\n\nfunction unpad(padded: Uint8Array): string {\n const dv = new DataView(padded.buffer, padded.byteOffset, padded.byteLength);\n const firstTwo = dv.getUint16(0);\n let unpaddedLen: number;\n let prefixLen: number;\n if (firstTwo === 0) {\n unpaddedLen = dv.getUint32(2);\n if (unpaddedLen < extendedPrefixThreshold) {\n throw new CryptoError(\"invalid padding\");\n }\n prefixLen = 6;\n } else {\n unpaddedLen = firstTwo;\n prefixLen = 2;\n }\n const unpadded = padded.subarray(prefixLen, prefixLen + unpaddedLen);\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== prefixLen + calcPaddedLen(unpaddedLen)\n ) {\n throw new CryptoError(\"invalid padding\");\n }\n return utf8Decoder.decode(unpadded);\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) {\n throw new CryptoError(\"AAD associated data must be 32 bytes\");\n }\n return hmac(sha256, key, concatBytes(aad, message));\n}\n\nfunction decodePayload(\n payload: string,\n maxPayloadChars: number,\n): {\n nonce: Uint8Array;\n ciphertext: Uint8Array;\n mac: Uint8Array;\n} {\n if (typeof payload !== \"string\") {\n throw new CryptoError(\"payload must be a valid string\");\n }\n if (payload.startsWith(\"#\")) {\n throw new CryptoError(\"unknown encryption version\");\n }\n if (payload.length < 132 || payload.length > maxPayloadChars) {\n throw new CryptoError(`invalid payload length: ${payload.length}`);\n }\n let data: Uint8Array;\n try {\n data = base64.decode(payload);\n } catch (error) {\n throw new CryptoError(\"invalid base64\", { cause: error });\n }\n if (data.length < 99) {\n throw new CryptoError(`invalid data length: ${data.length}`);\n }\n const version = data.at(0);\n if (version === undefined) {\n throw new CryptoError(\"invalid data length\");\n }\n if (version !== 2) {\n throw new CryptoError(`unknown encryption version ${version}`);\n }\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n };\n}\n\nexport function encrypt(\n plaintext: string,\n conversationKey: Uint8Array,\n nonce: Uint8Array = randomBytes(32),\n): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce);\n const padded = pad(plaintext);\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded);\n const mac = hmacAad(hmac_key, ciphertext, nonce);\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac));\n}\n\nexport function decrypt(\n payload: string,\n conversationKey: Uint8Array,\n opts?: { maxPayloadChars?: number },\n): string {\n const { nonce, ciphertext, mac } = decodePayload(\n payload,\n opts?.maxPayloadChars ?? DEFAULT_MAX_PAYLOAD_CHARS,\n );\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce);\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce);\n if (!equalBytes(calculatedMac, mac)) {\n throw new CryptoError(\"invalid MAC\");\n }\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext);\n return unpad(padded);\n}\n\n/** Convenience: derive conversation key from secret/public pair and encrypt. */\nexport function encryptToPubkey(\n plaintext: string,\n secretKey: Uint8Array,\n peerPubkey: string,\n): string {\n return encrypt(plaintext, getConversationKey(secretKey, peerPubkey));\n}\n\n/** Convenience: decrypt a payload from a peer pubkey. */\nexport function decryptFromPubkey(\n payload: string,\n secretKey: Uint8Array,\n peerPubkey: string,\n opts?: { maxPayloadChars?: number },\n): string {\n return decrypt(payload, getConversationKey(secretKey, peerPubkey), opts);\n}\n"],"mappings":"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"}
|
package/dist/nips/nip46.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export {
|
|
1
|
+
import { a as Nip46Response, c as decodeNip46Request, d as encodeNip46Response, f as parseBunkerURL, i as Nip46Request, l as decodeNip46Response, m as toBunkerURL, n as ClientMetadata, o as NostrConnectParams, p as parseNostrConnectURI, r as Nip46Error, s as createNostrConnectURI, t as BunkerPointer, u as encodeNip46Request } from "../nip46-BHaxC9TZ.mjs";
|
|
2
|
+
export { BunkerPointer, ClientMetadata, Nip46Error, Nip46Request, Nip46Response, NostrConnectParams, createNostrConnectURI, decodeNip46Request, decodeNip46Response, encodeNip46Request, encodeNip46Response, parseBunkerURL, parseNostrConnectURI, toBunkerURL };
|
package/dist/nips/nip46.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as isRecord,
|
|
1
|
+
import { c as isRecord, o as isHex32, v as NostrError } from "../util-DMF9AIO0.mjs";
|
|
2
2
|
//#region src/nips/nip46.ts
|
|
3
3
|
/**
|
|
4
4
|
* NIP-46 (Nostr Connect) protocol helpers: bunker URI, nostrconnect URI, RPC JSON.
|
|
@@ -6,12 +6,8 @@ import { c as isRecord, g as NostrError, n as assertHex32, o as isHex32 } from "
|
|
|
6
6
|
*
|
|
7
7
|
* @see https://github.com/nostr-protocol/nips/blob/master/46.md
|
|
8
8
|
*/
|
|
9
|
-
const BUNKER_REGEX = /^bunker:\/\/([0-9a-fA-F]{64})\??([?/\w:.=&%-]*)$/;
|
|
10
9
|
var Nip46Error = class extends NostrError {
|
|
11
10
|
name = "Nip46Error";
|
|
12
|
-
constructor(message, options) {
|
|
13
|
-
super(message, options);
|
|
14
|
-
}
|
|
15
11
|
};
|
|
16
12
|
/** Encode a bunker pointer as `bunker://…`. */
|
|
17
13
|
function toBunkerURL(pointer) {
|
|
@@ -25,20 +21,20 @@ function toBunkerURL(pointer) {
|
|
|
25
21
|
* (including NIP-05 identifiers).
|
|
26
22
|
*/
|
|
27
23
|
function parseBunkerURL(input) {
|
|
28
|
-
|
|
29
|
-
const hex = match?.at(1);
|
|
30
|
-
if (match === null || hex === void 0) return;
|
|
24
|
+
let url;
|
|
31
25
|
try {
|
|
32
|
-
|
|
33
|
-
const qs = new URLSearchParams(match.at(2) ?? "");
|
|
34
|
-
return {
|
|
35
|
-
pubkey,
|
|
36
|
-
relays: qs.getAll("relay"),
|
|
37
|
-
secret: qs.get("secret") ?? void 0
|
|
38
|
-
};
|
|
26
|
+
url = new URL(input.trim());
|
|
39
27
|
} catch {
|
|
40
28
|
return;
|
|
41
29
|
}
|
|
30
|
+
if (url.protocol !== "bunker:") return;
|
|
31
|
+
const pubkey = url.hostname || url.pathname.replace(/^\/*/, "");
|
|
32
|
+
if (!isHex32(pubkey.toLowerCase())) return;
|
|
33
|
+
return {
|
|
34
|
+
pubkey: pubkey.toLowerCase(),
|
|
35
|
+
relays: url.searchParams.getAll("relay"),
|
|
36
|
+
secret: url.searchParams.get("secret") ?? void 0
|
|
37
|
+
};
|
|
42
38
|
}
|
|
43
39
|
/** Build a client-initiated `nostrconnect://` URI. */
|
|
44
40
|
function createNostrConnectURI(params) {
|
|
@@ -60,7 +56,7 @@ function parseNostrConnectURI(uri) {
|
|
|
60
56
|
try {
|
|
61
57
|
url = new URL(uri);
|
|
62
58
|
} catch (error) {
|
|
63
|
-
throw new Nip46Error(`invalid nostrconnect URI: ${uri}`, { cause: error
|
|
59
|
+
throw new Nip46Error(`invalid nostrconnect URI: ${uri}`, { cause: error });
|
|
64
60
|
}
|
|
65
61
|
if (url.protocol !== "nostrconnect:") throw new Nip46Error(`expected nostrconnect: scheme, got ${url.protocol}`);
|
|
66
62
|
const clientPubkey = url.hostname || url.pathname.replace(/^\/*/, "");
|
|
@@ -96,7 +92,7 @@ function decodeNip46Request(json) {
|
|
|
96
92
|
try {
|
|
97
93
|
data = JSON.parse(json);
|
|
98
94
|
} catch (error) {
|
|
99
|
-
throw new Nip46Error("invalid NIP-46 request JSON", { cause: error
|
|
95
|
+
throw new Nip46Error("invalid NIP-46 request JSON", { cause: error });
|
|
100
96
|
}
|
|
101
97
|
if (!isRecord(data) || typeof data["id"] !== "string" || typeof data["method"] !== "string") throw new Nip46Error("invalid NIP-46 request shape");
|
|
102
98
|
if (!Array.isArray(data["params"]) || !data["params"].every((p) => typeof p === "string")) throw new Nip46Error("invalid NIP-46 request params");
|
|
@@ -117,7 +113,7 @@ function decodeNip46Response(json) {
|
|
|
117
113
|
try {
|
|
118
114
|
data = JSON.parse(json);
|
|
119
115
|
} catch (error) {
|
|
120
|
-
throw new Nip46Error("invalid NIP-46 response JSON", { cause: error
|
|
116
|
+
throw new Nip46Error("invalid NIP-46 response JSON", { cause: error });
|
|
121
117
|
}
|
|
122
118
|
if (!isRecord(data) || typeof data["id"] !== "string") throw new Nip46Error("invalid NIP-46 response shape");
|
|
123
119
|
const result = data["result"] === null ? void 0 : data["result"];
|
|
@@ -130,6 +126,6 @@ function decodeNip46Response(json) {
|
|
|
130
126
|
return response;
|
|
131
127
|
}
|
|
132
128
|
//#endregion
|
|
133
|
-
export {
|
|
129
|
+
export { Nip46Error, createNostrConnectURI, decodeNip46Request, decodeNip46Response, encodeNip46Request, encodeNip46Response, parseBunkerURL, parseNostrConnectURI, toBunkerURL };
|
|
134
130
|
|
|
135
131
|
//# sourceMappingURL=nip46.mjs.map
|
package/dist/nips/nip46.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nip46.mjs","names":[],"sources":["../../src/nips/nip46.ts"],"sourcesContent":["import { NostrError } from \"../core/error.ts\";\n/**\n * NIP-46 (Nostr Connect) protocol helpers: bunker URI, nostrconnect URI, RPC JSON.\n * Transport/signing live in {@link Nip46Signer}.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/46.md\n */\nimport { assertHex32, isHex32, isRecord } from \"../core/util.ts\";\n\n// oxlint-disable-next-line no-inferrable-types -- isolatedDeclarations requires the annotation for dts emit\nexport const BUNKER_REGEX: RegExp = /^bunker:\\/\\/([0-9a-fA-F]{64})\\??([?/\\w:.=&%-]*)$/;\n\nexport type BunkerPointer = {\n /** Remote signer / bunker public key (hex). */\n pubkey: string;\n relays: string[];\n secret: string | undefined;\n};\n\nexport type ClientMetadata = {\n name?: string | undefined;\n url?: string | undefined;\n image?: string | undefined;\n};\n\nexport type NostrConnectParams = {\n clientPubkey: string;\n relays: string[];\n secret: string;\n perms?: string[] | undefined;\n} & ClientMetadata;\n\nexport type Nip46Request = {\n id: string;\n method: string;\n params: string[];\n};\n\nexport type Nip46Response = {\n id: string;\n result?: string | undefined;\n error?: string | undefined;\n};\n\nexport class Nip46Error extends NostrError {\n override name = \"Nip46Error\";\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n }\n}\n\n/** Encode a bunker pointer as `bunker://…`. */\nexport function toBunkerURL(pointer: BunkerPointer): string {\n const url = new URL(`bunker://${pointer.pubkey.toLowerCase()}`);\n for (const relay of pointer.relays) {\n url.searchParams.append(\"relay\", relay);\n }\n if (pointer.secret !== undefined && pointer.secret !== \"\") {\n url.searchParams.set(\"secret\", pointer.secret);\n }\n return url.toString();\n}\n\n/**\n * Parse a `bunker://` URL into a pointer. Returns undefined when the input is not a bunker URL\n * (including NIP-05 identifiers).\n */\nexport function parseBunkerURL(input: string): BunkerPointer | undefined {\n const match = BUNKER_REGEX.exec(input.trim());\n const hex = match?.at(1);\n if (match === null || hex === undefined) {\n return undefined;\n }\n try {\n const pubkey = assertHex32(hex, \"bunker pubkey\");\n const qs = new URLSearchParams(match.at(2) ?? \"\");\n return {\n pubkey,\n relays: qs.getAll(\"relay\"),\n secret: qs.get(\"secret\") ?? undefined,\n };\n } catch {\n return undefined;\n }\n}\n\n/** Build a client-initiated `nostrconnect://` URI. */\nexport function createNostrConnectURI(params: NostrConnectParams): string {\n if (!isHex32(params.clientPubkey.toLowerCase())) {\n throw new Nip46Error(\"invalid client pubkey\");\n }\n if (!params.secret) {\n throw new Nip46Error(\"nostrconnect secret is required\");\n }\n if (params.relays.length === 0) {\n throw new Nip46Error(\"at least one relay is required\");\n }\n\n const query = new URLSearchParams();\n for (const relay of params.relays) {\n query.append(\"relay\", relay);\n }\n query.set(\"secret\", params.secret);\n if (params.perms !== undefined && params.perms.length > 0) {\n query.set(\"perms\", params.perms.join(\",\"));\n }\n if (params.name !== undefined && params.name !== \"\") {\n query.set(\"name\", params.name);\n }\n if (params.url !== undefined && params.url !== \"\") {\n query.set(\"url\", params.url);\n }\n if (params.image !== undefined && params.image !== \"\") {\n query.set(\"image\", params.image);\n }\n\n return `nostrconnect://${params.clientPubkey.toLowerCase()}?${query.toString()}`;\n}\n\n/** Parse a `nostrconnect://` URI. */\nexport function parseNostrConnectURI(uri: string): NostrConnectParams {\n let url: URL;\n try {\n url = new URL(uri);\n } catch (error) {\n throw new Nip46Error(`invalid nostrconnect URI: ${uri}`, {\n cause: error instanceof Error ? error : undefined,\n });\n }\n if (url.protocol !== \"nostrconnect:\") {\n throw new Nip46Error(`expected nostrconnect: scheme, got ${url.protocol}`);\n }\n const clientPubkey = url.hostname || url.pathname.replace(/^\\/*/, \"\");\n if (!isHex32(clientPubkey.toLowerCase())) {\n throw new Nip46Error(\"invalid client pubkey in nostrconnect URI\");\n }\n const secret = url.searchParams.get(\"secret\");\n if (secret === null || secret === \"\") {\n throw new Nip46Error(\"missing secret in nostrconnect URI\");\n }\n const relays = url.searchParams.getAll(\"relay\");\n if (relays.length === 0) {\n throw new Nip46Error(\"missing relays in nostrconnect URI\");\n }\n const params: NostrConnectParams = {\n clientPubkey: clientPubkey.toLowerCase(),\n relays,\n secret,\n };\n const permsRaw = url.searchParams.get(\"perms\");\n if (permsRaw !== null && permsRaw !== \"\") {\n params.perms = permsRaw.split(\",\").filter((p) => p !== \"\");\n }\n const name = url.searchParams.get(\"name\");\n if (name !== null) {\n params.name = name;\n }\n const metadataUrl = url.searchParams.get(\"url\");\n if (metadataUrl !== null) {\n params.url = metadataUrl;\n }\n const image = url.searchParams.get(\"image\");\n if (image !== null) {\n params.image = image;\n }\n return params;\n}\n\nexport function encodeNip46Request(req: Nip46Request): string {\n return JSON.stringify({ id: req.id, method: req.method, params: req.params });\n}\n\nexport function decodeNip46Request(json: string): Nip46Request {\n let data: unknown;\n try {\n data = JSON.parse(json);\n } catch (error) {\n throw new Nip46Error(\"invalid NIP-46 request JSON\", {\n cause: error instanceof Error ? error : undefined,\n });\n }\n if (!isRecord(data) || typeof data[\"id\"] !== \"string\" || typeof data[\"method\"] !== \"string\") {\n throw new Nip46Error(\"invalid NIP-46 request shape\");\n }\n if (!Array.isArray(data[\"params\"]) || !data[\"params\"].every((p) => typeof p === \"string\")) {\n throw new Nip46Error(\"invalid NIP-46 request params\");\n }\n return { id: data[\"id\"], method: data[\"method\"], params: data[\"params\"] };\n}\n\nexport function encodeNip46Response(res: Nip46Response): string {\n const body: Record<string, string> = { id: res.id };\n if (res.result !== undefined) {\n body[\"result\"] = res.result;\n }\n if (res.error !== undefined) {\n body[\"error\"] = res.error;\n }\n return JSON.stringify(body);\n}\n\nexport function decodeNip46Response(json: string): Nip46Response {\n let data: unknown;\n try {\n data = JSON.parse(json);\n } catch (error) {\n throw new Nip46Error(\"invalid NIP-46 response JSON\", {\n cause: error instanceof Error ? error : undefined,\n });\n }\n if (!isRecord(data) || typeof data[\"id\"] !== \"string\") {\n throw new Nip46Error(\"invalid NIP-46 response shape\");\n }\n // Some remote signers send explicit nulls for absent fields.\n const result = data[\"result\"] === null ? undefined : data[\"result\"];\n const error = data[\"error\"] === null ? undefined : data[\"error\"];\n if (result !== undefined && typeof result !== \"string\") {\n throw new Nip46Error(\"invalid NIP-46 response result\");\n }\n if (error !== undefined && typeof error !== \"string\") {\n throw new Nip46Error(\"invalid NIP-46 response error\");\n }\n const response: Nip46Response = { id: data[\"id\"] };\n if (result !== undefined) {\n response.result = result;\n }\n if (error !== undefined) {\n response.error = error;\n }\n return response;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nip46.mjs","names":[],"sources":["../../src/nips/nip46.ts"],"sourcesContent":["/**\n * NIP-46 (Nostr Connect) protocol helpers: bunker URI, nostrconnect URI, RPC JSON.\n * Transport/signing live in {@link Nip46Signer}.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/46.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport type { Mutable } from \"../core/util.ts\";\nimport { isHex32, isRecord } from \"../core/util.ts\";\n\nexport type BunkerPointer = {\n /** Remote signer / bunker public key (hex). */\n readonly pubkey: string;\n readonly relays: ReadonlyArray<string>;\n readonly secret?: string | undefined;\n};\n\nexport type ClientMetadata = {\n readonly name?: string | undefined;\n readonly url?: string | undefined;\n readonly image?: string | undefined;\n};\n\nexport type NostrConnectParams = {\n readonly clientPubkey: string;\n readonly relays: ReadonlyArray<string>;\n readonly secret: string;\n readonly perms?: ReadonlyArray<string> | undefined;\n} & ClientMetadata;\n\nexport type Nip46Request = {\n readonly id: string;\n readonly method: string;\n readonly params: ReadonlyArray<string>;\n};\n\nexport type Nip46Response = {\n readonly id: string;\n readonly result?: string | undefined;\n readonly error?: string | undefined;\n};\n\nexport class Nip46Error extends NostrError {\n override name = \"Nip46Error\";\n}\n\n/** Encode a bunker pointer as `bunker://…`. */\nexport function toBunkerURL(pointer: BunkerPointer): string {\n const url = new URL(`bunker://${pointer.pubkey.toLowerCase()}`);\n for (const relay of pointer.relays) {\n url.searchParams.append(\"relay\", relay);\n }\n if (pointer.secret !== undefined && pointer.secret !== \"\") {\n url.searchParams.set(\"secret\", pointer.secret);\n }\n return url.toString();\n}\n\n/**\n * Parse a `bunker://` URL into a pointer. Returns undefined when the input is not a bunker URL\n * (including NIP-05 identifiers).\n */\nexport function parseBunkerURL(input: string): BunkerPointer | undefined {\n let url: URL;\n try {\n url = new URL(input.trim());\n } catch {\n return undefined;\n }\n if (url.protocol !== \"bunker:\") {\n return undefined;\n }\n const pubkey = url.hostname || url.pathname.replace(/^\\/*/, \"\");\n if (!isHex32(pubkey.toLowerCase())) {\n return undefined;\n }\n return {\n pubkey: pubkey.toLowerCase(),\n relays: url.searchParams.getAll(\"relay\"),\n secret: url.searchParams.get(\"secret\") ?? undefined,\n };\n}\n\n/** Build a client-initiated `nostrconnect://` URI. */\nexport function createNostrConnectURI(params: NostrConnectParams): string {\n if (!isHex32(params.clientPubkey.toLowerCase())) {\n throw new Nip46Error(\"invalid client pubkey\");\n }\n if (!params.secret) {\n throw new Nip46Error(\"nostrconnect secret is required\");\n }\n if (params.relays.length === 0) {\n throw new Nip46Error(\"at least one relay is required\");\n }\n\n const query = new URLSearchParams();\n for (const relay of params.relays) {\n query.append(\"relay\", relay);\n }\n query.set(\"secret\", params.secret);\n if (params.perms !== undefined && params.perms.length > 0) {\n query.set(\"perms\", params.perms.join(\",\"));\n }\n if (params.name !== undefined && params.name !== \"\") {\n query.set(\"name\", params.name);\n }\n if (params.url !== undefined && params.url !== \"\") {\n query.set(\"url\", params.url);\n }\n if (params.image !== undefined && params.image !== \"\") {\n query.set(\"image\", params.image);\n }\n\n return `nostrconnect://${params.clientPubkey.toLowerCase()}?${query.toString()}`;\n}\n\n/** Parse a `nostrconnect://` URI. */\nexport function parseNostrConnectURI(uri: string): NostrConnectParams {\n let url: URL;\n try {\n url = new URL(uri);\n } catch (error) {\n throw new Nip46Error(`invalid nostrconnect URI: ${uri}`, {\n cause: error,\n });\n }\n if (url.protocol !== \"nostrconnect:\") {\n throw new Nip46Error(`expected nostrconnect: scheme, got ${url.protocol}`);\n }\n const clientPubkey = url.hostname || url.pathname.replace(/^\\/*/, \"\");\n if (!isHex32(clientPubkey.toLowerCase())) {\n throw new Nip46Error(\"invalid client pubkey in nostrconnect URI\");\n }\n const secret = url.searchParams.get(\"secret\");\n if (secret === null || secret === \"\") {\n throw new Nip46Error(\"missing secret in nostrconnect URI\");\n }\n const relays = url.searchParams.getAll(\"relay\");\n if (relays.length === 0) {\n throw new Nip46Error(\"missing relays in nostrconnect URI\");\n }\n const params: Mutable<NostrConnectParams> = {\n clientPubkey: clientPubkey.toLowerCase(),\n relays,\n secret,\n };\n const permsRaw = url.searchParams.get(\"perms\");\n if (permsRaw !== null && permsRaw !== \"\") {\n params.perms = permsRaw.split(\",\").filter((p) => p !== \"\");\n }\n const name = url.searchParams.get(\"name\");\n if (name !== null) {\n params.name = name;\n }\n const metadataUrl = url.searchParams.get(\"url\");\n if (metadataUrl !== null) {\n params.url = metadataUrl;\n }\n const image = url.searchParams.get(\"image\");\n if (image !== null) {\n params.image = image;\n }\n return params;\n}\n\nexport function encodeNip46Request(req: Nip46Request): string {\n return JSON.stringify({ id: req.id, method: req.method, params: req.params });\n}\n\nexport function decodeNip46Request(json: string): Nip46Request {\n let data: unknown;\n try {\n data = JSON.parse(json);\n } catch (error) {\n throw new Nip46Error(\"invalid NIP-46 request JSON\", {\n cause: error,\n });\n }\n if (!isRecord(data) || typeof data[\"id\"] !== \"string\" || typeof data[\"method\"] !== \"string\") {\n throw new Nip46Error(\"invalid NIP-46 request shape\");\n }\n if (!Array.isArray(data[\"params\"]) || !data[\"params\"].every((p) => typeof p === \"string\")) {\n throw new Nip46Error(\"invalid NIP-46 request params\");\n }\n return { id: data[\"id\"], method: data[\"method\"], params: data[\"params\"] };\n}\n\nexport function encodeNip46Response(res: Nip46Response): string {\n const body: Record<string, string> = { id: res.id };\n if (res.result !== undefined) {\n body[\"result\"] = res.result;\n }\n if (res.error !== undefined) {\n body[\"error\"] = res.error;\n }\n return JSON.stringify(body);\n}\n\nexport function decodeNip46Response(json: string): Nip46Response {\n let data: unknown;\n try {\n data = JSON.parse(json);\n } catch (error) {\n throw new Nip46Error(\"invalid NIP-46 response JSON\", {\n cause: error,\n });\n }\n if (!isRecord(data) || typeof data[\"id\"] !== \"string\") {\n throw new Nip46Error(\"invalid NIP-46 response shape\");\n }\n // Some remote signers send explicit nulls for absent fields.\n const result = data[\"result\"] === null ? undefined : data[\"result\"];\n const error = data[\"error\"] === null ? undefined : data[\"error\"];\n if (result !== undefined && typeof result !== \"string\") {\n throw new Nip46Error(\"invalid NIP-46 response result\");\n }\n if (error !== undefined && typeof error !== \"string\") {\n throw new Nip46Error(\"invalid NIP-46 response error\");\n }\n const response: Mutable<Nip46Response> = { id: data[\"id\"] };\n if (result !== undefined) {\n response.result = result;\n }\n if (error !== undefined) {\n response.error = error;\n }\n return response;\n}\n"],"mappings":"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"}
|
package/dist/nips/nip49.d.mts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import { a as NostrError } from "../error-
|
|
1
|
+
import { a as NostrError } from "../error-BquXDmIN.mjs";
|
|
2
2
|
//#region src/nips/nip49.d.ts
|
|
3
3
|
export type Ncryptsec = `ncryptsec1${string}`;
|
|
4
4
|
export type KeySecurityByte = 0x00 | 0x01 | 0x02;
|
|
5
5
|
export type ScryptParams = {
|
|
6
|
-
N: number;
|
|
7
|
-
r: number;
|
|
8
|
-
p: number;
|
|
9
|
-
dkLen: number;
|
|
6
|
+
readonly N: number;
|
|
7
|
+
readonly r: number;
|
|
8
|
+
readonly p: number;
|
|
9
|
+
readonly dkLen: number;
|
|
10
10
|
};
|
|
11
11
|
/** Derive `params.dkLen` bytes from the NFKC-normalized UTF-8 password and salt (RFC 7914). */
|
|
12
12
|
export type Scrypt = (password: Uint8Array, salt: Uint8Array, params: ScryptParams) => Promise<Uint8Array>;
|
|
13
13
|
export type Nip49EncryptOptions = {
|
|
14
14
|
/** Scrypt log2(N) work factor, 1..22. Defaults to 16. */
|
|
15
|
-
logn?: number;
|
|
15
|
+
logn?: number | undefined;
|
|
16
16
|
/** Key security byte recorded in the payload. Defaults to 0x02. */
|
|
17
|
-
ksb?: KeySecurityByte;
|
|
17
|
+
ksb?: KeySecurityByte | undefined;
|
|
18
18
|
/** Scrypt implementation. Defaults to noble `scryptAsync`. */
|
|
19
|
-
scrypt?: Scrypt;
|
|
19
|
+
scrypt?: Scrypt | undefined;
|
|
20
20
|
};
|
|
21
21
|
export type Nip49DecryptOptions = {
|
|
22
22
|
/** Scrypt implementation. Defaults to noble `scryptAsync`. */
|
|
23
|
-
scrypt?: Scrypt;
|
|
23
|
+
scrypt?: Scrypt | undefined;
|
|
24
24
|
};
|
|
25
25
|
export declare class Nip49Error extends NostrError {
|
|
26
26
|
name: string;
|