@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
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
//#region src/core/tag.d.ts
|
|
2
2
|
/** A NIP-01 tag: first element is the name, rest are values. */
|
|
3
|
-
type Tag =
|
|
3
|
+
type Tag = ReadonlyArray<string>;
|
|
4
4
|
/** Mutable tag builder input. */
|
|
5
5
|
type TagInput = string[];
|
|
6
|
+
/** Type guard: a non-empty array of strings. */
|
|
6
7
|
declare function isTag(value: unknown): value is Tag;
|
|
8
|
+
/** First element of a tag (its name). */
|
|
7
9
|
declare function tagName(tag: Tag): string;
|
|
10
|
+
/** Second element of a tag (its primary value), or undefined for a bare name tag. */
|
|
8
11
|
declare function tagValue(tag: Tag): string | undefined;
|
|
9
12
|
/** Construct common tags. */
|
|
10
13
|
declare const Tag: {
|
|
@@ -17,7 +20,7 @@ declare const Tag: {
|
|
|
17
20
|
readonly k: (kind: number | string) => Tag;
|
|
18
21
|
};
|
|
19
22
|
/** First `d` tag value on an event, if any. */
|
|
20
|
-
declare function getDTag(tags:
|
|
23
|
+
declare function getDTag(tags: ReadonlyArray<Tag>): string | undefined;
|
|
21
24
|
/** NIP-01 `a` tag: `kind:pubkey:identifier` (identifier may be empty and may contain extra colons). */
|
|
22
25
|
type EventAddress = {
|
|
23
26
|
kind: number;
|
|
@@ -26,22 +29,23 @@ type EventAddress = {
|
|
|
26
29
|
};
|
|
27
30
|
/** Parse a NIP-01 addressable/replaceable coordinate. */
|
|
28
31
|
declare function parseEventAddress(value: string): EventAddress | undefined;
|
|
32
|
+
/** Format an address as a `kind:pubkey:dTag` coordinate string. */
|
|
29
33
|
declare function formatEventAddress(kind: number, pubkey: string, identifier?: string): string;
|
|
30
34
|
/**
|
|
31
|
-
* Coordinate for replaceable (`kind:pubkey:`) and addressable (`kind:pubkey:d`) events.
|
|
32
|
-
*
|
|
35
|
+
* Coordinate for replaceable (`kind:pubkey:`) and addressable (`kind:pubkey:d`) events. Undefined
|
|
36
|
+
* for regular/ephemeral kinds.
|
|
33
37
|
*/
|
|
34
38
|
declare function eventAddress(event: {
|
|
35
39
|
kind: number;
|
|
36
40
|
pubkey: string;
|
|
37
|
-
tags:
|
|
41
|
+
tags: ReadonlyArray<Tag>;
|
|
38
42
|
}): string | undefined;
|
|
39
43
|
//#endregion
|
|
40
44
|
//#region src/core/event.d.ts
|
|
41
45
|
/** Wire event template before pubkey/id/sig. */
|
|
42
46
|
type EventTemplate = {
|
|
43
47
|
readonly kind: number;
|
|
44
|
-
readonly tags:
|
|
48
|
+
readonly tags: ReadonlyArray<Tag>;
|
|
45
49
|
readonly content: string;
|
|
46
50
|
readonly created_at: number;
|
|
47
51
|
};
|
|
@@ -50,8 +54,8 @@ type UnsignedEvent = EventTemplate & {
|
|
|
50
54
|
readonly pubkey: string;
|
|
51
55
|
};
|
|
52
56
|
/**
|
|
53
|
-
* Fully formed NIP-01 event (JSON-friendly plain object).
|
|
54
|
-
*
|
|
57
|
+
* Fully formed NIP-01 event (JSON-friendly plain object). Fields are readonly at the type level;
|
|
58
|
+
* wire interop remains plain JSON.
|
|
55
59
|
*/
|
|
56
60
|
type Event = UnsignedEvent & {
|
|
57
61
|
readonly id: string;
|
|
@@ -59,29 +63,28 @@ type Event = UnsignedEvent & {
|
|
|
59
63
|
};
|
|
60
64
|
declare function markVerified(event: Event): void;
|
|
61
65
|
declare function markUnverified(event: Event): void;
|
|
62
|
-
declare function isMarkedVerified(event: Event): boolean;
|
|
63
66
|
declare function isMarkedFailed(event: Event): boolean;
|
|
64
67
|
/** Structural validation of an unsigned event (no crypto). */
|
|
65
68
|
declare function validateEvent(event: unknown): event is UnsignedEvent;
|
|
66
69
|
/** Structural validation of a full event including id and sig hex shape. */
|
|
67
70
|
declare function validateSignedEvent(event: unknown): event is Event;
|
|
68
71
|
/**
|
|
69
|
-
* Canonical NIP-01 serialization used for hashing:
|
|
70
|
-
*
|
|
72
|
+
* Canonical NIP-01 serialization used for hashing: JSON array `[0, pubkey, created_at, kind, tags,
|
|
73
|
+
* content]` with no extra whitespace.
|
|
71
74
|
*/
|
|
72
75
|
declare function serializeEvent(event: UnsignedEvent): string;
|
|
73
76
|
/** SHA-256 of the canonical serialization, lowercase hex. */
|
|
74
77
|
declare function getEventHash(event: UnsignedEvent): string;
|
|
75
78
|
/**
|
|
76
|
-
* Sort events reverse-chronologically by `created_at`, then by `id` lexicographically.
|
|
77
|
-
*
|
|
79
|
+
* Sort events reverse-chronologically by `created_at`, then by `id` lexicographically. Mutates and
|
|
80
|
+
* returns the array.
|
|
78
81
|
*/
|
|
79
82
|
declare function sortEvents(events: Event[]): Event[];
|
|
80
83
|
/** Non-mutating sort; returns a new array. */
|
|
81
|
-
declare function sortedEvents(events:
|
|
84
|
+
declare function sortedEvents(events: ReadonlyArray<Event>): Event[];
|
|
82
85
|
/**
|
|
83
|
-
* Negentropy item order: `created_at` ascending, then `id` lexicographic (`<`/`>`).
|
|
84
|
-
*
|
|
86
|
+
* Negentropy item order: `created_at` ascending, then `id` lexicographic (`<`/`>`). Time axis is
|
|
87
|
+
* opposite {@link sortEvents}; id tie-break is the same direction.
|
|
85
88
|
*/
|
|
86
89
|
declare function itemCompare(a: {
|
|
87
90
|
id: string;
|
|
@@ -91,8 +94,8 @@ declare function itemCompare(a: {
|
|
|
91
94
|
created_at: number;
|
|
92
95
|
}): number;
|
|
93
96
|
/**
|
|
94
|
-
* NIP-01 replaceable/addressable winner: higher `created_at`, or equal timestamp
|
|
95
|
-
*
|
|
97
|
+
* NIP-01 replaceable/addressable winner: higher `created_at`, or equal timestamp and
|
|
98
|
+
* lexicographically lower `id`.
|
|
96
99
|
*/
|
|
97
100
|
declare function isReplaceableWinner(candidate: {
|
|
98
101
|
created_at: number;
|
|
@@ -104,5 +107,5 @@ declare function isReplaceableWinner(candidate: {
|
|
|
104
107
|
/** True when a signed event is the signed form of `unsigned` (kind/tags/content/time/pubkey). */
|
|
105
108
|
declare function signedMatchesUnsigned(signed: Event, unsigned: UnsignedEvent): boolean;
|
|
106
109
|
//#endregion
|
|
107
|
-
export {
|
|
108
|
-
//# sourceMappingURL=event-
|
|
110
|
+
export { parseEventAddress as C, isTag as S, tagValue as T, Tag as _, isMarkedFailed as a, formatEventAddress as b, markUnverified as c, signedMatchesUnsigned as d, sortEvents as f, EventAddress as g, validateSignedEvent as h, getEventHash as i, markVerified as l, validateEvent as m, EventTemplate as n, isReplaceableWinner as o, sortedEvents as p, UnsignedEvent as r, itemCompare as s, Event as t, serializeEvent as u, TagInput as v, tagName as w, getDTag as x, eventAddress as y };
|
|
111
|
+
//# sourceMappingURL=event-fU3Y01PR.d.mts.map
|
|
@@ -1,26 +1,28 @@
|
|
|
1
|
-
import { o as isReplaceableKind, r as isAddressableKind } from "./kind-
|
|
1
|
+
import { o as isReplaceableKind, r as isAddressableKind } from "./kind-Cxwhhkx8.mjs";
|
|
2
2
|
//#region src/core/filter.ts
|
|
3
3
|
/** Local NIP-01 match. `search` is ignored; relays interpret NIP-50. */
|
|
4
4
|
function matchFilter(filter, event) {
|
|
5
|
-
if (filter.ids && !filter.ids.some((id) => id.toLowerCase() === event.id
|
|
5
|
+
if (filter.ids && !filter.ids.some((id) => id.toLowerCase() === event.id)) return false;
|
|
6
6
|
if (filter.kinds && !filter.kinds.includes(event.kind)) return false;
|
|
7
|
-
if (filter.authors && !filter.authors.some((pk) => pk.toLowerCase() === event.pubkey
|
|
7
|
+
if (filter.authors && !filter.authors.some((pk) => pk.toLowerCase() === event.pubkey)) return false;
|
|
8
8
|
for (const key of Object.keys(filter)) {
|
|
9
|
-
if (key
|
|
9
|
+
if (!key.startsWith("#")) continue;
|
|
10
10
|
const tagName = key.slice(1);
|
|
11
11
|
const values = filter[`#${tagName}`];
|
|
12
12
|
if (!values) continue;
|
|
13
13
|
const hexTag = tagName === "e" || tagName === "p";
|
|
14
14
|
if (!event.tags.some((tag) => {
|
|
15
|
-
|
|
16
|
-
if (
|
|
17
|
-
return values.
|
|
15
|
+
const [tagKey, tagValue] = tag;
|
|
16
|
+
if (tagKey !== tagName || tagValue === void 0) return false;
|
|
17
|
+
if (hexTag) return values.some((v) => v.toLowerCase() === tagValue.toLowerCase());
|
|
18
|
+
return values.includes(tagValue);
|
|
18
19
|
})) return false;
|
|
19
20
|
}
|
|
20
21
|
if (filter.since !== void 0 && event.created_at < filter.since) return false;
|
|
21
22
|
if (filter.until !== void 0 && event.created_at > filter.until) return false;
|
|
22
23
|
return true;
|
|
23
24
|
}
|
|
25
|
+
/** True when the event matches any of the filters (NIP-01 OR semantics). */
|
|
24
26
|
function matchFilters(filters, event) {
|
|
25
27
|
for (const filter of filters) if (matchFilter(filter, event)) return true;
|
|
26
28
|
return false;
|
|
@@ -28,37 +30,45 @@ function matchFilters(filters, event) {
|
|
|
28
30
|
/** Merge filters by unioning list fields; returns a new plain object. */
|
|
29
31
|
function mergeFilters(...filters) {
|
|
30
32
|
const result = {};
|
|
33
|
+
const mergeList = (property, values) => {
|
|
34
|
+
if (values === void 0) return;
|
|
35
|
+
const existing = result[property];
|
|
36
|
+
const list = Array.isArray(existing) ? [...existing] : [];
|
|
37
|
+
for (const value of values) if (!list.includes(value)) list.push(value);
|
|
38
|
+
result[property] = list;
|
|
39
|
+
};
|
|
40
|
+
const mergeMax = (property, value) => {
|
|
41
|
+
if (value === void 0) return;
|
|
42
|
+
const prev = result[property];
|
|
43
|
+
if (typeof prev !== "number" || value > prev) result[property] = value;
|
|
44
|
+
};
|
|
31
45
|
for (const filter of filters) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const prev = result.limit;
|
|
39
|
-
if (prev === void 0 || filter.limit > prev) result.limit = filter.limit;
|
|
40
|
-
}
|
|
41
|
-
if (filter.until !== void 0) {
|
|
42
|
-
const prev = result.until;
|
|
43
|
-
if (prev === void 0 || filter.until > prev) result.until = filter.until;
|
|
46
|
+
mergeList("ids", filter.ids);
|
|
47
|
+
mergeList("authors", filter.authors);
|
|
48
|
+
mergeList("kinds", filter.kinds);
|
|
49
|
+
for (const key of Object.keys(filter)) {
|
|
50
|
+
if (!key.startsWith("#")) continue;
|
|
51
|
+
mergeList(key, filter[key]);
|
|
44
52
|
}
|
|
53
|
+
mergeMax("limit", filter.limit);
|
|
54
|
+
mergeMax("until", filter.until);
|
|
45
55
|
if (filter.since !== void 0) {
|
|
46
|
-
const prev = result
|
|
47
|
-
if (prev
|
|
56
|
+
const prev = result["since"];
|
|
57
|
+
if (typeof prev !== "number" || filter.since < prev) result["since"] = filter.since;
|
|
48
58
|
}
|
|
49
|
-
if (filter.search !== void 0) result
|
|
59
|
+
if (filter.search !== void 0) result["search"] = filter.search;
|
|
50
60
|
}
|
|
51
61
|
return result;
|
|
52
62
|
}
|
|
53
63
|
/**
|
|
54
|
-
* Intrinsic upper bound implied by the filter alone.
|
|
55
|
-
*
|
|
64
|
+
* Intrinsic upper bound implied by the filter alone. Returns a positive integer, or `Infinity` when
|
|
65
|
+
* unbounded.
|
|
56
66
|
*/
|
|
57
67
|
function getFilterLimit(filter) {
|
|
58
68
|
if (filter.ids && filter.ids.length === 0) return 0;
|
|
59
69
|
if (filter.kinds && filter.kinds.length === 0) return 0;
|
|
60
70
|
if (filter.authors && filter.authors.length === 0) return 0;
|
|
61
|
-
let limit =
|
|
71
|
+
let limit = Number.POSITIVE_INFINITY;
|
|
62
72
|
if (filter.ids) limit = Math.min(limit, filter.ids.length);
|
|
63
73
|
if (filter.limit !== void 0) limit = Math.min(limit, filter.limit);
|
|
64
74
|
if (filter.kinds && filter.authors) {
|
|
@@ -70,10 +80,6 @@ function getFilterLimit(filter) {
|
|
|
70
80
|
}
|
|
71
81
|
return limit;
|
|
72
82
|
}
|
|
73
|
-
/** Shallow-clone a filter (for per-relay narrowing). */
|
|
74
|
-
function cloneFilter(filter) {
|
|
75
|
-
return { ...filter };
|
|
76
|
-
}
|
|
77
83
|
const HEX_LIST_KEYS = /* @__PURE__ */ new Set([
|
|
78
84
|
"ids",
|
|
79
85
|
"authors",
|
|
@@ -89,18 +95,19 @@ function canonicalizeFilter(filter) {
|
|
|
89
95
|
if (value === void 0) continue;
|
|
90
96
|
if (Array.isArray(value)) {
|
|
91
97
|
if (HEX_LIST_KEYS.has(key)) out[key] = value.map((v) => String(v).toLowerCase()).sort();
|
|
92
|
-
else if (key === "kinds") out[key] = value.map(
|
|
93
|
-
else out[key] = value.map(
|
|
98
|
+
else if (key === "kinds") out[key] = value.map(Number).sort((a, b) => a - b);
|
|
99
|
+
else out[key] = value.map(String).sort();
|
|
94
100
|
} else out[key] = value;
|
|
95
101
|
}
|
|
96
102
|
return out;
|
|
97
103
|
}
|
|
104
|
+
/** Apply {@link canonicalizeFilter} to each filter. */
|
|
98
105
|
function canonicalizeFilters(filters) {
|
|
99
106
|
return filters.map(canonicalizeFilter);
|
|
100
107
|
}
|
|
101
108
|
/**
|
|
102
|
-
* Canonical identity for live REQ coalescing.
|
|
103
|
-
*
|
|
109
|
+
* Canonical identity for live REQ coalescing. Relays treat a missing list key as unconstrained and
|
|
110
|
+
* `[]` as match-nothing.
|
|
104
111
|
*/
|
|
105
112
|
function filterFingerprint(filters) {
|
|
106
113
|
const parts = filters.map((filter) => JSON.stringify(canonicalizeFilter(filter)));
|
|
@@ -108,6 +115,6 @@ function filterFingerprint(filters) {
|
|
|
108
115
|
return `[${parts.join(",")}]`;
|
|
109
116
|
}
|
|
110
117
|
//#endregion
|
|
111
|
-
export {
|
|
118
|
+
export { matchFilter as a, getFilterLimit as i, canonicalizeFilters as n, matchFilters as o, filterFingerprint as r, mergeFilters as s, canonicalizeFilter as t };
|
|
112
119
|
|
|
113
|
-
//# sourceMappingURL=filter-
|
|
120
|
+
//# sourceMappingURL=filter-BQl3GlHt.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-BQl3GlHt.mjs","names":[],"sources":["../src/core/filter.ts"],"sourcesContent":["import type { Event } from \"./event.ts\";\nimport { isAddressableKind, isReplaceableKind } from \"./kind.ts\";\n\n/** NIP-01 filter object (immutable-friendly; callers may still pass plain objects). */\nexport type Filter = {\n readonly ids?: ReadonlyArray<string> | undefined;\n readonly kinds?: ReadonlyArray<number> | undefined;\n readonly authors?: ReadonlyArray<string> | undefined;\n readonly since?: number | undefined;\n readonly until?: number | undefined;\n readonly limit?: number | undefined;\n /** NIP-50 full-text search. Relays interpret this. Local `matchFilter` / `query` ignore it. */\n readonly search?: string | undefined;\n readonly [key: `#${string}`]: ReadonlyArray<string> | undefined;\n};\n\n/** Local NIP-01 match. `search` is ignored; relays interpret NIP-50. */\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && !filter.ids.some((id) => id.toLowerCase() === event.id)) {\n return false;\n }\n if (filter.kinds && !filter.kinds.includes(event.kind)) {\n return false;\n }\n if (filter.authors && !filter.authors.some((pk) => pk.toLowerCase() === event.pubkey)) {\n return false;\n }\n\n for (const key of Object.keys(filter)) {\n if (!key.startsWith(\"#\")) {\n continue;\n }\n const tagName = key.slice(1);\n const values = filter[`#${tagName}`];\n if (!values) {\n continue;\n }\n const hexTag = tagName === \"e\" || tagName === \"p\";\n const hit = event.tags.some((tag) => {\n const [tagKey, tagValue] = tag;\n if (tagKey !== tagName || tagValue === undefined) {\n return false;\n }\n if (hexTag) {\n return values.some((v) => v.toLowerCase() === tagValue.toLowerCase());\n }\n return values.includes(tagValue);\n });\n if (!hit) {\n return false;\n }\n }\n\n if (filter.since !== undefined && event.created_at < filter.since) {\n return false;\n }\n if (filter.until !== undefined && event.created_at > filter.until) {\n return false;\n }\n\n return true;\n}\n\n/** True when the event matches any of the filters (NIP-01 OR semantics). */\nexport function matchFilters(filters: ReadonlyArray<Filter>, event: Event): boolean {\n for (const filter of filters) {\n if (matchFilter(filter, event)) {\n return true;\n }\n }\n return false;\n}\n\n/** Merge filters by unioning list fields; returns a new plain object. */\nexport function mergeFilters(...filters: Filter[]): Filter {\n const result: Record<string, unknown> = {};\n const mergeList = (property: string, values: ReadonlyArray<unknown> | undefined): void => {\n if (values === undefined) {\n return;\n }\n const existing = result[property];\n const list: unknown[] = Array.isArray(existing) ? [...(existing as unknown[])] : [];\n for (const value of values) {\n if (!list.includes(value)) {\n list.push(value);\n }\n }\n result[property] = list;\n };\n const mergeMax = (property: \"limit\" | \"until\", value: number | undefined): void => {\n if (value === undefined) {\n return;\n }\n const prev = result[property];\n if (typeof prev !== \"number\" || value > prev) {\n result[property] = value;\n }\n };\n for (const filter of filters) {\n mergeList(\"ids\", filter.ids);\n mergeList(\"authors\", filter.authors);\n mergeList(\"kinds\", filter.kinds);\n for (const key of Object.keys(filter)) {\n if (!key.startsWith(\"#\")) {\n continue;\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- startsWith(\"#\") above guarantees the template key\n mergeList(key, filter[key as `#${string}`]);\n }\n mergeMax(\"limit\", filter.limit);\n mergeMax(\"until\", filter.until);\n if (filter.since !== undefined) {\n const prev = result[\"since\"];\n if (typeof prev !== \"number\" || filter.since < prev) {\n result[\"since\"] = filter.since;\n }\n }\n if (filter.search !== undefined) {\n result[\"search\"] = filter.search;\n }\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- built key by key above; the record is filter-shaped by construction\n return result as Filter;\n}\n\n/**\n * Intrinsic upper bound implied by the filter alone. Returns a positive integer, or `Infinity` when\n * unbounded.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && filter.ids.length === 0) {\n return 0;\n }\n if (filter.kinds && filter.kinds.length === 0) {\n return 0;\n }\n if (filter.authors && filter.authors.length === 0) {\n return 0;\n }\n\n let limit = Number.POSITIVE_INFINITY;\n if (filter.ids) {\n limit = Math.min(limit, filter.ids.length);\n }\n if (filter.limit !== undefined) {\n limit = Math.min(limit, filter.limit);\n }\n\n if (filter.kinds && filter.authors) {\n const allReplaceable = filter.kinds.every((k) => isReplaceableKind(k) || isAddressableKind(k));\n if (allReplaceable) {\n const dTags = filter[\"#d\"];\n const perAuthor = dTags && dTags.length > 0 ? dTags.length : 1;\n limit = Math.min(limit, filter.authors.length * filter.kinds.length * perAuthor);\n }\n }\n\n return limit;\n}\n\nconst HEX_LIST_KEYS = new Set([\"ids\", \"authors\", \"#e\", \"#p\"]);\n\n/** Lowercase hex lists and sort every array. Omits undefined so `[]` stays distinct from missing. */\nexport function canonicalizeFilter(filter: Filter): Filter {\n const raw = filter as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(raw).sort()) {\n const value = raw[key];\n // omit undefined so a missing key is not `[]` / null\n if (value === undefined) {\n continue;\n }\n if (Array.isArray(value)) {\n if (HEX_LIST_KEYS.has(key)) {\n out[key] = value.map((v) => String(v).toLowerCase()).sort();\n } else if (key === \"kinds\") {\n out[key] = value.map(Number).sort((a, b) => a - b);\n } else {\n out[key] = value.map(String).sort();\n }\n } else {\n out[key] = value;\n }\n }\n // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- built key by key above; the record is filter-shaped by construction\n return out as Filter;\n}\n\n/** Apply {@link canonicalizeFilter} to each filter. */\nexport function canonicalizeFilters(filters: ReadonlyArray<Filter>): Filter[] {\n return filters.map(canonicalizeFilter);\n}\n\n/**\n * Canonical identity for live REQ coalescing. Relays treat a missing list key as unconstrained and\n * `[]` as match-nothing.\n */\nexport function filterFingerprint(filters: ReadonlyArray<Filter>): string {\n const parts = filters.map((filter) => JSON.stringify(canonicalizeFilter(filter)));\n parts.sort();\n return `[${parts.join(\",\")}]`;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { t as Event } from "./event-fU3Y01PR.mjs";
|
|
2
|
+
//#region src/core/filter.d.ts
|
|
3
|
+
/** NIP-01 filter object (immutable-friendly; callers may still pass plain objects). */
|
|
4
|
+
type Filter = {
|
|
5
|
+
readonly ids?: ReadonlyArray<string> | undefined;
|
|
6
|
+
readonly kinds?: ReadonlyArray<number> | undefined;
|
|
7
|
+
readonly authors?: ReadonlyArray<string> | undefined;
|
|
8
|
+
readonly since?: number | undefined;
|
|
9
|
+
readonly until?: number | undefined;
|
|
10
|
+
readonly limit?: number | undefined;
|
|
11
|
+
/** NIP-50 full-text search. Relays interpret this. Local `matchFilter` / `query` ignore it. */
|
|
12
|
+
readonly search?: string | undefined;
|
|
13
|
+
readonly [key: `#${string}`]: ReadonlyArray<string> | undefined;
|
|
14
|
+
};
|
|
15
|
+
/** Local NIP-01 match. `search` is ignored; relays interpret NIP-50. */
|
|
16
|
+
declare function matchFilter(filter: Filter, event: Event): boolean;
|
|
17
|
+
/** True when the event matches any of the filters (NIP-01 OR semantics). */
|
|
18
|
+
declare function matchFilters(filters: ReadonlyArray<Filter>, event: Event): boolean;
|
|
19
|
+
/** Merge filters by unioning list fields; returns a new plain object. */
|
|
20
|
+
declare function mergeFilters(...filters: Filter[]): Filter;
|
|
21
|
+
/**
|
|
22
|
+
* Intrinsic upper bound implied by the filter alone. Returns a positive integer, or `Infinity` when
|
|
23
|
+
* unbounded.
|
|
24
|
+
*/
|
|
25
|
+
declare function getFilterLimit(filter: Filter): number;
|
|
26
|
+
/** Lowercase hex lists and sort every array. Omits undefined so `[]` stays distinct from missing. */
|
|
27
|
+
declare function canonicalizeFilter(filter: Filter): Filter;
|
|
28
|
+
/** Apply {@link canonicalizeFilter} to each filter. */
|
|
29
|
+
declare function canonicalizeFilters(filters: ReadonlyArray<Filter>): Filter[];
|
|
30
|
+
/**
|
|
31
|
+
* Canonical identity for live REQ coalescing. Relays treat a missing list key as unconstrained and
|
|
32
|
+
* `[]` as match-nothing.
|
|
33
|
+
*/
|
|
34
|
+
declare function filterFingerprint(filters: ReadonlyArray<Filter>): string;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { getFilterLimit as a, mergeFilters as c, filterFingerprint as i, canonicalizeFilter as n, matchFilter as o, canonicalizeFilters as r, matchFilters as s, Filter as t };
|
|
37
|
+
//# sourceMappingURL=filter-C0IMByE3.d.mts.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { t as Event } from "./event-
|
|
2
|
-
import { t as Filter } from "./filter-
|
|
3
|
-
import { t as RelayListItem } from "./nip65-
|
|
1
|
+
import { t as Event } from "./event-fU3Y01PR.mjs";
|
|
2
|
+
import { t as Filter } from "./filter-C0IMByE3.mjs";
|
|
3
|
+
import { t as RelayListItem } from "./nip65-DBfh2smt.mjs";
|
|
4
4
|
//#region src/gossip/gossip.d.ts
|
|
5
|
+
/** Relay routing state for one pubkey: NIP-65 outbox/inbox plus NIP-17 DM relays. */
|
|
5
6
|
type PubkeyRoutes = {
|
|
6
7
|
/** Relays the user writes to (outbox). NIP-65. */
|
|
7
8
|
write: string[];
|
|
@@ -14,42 +15,44 @@ type PubkeyRoutes = {
|
|
|
14
15
|
/** `created_at` of the last accepted kind:10050 list. */
|
|
15
16
|
dmUpdatedAt: number;
|
|
16
17
|
/** Event id of the last accepted kind:10002 (NIP-01 equal-timestamp tie-break). */
|
|
17
|
-
relayListId?: string;
|
|
18
|
+
relayListId?: string | undefined;
|
|
18
19
|
/** Event id of the last accepted kind:10050. */
|
|
19
|
-
dmListId?: string;
|
|
20
|
+
dmListId?: string | undefined;
|
|
20
21
|
};
|
|
22
|
+
/** A filter split by gossip routes: per-relay narrowed filters plus the unrouted remainder. */
|
|
21
23
|
type RoutedFilter = {
|
|
22
|
-
/**
|
|
24
|
+
/** Url → already-narrowed filter. Empty when nothing routed. */
|
|
23
25
|
perRelay: Map<string, Filter>;
|
|
24
26
|
/**
|
|
25
|
-
* Unrouted work for the caller:
|
|
26
|
-
*
|
|
27
|
-
* -
|
|
28
|
-
* - mixed: narrowed leftover (today's fallback)
|
|
29
|
-
* - all routed: undefined
|
|
27
|
+
* Unrouted work for the caller: - no authors and no #p: original filter (today's "generic") -
|
|
28
|
+
* authors/#p all unrouted: original filter (today's "orphan") - mixed: narrowed leftover (today's
|
|
29
|
+
* fallback) - all routed: undefined
|
|
30
30
|
*/
|
|
31
31
|
remainder?: Filter;
|
|
32
32
|
};
|
|
33
33
|
type GossipOptions = {
|
|
34
34
|
/** Max relays to keep per direction when ranking. Default 4. */
|
|
35
35
|
maxRelaysPerPubkey?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Max pubkeys with tracked routes; the map is LRU — writes and lookups refresh recency, and
|
|
38
|
+
* inserting beyond the cap drops the oldest entry. Default 10_000.
|
|
39
|
+
*/
|
|
40
|
+
maxPubkeys?: number;
|
|
36
41
|
};
|
|
37
42
|
/**
|
|
38
|
-
* Routing table for NIP-65 (10002) and NIP-17 DM relays (10050).
|
|
39
|
-
*
|
|
43
|
+
* Routing table for NIP-65 (10002) and NIP-17 DM relays (10050). Ingest replaceable list events,
|
|
44
|
+
* then route filters into per-relay REQs.
|
|
40
45
|
*/
|
|
41
46
|
declare class Gossip {
|
|
42
47
|
#private;
|
|
43
48
|
constructor(opts?: GossipOptions);
|
|
44
49
|
/**
|
|
45
|
-
* Ingest a routing list event.
|
|
46
|
-
* - kind:10002 → write/read (NIP-65)
|
|
47
|
-
* - kind:10050 → dm (NIP-17)
|
|
50
|
+
* Ingest a routing list event. - kind:10002 → write/read (NIP-65) - kind:10050 → dm (NIP-17)
|
|
48
51
|
* Returns true if routes for that list type were updated.
|
|
49
52
|
*/
|
|
50
53
|
ingest(event: Event): boolean;
|
|
51
54
|
setRoutes(pubkey: string, items: RelayListItem[], updatedAt?: number, eventId?: string): boolean;
|
|
52
|
-
setDmRoutes(pubkey: string, relays:
|
|
55
|
+
setDmRoutes(pubkey: string, relays: ReadonlyArray<string>, updatedAt?: number, eventId?: string): boolean;
|
|
53
56
|
getRoutes(pubkey: string): PubkeyRoutes | undefined;
|
|
54
57
|
outboxRelays(pubkey: string): string[];
|
|
55
58
|
inboxRelays(pubkey: string): string[];
|
|
@@ -58,14 +61,13 @@ declare class Gossip {
|
|
|
58
61
|
clear(pubkey?: string): void;
|
|
59
62
|
get size(): number;
|
|
60
63
|
/**
|
|
61
|
-
* Route a user-facing filter into per-relay sub-filters plus leftover.
|
|
62
|
-
*
|
|
63
|
-
* -
|
|
64
|
-
*
|
|
65
|
-
* - mixed → remainder is the narrowed leftover; all routed → no remainder
|
|
64
|
+
* Route a user-facing filter into per-relay sub-filters plus leftover. - authors → outbox relays,
|
|
65
|
+
* filter narrowed per relay's authors - #p only → inbox relays of those pubkeys - neither / all
|
|
66
|
+
* unrouted → remainder is the original filter - mixed → remainder is the narrowed leftover; all
|
|
67
|
+
* routed → no remainder
|
|
66
68
|
*/
|
|
67
69
|
route(filter: Filter): RoutedFilter;
|
|
68
70
|
}
|
|
69
71
|
//#endregion
|
|
70
72
|
export { RoutedFilter as i, GossipOptions as n, PubkeyRoutes as r, Gossip as t };
|
|
71
|
-
//# sourceMappingURL=gossip-
|
|
73
|
+
//# sourceMappingURL=gossip-BRQwIM_q.d.mts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as Kind } from "./kind-
|
|
3
|
-
import {
|
|
1
|
+
import { l as normalizeURL } from "./util-LfQirgDk.mjs";
|
|
2
|
+
import { t as Kind } from "./kind-Cxwhhkx8.mjs";
|
|
3
|
+
import { a as isReplaceableWinner } from "./event-D8Nfoh4K.mjs";
|
|
4
4
|
import { parseRelayList } from "./nips/nip65.mjs";
|
|
5
5
|
import { parseDmRelayList } from "./nips/nip17.mjs";
|
|
6
6
|
//#region src/gossip/gossip.ts
|
|
@@ -14,19 +14,19 @@ function emptyRoutes() {
|
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* Routing table for NIP-65 (10002) and NIP-17 DM relays (10050).
|
|
18
|
-
*
|
|
17
|
+
* Routing table for NIP-65 (10002) and NIP-17 DM relays (10050). Ingest replaceable list events,
|
|
18
|
+
* then route filters into per-relay REQs.
|
|
19
19
|
*/
|
|
20
20
|
var Gossip = class {
|
|
21
21
|
#routes = /* @__PURE__ */ new Map();
|
|
22
22
|
#maxRelays;
|
|
23
|
+
#maxPubkeys;
|
|
23
24
|
constructor(opts = {}) {
|
|
24
25
|
this.#maxRelays = opts.maxRelaysPerPubkey ?? 4;
|
|
26
|
+
this.#maxPubkeys = opts.maxPubkeys ?? 1e4;
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
27
|
-
* Ingest a routing list event.
|
|
28
|
-
* - kind:10002 → write/read (NIP-65)
|
|
29
|
-
* - kind:10050 → dm (NIP-17)
|
|
29
|
+
* Ingest a routing list event. - kind:10002 → write/read (NIP-65) - kind:10050 → dm (NIP-17)
|
|
30
30
|
* Returns true if routes for that list type were updated.
|
|
31
31
|
*/
|
|
32
32
|
ingest(event) {
|
|
@@ -52,9 +52,9 @@ var Gossip = class {
|
|
|
52
52
|
}
|
|
53
53
|
setRoutes(pubkey, items, updatedAt = Math.floor(Date.now() / 1e3), eventId) {
|
|
54
54
|
const pk = pubkey.toLowerCase();
|
|
55
|
-
const prev = this.#
|
|
55
|
+
const prev = this.#lookup(pk) ?? emptyRoutes();
|
|
56
56
|
if (prev.updatedAt > updatedAt) return false;
|
|
57
|
-
if (eventId && prev.relayListId && prev.updatedAt === updatedAt && !isReplaceableWinner({
|
|
57
|
+
if (eventId !== void 0 && prev.relayListId !== void 0 && prev.updatedAt === updatedAt && !isReplaceableWinner({
|
|
58
58
|
created_at: updatedAt,
|
|
59
59
|
id: eventId
|
|
60
60
|
}, {
|
|
@@ -73,7 +73,7 @@ var Gossip = class {
|
|
|
73
73
|
if (item.write && !write.includes(url)) write.push(url);
|
|
74
74
|
if (item.read && !read.includes(url)) read.push(url);
|
|
75
75
|
}
|
|
76
|
-
this.#
|
|
76
|
+
this.#put(pk, {
|
|
77
77
|
write: write.slice(0, this.#maxRelays),
|
|
78
78
|
read: read.slice(0, this.#maxRelays),
|
|
79
79
|
dm: prev.dm,
|
|
@@ -86,9 +86,9 @@ var Gossip = class {
|
|
|
86
86
|
}
|
|
87
87
|
setDmRoutes(pubkey, relays, updatedAt = Math.floor(Date.now() / 1e3), eventId) {
|
|
88
88
|
const pk = pubkey.toLowerCase();
|
|
89
|
-
const prev = this.#
|
|
89
|
+
const prev = this.#lookup(pk) ?? emptyRoutes();
|
|
90
90
|
if (prev.dmUpdatedAt > updatedAt) return false;
|
|
91
|
-
if (eventId && prev.dmListId && prev.dmUpdatedAt === updatedAt && !isReplaceableWinner({
|
|
91
|
+
if (eventId !== void 0 && prev.dmListId !== void 0 && prev.dmUpdatedAt === updatedAt && !isReplaceableWinner({
|
|
92
92
|
created_at: updatedAt,
|
|
93
93
|
id: eventId
|
|
94
94
|
}, {
|
|
@@ -105,7 +105,7 @@ var Gossip = class {
|
|
|
105
105
|
}
|
|
106
106
|
if (!dm.includes(url)) dm.push(url);
|
|
107
107
|
}
|
|
108
|
-
this.#
|
|
108
|
+
this.#put(pk, {
|
|
109
109
|
write: prev.write,
|
|
110
110
|
read: prev.read,
|
|
111
111
|
dm: dm.slice(0, this.#maxRelays),
|
|
@@ -117,31 +117,30 @@ var Gossip = class {
|
|
|
117
117
|
return true;
|
|
118
118
|
}
|
|
119
119
|
getRoutes(pubkey) {
|
|
120
|
-
return this.#
|
|
120
|
+
return this.#lookup(pubkey.toLowerCase());
|
|
121
121
|
}
|
|
122
122
|
outboxRelays(pubkey) {
|
|
123
|
-
return this.#
|
|
123
|
+
return this.#lookup(pubkey.toLowerCase())?.write ?? [];
|
|
124
124
|
}
|
|
125
125
|
inboxRelays(pubkey) {
|
|
126
|
-
return this.#
|
|
126
|
+
return this.#lookup(pubkey.toLowerCase())?.read ?? [];
|
|
127
127
|
}
|
|
128
128
|
/** NIP-17 kind:10050 delivery relays for gift-wraps. */
|
|
129
129
|
dmRelays(pubkey) {
|
|
130
|
-
return this.#
|
|
130
|
+
return this.#lookup(pubkey.toLowerCase())?.dm ?? [];
|
|
131
131
|
}
|
|
132
132
|
clear(pubkey) {
|
|
133
|
-
if (pubkey) this.#routes.delete(pubkey.toLowerCase());
|
|
133
|
+
if (pubkey !== void 0 && pubkey !== "") this.#routes.delete(pubkey.toLowerCase());
|
|
134
134
|
else this.#routes.clear();
|
|
135
135
|
}
|
|
136
136
|
get size() {
|
|
137
137
|
return this.#routes.size;
|
|
138
138
|
}
|
|
139
139
|
/**
|
|
140
|
-
* Route a user-facing filter into per-relay sub-filters plus leftover.
|
|
141
|
-
*
|
|
142
|
-
* -
|
|
143
|
-
*
|
|
144
|
-
* - mixed → remainder is the narrowed leftover; all routed → no remainder
|
|
140
|
+
* Route a user-facing filter into per-relay sub-filters plus leftover. - authors → outbox relays,
|
|
141
|
+
* filter narrowed per relay's authors - #p only → inbox relays of those pubkeys - neither / all
|
|
142
|
+
* unrouted → remainder is the original filter - mixed → remainder is the narrowed leftover; all
|
|
143
|
+
* routed → no remainder
|
|
145
144
|
*/
|
|
146
145
|
route(filter) {
|
|
147
146
|
const authors = filter.authors?.map((a) => a.toLowerCase());
|
|
@@ -151,18 +150,18 @@ var Gossip = class {
|
|
|
151
150
|
remainder: filter
|
|
152
151
|
};
|
|
153
152
|
if (authors && authors.length > 0 && (!pTags || pTags.length === 0)) return this.#breakAuthors(filter, authors, "write");
|
|
154
|
-
if (pTags && pTags.length > 0 && (!authors || authors.length === 0))
|
|
155
|
-
...filter
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
153
|
+
if (pTags && pTags.length > 0 && (!authors || authors.length === 0)) {
|
|
154
|
+
const { authors: _authors, ...base } = filter;
|
|
155
|
+
return this.#breakAuthors(base, pTags, "read", (b, pubkeys) => ({
|
|
156
|
+
...b,
|
|
157
|
+
"#p": pubkeys
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
161
160
|
const unionKeys = /* @__PURE__ */ new Set([...authors ?? [], ...pTags ?? []]);
|
|
162
161
|
const relays = /* @__PURE__ */ new Set();
|
|
163
162
|
let anyUnrouted = false;
|
|
164
163
|
for (const pk of unionKeys) {
|
|
165
|
-
const r = this.#
|
|
164
|
+
const r = this.#lookup(pk);
|
|
166
165
|
const urls = r ? [...r.write, ...r.read] : [];
|
|
167
166
|
if (urls.length === 0) {
|
|
168
167
|
anyUnrouted = true;
|
|
@@ -189,7 +188,7 @@ var Gossip = class {
|
|
|
189
188
|
const unrouted = [];
|
|
190
189
|
let anyRoute = false;
|
|
191
190
|
for (const pk of pubkeys) {
|
|
192
|
-
const routes = this.#
|
|
191
|
+
const routes = this.#lookup(pk);
|
|
193
192
|
const urls = direction === "write" ? routes?.write : routes?.read;
|
|
194
193
|
if (!urls || urls.length === 0) {
|
|
195
194
|
unrouted.push(pk);
|
|
@@ -213,8 +212,27 @@ var Gossip = class {
|
|
|
213
212
|
remainder: narrow(filter, unrouted)
|
|
214
213
|
} : { perRelay: map };
|
|
215
214
|
}
|
|
215
|
+
/** Read that refreshes LRU recency. */
|
|
216
|
+
#lookup(pk) {
|
|
217
|
+
const routes = this.#routes.get(pk);
|
|
218
|
+
if (routes !== void 0) {
|
|
219
|
+
this.#routes.delete(pk);
|
|
220
|
+
this.#routes.set(pk, routes);
|
|
221
|
+
}
|
|
222
|
+
return routes;
|
|
223
|
+
}
|
|
224
|
+
/** Write at the newest LRU end, then trim the oldest beyond the cap. */
|
|
225
|
+
#put(pk, routes) {
|
|
226
|
+
this.#routes.delete(pk);
|
|
227
|
+
this.#routes.set(pk, routes);
|
|
228
|
+
while (this.#routes.size > this.#maxPubkeys) {
|
|
229
|
+
const oldest = this.#routes.keys().next().value;
|
|
230
|
+
if (oldest === void 0) break;
|
|
231
|
+
this.#routes.delete(oldest);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
216
234
|
};
|
|
217
235
|
//#endregion
|
|
218
236
|
export { Gossip as t };
|
|
219
237
|
|
|
220
|
-
//# sourceMappingURL=gossip-
|
|
238
|
+
//# sourceMappingURL=gossip-oloDMWEj.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gossip-oloDMWEj.mjs","names":[],"sources":["../src/gossip/gossip.ts"],"sourcesContent":["import type { Event } from \"../core/event.ts\";\nimport { isReplaceableWinner } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { Kind } from \"../core/kind.ts\";\nimport { normalizeURL } from \"../core/util.ts\";\nimport { parseDmRelayList } from \"../nips/nip17.ts\";\nimport { parseRelayList } from \"../nips/nip65.ts\";\nimport type { RelayListItem } from \"../nips/nip65.ts\";\n\n/** Relay routing state for one pubkey: NIP-65 outbox/inbox plus NIP-17 DM relays. */\nexport type PubkeyRoutes = {\n /** Relays the user writes to (outbox). NIP-65. */\n write: string[];\n /** Relays the user reads from (inbox). NIP-65. */\n read: string[];\n /** Relays for NIP-17 gift-wrap delivery. Kind 10050. */\n dm: string[];\n /** `created_at` of the last accepted kind:10002 list. */\n updatedAt: number;\n /** `created_at` of the last accepted kind:10050 list. */\n dmUpdatedAt: number;\n /** Event id of the last accepted kind:10002 (NIP-01 equal-timestamp tie-break). */\n relayListId?: string | undefined;\n /** Event id of the last accepted kind:10050. */\n dmListId?: string | undefined;\n};\n\n/** A filter split by gossip routes: per-relay narrowed filters plus the unrouted remainder. */\nexport type RoutedFilter = {\n /** Url → already-narrowed filter. Empty when nothing routed. */\n perRelay: Map<string, Filter>;\n /**\n * Unrouted work for the caller: - no authors and no #p: original filter (today's \"generic\") -\n * authors/#p all unrouted: original filter (today's \"orphan\") - mixed: narrowed leftover (today's\n * fallback) - all routed: undefined\n */\n remainder?: Filter;\n};\n\nexport type GossipOptions = {\n /** Max relays to keep per direction when ranking. Default 4. */\n maxRelaysPerPubkey?: number;\n /**\n * Max pubkeys with tracked routes; the map is LRU — writes and lookups refresh recency, and\n * inserting beyond the cap drops the oldest entry. Default 10_000.\n */\n maxPubkeys?: number;\n};\n\nfunction emptyRoutes(): PubkeyRoutes {\n return {\n write: [],\n read: [],\n dm: [],\n updatedAt: 0,\n dmUpdatedAt: 0,\n };\n}\n\n/**\n * Routing table for NIP-65 (10002) and NIP-17 DM relays (10050). Ingest replaceable list events,\n * then route filters into per-relay REQs.\n */\nexport class Gossip {\n readonly #routes = new Map<string, PubkeyRoutes>();\n readonly #maxRelays: number;\n readonly #maxPubkeys: number;\n\n constructor(opts: GossipOptions = {}) {\n this.#maxRelays = opts.maxRelaysPerPubkey ?? 4;\n this.#maxPubkeys = opts.maxPubkeys ?? 10_000;\n }\n\n /**\n * Ingest a routing list event. - kind:10002 → write/read (NIP-65) - kind:10050 → dm (NIP-17)\n * Returns true if routes for that list type were updated.\n */\n ingest(event: Event): boolean {\n if (event.kind === Kind.RelayList) {\n let items: RelayListItem[];\n try {\n items = parseRelayList(event);\n } catch {\n return false;\n }\n return this.setRoutes(event.pubkey, items, event.created_at, event.id);\n }\n if (event.kind === Kind.DirectMessageRelaysList) {\n let relays: string[];\n try {\n relays = parseDmRelayList(event);\n } catch {\n return false;\n }\n return this.setDmRoutes(event.pubkey, relays, event.created_at, event.id);\n }\n return false;\n }\n\n setRoutes(\n pubkey: string,\n items: RelayListItem[],\n updatedAt: number = Math.floor(Date.now() / 1000),\n eventId?: string,\n ): boolean {\n const pk = pubkey.toLowerCase();\n const prev = this.#lookup(pk) ?? emptyRoutes();\n if (prev.updatedAt > updatedAt) {\n return false;\n }\n if (\n eventId !== undefined &&\n prev.relayListId !== undefined &&\n prev.updatedAt === updatedAt &&\n !isReplaceableWinner(\n { created_at: updatedAt, id: eventId },\n { created_at: prev.updatedAt, id: prev.relayListId },\n )\n ) {\n return false;\n }\n\n const write: string[] = [];\n const read: string[] = [];\n for (const item of items) {\n let url: string;\n try {\n url = normalizeURL(item.url);\n } catch {\n continue;\n }\n if (item.write && !write.includes(url)) {\n write.push(url);\n }\n if (item.read && !read.includes(url)) {\n read.push(url);\n }\n }\n\n this.#put(pk, {\n write: write.slice(0, this.#maxRelays),\n read: read.slice(0, this.#maxRelays),\n dm: prev.dm,\n updatedAt,\n dmUpdatedAt: prev.dmUpdatedAt,\n relayListId: eventId ?? prev.relayListId,\n dmListId: prev.dmListId,\n });\n return true;\n }\n\n setDmRoutes(\n pubkey: string,\n relays: ReadonlyArray<string>,\n updatedAt: number = Math.floor(Date.now() / 1000),\n eventId?: string,\n ): boolean {\n const pk = pubkey.toLowerCase();\n const prev = this.#lookup(pk) ?? emptyRoutes();\n if (prev.dmUpdatedAt > updatedAt) {\n return false;\n }\n if (\n eventId !== undefined &&\n prev.dmListId !== undefined &&\n prev.dmUpdatedAt === updatedAt &&\n !isReplaceableWinner(\n { created_at: updatedAt, id: eventId },\n { created_at: prev.dmUpdatedAt, id: prev.dmListId },\n )\n ) {\n return false;\n }\n\n const dm: string[] = [];\n for (const raw of relays) {\n let url: string;\n try {\n url = normalizeURL(raw);\n } catch {\n continue;\n }\n if (!dm.includes(url)) {\n dm.push(url);\n }\n }\n\n this.#put(pk, {\n write: prev.write,\n read: prev.read,\n dm: dm.slice(0, this.#maxRelays),\n updatedAt: prev.updatedAt,\n dmUpdatedAt: updatedAt,\n relayListId: prev.relayListId,\n dmListId: eventId ?? prev.dmListId,\n });\n return true;\n }\n\n getRoutes(pubkey: string): PubkeyRoutes | undefined {\n return this.#lookup(pubkey.toLowerCase());\n }\n\n outboxRelays(pubkey: string): string[] {\n return this.#lookup(pubkey.toLowerCase())?.write ?? [];\n }\n\n inboxRelays(pubkey: string): string[] {\n return this.#lookup(pubkey.toLowerCase())?.read ?? [];\n }\n\n /** NIP-17 kind:10050 delivery relays for gift-wraps. */\n dmRelays(pubkey: string): string[] {\n return this.#lookup(pubkey.toLowerCase())?.dm ?? [];\n }\n\n clear(pubkey?: string): void {\n if (pubkey !== undefined && pubkey !== \"\") {\n this.#routes.delete(pubkey.toLowerCase());\n } else {\n this.#routes.clear();\n }\n }\n\n get size(): number {\n return this.#routes.size;\n }\n\n /**\n * Route a user-facing filter into per-relay sub-filters plus leftover. - authors → outbox relays,\n * filter narrowed per relay's authors - #p only → inbox relays of those pubkeys - neither / all\n * unrouted → remainder is the original filter - mixed → remainder is the narrowed leftover; all\n * routed → no remainder\n */\n route(filter: Filter): RoutedFilter {\n const authors = filter.authors?.map((a) => a.toLowerCase());\n const pTags = filter[\"#p\"]?.map((p) => p.toLowerCase());\n\n if ((!authors || authors.length === 0) && (!pTags || pTags.length === 0)) {\n return { perRelay: new Map(), remainder: filter };\n }\n\n if (authors && authors.length > 0 && (!pTags || pTags.length === 0)) {\n return this.#breakAuthors(filter, authors, \"write\");\n }\n\n if (pTags && pTags.length > 0 && (!authors || authors.length === 0)) {\n const { authors: _authors, ...base } = filter;\n return this.#breakAuthors(base, pTags, \"read\", (b, pubkeys) => ({ ...b, \"#p\": pubkeys }));\n }\n\n // both authors and #p: send full filter to union of routes\n const unionKeys = new Set([...(authors ?? []), ...(pTags ?? [])]);\n const relays = new Set<string>();\n let anyUnrouted = false;\n for (const pk of unionKeys) {\n const r = this.#lookup(pk);\n const urls = r ? [...r.write, ...r.read] : [];\n if (urls.length === 0) {\n anyUnrouted = true;\n continue;\n }\n for (const u of urls) {\n relays.add(u);\n }\n }\n if (relays.size === 0) {\n return { perRelay: new Map(), remainder: filter };\n }\n const map = new Map<string, Filter>();\n for (const url of relays) {\n map.set(url, { ...filter });\n }\n return anyUnrouted ? { perRelay: map, remainder: filter } : { perRelay: map };\n }\n\n #breakAuthors(\n filter: Filter,\n pubkeys: string[],\n direction: \"read\" | \"write\",\n narrow: (base: Filter, pubkeys: string[]) => Filter = (base, pks) => ({\n ...base,\n authors: pks,\n }),\n ): RoutedFilter {\n const perRelay = new Map<string, string[]>();\n const unrouted: string[] = [];\n let anyRoute = false;\n\n for (const pk of pubkeys) {\n const routes = this.#lookup(pk);\n const urls = direction === \"write\" ? routes?.write : routes?.read;\n if (!urls || urls.length === 0) {\n unrouted.push(pk);\n continue;\n }\n anyRoute = true;\n for (const url of urls) {\n const list = perRelay.get(url) ?? [];\n list.push(pk);\n perRelay.set(url, list);\n }\n }\n\n if (!anyRoute) {\n return { perRelay: new Map(), remainder: filter };\n }\n\n const map = new Map<string, Filter>();\n for (const [url, pks] of perRelay) {\n map.set(url, narrow(filter, pks));\n }\n return unrouted.length > 0\n ? { perRelay: map, remainder: narrow(filter, unrouted) }\n : { perRelay: map };\n }\n\n /** Read that refreshes LRU recency. */\n #lookup(pk: string): PubkeyRoutes | undefined {\n const routes = this.#routes.get(pk);\n if (routes !== undefined) {\n this.#routes.delete(pk);\n this.#routes.set(pk, routes);\n }\n return routes;\n }\n\n /** Write at the newest LRU end, then trim the oldest beyond the cap. */\n #put(pk: string, routes: PubkeyRoutes): void {\n this.#routes.delete(pk);\n this.#routes.set(pk, routes);\n while (this.#routes.size > this.#maxPubkeys) {\n const oldest = this.#routes.keys().next().value;\n if (oldest === undefined) {\n break;\n }\n this.#routes.delete(oldest);\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/gossip.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as RoutedFilter, n as GossipOptions, r as PubkeyRoutes, t as Gossip } from "./gossip-
|
|
1
|
+
import { i as RoutedFilter, n as GossipOptions, r as PubkeyRoutes, t as Gossip } from "./gossip-BRQwIM_q.mjs";
|
|
2
2
|
import "./index-CaxrMD1A.mjs";
|
|
3
3
|
export { Gossip, type GossipOptions, type PubkeyRoutes, type RoutedFilter };
|
package/dist/gossip.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as Gossip } from "./gossip-
|
|
1
|
+
import { t as Gossip } from "./gossip-oloDMWEj.mjs";
|
|
2
2
|
export { Gossip };
|