@qntx/nostr 0.6.0 → 0.7.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-9tjI6WQ3.mjs → builder-CdLE4J6O.mjs} +11 -17
- package/dist/builder-CdLE4J6O.mjs.map +1 -0
- package/dist/{builder-sSflu6nB.d.mts → builder-DgkqDylK.d.mts} +5 -6
- package/dist/{client-CadO5fAX.mjs → client-CILhdfsF.mjs} +104 -314
- package/dist/client-CILhdfsF.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/{error-BW7re1UN.d.mts → error-BD_0QFKT.d.mts} +2 -2
- package/dist/{error-CR8Urc84.d.mts → error-BquXDmIN.d.mts} +4 -4
- package/dist/{error-DrEIM7FO.mjs → error-L_QdmSnV.mjs} +2 -2
- package/dist/{error-DrEIM7FO.mjs.map → error-L_QdmSnV.mjs.map} +1 -1
- package/dist/{error-B__OMBRY.mjs → error-gtJvV6YS.mjs} +2 -2
- package/dist/{error-B__OMBRY.mjs.map → error-gtJvV6YS.mjs.map} +1 -1
- package/dist/{event-fU3Y01PR.d.mts → event-DJeb_DIL.d.mts} +4 -2
- package/dist/{event-D8Nfoh4K.mjs → event-DinQMmJ1.mjs} +16 -10
- package/dist/event-DinQMmJ1.mjs.map +1 -0
- package/dist/{filter-C0IMByE3.d.mts → filter-jI_9htF7.d.mts} +2 -2
- package/dist/{gossip-DpIvkBuj.d.mts → gossip-C7HLW5kI.d.mts} +35 -26
- package/dist/{gossip-oloDMWEj.mjs → gossip-CcTp9VpU.mjs} +23 -33
- package/dist/gossip-CcTp9VpU.mjs.map +1 -0
- package/dist/gossip.d.mts +1 -1
- package/dist/gossip.mjs +1 -1
- package/dist/{index-CvkvqB16.d.mts → index-DU9tRFTZ.d.mts} +7 -20
- package/dist/{index-q4MDce_r.d.mts → index-DiXwNn2M.d.mts} +6 -8
- package/dist/{index-CNl2q67H.d.mts → index-DocgD9K0.d.mts} +92 -167
- package/dist/{index-D1bqFHKB.d.mts → index-InQZpHyQ.d.mts} +18 -18
- package/dist/{index-MxC28S4P.d.mts → index-Tx15HGAD.d.mts} +26 -28
- package/dist/{index-lvXeER5t.d.mts → index-iLT8UzY3.d.mts} +19 -37
- package/dist/index.d.mts +23 -21
- package/dist/index.mjs +21 -19
- package/dist/{instance-DQE8BoWt.mjs → instance-BcKzxHIP.mjs} +26 -27
- package/dist/instance-BcKzxHIP.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-bshqfmZL.mjs} +13 -9
- package/dist/key-bshqfmZL.mjs.map +1 -0
- package/dist/{loaders-o6YXB_Ri.mjs → loaders-DD0XAGzw.mjs} +73 -82
- package/dist/loaders-DD0XAGzw.mjs.map +1 -0
- package/dist/loaders.d.mts +3 -3
- package/dist/loaders.mjs +2 -2
- package/dist/{memory-C2EVx0_O.mjs → memory-D_-5-T31.mjs} +2 -2
- package/dist/memory-D_-5-T31.mjs.map +1 -0
- package/dist/{memory-index-Do1mz0WF.mjs → memory-index-C6rujtoc.mjs} +30 -247
- package/dist/memory-index-C6rujtoc.mjs.map +1 -0
- package/dist/message-CWLcFTQ1.mjs +194 -0
- package/dist/message-CWLcFTQ1.mjs.map +1 -0
- package/dist/{message-iGPIqnn0.d.mts → message-CbBZOhq3.d.mts} +3 -3
- package/dist/{nip17-CKIufV98.d.mts → nip17-cTDFfFVt.d.mts} +5 -6
- package/dist/{nip19-BevCJZsp.d.mts → nip19-D1OnJ192.d.mts} +3 -9
- package/dist/{nip46-DDV4dC56.d.mts → nip46-DrsPI8EX.d.mts} +3 -5
- package/dist/nip51-DoPUvQ--.d.mts +87 -0
- package/dist/{nip59-zQgdLcEr.d.mts → nip59-BFIihLYY.d.mts} +3 -4
- package/dist/nip65-52HiwiyD.d.mts +23 -0
- package/dist/{nip77-DH4RhS5r.d.mts → nip77-C9QcZn7b.d.mts} +3 -4
- package/dist/nips/blossom.d.mts +12 -8
- 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 +2 -3
- package/dist/nips/nip05.mjs +1 -4
- package/dist/nips/nip05.mjs.map +1 -1
- package/dist/nips/nip10.d.mts +3 -3
- package/dist/nips/nip10.mjs +3 -3
- package/dist/nips/nip11.d.mts +1 -1
- 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 +13 -33
- 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 +6 -1
- package/dist/nips/nip21.mjs +15 -5
- package/dist/nips/nip21.mjs.map +1 -1
- package/dist/nips/nip27.d.mts +4 -4
- 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 +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 +5 -5
- 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 +7 -5
- 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 +16 -16
- 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-SzJKPIa3.d.mts} +96 -91
- package/dist/pool-YHRZgcQ3.mjs +596 -0
- package/dist/pool-YHRZgcQ3.mjs.map +1 -0
- package/dist/put-DS0yzVJx.mjs +187 -0
- package/dist/put-DS0yzVJx.mjs.map +1 -0
- package/dist/{reactive-7aqeip4A.d.mts → reactive-BJ1ggn4d.d.mts} +7 -22
- package/dist/{reactive-BfhPp9a3.mjs → reactive-BJRoVHxU.mjs} +80 -65
- package/dist/reactive-BJRoVHxU.mjs.map +1 -0
- package/dist/{pool-As20OGxB.mjs → relay-CvxPiQ_m.mjs} +178 -721
- package/dist/relay-CvxPiQ_m.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-yW3slDC2.mjs} +12 -14
- package/dist/signer-yW3slDC2.mjs.map +1 -0
- package/dist/signer.d.mts +2 -2
- package/dist/signer.mjs +2 -2
- package/dist/{storage-Dky3wuoH.mjs → storage-CZ52ifcQ.mjs} +17 -42
- package/dist/storage-CZ52ifcQ.mjs.map +1 -0
- package/dist/storage.d.mts +3 -3
- package/dist/storage.mjs +4 -4
- package/dist/store.d.mts +1 -1
- package/dist/store.mjs +1 -1
- package/dist/testing.d.mts +18 -18
- package/dist/testing.mjs +9 -9
- package/dist/testing.mjs.map +1 -1
- package/dist/{types-2pCUprRU.d.mts → types-Cm-XMgtH.d.mts} +6 -6
- package/dist/{types-CRQEk0Oi.d.mts → types-DNmiscfd.d.mts} +2 -2
- package/dist/{util-LfQirgDk.mjs → util-yFYzlbrm.mjs} +29 -7
- package/dist/util-yFYzlbrm.mjs.map +1 -0
- package/dist/{verifier-t5WoWbtY.mjs → verifier-BTLOpo1n.mjs} +3 -3
- package/dist/verifier-BTLOpo1n.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.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/nip05.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nip05.mjs","names":[],"sources":["../../src/nips/nip05.ts"],"sourcesContent":["/**\n * NIP-05: Mapping Nostr keys to DNS-based internet identifiers\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/05.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport { isHex32, isRecord } from \"../core/util.ts\";\nimport { fetchManual, requireGlobalFetch } from \"./http.ts\";\nimport type { ManualFetch } from \"./http.ts\";\nimport type { ProfilePointer } from \"./nip19.ts\";\n\n/** Root local-part (`_@domain` rendered as just the domain). */\nexport const NIP05_ROOT_LOCAL = \"_\";\n\nexport const WELL_KNOWN_PATH = \"/.well-known/nostr.json\";\n\n/**\n * NIP-05 identifier string.\n *\n * - Full: `name@domain`\n * - Root: `domain` or `_@domain`\n */\nexport type Nip05 = string;\n\nexport type Nip05Address = {\n /** Local part (lowercased). `_` for domain-only identifiers. */\n local: string;\n /** Domain (lowercased). */\n domain: string;\n};\n\n/** 46.md appendix discovery metadata (`{relays, nostrconnect_url}`). Not a bunker pointer. */\nexport type Nip05Nip46 = {\n relays?: string[];\n nostrconnectUrl?: string;\n};\n\nexport type Nip05Document = {\n names: Record<string, string>;\n /** NIP-05 profile relay hints */\n relays?: Record<string, string[]>;\n nip46?: Nip05Nip46;\n};\n\nexport type Nip05Fetch = ManualFetch;\n\nexport class Nip05Error extends NostrError {\n override name = \"Nip05Error\";\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n }\n}\n\n/** Matches optional local@domain. Groups: 1=local (optional), 2=domain. */\n// oxlint-disable-next-line no-inferrable-types -- isolatedDeclarations requires the annotation for dts emit\nexport const NIP05_REGEX: RegExp = /^(?:([a-z0-9._-]+)@)?([a-z0-9-]+(?:\\.[a-z0-9-]+)+)$/i;\n\nexport function isNip05(value: unknown): value is string {\n if (typeof value !== \"string\") {\n return false;\n }\n try {\n parseNip05(value);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Parse an identifier into local + domain. Accepts `name@domain`, `_@domain`, or bare `domain`\n * (local becomes `_`).\n */\nexport function parseNip05(input: string): Nip05Address {\n const match = NIP05_REGEX.exec(input.trim());\n const domain = match?.at(2);\n if (match === null || domain === undefined || domain === \"\") {\n throw new Nip05Error(`invalid NIP-05 identifier: ${input}`);\n }\n const localRaw = match.at(1) ?? NIP05_ROOT_LOCAL;\n return { local: localRaw.toLowerCase(), domain: domain.toLowerCase() };\n}\n\n/** Build the well-known HTTPS URL for an address. */\nexport function wellKnownUrl(address: Nip05Address): string {\n const url = new URL(`https://${address.domain}${WELL_KNOWN_PATH}`);\n url.searchParams.set(\"name\", address.local);\n return url.toString();\n}\n\nfunction stringUrls(list: unknown): string[] | undefined {\n if (!Array.isArray(list)) {\n return undefined;\n }\n return list.filter((u): u is string => typeof u === \"string\" && u.length > 0);\n}\n\n/**\n * Parse nostr.json `nip46`: 46.md appendix `{relays, nostrconnect_url}`. Hex-pubkey maps and other\n * keys are ignored.\n */\nexport function parseNip05Nip46(raw: unknown): Nip05Nip46 | undefined {\n if (!isRecord(raw)) {\n return undefined;\n }\n const obj = raw;\n const result: Nip05Nip46 = {};\n\n if (Array.isArray(obj[\"relays\"])) {\n result.relays = stringUrls(obj[\"relays\"]) ?? [];\n }\n\n if (typeof obj[\"nostrconnect_url\"] === \"string\" && obj[\"nostrconnect_url\"].length > 0) {\n result.nostrconnectUrl = obj[\"nostrconnect_url\"];\n }\n\n if (result.relays === undefined && result.nostrconnectUrl === undefined) {\n return undefined;\n }\n return result;\n}\n\n/** Parse and validate a nostr.json document body. */\nexport function parseNip05Document(json: unknown): Nip05Document {\n if (!isRecord(json)) {\n throw new Nip05Error(\"NIP-05 document must be a JSON object\");\n }\n const raw = json;\n if (!isRecord(raw[\"names\"])) {\n throw new Nip05Error(\"NIP-05 document missing names map\");\n }\n\n const names: Record<string, string> = {};\n for (const [k, v] of Object.entries(raw[\"names\"])) {\n if (typeof v !== \"string\" || !isHex32(v.toLowerCase())) {\n continue;\n }\n names[k.toLowerCase()] = v.toLowerCase();\n }\n\n const rawRelays = raw[\"relays\"];\n let relays: Record<string, string[]> | undefined;\n if (isRecord(rawRelays)) {\n relays = {};\n for (const [pk, list] of Object.entries(rawRelays)) {\n if (!isHex32(pk.toLowerCase())) {\n continue;\n }\n const urls = stringUrls(list);\n if (urls !== undefined && urls.length > 0) {\n relays[pk.toLowerCase()] = urls;\n }\n }\n }\n\n const doc: Nip05Document = { names };\n if (relays !== undefined) {\n doc.relays = relays;\n }\n const nip46 = parseNip05Nip46(raw[\"nip46\"]);\n if (nip46 !== undefined) {\n doc.nip46 = nip46;\n }\n return doc;\n}\n\n/** Resolve local name from an already-parsed document. */\nexport function lookupFromDocument(\n doc: Nip05Document,\n address: Nip05Address,\n): ProfilePointer | undefined {\n const pubkey = doc.names[address.local];\n if (pubkey === undefined) {\n return undefined;\n }\n const relays = doc.relays?.[pubkey];\n return relays !== undefined && relays.length > 0 ? { pubkey, relays: [...relays] } : { pubkey };\n}\n\n/**\n * Fetch and parse `/.well-known/nostr.json`. Returns `undefined` on network/parse failure (does not\n * throw for those). Rejects HTTP redirects (non-200) per NIP-05 security constraints. AbortError\n * rethrows; it is not mapped to `undefined`.\n */\nexport async function queryNip05Document(\n identifier: string,\n opts?: { fetch?: Nip05Fetch; signal?: AbortSignal },\n): Promise<{ address: Nip05Address; doc: Nip05Document } | undefined> {\n let address: Nip05Address;\n try {\n address = parseNip05(identifier);\n } catch {\n return undefined;\n }\n\n const url = wellKnownUrl(address);\n const fetchImpl =\n opts?.fetch ??\n requireGlobalFetch(() => new Nip05Error(\"no fetch implementation available; pass opts.fetch\"));\n\n try {\n const res = await fetchManual(fetchImpl, url, { signal: opts?.signal }, (err) =>\n err instanceof Error ? err : new Error(\"NIP-05 request failed\"),\n );\n // Redirects and errors must not be trusted (NIP-05 security).\n if (res.status !== 200) {\n return undefined;\n }\n const json = await res.json();\n return { address, doc: parseNip05Document(json) };\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n throw error;\n }\n return undefined;\n }\n}\n\n/**\n * Query `/.well-known/nostr.json` for an identifier. Returns `undefined` on network/parse/lookup\n * failure (does not throw for those). Profile `relays` only. `nip46` is discovery metadata, not a\n * bunker pointer.\n */\nexport async function queryProfile(\n identifier: string,\n opts?: { fetch?: Nip05Fetch; signal?: AbortSignal },\n): Promise<ProfilePointer | undefined> {\n const fetched = await queryNip05Document(identifier, opts);\n if (fetched === undefined) {\n return undefined;\n }\n return lookupFromDocument(fetched.doc, fetched.address);\n}\n\n/** True when the identifier resolves to exactly `pubkey`. */\nexport async function verifyNip05(\n pubkey: string,\n identifier: string,\n opts?: { fetch?: Nip05Fetch; signal?: AbortSignal },\n): Promise<boolean> {\n if (!isHex32(pubkey.toLowerCase())) {\n return false;\n }\n const profile = await queryProfile(identifier, opts);\n return profile !== undefined && profile.pubkey === pubkey.toLowerCase();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nip05.mjs","names":[],"sources":["../../src/nips/nip05.ts"],"sourcesContent":["/**\n * NIP-05: Mapping Nostr keys to DNS-based internet identifiers\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/05.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport { isHex32, isRecord } from \"../core/util.ts\";\nimport { fetchManual, requireGlobalFetch } from \"./http.ts\";\nimport type { ManualFetch } from \"./http.ts\";\nimport type { ProfilePointer } from \"./nip19.ts\";\n\n/** Root local-part (`_@domain` rendered as just the domain). */\nexport const NIP05_ROOT_LOCAL = \"_\";\n\nexport const WELL_KNOWN_PATH = \"/.well-known/nostr.json\";\n\n/**\n * NIP-05 identifier string.\n *\n * - Full: `name@domain`\n * - Root: `domain` or `_@domain`\n */\nexport type Nip05 = string;\n\nexport type Nip05Address = {\n /** Local part (lowercased). `_` for domain-only identifiers. */\n local: string;\n /** Domain (lowercased). */\n domain: string;\n};\n\n/** 46.md appendix discovery metadata (`{relays, nostrconnect_url}`). Not a bunker pointer. */\nexport type Nip05Nip46 = {\n relays?: string[];\n nostrconnectUrl?: string;\n};\n\nexport type Nip05Document = {\n names: Record<string, string>;\n /** NIP-05 profile relay hints */\n relays?: Record<string, string[]>;\n nip46?: Nip05Nip46;\n};\n\nexport type Nip05Fetch = ManualFetch;\n\nexport class Nip05Error extends NostrError {\n override name = \"Nip05Error\";\n}\n\n/** Matches optional local@domain. Groups: 1=local (optional), 2=domain. */\n// oxlint-disable-next-line no-inferrable-types -- isolatedDeclarations requires the annotation for dts emit\nexport const NIP05_REGEX: RegExp = /^(?:([a-z0-9._-]+)@)?([a-z0-9-]+(?:\\.[a-z0-9-]+)+)$/i;\n\nexport function isNip05(value: unknown): value is string {\n if (typeof value !== \"string\") {\n return false;\n }\n try {\n parseNip05(value);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Parse an identifier into local + domain. Accepts `name@domain`, `_@domain`, or bare `domain`\n * (local becomes `_`).\n */\nexport function parseNip05(input: string): Nip05Address {\n const match = NIP05_REGEX.exec(input.trim());\n const domain = match?.at(2);\n if (match === null || domain === undefined || domain === \"\") {\n throw new Nip05Error(`invalid NIP-05 identifier: ${input}`);\n }\n const localRaw = match.at(1) ?? NIP05_ROOT_LOCAL;\n return { local: localRaw.toLowerCase(), domain: domain.toLowerCase() };\n}\n\n/** Build the well-known HTTPS URL for an address. */\nexport function wellKnownUrl(address: Nip05Address): string {\n const url = new URL(`https://${address.domain}${WELL_KNOWN_PATH}`);\n url.searchParams.set(\"name\", address.local);\n return url.toString();\n}\n\nfunction stringUrls(list: unknown): string[] | undefined {\n if (!Array.isArray(list)) {\n return undefined;\n }\n return list.filter((u): u is string => typeof u === \"string\" && u.length > 0);\n}\n\n/**\n * Parse nostr.json `nip46`: 46.md appendix `{relays, nostrconnect_url}`. Hex-pubkey maps and other\n * keys are ignored.\n */\nexport function parseNip05Nip46(raw: unknown): Nip05Nip46 | undefined {\n if (!isRecord(raw)) {\n return undefined;\n }\n const obj = raw;\n const result: Nip05Nip46 = {};\n\n if (Array.isArray(obj[\"relays\"])) {\n result.relays = stringUrls(obj[\"relays\"]) ?? [];\n }\n\n if (typeof obj[\"nostrconnect_url\"] === \"string\" && obj[\"nostrconnect_url\"].length > 0) {\n result.nostrconnectUrl = obj[\"nostrconnect_url\"];\n }\n\n if (result.relays === undefined && result.nostrconnectUrl === undefined) {\n return undefined;\n }\n return result;\n}\n\n/** Parse and validate a nostr.json document body. */\nexport function parseNip05Document(json: unknown): Nip05Document {\n if (!isRecord(json)) {\n throw new Nip05Error(\"NIP-05 document must be a JSON object\");\n }\n const raw = json;\n if (!isRecord(raw[\"names\"])) {\n throw new Nip05Error(\"NIP-05 document missing names map\");\n }\n\n const names: Record<string, string> = {};\n for (const [k, v] of Object.entries(raw[\"names\"])) {\n if (typeof v !== \"string\" || !isHex32(v.toLowerCase())) {\n continue;\n }\n names[k.toLowerCase()] = v.toLowerCase();\n }\n\n const rawRelays = raw[\"relays\"];\n let relays: Record<string, string[]> | undefined;\n if (isRecord(rawRelays)) {\n relays = {};\n for (const [pk, list] of Object.entries(rawRelays)) {\n if (!isHex32(pk.toLowerCase())) {\n continue;\n }\n const urls = stringUrls(list);\n if (urls !== undefined && urls.length > 0) {\n relays[pk.toLowerCase()] = urls;\n }\n }\n }\n\n const doc: Nip05Document = { names };\n if (relays !== undefined) {\n doc.relays = relays;\n }\n const nip46 = parseNip05Nip46(raw[\"nip46\"]);\n if (nip46 !== undefined) {\n doc.nip46 = nip46;\n }\n return doc;\n}\n\n/** Resolve local name from an already-parsed document. */\nexport function lookupFromDocument(\n doc: Nip05Document,\n address: Nip05Address,\n): ProfilePointer | undefined {\n const pubkey = doc.names[address.local];\n if (pubkey === undefined) {\n return undefined;\n }\n const relays = doc.relays?.[pubkey];\n return relays !== undefined && relays.length > 0 ? { pubkey, relays: [...relays] } : { pubkey };\n}\n\n/**\n * Fetch and parse `/.well-known/nostr.json`. Returns `undefined` on network/parse failure (does not\n * throw for those). Rejects HTTP redirects (non-200) per NIP-05 security constraints. AbortError\n * rethrows; it is not mapped to `undefined`.\n */\nexport async function queryNip05Document(\n identifier: string,\n opts?: { fetch?: Nip05Fetch; signal?: AbortSignal },\n): Promise<{ address: Nip05Address; doc: Nip05Document } | undefined> {\n let address: Nip05Address;\n try {\n address = parseNip05(identifier);\n } catch {\n return undefined;\n }\n\n const url = wellKnownUrl(address);\n const fetchImpl =\n opts?.fetch ??\n requireGlobalFetch(() => new Nip05Error(\"no fetch implementation available; pass opts.fetch\"));\n\n try {\n const res = await fetchManual(fetchImpl, url, { signal: opts?.signal }, (err) =>\n err instanceof Error ? err : new Error(\"NIP-05 request failed\"),\n );\n // Redirects and errors must not be trusted (NIP-05 security).\n if (res.status !== 200) {\n return undefined;\n }\n const json = await res.json();\n return { address, doc: parseNip05Document(json) };\n } catch (error) {\n if (error instanceof Error && error.name === \"AbortError\") {\n throw error;\n }\n return undefined;\n }\n}\n\n/**\n * Query `/.well-known/nostr.json` for an identifier. Returns `undefined` on network/parse/lookup\n * failure (does not throw for those). Profile `relays` only. `nip46` is discovery metadata, not a\n * bunker pointer.\n */\nexport async function queryProfile(\n identifier: string,\n opts?: { fetch?: Nip05Fetch; signal?: AbortSignal },\n): Promise<ProfilePointer | undefined> {\n const fetched = await queryNip05Document(identifier, opts);\n if (fetched === undefined) {\n return undefined;\n }\n return lookupFromDocument(fetched.doc, fetched.address);\n}\n\n/** True when the identifier resolves to exactly `pubkey`. */\nexport async function verifyNip05(\n pubkey: string,\n identifier: string,\n opts?: { fetch?: Nip05Fetch; signal?: AbortSignal },\n): Promise<boolean> {\n if (!isHex32(pubkey.toLowerCase())) {\n return false;\n }\n const profile = await queryProfile(identifier, opts);\n return profile !== undefined && profile.pubkey === pubkey.toLowerCase();\n}\n"],"mappings":"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"}
|
package/dist/nips/nip10.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { _ as Tag, t as Event } from "../event-
|
|
2
|
-
import { t as EventBuilder } from "../builder-
|
|
3
|
-
import { f as ProfilePointer, i as EventPointer, t as AddressPointer } from "../nip19-
|
|
1
|
+
import { _ as Tag, t as Event } from "../event-DJeb_DIL.mjs";
|
|
2
|
+
import { t as EventBuilder } from "../builder-DgkqDylK.mjs";
|
|
3
|
+
import { f as ProfilePointer, i as EventPointer, t as AddressPointer } from "../nip19-D1OnJ192.mjs";
|
|
4
4
|
//#region src/nips/nip10.d.ts
|
|
5
5
|
/** Parsed NIP-10 thread references from an event's `e`/`q`/`p` tags. */
|
|
6
6
|
export type ThreadReferences = {
|
package/dist/nips/nip10.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { h as EventValidationError, o as isHex32 } from "../util-yFYzlbrm.mjs";
|
|
2
2
|
import { t as Kind } from "../kind-Cxwhhkx8.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { t as EventBuilder } from "../builder-
|
|
3
|
+
import { h as Tag, v as formatEventAddress, x as parseEventAddress } from "../event-DinQMmJ1.mjs";
|
|
4
|
+
import { t as EventBuilder } from "../builder-CdLE4J6O.mjs";
|
|
5
5
|
//#region src/nips/nip10.ts
|
|
6
6
|
/**
|
|
7
7
|
* NIP-10: Text Notes and Threads
|
package/dist/nips/nip11.d.mts
CHANGED
package/dist/nips/nip11.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as isRecord,
|
|
1
|
+
import { c as isRecord, v as NostrError } from "../util-yFYzlbrm.mjs";
|
|
2
2
|
import { n as requireGlobalFetch, t as fetchManual } from "../http-CuazNRIP.mjs";
|
|
3
3
|
//#region src/nips/nip11.ts
|
|
4
4
|
/**
|
|
@@ -46,7 +46,7 @@ function relayInfoHttpUrl(wsUrl) {
|
|
|
46
46
|
try {
|
|
47
47
|
url = new URL(wsUrl);
|
|
48
48
|
} catch (error) {
|
|
49
|
-
throw new Nip11Error(`invalid relay URL: ${wsUrl}`, { cause: error
|
|
49
|
+
throw new Nip11Error(`invalid relay URL: ${wsUrl}`, { cause: error });
|
|
50
50
|
}
|
|
51
51
|
if (url.protocol === "wss:") url.protocol = "https:";
|
|
52
52
|
else if (url.protocol === "ws:") url.protocol = "http:";
|
|
@@ -86,13 +86,13 @@ async function fetchRelayInformation(wsUrl, opts) {
|
|
|
86
86
|
const res = await fetchManual(fetchImpl, httpUrl, {
|
|
87
87
|
headers: { Accept: ACCEPT },
|
|
88
88
|
signal: opts?.signal
|
|
89
|
-
}, (cause) => new Nip11Error(`relay information request failed: ${httpUrl}`, { cause
|
|
89
|
+
}, (cause) => new Nip11Error(`relay information request failed: ${httpUrl}`, { cause }));
|
|
90
90
|
if (!res.ok) throw new Nip11Error(`relay information request failed: HTTP ${res.status}`);
|
|
91
91
|
let json;
|
|
92
92
|
try {
|
|
93
93
|
json = await res.json();
|
|
94
94
|
} catch (error) {
|
|
95
|
-
throw new Nip11Error("relay information document is not valid JSON", { cause: error
|
|
95
|
+
throw new Nip11Error("relay information document is not valid JSON", { cause: error });
|
|
96
96
|
}
|
|
97
97
|
return parseRelayInformation(json);
|
|
98
98
|
}
|
package/dist/nips/nip11.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nip11.mjs","names":[],"sources":["../../src/nips/nip11.ts"],"sourcesContent":["/**\n * NIP-11: Relay Information Document\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/11.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport { isRecord } from \"../core/util.ts\";\nimport { fetchManual, requireGlobalFetch } from \"./http.ts\";\nimport type { ManualFetch } from \"./http.ts\";\n\nconst ACCEPT = \"application/nostr+json\";\n\nconst STRING_FIELDS = [\n \"name\",\n \"description\",\n \"banner\",\n \"icon\",\n \"pubkey\",\n \"self\",\n \"contact\",\n \"software\",\n \"version\",\n \"payments_url\",\n \"terms_of_service\",\n] as const;\n\nconst LIMITATION_NUMBERS = [\n \"max_message_length\",\n \"max_subscriptions\",\n \"max_limit\",\n \"max_subid_length\",\n \"max_event_tags\",\n \"max_content_length\",\n \"min_pow_difficulty\",\n \"created_at_lower_limit\",\n \"created_at_upper_limit\",\n \"default_limit\",\n] as const;\n\nconst LIMITATION_BOOLEANS = [\"auth_required\", \"payment_required\", \"restricted_writes\"] as const;\n\nexport type Nip11Fetch = ManualFetch;\n\nexport type RelayInformation = {\n name?: string;\n description?: string;\n banner?: string;\n icon?: string;\n pubkey?: string;\n self?: string;\n contact?: string;\n supported_nips?: number[];\n software?: string;\n version?: string;\n limitation?: {\n max_message_length?: number;\n max_subscriptions?: number;\n max_limit?: number;\n max_subid_length?: number;\n max_event_tags?: number;\n max_content_length?: number;\n default_limit?: number;\n auth_required?: boolean;\n payment_required?: boolean;\n restricted_writes?: boolean;\n min_pow_difficulty?: number;\n created_at_lower_limit?: number;\n created_at_upper_limit?: number;\n };\n payments_url?: string;\n terms_of_service?: string;\n};\n\nexport class Nip11Error extends NostrError {\n override name = \"Nip11Error\";\n}\n\n/** Convert a relay websocket URL to the HTTP URL that serves the NIP-11 document. */\nexport function relayInfoHttpUrl(wsUrl: string): string {\n let url: URL;\n try {\n url = new URL(wsUrl);\n } catch (error) {\n throw new Nip11Error(`invalid relay URL: ${wsUrl}`, {\n cause: error
|
|
1
|
+
{"version":3,"file":"nip11.mjs","names":[],"sources":["../../src/nips/nip11.ts"],"sourcesContent":["/**\n * NIP-11: Relay Information Document\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/11.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport { isRecord } from \"../core/util.ts\";\nimport { fetchManual, requireGlobalFetch } from \"./http.ts\";\nimport type { ManualFetch } from \"./http.ts\";\n\nconst ACCEPT = \"application/nostr+json\";\n\nconst STRING_FIELDS = [\n \"name\",\n \"description\",\n \"banner\",\n \"icon\",\n \"pubkey\",\n \"self\",\n \"contact\",\n \"software\",\n \"version\",\n \"payments_url\",\n \"terms_of_service\",\n] as const;\n\nconst LIMITATION_NUMBERS = [\n \"max_message_length\",\n \"max_subscriptions\",\n \"max_limit\",\n \"max_subid_length\",\n \"max_event_tags\",\n \"max_content_length\",\n \"min_pow_difficulty\",\n \"created_at_lower_limit\",\n \"created_at_upper_limit\",\n \"default_limit\",\n] as const;\n\nconst LIMITATION_BOOLEANS = [\"auth_required\", \"payment_required\", \"restricted_writes\"] as const;\n\nexport type Nip11Fetch = ManualFetch;\n\nexport type RelayInformation = {\n name?: string;\n description?: string;\n banner?: string;\n icon?: string;\n pubkey?: string;\n self?: string;\n contact?: string;\n supported_nips?: number[];\n software?: string;\n version?: string;\n limitation?: {\n max_message_length?: number;\n max_subscriptions?: number;\n max_limit?: number;\n max_subid_length?: number;\n max_event_tags?: number;\n max_content_length?: number;\n default_limit?: number;\n auth_required?: boolean;\n payment_required?: boolean;\n restricted_writes?: boolean;\n min_pow_difficulty?: number;\n created_at_lower_limit?: number;\n created_at_upper_limit?: number;\n };\n payments_url?: string;\n terms_of_service?: string;\n};\n\nexport class Nip11Error extends NostrError {\n override name = \"Nip11Error\";\n}\n\n/** Convert a relay websocket URL to the HTTP URL that serves the NIP-11 document. */\nexport function relayInfoHttpUrl(wsUrl: string): string {\n let url: URL;\n try {\n url = new URL(wsUrl);\n } catch (error) {\n throw new Nip11Error(`invalid relay URL: ${wsUrl}`, {\n cause: error,\n });\n }\n\n if (url.protocol === \"wss:\") {\n url.protocol = \"https:\";\n } else if (url.protocol === \"ws:\") {\n url.protocol = \"http:\";\n } else if (url.protocol !== \"https:\" && url.protocol !== \"http:\") {\n throw new Nip11Error(`unsupported relay URL scheme: ${url.protocol}`);\n }\n\n return url.toString();\n}\n\nfunction isNonNegativeInteger(value: unknown): value is number {\n return typeof value === \"number\" && Number.isInteger(value) && value >= 0;\n}\n\nfunction parseRelayInformation(json: unknown): RelayInformation {\n if (!isRecord(json)) {\n throw new Nip11Error(\"relay information document must be a JSON object\");\n }\n const raw = json;\n const info: RelayInformation = {};\n\n for (const key of STRING_FIELDS) {\n const value = raw[key];\n if (typeof value === \"string\") {\n info[key] = value;\n }\n }\n\n if (Array.isArray(raw[\"supported_nips\"])) {\n info.supported_nips = raw[\"supported_nips\"].filter(isNonNegativeInteger);\n }\n\n const rawLim = raw[\"limitation\"];\n if (isRecord(rawLim)) {\n const limitation: NonNullable<RelayInformation[\"limitation\"]> = {};\n for (const key of LIMITATION_NUMBERS) {\n const value = rawLim[key];\n if (isNonNegativeInteger(value)) {\n limitation[key] = value;\n }\n }\n for (const key of LIMITATION_BOOLEANS) {\n const value = rawLim[key];\n if (typeof value === \"boolean\") {\n limitation[key] = value;\n }\n }\n if (Object.keys(limitation).length > 0) {\n info.limitation = limitation;\n }\n }\n\n return info;\n}\n\nexport async function fetchRelayInformation(\n wsUrl: string,\n opts?: { fetch?: Nip11Fetch; signal?: AbortSignal },\n): Promise<RelayInformation> {\n const httpUrl = relayInfoHttpUrl(wsUrl);\n const fetchImpl =\n opts?.fetch ??\n requireGlobalFetch(() => new Nip11Error(\"no fetch implementation available; pass opts.fetch\"));\n\n const res = await fetchManual(\n fetchImpl,\n httpUrl,\n { headers: { Accept: ACCEPT }, signal: opts?.signal },\n (cause) =>\n new Nip11Error(`relay information request failed: ${httpUrl}`, {\n cause,\n }),\n );\n\n if (!res.ok) {\n throw new Nip11Error(`relay information request failed: HTTP ${res.status}`);\n }\n\n let json: unknown;\n try {\n json = await res.json();\n } catch (error) {\n throw new Nip11Error(\"relay information document is not valid JSON\", {\n cause: error,\n });\n }\n\n return parseRelayInformation(json);\n}\n"],"mappings":";;;;;;;;AAUA,MAAM,SAAS;AAEf,MAAM,gBAAgB;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,qBAAqB;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAEA,MAAM,sBAAsB;CAAC;CAAiB;CAAoB;AAAmB;AAkCrF,IAAa,aAAb,cAAgC,WAAW;CACzC,OAAgB;AAClB;;AAGA,SAAgB,iBAAiB,OAAuB;CACtD,IAAI;CACJ,IAAI;EACF,MAAM,IAAI,IAAI,KAAK;CACrB,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,sBAAsB,SAAS,EAClD,OAAO,MACT,CAAC;CACH;CAEA,IAAI,IAAI,aAAa,QACnB,IAAI,WAAW;MACV,IAAI,IAAI,aAAa,OAC1B,IAAI,WAAW;MACV,IAAI,IAAI,aAAa,YAAY,IAAI,aAAa,SACvD,MAAM,IAAI,WAAW,iCAAiC,IAAI,UAAU;CAGtE,OAAO,IAAI,SAAS;AACtB;AAEA,SAAS,qBAAqB,OAAiC;CAC7D,OAAO,OAAO,UAAU,YAAY,OAAO,UAAU,KAAK,KAAK,SAAS;AAC1E;AAEA,SAAS,sBAAsB,MAAiC;CAC9D,IAAI,CAAC,SAAS,IAAI,GAChB,MAAM,IAAI,WAAW,kDAAkD;CAEzE,MAAM,MAAM;CACZ,MAAM,OAAyB,CAAC;CAEhC,KAAK,MAAM,OAAO,eAAe;EAC/B,MAAM,QAAQ,IAAI;EAClB,IAAI,OAAO,UAAU,UACnB,KAAK,OAAO;CAEhB;CAEA,IAAI,MAAM,QAAQ,IAAI,iBAAiB,GACrC,KAAK,iBAAiB,IAAI,iBAAiB,CAAC,OAAO,oBAAoB;CAGzE,MAAM,SAAS,IAAI;CACnB,IAAI,SAAS,MAAM,GAAG;EACpB,MAAM,aAA0D,CAAC;EACjE,KAAK,MAAM,OAAO,oBAAoB;GACpC,MAAM,QAAQ,OAAO;GACrB,IAAI,qBAAqB,KAAK,GAC5B,WAAW,OAAO;EAEtB;EACA,KAAK,MAAM,OAAO,qBAAqB;GACrC,MAAM,QAAQ,OAAO;GACrB,IAAI,OAAO,UAAU,WACnB,WAAW,OAAO;EAEtB;EACA,IAAI,OAAO,KAAK,UAAU,CAAC,CAAC,SAAS,GACnC,KAAK,aAAa;CAEtB;CAEA,OAAO;AACT;AAEA,eAAsB,sBACpB,OACA,MAC2B;CAC3B,MAAM,UAAU,iBAAiB,KAAK;CACtC,MAAM,YACJ,MAAM,SACN,yBAAyB,IAAI,WAAW,oDAAoD,CAAC;CAE/F,MAAM,MAAM,MAAM,YAChB,WACA,SACA;EAAE,SAAS,EAAE,QAAQ,OAAO;EAAG,QAAQ,MAAM;CAAO,IACnD,UACC,IAAI,WAAW,qCAAqC,WAAW,EAC7D,MACF,CAAC,CACL;CAEA,IAAI,CAAC,IAAI,IACP,MAAM,IAAI,WAAW,0CAA0C,IAAI,QAAQ;CAG7E,IAAI;CACJ,IAAI;EACF,OAAO,MAAM,IAAI,KAAK;CACxB,SAAS,OAAO;EACd,MAAM,IAAI,WAAW,gDAAgD,EACnE,OAAO,MACT,CAAC;CACH;CAEA,OAAO,sBAAsB,IAAI;AACnC"}
|
package/dist/nips/nip13.d.mts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { r as UnsignedEvent } from "../event-
|
|
2
|
-
import { a as NostrError } from "../error-
|
|
1
|
+
import { r as UnsignedEvent } from "../event-DJeb_DIL.mjs";
|
|
2
|
+
import { a as NostrError } from "../error-BquXDmIN.mjs";
|
|
3
3
|
//#region src/nips/nip13.d.ts
|
|
4
4
|
export declare class Nip13Error extends NostrError {
|
|
5
5
|
name: string;
|
|
6
|
-
constructor(message: string, options?: ErrorOptions);
|
|
7
6
|
}
|
|
8
7
|
export type MinePowOptions = {
|
|
9
8
|
/** Yield to the event loop after this many hashes. Default 1000. */
|
|
10
|
-
yieldEvery?: number;
|
|
11
|
-
signal?: AbortSignal;
|
|
9
|
+
yieldEvery?: number | undefined;
|
|
10
|
+
signal?: AbortSignal | undefined;
|
|
12
11
|
};
|
|
13
12
|
/** Leading zero bits of a hex event id or raw sha256 bytes. */
|
|
14
13
|
export declare function getPow(idOrHash: string | Uint8Array): number;
|
|
15
14
|
/**
|
|
16
|
-
* Returns a new unsigned event with nonce tag and computed id. Does not mutate input.
|
|
17
|
-
* `yieldEvery`
|
|
15
|
+
* Returns a new unsigned event with nonce tag and computed id. Does not mutate input. `created_at`
|
|
16
|
+
* is advanced to the current second whenever it elapses while mining. Yields every `yieldEvery`
|
|
17
|
+
* hashes.
|
|
18
18
|
*/
|
|
19
19
|
export declare function minePow(unsigned: UnsignedEvent, difficulty: number, opts?: MinePowOptions): Promise<UnsignedEvent & {
|
|
20
20
|
id: string;
|
package/dist/nips/nip13.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { d as
|
|
2
|
-
import {
|
|
3
|
-
import { t as abortReason } from "../abort-Ba8tDrOI.mjs";
|
|
1
|
+
import { d as nowSeconds, i as bytesToHex, o as isHex32, p as utf8Encoder, v as NostrError } from "../util-yFYzlbrm.mjs";
|
|
2
|
+
import { t as abortReason } from "../abort-DBq2STPj.mjs";
|
|
4
3
|
import { sha256 } from "@noble/hashes/sha2.js";
|
|
5
4
|
//#region src/nips/nip13.ts
|
|
6
5
|
/**
|
|
@@ -10,9 +9,6 @@ import { sha256 } from "@noble/hashes/sha2.js";
|
|
|
10
9
|
*/
|
|
11
10
|
var Nip13Error = class extends NostrError {
|
|
12
11
|
name = "Nip13Error";
|
|
13
|
-
constructor(message, options) {
|
|
14
|
-
super(message, options);
|
|
15
|
-
}
|
|
16
12
|
};
|
|
17
13
|
/** Leading zero bits of a hex event id or raw sha256 bytes. */
|
|
18
14
|
function getPow(idOrHash) {
|
|
@@ -38,8 +34,9 @@ function getPow(idOrHash) {
|
|
|
38
34
|
return count;
|
|
39
35
|
}
|
|
40
36
|
/**
|
|
41
|
-
* Returns a new unsigned event with nonce tag and computed id. Does not mutate input.
|
|
42
|
-
* `yieldEvery`
|
|
37
|
+
* Returns a new unsigned event with nonce tag and computed id. Does not mutate input. `created_at`
|
|
38
|
+
* is advanced to the current second whenever it elapses while mining. Yields every `yieldEvery`
|
|
39
|
+
* hashes.
|
|
43
40
|
*/
|
|
44
41
|
async function minePow(unsigned, difficulty, opts) {
|
|
45
42
|
const signal = opts?.signal;
|
|
@@ -56,17 +53,42 @@ async function minePow(unsigned, difficulty, opts) {
|
|
|
56
53
|
created_at: unsigned.created_at,
|
|
57
54
|
pubkey: unsigned.pubkey
|
|
58
55
|
};
|
|
56
|
+
let head = /* @__PURE__ */ new Uint8Array(0);
|
|
57
|
+
let tail = /* @__PURE__ */ new Uint8Array(0);
|
|
58
|
+
let buf = /* @__PURE__ */ new Uint8Array(0);
|
|
59
|
+
const rebuild = () => {
|
|
60
|
+
const headText = JSON.stringify([
|
|
61
|
+
0,
|
|
62
|
+
mined.pubkey,
|
|
63
|
+
mined.created_at,
|
|
64
|
+
mined.kind,
|
|
65
|
+
[...unsigned.tags, ["nonce", ""]]
|
|
66
|
+
]).slice(0, -4);
|
|
67
|
+
head = utf8Encoder.encode(headText);
|
|
68
|
+
tail = utf8Encoder.encode(`","${difficulty}"]],${JSON.stringify(mined.content)}]`);
|
|
69
|
+
buf = new Uint8Array(head.length + 24 + tail.length);
|
|
70
|
+
buf.set(head, 0);
|
|
71
|
+
};
|
|
72
|
+
rebuild();
|
|
59
73
|
let count = 0;
|
|
60
74
|
let iterations = 0;
|
|
61
75
|
while (true) {
|
|
62
76
|
if (signal?.aborted === true) throw abortReason(signal);
|
|
63
|
-
const now =
|
|
77
|
+
const now = nowSeconds();
|
|
64
78
|
if (now !== mined.created_at) {
|
|
65
79
|
count = 0;
|
|
66
80
|
mined.created_at = now;
|
|
81
|
+
rebuild();
|
|
67
82
|
}
|
|
68
83
|
nonce[1] = String(++count);
|
|
69
|
-
|
|
84
|
+
let pos = head.length;
|
|
85
|
+
for (let i = 0; i < nonce[1].length; i++) {
|
|
86
|
+
buf[pos] = nonce[1].codePointAt(i) ?? 0;
|
|
87
|
+
pos += 1;
|
|
88
|
+
}
|
|
89
|
+
buf.set(tail, pos);
|
|
90
|
+
pos += tail.length;
|
|
91
|
+
const hash = sha256(buf.subarray(0, pos));
|
|
70
92
|
if (getPow(hash) >= difficulty) return {
|
|
71
93
|
...mined,
|
|
72
94
|
id: bytesToHex(hash)
|
package/dist/nips/nip13.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nip13.mjs","names":[],"sources":["../../src/nips/nip13.ts"],"sourcesContent":["/**\n * NIP-13: Proof of Work. Does not import signer, relay, or client. Does not sign.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/13.md\n */\nimport { sha256 } from \"@noble/hashes/sha2.js\";\n\nimport { abortReason } from \"../core/abort.ts\";\nimport { NostrError } from \"../core/error.ts\";\nimport
|
|
1
|
+
{"version":3,"file":"nip13.mjs","names":[],"sources":["../../src/nips/nip13.ts"],"sourcesContent":["/**\n * NIP-13: Proof of Work. Does not import signer, relay, or client. Does not sign.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/13.md\n */\nimport { sha256 } from \"@noble/hashes/sha2.js\";\n\nimport { abortReason } from \"../core/abort.ts\";\nimport { NostrError } from \"../core/error.ts\";\nimport type { UnsignedEvent } from \"../core/event.ts\";\nimport { bytesToHex, isHex32, nowSeconds, utf8Encoder } from \"../core/util.ts\";\n\nexport class Nip13Error extends NostrError {\n override name = \"Nip13Error\";\n}\n\nexport type MinePowOptions = {\n /** Yield to the event loop after this many hashes. Default 1000. */\n yieldEvery?: number | undefined;\n signal?: AbortSignal | undefined;\n};\n\n/** Leading zero bits of a hex event id or raw sha256 bytes. */\nexport function getPow(idOrHash: string | Uint8Array): number {\n if (typeof idOrHash === \"string\") {\n if (!isHex32(idOrHash.toLowerCase())) {\n throw new Nip13Error(`expected 64-char hex event id, got ${idOrHash.length} chars`);\n }\n let count = 0;\n for (let i = 0; i < idOrHash.length; i += 8) {\n const chunk = Number.parseInt(idOrHash.slice(i, i + 8), 16);\n if (chunk === 0) {\n count += 32;\n } else {\n count += Math.clz32(chunk);\n break;\n }\n }\n return count;\n }\n\n let count = 0;\n for (const byte of idOrHash) {\n if (byte === 0) {\n count += 8;\n } else {\n count += Math.clz32(byte) - 24;\n break;\n }\n }\n return count;\n}\n\n/**\n * Returns a new unsigned event with nonce tag and computed id. Does not mutate input. `created_at`\n * is advanced to the current second whenever it elapses while mining. Yields every `yieldEvery`\n * hashes.\n */\nexport async function minePow(\n unsigned: UnsignedEvent,\n difficulty: number,\n opts?: MinePowOptions,\n): Promise<UnsignedEvent & { id: string }> {\n const signal = opts?.signal;\n const yieldEvery = Math.max(1, opts?.yieldEvery ?? 1000);\n\n const nonce: [string, string, string] = [\"nonce\", \"0\", String(difficulty)];\n const mined = {\n kind: unsigned.kind,\n tags: [...unsigned.tags, nonce],\n content: unsigned.content,\n created_at: unsigned.created_at,\n pubkey: unsigned.pubkey,\n };\n\n // Serialize once per created_at second: the reused buffer holds\n // [0, pubkey, created_at, kind, [...tags, [\"nonce\",\"<digits>\",\"<difficulty>\"]], content]\n // where `head` ends at the opening quote of the nonce value and `tail` completes the tag, the\n // tags array, and the trailing content element.\n let head = new Uint8Array(0);\n let tail = new Uint8Array(0);\n let buf = new Uint8Array(0);\n\n const rebuild = (): void => {\n const headText = JSON.stringify([\n 0,\n mined.pubkey,\n mined.created_at,\n mined.kind,\n [...unsigned.tags, [\"nonce\", \"\"]],\n ]).slice(0, -4);\n head = utf8Encoder.encode(headText);\n tail = utf8Encoder.encode(`\",\"${difficulty}\"]],${JSON.stringify(mined.content)}]`);\n buf = new Uint8Array(head.length + 24 + tail.length);\n buf.set(head, 0);\n };\n rebuild();\n\n let count = 0;\n let iterations = 0;\n\n while (true) {\n if (signal?.aborted === true) {\n throw abortReason(signal);\n }\n\n const now = nowSeconds();\n if (now !== mined.created_at) {\n count = 0;\n mined.created_at = now;\n rebuild();\n }\n\n nonce[1] = String(++count);\n let pos = head.length;\n for (let i = 0; i < nonce[1].length; i++) {\n buf[pos] = nonce[1].codePointAt(i) ?? 0;\n pos += 1;\n }\n buf.set(tail, pos);\n pos += tail.length;\n const hash = sha256(buf.subarray(0, pos));\n if (getPow(hash) >= difficulty) {\n return { ...mined, id: bytesToHex(hash) };\n }\n\n iterations++;\n if (iterations >= yieldEvery) {\n iterations = 0;\n // oxlint-disable-next-line no-await-in-loop -- the yield is part of each mining round\n await new Promise<void>((resolve) => {\n setTimeout(resolve);\n });\n }\n }\n}\n"],"mappings":";;;;;;;;;AAYA,IAAa,aAAb,cAAgC,WAAW;CACzC,OAAgB;AAClB;;AASA,SAAgB,OAAO,UAAuC;CAC5D,IAAI,OAAO,aAAa,UAAU;EAChC,IAAI,CAAC,QAAQ,SAAS,YAAY,CAAC,GACjC,MAAM,IAAI,WAAW,sCAAsC,SAAS,OAAO,OAAO;EAEpF,IAAI,QAAQ;EACZ,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;GAC3C,MAAM,QAAQ,OAAO,SAAS,SAAS,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE;GAC1D,IAAI,UAAU,GACZ,SAAS;QACJ;IACL,SAAS,KAAK,MAAM,KAAK;IACzB;GACF;EACF;EACA,OAAO;CACT;CAEA,IAAI,QAAQ;CACZ,KAAK,MAAM,QAAQ,UACjB,IAAI,SAAS,GACX,SAAS;MACJ;EACL,SAAS,KAAK,MAAM,IAAI,IAAI;EAC5B;CACF;CAEF,OAAO;AACT;;;;;;AAOA,eAAsB,QACpB,UACA,YACA,MACyC;CACzC,MAAM,SAAS,MAAM;CACrB,MAAM,aAAa,KAAK,IAAI,GAAG,MAAM,cAAc,GAAI;CAEvD,MAAM,QAAkC;EAAC;EAAS;EAAK,OAAO,UAAU;CAAC;CACzE,MAAM,QAAQ;EACZ,MAAM,SAAS;EACf,MAAM,CAAC,GAAG,SAAS,MAAM,KAAK;EAC9B,SAAS,SAAS;EAClB,YAAY,SAAS;EACrB,QAAQ,SAAS;CACnB;CAMA,IAAI,uBAAO,IAAI,WAAW,CAAC;CAC3B,IAAI,uBAAO,IAAI,WAAW,CAAC;CAC3B,IAAI,sBAAM,IAAI,WAAW,CAAC;CAE1B,MAAM,gBAAsB;EAC1B,MAAM,WAAW,KAAK,UAAU;GAC9B;GACA,MAAM;GACN,MAAM;GACN,MAAM;GACN,CAAC,GAAG,SAAS,MAAM,CAAC,SAAS,EAAE,CAAC;EAClC,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE;EACd,OAAO,YAAY,OAAO,QAAQ;EAClC,OAAO,YAAY,OAAO,MAAM,WAAW,MAAM,KAAK,UAAU,MAAM,OAAO,EAAE,EAAE;EACjF,MAAM,IAAI,WAAW,KAAK,SAAS,KAAK,KAAK,MAAM;EACnD,IAAI,IAAI,MAAM,CAAC;CACjB;CACA,QAAQ;CAER,IAAI,QAAQ;CACZ,IAAI,aAAa;CAEjB,OAAO,MAAM;EACX,IAAI,QAAQ,YAAY,MACtB,MAAM,YAAY,MAAM;EAG1B,MAAM,MAAM,WAAW;EACvB,IAAI,QAAQ,MAAM,YAAY;GAC5B,QAAQ;GACR,MAAM,aAAa;GACnB,QAAQ;EACV;EAEA,MAAM,KAAK,OAAO,EAAE,KAAK;EACzB,IAAI,MAAM,KAAK;EACf,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,EAAE,CAAC,QAAQ,KAAK;GACxC,IAAI,OAAO,MAAM,EAAE,CAAC,YAAY,CAAC,KAAK;GACtC,OAAO;EACT;EACA,IAAI,IAAI,MAAM,GAAG;EACjB,OAAO,KAAK;EACZ,MAAM,OAAO,OAAO,IAAI,SAAS,GAAG,GAAG,CAAC;EACxC,IAAI,OAAO,IAAI,KAAK,YAClB,OAAO;GAAE,GAAG;GAAO,IAAI,WAAW,IAAI;EAAE;EAG1C;EACA,IAAI,cAAc,YAAY;GAC5B,aAAa;GAEb,MAAM,IAAI,SAAe,YAAY;IACnC,WAAW,OAAO;GACpB,CAAC;EACH;CACF;AACF"}
|
package/dist/nips/nip17.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as buildChatMessageRumor, c as normalizeRecipients, d as wrapDirectMessage, i as ReplyTo, l as parseDmRelayList, n as Nip17Error, o as dmRelayListEventBuilder, r as Recipient, s as dmRelayListToTags, t as ChatMessageOptions, u as requireDmRelays } from "../nip17-
|
|
1
|
+
import { a as buildChatMessageRumor, c as normalizeRecipients, d as wrapDirectMessage, i as ReplyTo, l as parseDmRelayList, n as Nip17Error, o as dmRelayListEventBuilder, r as Recipient, s as dmRelayListToTags, t as ChatMessageOptions, u as requireDmRelays } from "../nip17-cTDFfFVt.mjs";
|
|
2
2
|
export { ChatMessageOptions, Nip17Error, Recipient, ReplyTo, buildChatMessageRumor, dmRelayListEventBuilder, dmRelayListToTags, normalizeRecipients, parseDmRelayList, requireDmRelays, wrapDirectMessage };
|
package/dist/nips/nip17.mjs
CHANGED
|
@@ -1,51 +1,31 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { h as EventValidationError, l as normalizeRelayUrls, n as assertHex32, v as NostrError } from "../util-yFYzlbrm.mjs";
|
|
2
2
|
import { t as Kind } from "../kind-Cxwhhkx8.mjs";
|
|
3
|
-
import { h as Tag } from "../event-
|
|
4
|
-
import { t as EventBuilder } from "../builder-
|
|
3
|
+
import { h as Tag } from "../event-DinQMmJ1.mjs";
|
|
4
|
+
import { t as EventBuilder } from "../builder-CdLE4J6O.mjs";
|
|
5
5
|
import { createGiftWrap, createRumor, createSeal } from "./nip59.mjs";
|
|
6
6
|
//#region src/nips/nip17.ts
|
|
7
|
+
/**
|
|
8
|
+
* NIP-17: Private Direct Messages. Kind 10050 advertises where gift-wraps should be delivered. Kind
|
|
9
|
+
* 14 rumor construction and per-recipient wrap live here. Envelope primitives live in nip59.ts.
|
|
10
|
+
*
|
|
11
|
+
* @see https://github.com/nostr-protocol/nips/blob/master/17.md
|
|
12
|
+
*/
|
|
7
13
|
var Nip17Error = class extends NostrError {
|
|
8
14
|
name = "Nip17Error";
|
|
9
|
-
constructor(message, options) {
|
|
10
|
-
super(message, options);
|
|
11
|
-
}
|
|
12
15
|
};
|
|
13
16
|
/** Parse kind:10050 DM relay list (`["relay", url]` tags). */
|
|
14
17
|
function parseDmRelayList(event) {
|
|
15
18
|
if (event.kind !== Kind.DirectMessageRelaysList) throw new EventValidationError(`expected kind ${Kind.DirectMessageRelaysList}, got ${event.kind}`);
|
|
16
|
-
const
|
|
17
|
-
const seen = /* @__PURE__ */ new Set();
|
|
19
|
+
const urls = [];
|
|
18
20
|
for (const tag of event.tags) {
|
|
19
21
|
const value = tag.at(1);
|
|
20
|
-
if (tag[0]
|
|
21
|
-
let url;
|
|
22
|
-
try {
|
|
23
|
-
url = normalizeURL(value);
|
|
24
|
-
} catch {
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
if (seen.has(url)) continue;
|
|
28
|
-
seen.add(url);
|
|
29
|
-
out.push(url);
|
|
22
|
+
if (tag[0] === "relay" && value !== void 0) urls.push(value);
|
|
30
23
|
}
|
|
31
|
-
return
|
|
24
|
+
return normalizeRelayUrls(urls);
|
|
32
25
|
}
|
|
33
26
|
/** Encode DM relay URLs as NIP-17 `relay` tags. */
|
|
34
27
|
function dmRelayListToTags(relays) {
|
|
35
|
-
|
|
36
|
-
const seen = /* @__PURE__ */ new Set();
|
|
37
|
-
for (const raw of relays) {
|
|
38
|
-
let url;
|
|
39
|
-
try {
|
|
40
|
-
url = normalizeURL(raw);
|
|
41
|
-
} catch {
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
if (seen.has(url)) continue;
|
|
45
|
-
seen.add(url);
|
|
46
|
-
tags.push(["relay", url]);
|
|
47
|
-
}
|
|
48
|
-
return tags;
|
|
28
|
+
return normalizeRelayUrls(relays).map((url) => ["relay", url]);
|
|
49
29
|
}
|
|
50
30
|
/** Build an unsigned kind:10050 EventBuilder. NIP-17 requires ≥1 relay tag. */
|
|
51
31
|
function dmRelayListEventBuilder(relays) {
|
package/dist/nips/nip17.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nip17.mjs","names":["TagBuilder"],"sources":["../../src/nips/nip17.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"nip17.mjs","names":["TagBuilder"],"sources":["../../src/nips/nip17.ts"],"sourcesContent":["/**\n * NIP-17: Private Direct Messages. Kind 10050 advertises where gift-wraps should be delivered. Kind\n * 14 rumor construction and per-recipient wrap live here. Envelope primitives live in nip59.ts.\n *\n * @see https://github.com/nostr-protocol/nips/blob/master/17.md\n */\nimport { EventBuilder } from \"../core/builder.ts\";\nimport { EventValidationError, NostrError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport type { Tag } from \"../core/tag.ts\";\nimport { Tag as TagBuilder } from \"../core/tag.ts\";\nimport { assertHex32, normalizeRelayUrls } from \"../core/util.ts\";\nimport { createGiftWrap, createRumor, createSeal } from \"./nip59.ts\";\nimport type { Nip59Crypto, Rumor, WrapOptions } from \"./nip59.ts\";\n\nexport class Nip17Error extends NostrError {\n override name = \"Nip17Error\";\n}\n\nexport type Recipient = {\n readonly pubkey: string;\n readonly relayHint?: string | undefined;\n};\n\nexport type ReplyTo = {\n readonly id: string;\n readonly relayHint?: string | undefined;\n};\n\nexport type ChatMessageOptions = {\n readonly created_at?: number | undefined;\n readonly subject?: string | undefined;\n readonly replyTo?: ReplyTo | undefined;\n};\n\n/** Parse kind:10050 DM relay list (`[\"relay\", url]` tags). */\nexport function parseDmRelayList(event: Pick<Event, \"kind\" | \"tags\">): string[] {\n if (event.kind !== Kind.DirectMessageRelaysList) {\n throw new EventValidationError(\n `expected kind ${Kind.DirectMessageRelaysList}, got ${event.kind}`,\n );\n }\n const urls: string[] = [];\n for (const tag of event.tags) {\n const value = tag.at(1);\n if (tag[0] === \"relay\" && value !== undefined) {\n urls.push(value);\n }\n }\n return normalizeRelayUrls(urls);\n}\n\n/** Encode DM relay URLs as NIP-17 `relay` tags. */\nexport function dmRelayListToTags(relays: ReadonlyArray<string>): Tag[] {\n return normalizeRelayUrls(relays).map((url) => [\"relay\", url]);\n}\n\n/** Build an unsigned kind:10050 EventBuilder. NIP-17 requires ≥1 relay tag. */\nexport function dmRelayListEventBuilder(relays: ReadonlyArray<string>): EventBuilder {\n const tags = dmRelayListToTags(relays);\n if (tags.length === 0) {\n throw new Nip17Error(\"DM relay list requires at least one relay\");\n }\n return new EventBuilder(Kind.DirectMessageRelaysList, \"\").tags(tags);\n}\n\nfunction isRecipient(value: unknown): value is Recipient {\n return typeof value === \"object\" && value !== null && \"pubkey\" in value;\n}\n\nfunction asRecipientList(\n input: string | Recipient | ReadonlyArray<string | Recipient>,\n): ReadonlyArray<string | Recipient> {\n if (typeof input === \"string\" || isRecipient(input)) {\n return [input];\n }\n return input;\n}\n\n/** Accept a hex pubkey, a Recipient, or a readonly array of either. Dedup by pubkey. */\nexport function normalizeRecipients(\n input: string | Recipient | ReadonlyArray<string | Recipient>,\n): Recipient[] {\n const out: Recipient[] = [];\n const seen = new Set<string>();\n for (const item of asRecipientList(input)) {\n const rec: Recipient = typeof item === \"string\" ? { pubkey: item } : item;\n const pubkey = assertHex32(rec.pubkey, \"public key\");\n if (seen.has(pubkey)) {\n continue;\n }\n seen.add(pubkey);\n out.push({ pubkey, relayHint: rec.relayHint });\n }\n return out;\n}\n\nexport function buildChatMessageRumor(\n senderPubkey: string,\n recipients: ReadonlyArray<Recipient>,\n content: string,\n opts?: ChatMessageOptions,\n): Rumor {\n if (recipients.length === 0) {\n throw new Nip17Error(\"recipients must not be empty\");\n }\n const tags: Tag[] = [];\n for (const recipient of recipients) {\n const pk = assertHex32(recipient.pubkey, \"public key\");\n tags.push(TagBuilder.p(pk, recipient.relayHint));\n }\n if (opts?.replyTo) {\n // Kind 14 reply e-tag is unmarked: [\"e\", <id>, <relay-url>]\n tags.push(TagBuilder.e(assertHex32(opts.replyTo.id, \"event id\"), opts.replyTo.relayHint ?? \"\"));\n }\n if (opts?.subject !== undefined) {\n tags.push([\"subject\", opts.subject]);\n }\n return createRumor(senderPubkey, {\n kind: Kind.PrivateDirectMessage,\n content,\n tags,\n created_at: opts?.created_at,\n });\n}\n\nfunction wrapTargets(sender: string, recipients: ReadonlyArray<Recipient>): Recipient[] {\n const senderPk = sender.toLowerCase();\n const self = recipients.find((r) => r.pubkey.toLowerCase() === senderPk);\n const out: Recipient[] = [{ pubkey: senderPk, relayHint: self?.relayHint }];\n const seen = new Set<string>([senderPk]);\n for (const recipient of recipients) {\n const pk = recipient.pubkey.toLowerCase();\n if (seen.has(pk)) {\n continue;\n }\n seen.add(pk);\n out.push({ pubkey: pk, relayHint: recipient.relayHint });\n }\n return out;\n}\n\nexport async function wrapDirectMessage(\n crypto: Nip59Crypto,\n recipients: ReadonlyArray<Recipient>,\n rumor: Rumor,\n opts?: Pick<WrapOptions, \"now\" | \"randomInt\" | \"timestamps\" | \"randomize\">,\n): Promise<ReadonlyArray<{ recipient: string; wrap: Event }>> {\n if (recipients.length === 0) {\n throw new Nip17Error(\"recipients must not be empty\");\n }\n const targets = wrapTargets(rumor.pubkey, recipients);\n const out: Array<{ recipient: string; wrap: Event }> = [];\n const timeOpts = opts\n ? {\n now: opts.now,\n randomInt: opts.randomInt,\n timestamps: opts.timestamps,\n randomize: opts.randomize,\n }\n : undefined;\n for (const target of targets) {\n // oxlint-disable-next-line no-await-in-loop -- signer calls stay ordered, one recipient at a time\n const seal = await createSeal(crypto, target.pubkey, rumor, timeOpts);\n const wrap = createGiftWrap(seal, target.pubkey, {\n ...timeOpts,\n relayHint: target.relayHint,\n });\n out.push({ recipient: target.pubkey, wrap });\n }\n return out;\n}\n\nexport function requireDmRelays(pubkey: string, relays: ReadonlyArray<string>): string[] {\n if (relays.length === 0) {\n throw new Nip17Error(`pubkey ${pubkey} is not ready to receive DMs (no kind 10050)`);\n }\n return [...relays];\n}\n"],"mappings":"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"}
|
package/dist/nips/nip19.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
export { AddressPointer, Bech32MaxSize, DecodedResult, EventPointer, NAddr, NEvent, NProfile, NPub, NSec, Nip19Error, Note, ProfilePointer, decode,
|
|
1
|
+
import { _ as noteEncode, a as NAddr, b as nsecEncode, c as NPub, d as Note, f as ProfilePointer, g as neventEncode, h as naddrEncode, i as EventPointer, l as NSec, m as encodeBytes, n as Bech32MaxSize, o as NEvent, p as decode, r as DecodedResult, s as NProfile, t as AddressPointer, u as Nip19Error, v as nprofileEncode, y as npubEncode } from "../nip19-D1OnJ192.mjs";
|
|
2
|
+
export { AddressPointer, Bech32MaxSize, DecodedResult, EventPointer, NAddr, NEvent, NProfile, NPub, NSec, Nip19Error, Note, ProfilePointer, decode, encodeBytes, naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nsecEncode };
|
package/dist/nips/nip19.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as hexToBytes,
|
|
1
|
+
import { a as hexToBytes, f as utf8Decoder, i as bytesToHex, n as assertHex32, p as utf8Encoder, t as assertByteLength, v as NostrError, x as errorMessage } from "../util-yFYzlbrm.mjs";
|
|
2
2
|
import { bech32 } from "@scure/base";
|
|
3
3
|
//#region src/nips/nip19.ts
|
|
4
4
|
/** Maximum bech32 string length accepted by {@link decode} (NIP-19). */
|
|
@@ -6,9 +6,6 @@ const Bech32MaxSize = 5e3;
|
|
|
6
6
|
/** Error thrown by NIP-19 encoding/decoding failures. */
|
|
7
7
|
var Nip19Error = class extends NostrError {
|
|
8
8
|
name = "Nip19Error";
|
|
9
|
-
constructor(message) {
|
|
10
|
-
super(message);
|
|
11
|
-
}
|
|
12
9
|
};
|
|
13
10
|
function integerToUint8Array(number) {
|
|
14
11
|
const out = /* @__PURE__ */ new Uint8Array(4);
|
|
@@ -103,10 +100,20 @@ function naddrEncode(addr) {
|
|
|
103
100
|
3: [kind]
|
|
104
101
|
}));
|
|
105
102
|
}
|
|
103
|
+
function readUint32(bytes) {
|
|
104
|
+
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(0);
|
|
105
|
+
}
|
|
106
106
|
/** Decode a NIP-19 bech32 entity; throws {@link Nip19Error} on bad input or unknown prefix. */
|
|
107
107
|
function decode(code) {
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
let prefix;
|
|
109
|
+
let data;
|
|
110
|
+
try {
|
|
111
|
+
const { prefix: hrp, words } = bech32.decode(code, Bech32MaxSize);
|
|
112
|
+
prefix = hrp;
|
|
113
|
+
data = new Uint8Array(bech32.fromWords(words));
|
|
114
|
+
} catch (error) {
|
|
115
|
+
throw new Nip19Error(`invalid bech32: ${errorMessage(error)}`, { cause: error });
|
|
116
|
+
}
|
|
110
117
|
switch (prefix) {
|
|
111
118
|
case "nprofile": {
|
|
112
119
|
const tlv = parseTLV(data);
|
|
@@ -133,7 +140,7 @@ function decode(code) {
|
|
|
133
140
|
const author = tlv[2]?.[0];
|
|
134
141
|
if (author !== void 0) pointer.author = bytesToHex(author);
|
|
135
142
|
const kind = tlv[3]?.[0];
|
|
136
|
-
if (kind !== void 0) pointer.kind =
|
|
143
|
+
if (kind !== void 0) pointer.kind = readUint32(kind);
|
|
137
144
|
return {
|
|
138
145
|
type: "nevent",
|
|
139
146
|
data: pointer
|
|
@@ -151,7 +158,7 @@ function decode(code) {
|
|
|
151
158
|
data: {
|
|
152
159
|
identifier: utf8Decoder.decode(tlv[0][0]),
|
|
153
160
|
pubkey: bytesToHex(tlv[2][0]),
|
|
154
|
-
kind:
|
|
161
|
+
kind: readUint32(tlv[3][0]),
|
|
155
162
|
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
|
156
163
|
}
|
|
157
164
|
};
|
|
@@ -172,26 +179,7 @@ function decode(code) {
|
|
|
172
179
|
default: throw new Nip19Error(`unknown prefix ${prefix}`);
|
|
173
180
|
}
|
|
174
181
|
}
|
|
175
|
-
/** Decode `nostr:` URI or bare bech32; returns invalid sentinel instead of throwing. */
|
|
176
|
-
function decodeNostrURI(nip19code) {
|
|
177
|
-
try {
|
|
178
|
-
let code = nip19code;
|
|
179
|
-
if (code.startsWith("nostr:")) {
|
|
180
|
-
code = code.slice(6);
|
|
181
|
-
if (code.startsWith("nsec1")) return {
|
|
182
|
-
type: "invalid",
|
|
183
|
-
data: void 0
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
return decode(code);
|
|
187
|
-
} catch {
|
|
188
|
-
return {
|
|
189
|
-
type: "invalid",
|
|
190
|
-
data: void 0
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
182
|
//#endregion
|
|
195
|
-
export { Bech32MaxSize, Nip19Error, decode,
|
|
183
|
+
export { Bech32MaxSize, Nip19Error, decode, encodeBytes, naddrEncode, neventEncode, noteEncode, nprofileEncode, npubEncode, nsecEncode };
|
|
196
184
|
|
|
197
185
|
//# sourceMappingURL=nip19.mjs.map
|
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 {\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}\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: 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,5 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as NostrError } from "../error-BquXDmIN.mjs";
|
|
2
|
+
import { r as DecodedResult } from "../nip19-D1OnJ192.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 = {
|