@qntx/nostr 0.0.1 → 0.2.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 +38 -0
- package/dist/abort-Ba8tDrOI.mjs.map +1 -0
- package/dist/{builder-BphJa-Y-.d.mts → builder-BWn55Paf.d.mts} +20 -14
- package/dist/{builder-q0VsvnYE.mjs → builder-CyrGKRVP.mjs} +32 -16
- package/dist/builder-CyrGKRVP.mjs.map +1 -0
- package/dist/{client-Bd8B1mYm.mjs → client-BWsX9Cv1.mjs} +354 -195
- package/dist/client-BWsX9Cv1.mjs.map +1 -0
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +1 -1
- package/dist/core.d.mts +8 -8
- package/dist/core.mjs +8 -9
- package/dist/error-BW7re1UN.d.mts +9 -0
- package/dist/error-B__OMBRY.mjs +14 -0
- package/dist/error-B__OMBRY.mjs.map +1 -0
- package/dist/{error-WEFS-R-4.d.mts → error-CR8Urc84.d.mts} +20 -8
- package/dist/{error-CwBxle6N.mjs → error-DrEIM7FO.mjs} +5 -3
- package/dist/error-DrEIM7FO.mjs.map +1 -0
- package/dist/{event-CzoQEFMF.mjs → event-D8Nfoh4K.mjs} +40 -32
- package/dist/event-D8Nfoh4K.mjs.map +1 -0
- package/dist/{event-B5D2jxt_.d.mts → event-fU3Y01PR.d.mts} +23 -20
- package/dist/{filter-BxwjEkZp.mjs → filter-BQl3GlHt.mjs} +42 -35
- package/dist/filter-BQl3GlHt.mjs.map +1 -0
- package/dist/filter-C0IMByE3.d.mts +37 -0
- package/dist/{gossip-C5RVB1UB.d.mts → gossip-BRQwIM_q.d.mts} +25 -23
- package/dist/{gossip-3xkRRCm_.mjs → gossip-oloDMWEj.mjs} +52 -34
- package/dist/gossip-oloDMWEj.mjs.map +1 -0
- package/dist/gossip.d.mts +1 -1
- package/dist/gossip.mjs +1 -1
- package/dist/{http-6vevbBlu.d.mts → http-C4HwIu4B.d.mts} +7 -7
- package/dist/{http-D2rhokZo.mjs → http-CuazNRIP.mjs} +10 -6
- package/dist/http-CuazNRIP.mjs.map +1 -0
- package/dist/index-B425CAcQ.d.mts +328 -0
- package/dist/index-BVyfUBuG.d.mts +181 -0
- package/dist/{index-BYMnhRIC.d.mts → index-Ba7bJ7DD.d.mts} +68 -50
- package/dist/{index-DaRyjo7O.d.mts → index-Boe8FshM.d.mts} +13 -7
- package/dist/index-CUIvFQdE.d.mts +73 -0
- package/dist/index-JdaS_uce.d.mts +207 -0
- package/dist/index.d.mts +22 -20
- package/dist/index.mjs +19 -18
- package/dist/{key-Dn-aX4x4.mjs → key-Bbtys6o7.mjs} +22 -14
- package/dist/key-Bbtys6o7.mjs.map +1 -0
- package/dist/{key-BiGxGLhg.d.mts → key-BlsYhN1V.d.mts} +9 -6
- package/dist/{kind-BLl4cLOc.mjs → kind-Cxwhhkx8.mjs} +2 -1
- package/dist/kind-Cxwhhkx8.mjs.map +1 -0
- package/dist/{loaders-BNQszDAn.mjs → loaders-o6YXB_Ri.mjs} +329 -305
- package/dist/loaders-o6YXB_Ri.mjs.map +1 -0
- package/dist/loaders.d.mts +3 -3
- package/dist/loaders.mjs +2 -2
- package/dist/memory-C2EVx0_O.mjs +46 -0
- package/dist/memory-C2EVx0_O.mjs.map +1 -0
- package/dist/{memory-BCmhZPek.mjs → memory-index-Do1mz0WF.mjs} +212 -82
- package/dist/memory-index-Do1mz0WF.mjs.map +1 -0
- package/dist/{message-C_Uj-Y-c.mjs → message-DcY6Fi9o.mjs} +38 -24
- package/dist/message-DcY6Fi9o.mjs.map +1 -0
- package/dist/{message-DJC-Jz6T.d.mts → message-iGPIqnn0.d.mts} +15 -8
- package/dist/{nip17-BWq-Kfq5.d.mts → nip17-DNEkz8rM.d.mts} +18 -17
- package/dist/{nip19-D7905oIv.d.mts → nip19-BevCJZsp.d.mts} +23 -3
- package/dist/{nip46-C_DoxiS_.d.mts → nip46-DDV4dC56.d.mts} +13 -12
- package/dist/{nip59-DljW_sYh.d.mts → nip59-zQgdLcEr.d.mts} +28 -25
- package/dist/{nip65-Di5hZRuV.d.mts → nip65-DBfh2smt.d.mts} +8 -3
- package/dist/{nip77-ByxlgoQO.d.mts → nip77-DH4RhS5r.d.mts} +9 -8
- package/dist/nips/blossom.d.mts +37 -37
- package/dist/nips/blossom.mjs +67 -52
- package/dist/nips/blossom.mjs.map +1 -1
- package/dist/nips/nip04.d.mts +2 -3
- package/dist/nips/nip04.mjs +6 -10
- package/dist/nips/nip04.mjs.map +1 -1
- package/dist/nips/nip05.d.mts +37 -43
- package/dist/nips/nip05.mjs +57 -57
- package/dist/nips/nip05.mjs.map +1 -1
- package/dist/nips/nip10.d.mts +18 -19
- package/dist/nips/nip10.mjs +76 -61
- package/dist/nips/nip10.mjs.map +1 -1
- package/dist/nips/nip11.d.mts +9 -8
- package/dist/nips/nip11.mjs +14 -11
- package/dist/nips/nip11.mjs.map +1 -1
- package/dist/nips/nip13.d.mts +9 -9
- package/dist/nips/nip13.mjs +15 -17
- package/dist/nips/nip13.mjs.map +1 -1
- package/dist/nips/nip17.d.mts +1 -1
- package/dist/nips/nip17.mjs +17 -12
- package/dist/nips/nip17.mjs.map +1 -1
- package/dist/nips/nip19.d.mts +1 -1
- package/dist/nips/nip19.mjs +52 -29
- package/dist/nips/nip19.mjs.map +1 -1
- package/dist/nips/nip21.d.mts +5 -6
- package/dist/nips/nip21.mjs +8 -7
- package/dist/nips/nip21.mjs.map +1 -1
- package/dist/nips/nip27.d.mts +7 -8
- package/dist/nips/nip27.mjs +26 -25
- package/dist/nips/nip27.mjs.map +1 -1
- package/dist/nips/nip42.d.mts +5 -6
- package/dist/nips/nip42.mjs +3 -3
- package/dist/nips/nip42.mjs.map +1 -1
- package/dist/nips/nip44.d.mts +24 -7
- package/dist/nips/nip44.mjs +25 -15
- package/dist/nips/nip44.mjs.map +1 -1
- package/dist/nips/nip46.d.mts +1 -1
- package/dist/nips/nip46.mjs +52 -49
- package/dist/nips/nip46.mjs.map +1 -1
- package/dist/nips/nip49.d.mts +8 -7
- package/dist/nips/nip49.mjs +16 -12
- package/dist/nips/nip49.mjs.map +1 -1
- package/dist/nips/nip51.d.mts +25 -27
- package/dist/nips/nip51.mjs +47 -36
- package/dist/nips/nip51.mjs.map +1 -1
- package/dist/nips/nip57.d.mts +12 -13
- package/dist/nips/nip57.mjs +35 -38
- package/dist/nips/nip57.mjs.map +1 -1
- package/dist/nips/nip59.d.mts +1 -1
- package/dist/nips/nip59.mjs +14 -18
- package/dist/nips/nip59.mjs.map +1 -1
- package/dist/nips/nip65.d.mts +1 -1
- package/dist/nips/nip65.mjs +11 -8
- package/dist/nips/nip65.mjs.map +1 -1
- package/dist/nips/nip77.d.mts +1 -1
- package/dist/nips/nip77.mjs +56 -34
- package/dist/nips/nip77.mjs.map +1 -1
- package/dist/nips/nip96.d.mts +21 -12
- package/dist/nips/nip96.mjs +59 -36
- package/dist/nips/nip96.mjs.map +1 -1
- package/dist/nips/nip98.d.mts +12 -12
- package/dist/nips/nip98.mjs +18 -19
- package/dist/nips/nip98.mjs.map +1 -1
- package/dist/{nostr_crypto_wasm_bg-hi5aXi5P.mjs → nostr_crypto_wasm_bg-Czrdty7Q.mjs} +1 -1
- package/dist/nostr_crypto_wasm_bg.wasm +0 -0
- package/dist/{pool-C_j1OmBB.mjs → pool-XmAGaufS.mjs} +611 -487
- package/dist/pool-XmAGaufS.mjs.map +1 -0
- package/dist/pool-tEr7c5bG.d.mts +302 -0
- package/dist/reactive-DDlThDSZ.mjs +324 -0
- package/dist/reactive-DDlThDSZ.mjs.map +1 -0
- package/dist/reactive-DFpqtIf_.d.mts +66 -0
- package/dist/relay.d.mts +5 -4
- package/dist/relay.mjs +2 -2
- package/dist/report-CHld4uWj.mjs +32 -0
- package/dist/report-CHld4uWj.mjs.map +1 -0
- package/dist/{signer-CZ6K6FUc.mjs → signer-CKR9EHce.mjs} +107 -72
- package/dist/signer-CKR9EHce.mjs.map +1 -0
- package/dist/signer.d.mts +3 -3
- package/dist/signer.mjs +3 -2
- package/dist/storage-xXxLGCVb.mjs +1376 -0
- package/dist/storage-xXxLGCVb.mjs.map +1 -0
- package/dist/storage.d.mts +4 -4
- package/dist/storage.mjs +5 -4
- package/dist/store.d.mts +2 -0
- package/dist/store.mjs +2 -0
- package/dist/testing.d.mts +125 -0
- package/dist/testing.mjs +957 -0
- package/dist/testing.mjs.map +1 -0
- package/dist/types-2pCUprRU.d.mts +47 -0
- package/dist/types-CRQEk0Oi.d.mts +19 -0
- package/dist/util-LfQirgDk.mjs +113 -0
- package/dist/util-LfQirgDk.mjs.map +1 -0
- package/dist/wasm.d.mts +4 -4
- package/dist/wasm.mjs +55 -56
- package/dist/wasm.mjs.map +1 -1
- package/dist/websocket-CmeqvAkp.d.mts +27 -0
- package/package.json +31 -9
- package/dist/builder-q0VsvnYE.mjs.map +0 -1
- package/dist/client-Bd8B1mYm.mjs.map +0 -1
- package/dist/error-B49rbDzT.d.mts +0 -7
- package/dist/error-CwBxle6N.mjs.map +0 -1
- package/dist/error-DZEs5OuZ.mjs +0 -24
- package/dist/error-DZEs5OuZ.mjs.map +0 -1
- package/dist/event-CzoQEFMF.mjs.map +0 -1
- package/dist/filter-BxwjEkZp.mjs.map +0 -1
- package/dist/filter-DUEKP3q1.d.mts +0 -40
- package/dist/gossip-3xkRRCm_.mjs.map +0 -1
- package/dist/http-D2rhokZo.mjs.map +0 -1
- package/dist/index-C0C4e-Gn.d.mts +0 -55
- package/dist/index-DgOugrpF.d.mts +0 -275
- package/dist/index-EwL6fHLo.d.mts +0 -267
- package/dist/index-k2YhCgsh.d.mts +0 -57
- package/dist/key-Dn-aX4x4.mjs.map +0 -1
- package/dist/kind-BLl4cLOc.mjs.map +0 -1
- package/dist/loaders-BNQszDAn.mjs.map +0 -1
- package/dist/memory-BCmhZPek.mjs.map +0 -1
- package/dist/message-C_Uj-Y-c.mjs.map +0 -1
- package/dist/pool-C_j1OmBB.mjs.map +0 -1
- package/dist/pool-DhRi7l-b.d.mts +0 -297
- package/dist/signer-CZ6K6FUc.mjs.map +0 -1
- package/dist/storage-DOy0iLRE.mjs +0 -870
- package/dist/storage-DOy0iLRE.mjs.map +0 -1
- package/dist/types-BzyADqnw.d.mts +0 -19
- package/dist/types-Dn24TPFs.d.mts +0 -43
- package/dist/util-6tfLQ9JF.mjs +0 -73
- package/dist/util-6tfLQ9JF.mjs.map +0 -1
package/dist/nips/nip05.d.mts
CHANGED
|
@@ -1,89 +1,83 @@
|
|
|
1
|
-
import { a as NostrError } from "../error-
|
|
2
|
-
import { f as ProfilePointer } from "../nip19-
|
|
3
|
-
import { t as ManualFetch } from "../http-
|
|
1
|
+
import { a as NostrError } from "../error-CR8Urc84.mjs";
|
|
2
|
+
import { f as ProfilePointer } from "../nip19-BevCJZsp.mjs";
|
|
3
|
+
import { t as ManualFetch } from "../http-C4HwIu4B.mjs";
|
|
4
4
|
//#region src/nips/nip05.d.ts
|
|
5
5
|
/** Root local-part (`_@domain` rendered as just the domain). */
|
|
6
|
-
declare const NIP05_ROOT_LOCAL = "_";
|
|
7
|
-
declare const WELL_KNOWN_PATH = "/.well-known/nostr.json";
|
|
6
|
+
export declare const NIP05_ROOT_LOCAL = "_";
|
|
7
|
+
export declare const WELL_KNOWN_PATH = "/.well-known/nostr.json";
|
|
8
8
|
/**
|
|
9
9
|
* NIP-05 identifier string.
|
|
10
|
+
*
|
|
10
11
|
* - Full: `name@domain`
|
|
11
12
|
* - Root: `domain` or `_@domain`
|
|
12
13
|
*/
|
|
13
|
-
type Nip05 = string;
|
|
14
|
-
type Nip05Address = {
|
|
14
|
+
export type Nip05 = string;
|
|
15
|
+
export type Nip05Address = {
|
|
15
16
|
/** Local part (lowercased). `_` for domain-only identifiers. */
|
|
16
17
|
local: string;
|
|
17
18
|
/** Domain (lowercased). */
|
|
18
19
|
domain: string;
|
|
19
20
|
};
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
* Not a bunker pointer.
|
|
23
|
-
*/
|
|
24
|
-
type Nip05Nip46 = {
|
|
21
|
+
/** 46.md appendix discovery metadata (`{relays, nostrconnect_url}`). Not a bunker pointer. */
|
|
22
|
+
export type Nip05Nip46 = {
|
|
25
23
|
relays?: string[];
|
|
26
24
|
nostrconnectUrl?: string;
|
|
27
25
|
};
|
|
28
|
-
type Nip05Document = {
|
|
26
|
+
export type Nip05Document = {
|
|
29
27
|
names: Record<string, string>;
|
|
30
28
|
/** NIP-05 profile relay hints */
|
|
31
29
|
relays?: Record<string, string[]>;
|
|
32
30
|
nip46?: Nip05Nip46;
|
|
33
31
|
};
|
|
34
|
-
type Nip05Fetch = ManualFetch;
|
|
35
|
-
declare class Nip05Error extends NostrError {
|
|
32
|
+
export type Nip05Fetch = ManualFetch;
|
|
33
|
+
export declare class Nip05Error extends NostrError {
|
|
34
|
+
name: string;
|
|
36
35
|
constructor(message: string, options?: ErrorOptions);
|
|
37
36
|
}
|
|
37
|
+
/** Matches optional local@domain. Groups: 1=local (optional), 2=domain. */
|
|
38
|
+
export declare const NIP05_REGEX: RegExp;
|
|
39
|
+
export declare function isNip05(value: unknown): value is string;
|
|
38
40
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*/
|
|
42
|
-
declare const NIP05_REGEX: RegExp;
|
|
43
|
-
declare function isNip05(value: unknown): value is string;
|
|
44
|
-
/**
|
|
45
|
-
* Parse an identifier into local + domain.
|
|
46
|
-
* Accepts `name@domain`, `_@domain`, or bare `domain` (local becomes `_`).
|
|
41
|
+
* Parse an identifier into local + domain. Accepts `name@domain`, `_@domain`, or bare `domain`
|
|
42
|
+
* (local becomes `_`).
|
|
47
43
|
*/
|
|
48
|
-
declare function parseNip05(input: string): Nip05Address;
|
|
44
|
+
export declare function parseNip05(input: string): Nip05Address;
|
|
49
45
|
/** Build the well-known HTTPS URL for an address. */
|
|
50
|
-
declare function wellKnownUrl(address: Nip05Address): string;
|
|
46
|
+
export declare function wellKnownUrl(address: Nip05Address): string;
|
|
51
47
|
/**
|
|
52
|
-
* Parse nostr.json `nip46`: 46.md appendix `{relays, nostrconnect_url}`.
|
|
53
|
-
*
|
|
48
|
+
* Parse nostr.json `nip46`: 46.md appendix `{relays, nostrconnect_url}`. Hex-pubkey maps and other
|
|
49
|
+
* keys are ignored.
|
|
54
50
|
*/
|
|
55
|
-
declare function parseNip05Nip46(raw: unknown): Nip05Nip46 | undefined;
|
|
51
|
+
export declare function parseNip05Nip46(raw: unknown): Nip05Nip46 | undefined;
|
|
56
52
|
/** Parse and validate a nostr.json document body. */
|
|
57
|
-
declare function parseNip05Document(json: unknown): Nip05Document;
|
|
53
|
+
export declare function parseNip05Document(json: unknown): Nip05Document;
|
|
58
54
|
/** Resolve local name from an already-parsed document. */
|
|
59
|
-
declare function lookupFromDocument(doc: Nip05Document, address: Nip05Address): ProfilePointer | undefined;
|
|
55
|
+
export declare function lookupFromDocument(doc: Nip05Document, address: Nip05Address): ProfilePointer | undefined;
|
|
60
56
|
/**
|
|
61
|
-
* Fetch and parse `/.well-known/nostr.json`.
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* AbortError rethrows; it is not mapped to `null`.
|
|
57
|
+
* Fetch and parse `/.well-known/nostr.json`. Returns `undefined` on network/parse failure (does not
|
|
58
|
+
* throw for those). Rejects HTTP redirects (non-200) per NIP-05 security constraints. AbortError
|
|
59
|
+
* rethrows; it is not mapped to `undefined`.
|
|
65
60
|
*/
|
|
66
|
-
declare function queryNip05Document(identifier: string, opts?: {
|
|
61
|
+
export declare function queryNip05Document(identifier: string, opts?: {
|
|
67
62
|
fetch?: Nip05Fetch;
|
|
68
63
|
signal?: AbortSignal;
|
|
69
64
|
}): Promise<{
|
|
70
65
|
address: Nip05Address;
|
|
71
66
|
doc: Nip05Document;
|
|
72
|
-
} |
|
|
67
|
+
} | undefined>;
|
|
73
68
|
/**
|
|
74
|
-
* Query `/.well-known/nostr.json` for an identifier.
|
|
75
|
-
*
|
|
76
|
-
*
|
|
69
|
+
* Query `/.well-known/nostr.json` for an identifier. Returns `undefined` on network/parse/lookup
|
|
70
|
+
* failure (does not throw for those). Profile `relays` only. `nip46` is discovery metadata, not a
|
|
71
|
+
* bunker pointer.
|
|
77
72
|
*/
|
|
78
|
-
declare function queryProfile(identifier: string, opts?: {
|
|
73
|
+
export declare function queryProfile(identifier: string, opts?: {
|
|
79
74
|
fetch?: Nip05Fetch;
|
|
80
75
|
signal?: AbortSignal;
|
|
81
|
-
}): Promise<ProfilePointer |
|
|
76
|
+
}): Promise<ProfilePointer | undefined>;
|
|
82
77
|
/** True when the identifier resolves to exactly `pubkey`. */
|
|
83
|
-
declare function verifyNip05(pubkey: string, identifier: string, opts?: {
|
|
78
|
+
export declare function verifyNip05(pubkey: string, identifier: string, opts?: {
|
|
84
79
|
fetch?: Nip05Fetch;
|
|
85
80
|
signal?: AbortSignal;
|
|
86
81
|
}): Promise<boolean>;
|
|
87
82
|
//#endregion
|
|
88
|
-
export { NIP05_REGEX, NIP05_ROOT_LOCAL, Nip05, Nip05Address, Nip05Document, Nip05Error, Nip05Fetch, Nip05Nip46, WELL_KNOWN_PATH, isNip05, lookupFromDocument, parseNip05, parseNip05Document, parseNip05Nip46, queryNip05Document, queryProfile, verifyNip05, wellKnownUrl };
|
|
89
83
|
//# sourceMappingURL=nip05.d.mts.map
|
package/dist/nips/nip05.mjs
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { n as requireGlobalFetch, t as fetchManual } from "../http-D2rhokZo.mjs";
|
|
1
|
+
import { c as isRecord, g as NostrError, o as isHex32 } from "../util-LfQirgDk.mjs";
|
|
2
|
+
import { n as requireGlobalFetch, t as fetchManual } from "../http-CuazNRIP.mjs";
|
|
4
3
|
//#region src/nips/nip05.ts
|
|
5
4
|
/**
|
|
6
5
|
* NIP-05: Mapping Nostr keys to DNS-based internet identifiers
|
|
6
|
+
*
|
|
7
7
|
* @see https://github.com/nostr-protocol/nips/blob/master/05.md
|
|
8
8
|
*/
|
|
9
9
|
/** Root local-part (`_@domain` rendered as just the domain). */
|
|
10
10
|
const NIP05_ROOT_LOCAL = "_";
|
|
11
11
|
const WELL_KNOWN_PATH = "/.well-known/nostr.json";
|
|
12
12
|
var Nip05Error = class extends NostrError {
|
|
13
|
+
name = "Nip05Error";
|
|
13
14
|
constructor(message, options) {
|
|
14
15
|
super(message, options);
|
|
15
16
|
}
|
|
16
17
|
};
|
|
17
|
-
/**
|
|
18
|
-
|
|
19
|
-
* Groups: 1=local (optional), 2=domain.
|
|
20
|
-
*/
|
|
21
|
-
const NIP05_REGEX = /^(?:([\w.+-]+)@)?([\w-]+(?:\.[\w-]+)+)$/;
|
|
18
|
+
/** Matches optional local@domain. Groups: 1=local (optional), 2=domain. */
|
|
19
|
+
const NIP05_REGEX = /^(?:([a-z0-9._-]+)@)?([a-z0-9-]+(?:\.[a-z0-9-]+)+)$/i;
|
|
22
20
|
function isNip05(value) {
|
|
23
|
-
|
|
21
|
+
if (typeof value !== "string") return false;
|
|
22
|
+
try {
|
|
23
|
+
parseNip05(value);
|
|
24
|
+
return true;
|
|
25
|
+
} catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
24
28
|
}
|
|
25
29
|
/**
|
|
26
|
-
* Parse an identifier into local + domain.
|
|
27
|
-
*
|
|
30
|
+
* Parse an identifier into local + domain. Accepts `name@domain`, `_@domain`, or bare `domain`
|
|
31
|
+
* (local becomes `_`).
|
|
28
32
|
*/
|
|
29
33
|
function parseNip05(input) {
|
|
30
|
-
const match = input.trim()
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const local = localRaw.toLowerCase();
|
|
34
|
-
const domain = match[2].toLowerCase();
|
|
35
|
-
if (!/^[a-z0-9._-]+$/.test(local)) throw new Nip05Error(`invalid NIP-05 local-part: ${localRaw}`);
|
|
36
|
-
if (!domain) throw new Nip05Error("NIP-05 domain must not be empty");
|
|
34
|
+
const match = NIP05_REGEX.exec(input.trim());
|
|
35
|
+
const domain = match?.at(2);
|
|
36
|
+
if (match === null || domain === void 0 || domain === "") throw new Nip05Error(`invalid NIP-05 identifier: ${input}`);
|
|
37
37
|
return {
|
|
38
|
-
local,
|
|
39
|
-
domain
|
|
38
|
+
local: (match.at(1) ?? "_").toLowerCase(),
|
|
39
|
+
domain: domain.toLowerCase()
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
/** Build the well-known HTTPS URL for an address. */
|
|
@@ -46,100 +46,100 @@ function wellKnownUrl(address) {
|
|
|
46
46
|
return url.toString();
|
|
47
47
|
}
|
|
48
48
|
function stringUrls(list) {
|
|
49
|
-
if (!Array.isArray(list)) return
|
|
49
|
+
if (!Array.isArray(list)) return;
|
|
50
50
|
return list.filter((u) => typeof u === "string" && u.length > 0);
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
|
-
* Parse nostr.json `nip46`: 46.md appendix `{relays, nostrconnect_url}`.
|
|
54
|
-
*
|
|
53
|
+
* Parse nostr.json `nip46`: 46.md appendix `{relays, nostrconnect_url}`. Hex-pubkey maps and other
|
|
54
|
+
* keys are ignored.
|
|
55
55
|
*/
|
|
56
56
|
function parseNip05Nip46(raw) {
|
|
57
|
-
if (!
|
|
57
|
+
if (!isRecord(raw)) return;
|
|
58
58
|
const obj = raw;
|
|
59
59
|
const result = {};
|
|
60
|
-
if (Array.isArray(obj
|
|
61
|
-
if (typeof obj
|
|
60
|
+
if (Array.isArray(obj["relays"])) result.relays = stringUrls(obj["relays"]) ?? [];
|
|
61
|
+
if (typeof obj["nostrconnect_url"] === "string" && obj["nostrconnect_url"].length > 0) result.nostrconnectUrl = obj["nostrconnect_url"];
|
|
62
62
|
if (result.relays === void 0 && result.nostrconnectUrl === void 0) return;
|
|
63
63
|
return result;
|
|
64
64
|
}
|
|
65
65
|
/** Parse and validate a nostr.json document body. */
|
|
66
66
|
function parseNip05Document(json) {
|
|
67
|
-
if (!json
|
|
67
|
+
if (!isRecord(json)) throw new Nip05Error("NIP-05 document must be a JSON object");
|
|
68
68
|
const raw = json;
|
|
69
|
-
if (!raw
|
|
69
|
+
if (!isRecord(raw["names"])) throw new Nip05Error("NIP-05 document missing names map");
|
|
70
70
|
const names = {};
|
|
71
|
-
for (const [k, v] of Object.entries(raw
|
|
72
|
-
if (typeof v !== "string" || !isHex32(v)) continue;
|
|
71
|
+
for (const [k, v] of Object.entries(raw["names"])) {
|
|
72
|
+
if (typeof v !== "string" || !isHex32(v.toLowerCase())) continue;
|
|
73
73
|
names[k.toLowerCase()] = v.toLowerCase();
|
|
74
74
|
}
|
|
75
|
+
const rawRelays = raw["relays"];
|
|
75
76
|
let relays;
|
|
76
|
-
if (
|
|
77
|
+
if (isRecord(rawRelays)) {
|
|
77
78
|
relays = {};
|
|
78
|
-
for (const [pk, list] of Object.entries(
|
|
79
|
-
if (!isHex32(pk)) continue;
|
|
79
|
+
for (const [pk, list] of Object.entries(rawRelays)) {
|
|
80
|
+
if (!isHex32(pk.toLowerCase())) continue;
|
|
80
81
|
const urls = stringUrls(list);
|
|
81
|
-
if (urls
|
|
82
|
+
if (urls !== void 0 && urls.length > 0) relays[pk.toLowerCase()] = urls;
|
|
82
83
|
}
|
|
83
84
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
const doc = { names };
|
|
86
|
+
if (relays !== void 0) doc.relays = relays;
|
|
87
|
+
const nip46 = parseNip05Nip46(raw["nip46"]);
|
|
88
|
+
if (nip46 !== void 0) doc.nip46 = nip46;
|
|
89
|
+
return doc;
|
|
89
90
|
}
|
|
90
91
|
/** Resolve local name from an already-parsed document. */
|
|
91
92
|
function lookupFromDocument(doc, address) {
|
|
92
93
|
const pubkey = doc.names[address.local];
|
|
93
|
-
if (
|
|
94
|
+
if (pubkey === void 0) return;
|
|
94
95
|
const relays = doc.relays?.[pubkey];
|
|
95
|
-
return relays
|
|
96
|
+
return relays !== void 0 && relays.length > 0 ? {
|
|
96
97
|
pubkey,
|
|
97
98
|
relays: [...relays]
|
|
98
99
|
} : { pubkey };
|
|
99
100
|
}
|
|
100
101
|
/**
|
|
101
|
-
* Fetch and parse `/.well-known/nostr.json`.
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* AbortError rethrows; it is not mapped to `null`.
|
|
102
|
+
* Fetch and parse `/.well-known/nostr.json`. Returns `undefined` on network/parse failure (does not
|
|
103
|
+
* throw for those). Rejects HTTP redirects (non-200) per NIP-05 security constraints. AbortError
|
|
104
|
+
* rethrows; it is not mapped to `undefined`.
|
|
105
105
|
*/
|
|
106
106
|
async function queryNip05Document(identifier, opts) {
|
|
107
107
|
let address;
|
|
108
108
|
try {
|
|
109
109
|
address = parseNip05(identifier);
|
|
110
110
|
} catch {
|
|
111
|
-
return
|
|
111
|
+
return;
|
|
112
112
|
}
|
|
113
113
|
const url = wellKnownUrl(address);
|
|
114
114
|
const fetchImpl = opts?.fetch ?? requireGlobalFetch(() => new Nip05Error("no fetch implementation available; pass opts.fetch"));
|
|
115
115
|
try {
|
|
116
116
|
const res = await fetchManual(fetchImpl, url, { signal: opts?.signal }, (err) => err instanceof Error ? err : /* @__PURE__ */ new Error("NIP-05 request failed"));
|
|
117
|
-
if (res.status !== 200) return
|
|
117
|
+
if (res.status !== 200) return;
|
|
118
118
|
const json = await res.json();
|
|
119
119
|
return {
|
|
120
120
|
address,
|
|
121
121
|
doc: parseNip05Document(json)
|
|
122
122
|
};
|
|
123
|
-
} catch (
|
|
124
|
-
if (
|
|
125
|
-
return
|
|
123
|
+
} catch (error) {
|
|
124
|
+
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
125
|
+
return;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
/**
|
|
129
|
-
* Query `/.well-known/nostr.json` for an identifier.
|
|
130
|
-
*
|
|
131
|
-
*
|
|
129
|
+
* Query `/.well-known/nostr.json` for an identifier. Returns `undefined` on network/parse/lookup
|
|
130
|
+
* failure (does not throw for those). Profile `relays` only. `nip46` is discovery metadata, not a
|
|
131
|
+
* bunker pointer.
|
|
132
132
|
*/
|
|
133
133
|
async function queryProfile(identifier, opts) {
|
|
134
134
|
const fetched = await queryNip05Document(identifier, opts);
|
|
135
|
-
if (
|
|
136
|
-
return lookupFromDocument(fetched.doc, fetched.address)
|
|
135
|
+
if (fetched === void 0) return;
|
|
136
|
+
return lookupFromDocument(fetched.doc, fetched.address);
|
|
137
137
|
}
|
|
138
138
|
/** True when the identifier resolves to exactly `pubkey`. */
|
|
139
139
|
async function verifyNip05(pubkey, identifier, opts) {
|
|
140
|
-
if (!isHex32(pubkey)) return false;
|
|
140
|
+
if (!isHex32(pubkey.toLowerCase())) return false;
|
|
141
141
|
const profile = await queryProfile(identifier, opts);
|
|
142
|
-
return profile !==
|
|
142
|
+
return profile !== void 0 && profile.pubkey === pubkey.toLowerCase();
|
|
143
143
|
}
|
|
144
144
|
//#endregion
|
|
145
145
|
export { NIP05_REGEX, NIP05_ROOT_LOCAL, Nip05Error, WELL_KNOWN_PATH, isNip05, lookupFromDocument, parseNip05, parseNip05Document, parseNip05Nip46, queryNip05Document, queryProfile, verifyNip05, wellKnownUrl };
|
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 * @see https://github.com/nostr-protocol/nips/blob/master/05.md\n */\nimport { NostrError } from \"../core/error.ts\";\nimport { isHex32 } from \"../core/util.ts\";\nimport { fetchManual, requireGlobalFetch, 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 * - 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/**\n * 46.md appendix discovery metadata (`{relays, nostrconnect_url}`).\n * Not a bunker pointer.\n */\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 constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n }\n}\n\n/**\n * Matches optional local@domain.\n * Groups: 1=local (optional), 2=domain.\n */\nexport const NIP05_REGEX = /^(?:([\\w.+-]+)@)?([\\w-]+(?:\\.[\\w-]+)+)$/;\n\nexport function isNip05(value: unknown): value is string {\n return typeof value === \"string\" && NIP05_REGEX.test(value);\n}\n\n/**\n * Parse an identifier into local + domain.\n * Accepts `name@domain`, `_@domain`, or bare `domain` (local becomes `_`).\n */\nexport function parseNip05(input: string): Nip05Address {\n const match = input.trim().match(NIP05_REGEX);\n if (!match?.[2]) {\n throw new Nip05Error(`invalid NIP-05 identifier: ${input}`);\n }\n const localRaw = match[1] ?? NIP05_ROOT_LOCAL;\n const local = localRaw.toLowerCase();\n const domain = match[2].toLowerCase();\n\n // NIP-05 local-part: a-z0-9-_.\n if (!/^[a-z0-9._-]+$/.test(local)) {\n throw new Nip05Error(`invalid NIP-05 local-part: ${localRaw}`);\n }\n if (!domain) {\n throw new Nip05Error(\"NIP-05 domain must not be empty\");\n }\n\n return { local, domain };\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)) return undefined;\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}`.\n * Hex-pubkey maps and other keys are ignored.\n */\nexport function parseNip05Nip46(raw: unknown): Nip05Nip46 | undefined {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) return undefined;\n const obj = raw as Record<string, unknown>;\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 (!json || typeof json !== \"object\") {\n throw new Nip05Error(\"NIP-05 document must be a JSON object\");\n }\n const raw = json as { names?: unknown; relays?: unknown; nip46?: unknown };\n if (!raw.names || typeof raw.names !== \"object\" || Array.isArray(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 as Record<string, unknown>)) {\n if (typeof v !== \"string\" || !isHex32(v)) continue;\n names[k.toLowerCase()] = v.toLowerCase();\n }\n\n let relays: Record<string, string[]> | undefined;\n if (raw.relays && typeof raw.relays === \"object\" && !Array.isArray(raw.relays)) {\n relays = {};\n for (const [pk, list] of Object.entries(raw.relays as Record<string, unknown>)) {\n if (!isHex32(pk)) continue;\n const urls = stringUrls(list);\n if (urls?.length) relays[pk.toLowerCase()] = urls;\n }\n }\n\n return { names, relays, nip46: parseNip05Nip46(raw.nip46) };\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) return undefined;\n const relays = doc.relays?.[pubkey];\n return relays?.length ? { pubkey, relays: [...relays] } : { pubkey };\n}\n\n/**\n * Fetch and parse `/.well-known/nostr.json`.\n * Returns `null` on network/parse failure (does not throw for those).\n * Rejects HTTP redirects (non-200) per NIP-05 security constraints.\n * AbortError rethrows; it is not mapped to `null`.\n */\nexport async function queryNip05Document(\n identifier: string,\n opts?: { fetch?: Nip05Fetch; signal?: AbortSignal },\n): Promise<{ address: Nip05Address; doc: Nip05Document } | null> {\n let address: Nip05Address;\n try {\n address = parseNip05(identifier);\n } catch {\n return null;\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) return null;\n const json = await res.json();\n return { address, doc: parseNip05Document(json) };\n } catch (err) {\n if (err instanceof Error && err.name === \"AbortError\") throw err;\n return null;\n }\n}\n\n/**\n * Query `/.well-known/nostr.json` for an identifier.\n * Returns `null` on network/parse/lookup failure (does not throw for those).\n * Profile `relays` only. `nip46` is discovery metadata, not a bunker pointer.\n */\nexport async function queryProfile(\n identifier: string,\n opts?: { fetch?: Nip05Fetch; signal?: AbortSignal },\n): Promise<ProfilePointer | null> {\n const fetched = await queryNip05Document(identifier, opts);\n if (!fetched) return null;\n return lookupFromDocument(fetched.doc, fetched.address) ?? null;\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)) return false;\n const profile = await queryProfile(identifier, opts);\n return profile !== null && 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 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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"}
|
package/dist/nips/nip10.d.mts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
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-fU3Y01PR.mjs";
|
|
2
|
+
import { t as EventBuilder } from "../builder-BWn55Paf.mjs";
|
|
3
|
+
import { f as ProfilePointer, i as EventPointer, t as AddressPointer } from "../nip19-BevCJZsp.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
|
+
export type ThreadReferences = {
|
|
6
7
|
/** Pointer to the root of the thread. */
|
|
7
8
|
root: EventPointer | undefined;
|
|
8
9
|
/** Pointer to the parent event this note replies to. */
|
|
@@ -11,33 +12,31 @@ type ThreadReferences = {
|
|
|
11
12
|
mentions: EventPointer[];
|
|
12
13
|
/** Quoted events (`q` tags): event ids or addresses. Discriminate with `"id" in q`. */
|
|
13
14
|
quotes: Array<EventPointer | AddressPointer>;
|
|
14
|
-
/**
|
|
15
|
+
/** P-tagged profiles involved in the thread. */
|
|
15
16
|
profiles: ProfilePointer[];
|
|
16
17
|
};
|
|
17
18
|
type ReplyParent = Pick<Event, "id" | "pubkey" | "tags" | "kind">;
|
|
18
19
|
type QuoteInput = string | EventPointer | AddressPointer;
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
type ReplyTagsOptions = {
|
|
20
|
+
/** Parse NIP-10 thread markers and legacy positional e-tags from an event. */
|
|
21
|
+
export declare function parseThreadTags(event: Pick<Event, "tags">): ThreadReferences;
|
|
22
|
+
/** Options for {@link buildReplyTags}. */
|
|
23
|
+
export type ReplyTagsOptions = {
|
|
24
24
|
/** Parent event being replied to. */
|
|
25
25
|
parent: ReplyParent;
|
|
26
26
|
/** Optional relay hint for the parent e-tag. */
|
|
27
|
-
relayHint?: string;
|
|
27
|
+
relayHint?: string | undefined;
|
|
28
28
|
/** Quoted events (`q` tags): hex ids, `kind:pubkey:d` coords, or pointers. */
|
|
29
|
-
quotes?: QuoteInput[];
|
|
29
|
+
quotes?: QuoteInput[] | undefined;
|
|
30
30
|
};
|
|
31
31
|
/**
|
|
32
|
-
* Build NIP-10 e/p tags for a reply to `parent`.
|
|
33
|
-
*
|
|
32
|
+
* Build NIP-10 e/p tags for a reply to `parent`. Uses marked tags (`root` / `reply`) per preferred
|
|
33
|
+
* modern style.
|
|
34
34
|
*/
|
|
35
|
-
declare function buildReplyTags(opts: ReplyTagsOptions): Tag[];
|
|
35
|
+
export declare function buildReplyTags(opts: ReplyTagsOptions): Tag[];
|
|
36
36
|
/**
|
|
37
|
-
* Build an {@link EventBuilder} reply with NIP-10 tags.
|
|
38
|
-
*
|
|
37
|
+
* Build an {@link EventBuilder} reply with NIP-10 tags. Lives here (not on EventBuilder) so core
|
|
38
|
+
* does not depend on nips.
|
|
39
39
|
*/
|
|
40
|
-
declare function replyTo(parent: ReplyParent, content: string, opts?: Pick<ReplyTagsOptions, "relayHint" | "quotes">): EventBuilder;
|
|
40
|
+
export declare function replyTo(parent: ReplyParent, content: string, opts?: Pick<ReplyTagsOptions, "relayHint" | "quotes">): EventBuilder;
|
|
41
41
|
//#endregion
|
|
42
|
-
export { ReplyTagsOptions, ThreadReferences, buildReplyTags, parseThreadTags, replyTo };
|
|
43
42
|
//# sourceMappingURL=nip10.d.mts.map
|