nostr-tools 2.23.8 → 2.23.11
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/lib/cjs/abstract-pool.js +163 -7
- package/lib/cjs/abstract-pool.js.map +4 -4
- package/lib/cjs/abstract-relay.js +59 -6
- package/lib/cjs/abstract-relay.js.map +2 -2
- package/lib/cjs/filter.js.map +1 -1
- package/lib/cjs/index.js +412 -64
- package/lib/cjs/index.js.map +4 -4
- package/lib/cjs/kinds.js +196 -4
- package/lib/cjs/kinds.js.map +2 -2
- package/lib/cjs/nip17.js.map +2 -2
- package/lib/cjs/nip18.js.map +2 -2
- package/lib/cjs/nip25.js.map +1 -1
- package/lib/cjs/nip28.js.map +2 -2
- package/lib/cjs/nip42.js.map +2 -2
- package/lib/cjs/nip45.js +183 -0
- package/lib/cjs/nip45.js.map +7 -0
- package/lib/cjs/nip46.js +163 -7
- package/lib/cjs/nip46.js.map +4 -4
- package/lib/cjs/nip47.js.map +2 -2
- package/lib/cjs/nip57.js.map +1 -1
- package/lib/cjs/nip58.js.map +2 -2
- package/lib/cjs/nip59.js.map +2 -2
- package/lib/cjs/nip75.js.map +2 -2
- package/lib/cjs/nip94.js.map +2 -2
- package/lib/cjs/nip98.js.map +2 -2
- package/lib/cjs/nip99.js.map +2 -2
- package/lib/cjs/nipb0.js +1064 -0
- package/lib/cjs/nipb0.js.map +7 -0
- package/lib/cjs/pool.js +163 -7
- package/lib/cjs/pool.js.map +4 -4
- package/lib/cjs/relay.js +59 -6
- package/lib/cjs/relay.js.map +2 -2
- package/lib/esm/abstract-pool.js +163 -7
- package/lib/esm/abstract-pool.js.map +4 -4
- package/lib/esm/abstract-relay.js +59 -6
- package/lib/esm/abstract-relay.js.map +2 -2
- package/lib/esm/filter.js.map +1 -1
- package/lib/esm/index.js +388 -40
- package/lib/esm/index.js.map +4 -4
- package/lib/esm/kinds.js +196 -4
- package/lib/esm/kinds.js.map +2 -2
- package/lib/esm/nip17.js.map +2 -2
- package/lib/esm/nip18.js.map +2 -2
- package/lib/esm/nip25.js.map +1 -1
- package/lib/esm/nip28.js.map +2 -2
- package/lib/esm/nip42.js.map +2 -2
- package/lib/esm/nip45.js +162 -0
- package/lib/esm/nip45.js.map +7 -0
- package/lib/esm/nip46.js +163 -7
- package/lib/esm/nip46.js.map +4 -4
- package/lib/esm/nip47.js.map +2 -2
- package/lib/esm/nip57.js.map +1 -1
- package/lib/esm/nip58.js.map +2 -2
- package/lib/esm/nip59.js.map +2 -2
- package/lib/esm/nip75.js.map +2 -2
- package/lib/esm/nip94.js.map +2 -2
- package/lib/esm/nip98.js.map +2 -2
- package/lib/esm/nip99.js.map +2 -2
- package/lib/esm/nipb0.js +1049 -0
- package/lib/esm/nipb0.js.map +7 -0
- package/lib/esm/pool.js +163 -7
- package/lib/esm/pool.js.map +4 -4
- package/lib/esm/relay.js +59 -6
- package/lib/esm/relay.js.map +2 -2
- package/lib/nostr.bundle.js +361 -15
- package/lib/nostr.bundle.js.map +4 -4
- package/lib/types/abstract-pool.d.ts +10 -0
- package/lib/types/abstract-relay.d.ts +15 -1
- package/lib/types/kinds.d.ts +200 -8
- package/lib/types/nip45.d.ts +13 -0
- package/lib/types/nip45.test.d.ts +1 -0
- package/lib/types/nipb0.d.ts +129 -0
- package/lib/types/relay.d.ts +2 -2
- package/package.json +13 -1
package/lib/cjs/nip46.js
CHANGED
|
@@ -372,12 +372,14 @@ var AbstractRelay = class {
|
|
|
372
372
|
openSubs = /* @__PURE__ */ new Map();
|
|
373
373
|
enablePing;
|
|
374
374
|
enableReconnect;
|
|
375
|
+
idleTimeout = 0;
|
|
375
376
|
idleSince = Date.now();
|
|
376
377
|
ongoingOperations = 0;
|
|
377
378
|
reconnectTimeoutHandle;
|
|
378
379
|
pingIntervalHandle;
|
|
379
380
|
reconnectAttempts = 0;
|
|
380
381
|
skipReconnection = false;
|
|
382
|
+
idleTimeoutHandle;
|
|
381
383
|
connectionPromise;
|
|
382
384
|
openCountRequests = /* @__PURE__ */ new Map();
|
|
383
385
|
openEventPublishes = /* @__PURE__ */ new Map();
|
|
@@ -393,6 +395,8 @@ var AbstractRelay = class {
|
|
|
393
395
|
this._WebSocket = opts.websocketImplementation || WebSocket;
|
|
394
396
|
this.enablePing = opts.enablePing;
|
|
395
397
|
this.enableReconnect = opts.enableReconnect || false;
|
|
398
|
+
if (opts.idleTimeout)
|
|
399
|
+
this.idleTimeout = opts.idleTimeout;
|
|
396
400
|
}
|
|
397
401
|
static async connect(url, opts) {
|
|
398
402
|
const relay = new AbstractRelay(url, opts);
|
|
@@ -416,6 +420,22 @@ var AbstractRelay = class {
|
|
|
416
420
|
get connected() {
|
|
417
421
|
return this._connected;
|
|
418
422
|
}
|
|
423
|
+
clearIdleTimeout() {
|
|
424
|
+
if (this.idleTimeoutHandle) {
|
|
425
|
+
clearTimeout(this.idleTimeoutHandle);
|
|
426
|
+
this.idleTimeoutHandle = void 0;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
scheduleIdleClose() {
|
|
430
|
+
this.clearIdleTimeout();
|
|
431
|
+
if (this.idleTimeout > 0) {
|
|
432
|
+
this.idleTimeoutHandle = setTimeout(() => {
|
|
433
|
+
if (this.ongoingOperations === 0 && this.idleSince) {
|
|
434
|
+
this.close();
|
|
435
|
+
}
|
|
436
|
+
}, this.idleTimeout);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
419
439
|
async reconnect() {
|
|
420
440
|
const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)];
|
|
421
441
|
this.reconnectAttempts++;
|
|
@@ -434,6 +454,7 @@ var AbstractRelay = class {
|
|
|
434
454
|
this._connected = false;
|
|
435
455
|
this.connectionPromise = void 0;
|
|
436
456
|
this.idleSince = void 0;
|
|
457
|
+
this.clearIdleTimeout();
|
|
437
458
|
if (this.enableReconnect && !this.skipReconnection) {
|
|
438
459
|
this.reconnect();
|
|
439
460
|
} else {
|
|
@@ -591,6 +612,7 @@ var AbstractRelay = class {
|
|
|
591
612
|
}
|
|
592
613
|
async publish(event) {
|
|
593
614
|
this.idleSince = void 0;
|
|
615
|
+
this.clearIdleTimeout();
|
|
594
616
|
this.ongoingOperations++;
|
|
595
617
|
const ret = new Promise((resolve, reject) => {
|
|
596
618
|
const timeout = setTimeout(() => {
|
|
@@ -602,24 +624,46 @@ var AbstractRelay = class {
|
|
|
602
624
|
}, this.publishTimeout);
|
|
603
625
|
this.openEventPublishes.set(event.id, { resolve, reject, timeout });
|
|
604
626
|
});
|
|
605
|
-
|
|
627
|
+
try {
|
|
628
|
+
await this.send('["EVENT",' + JSON.stringify(event) + "]");
|
|
629
|
+
} catch (err) {
|
|
630
|
+
const ep = this.openEventPublishes.get(event.id);
|
|
631
|
+
if (ep) {
|
|
632
|
+
ep.reject(err);
|
|
633
|
+
this.openEventPublishes.delete(event.id);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
606
636
|
this.ongoingOperations--;
|
|
607
|
-
if (this.ongoingOperations === 0)
|
|
637
|
+
if (this.ongoingOperations === 0) {
|
|
608
638
|
this.idleSince = Date.now();
|
|
639
|
+
this.scheduleIdleClose();
|
|
640
|
+
}
|
|
609
641
|
return ret;
|
|
610
642
|
}
|
|
611
643
|
async count(filters, params) {
|
|
644
|
+
return (await this.countWithHLL(filters, params)).count;
|
|
645
|
+
}
|
|
646
|
+
async countWithHLL(filters, params) {
|
|
612
647
|
this.serial++;
|
|
613
648
|
const id = params?.id || "count:" + this.serial;
|
|
614
649
|
const ret = new Promise((resolve, reject) => {
|
|
615
650
|
this.openCountRequests.set(id, { resolve, reject });
|
|
616
651
|
});
|
|
617
|
-
|
|
652
|
+
try {
|
|
653
|
+
await this.send('["COUNT","' + id + '",' + JSON.stringify(filters).substring(1));
|
|
654
|
+
} catch (err) {
|
|
655
|
+
const cr = this.openCountRequests.get(id);
|
|
656
|
+
if (cr) {
|
|
657
|
+
cr.reject(err);
|
|
658
|
+
this.openCountRequests.delete(id);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
618
661
|
return ret;
|
|
619
662
|
}
|
|
620
663
|
subscribe(filters, params) {
|
|
621
664
|
if (params.label !== "<forced-ping>") {
|
|
622
665
|
this.idleSince = void 0;
|
|
666
|
+
this.clearIdleTimeout();
|
|
623
667
|
this.ongoingOperations++;
|
|
624
668
|
}
|
|
625
669
|
const sub = this.prepareSubscription(filters, params);
|
|
@@ -649,6 +693,7 @@ var AbstractRelay = class {
|
|
|
649
693
|
this.closeAllSubscriptions("relay connection closed by us");
|
|
650
694
|
this._connected = false;
|
|
651
695
|
this.idleSince = void 0;
|
|
696
|
+
this.clearIdleTimeout();
|
|
652
697
|
this.onclose?.();
|
|
653
698
|
if (this.ws?.readyState === this._WebSocket.OPEN) {
|
|
654
699
|
this.ws?.close();
|
|
@@ -692,7 +737,7 @@ var AbstractRelay = class {
|
|
|
692
737
|
const payload = data[2];
|
|
693
738
|
const cr = this.openCountRequests.get(id);
|
|
694
739
|
if (cr) {
|
|
695
|
-
cr.resolve(payload
|
|
740
|
+
cr.resolve(payload);
|
|
696
741
|
this.openCountRequests.delete(id);
|
|
697
742
|
}
|
|
698
743
|
return;
|
|
@@ -722,8 +767,14 @@ var AbstractRelay = class {
|
|
|
722
767
|
case "CLOSED": {
|
|
723
768
|
const id = data[1];
|
|
724
769
|
const so = this.openSubs.get(id);
|
|
725
|
-
if (!so)
|
|
770
|
+
if (!so) {
|
|
771
|
+
const cr = this.openCountRequests.get(id);
|
|
772
|
+
if (cr) {
|
|
773
|
+
cr.reject(new Error(data[2]));
|
|
774
|
+
this.openCountRequests.delete(id);
|
|
775
|
+
}
|
|
726
776
|
return;
|
|
777
|
+
}
|
|
727
778
|
so.closed = true;
|
|
728
779
|
so.close(data[2]);
|
|
729
780
|
return;
|
|
@@ -820,8 +871,10 @@ var Subscription = class {
|
|
|
820
871
|
}
|
|
821
872
|
this.relay.openSubs.delete(this.id);
|
|
822
873
|
this.relay.ongoingOperations--;
|
|
823
|
-
if (this.relay.ongoingOperations === 0)
|
|
874
|
+
if (this.relay.ongoingOperations === 0) {
|
|
824
875
|
this.relay.idleSince = Date.now();
|
|
876
|
+
this.relay.scheduleIdleClose();
|
|
877
|
+
}
|
|
825
878
|
this.onclose?.(reason);
|
|
826
879
|
}
|
|
827
880
|
};
|
|
@@ -832,6 +885,63 @@ var alwaysTrue = (t) => {
|
|
|
832
885
|
return true;
|
|
833
886
|
};
|
|
834
887
|
|
|
888
|
+
// nip45.ts
|
|
889
|
+
var import_sha23 = require("@noble/hashes/sha2.js");
|
|
890
|
+
var import_utils8 = require("@noble/hashes/utils.js");
|
|
891
|
+
var M = 256;
|
|
892
|
+
var HLL_HEX_LENGTH = M * 2;
|
|
893
|
+
var utf8Encoder2 = new TextEncoder();
|
|
894
|
+
function getCountManyFilter(target, directive) {
|
|
895
|
+
switch (directive) {
|
|
896
|
+
case "reactions":
|
|
897
|
+
return { "#e": [target], kinds: [7] };
|
|
898
|
+
case "reposts":
|
|
899
|
+
return { "#e": [target], kinds: [6] };
|
|
900
|
+
case "quotes":
|
|
901
|
+
return { "#q": [target], kinds: [1, 1111] };
|
|
902
|
+
case "replies":
|
|
903
|
+
return { "#e": [target], kinds: [1] };
|
|
904
|
+
case "comments":
|
|
905
|
+
return { "#E": [target], kinds: [1111] };
|
|
906
|
+
case "followers":
|
|
907
|
+
return { "#p": [target], kinds: [3] };
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
function newHll() {
|
|
911
|
+
return new Uint8Array(M);
|
|
912
|
+
}
|
|
913
|
+
function hllDecode(hex) {
|
|
914
|
+
if (hex.length !== HLL_HEX_LENGTH || !/^[0-9a-fA-F]+$/.test(hex))
|
|
915
|
+
return void 0;
|
|
916
|
+
const registers = new Uint8Array(M);
|
|
917
|
+
for (let i2 = 0; i2 < M; i2++) {
|
|
918
|
+
registers[i2] = parseInt(hex.slice(i2 * 2, i2 * 2 + 2), 16);
|
|
919
|
+
}
|
|
920
|
+
return registers;
|
|
921
|
+
}
|
|
922
|
+
function hllEncode(registers) {
|
|
923
|
+
if (registers.length !== M)
|
|
924
|
+
throw new Error(`invalid number of registers ${registers.length}`);
|
|
925
|
+
let hex = "";
|
|
926
|
+
for (let i2 = 0; i2 < M; i2++) {
|
|
927
|
+
hex += registers[i2].toString(16).padStart(2, "0");
|
|
928
|
+
}
|
|
929
|
+
return hex;
|
|
930
|
+
}
|
|
931
|
+
function mergeHll(target, source) {
|
|
932
|
+
if (target.length === 0)
|
|
933
|
+
target = newHll();
|
|
934
|
+
if (target.length !== M)
|
|
935
|
+
throw new Error(`invalid number of registers ${target.length}`);
|
|
936
|
+
if (source.length !== M)
|
|
937
|
+
throw new Error(`invalid number of registers ${source.length}`);
|
|
938
|
+
for (let i2 = 0; i2 < M; i2++) {
|
|
939
|
+
if (source[i2] > target[i2])
|
|
940
|
+
target[i2] = source[i2];
|
|
941
|
+
}
|
|
942
|
+
return target;
|
|
943
|
+
}
|
|
944
|
+
|
|
835
945
|
// abstract-pool.ts
|
|
836
946
|
var AbstractSimplePool = class {
|
|
837
947
|
relays = /* @__PURE__ */ new Map();
|
|
@@ -840,6 +950,7 @@ var AbstractSimplePool = class {
|
|
|
840
950
|
verifyEvent;
|
|
841
951
|
enablePing;
|
|
842
952
|
enableReconnect;
|
|
953
|
+
idleTimeout = 2e4;
|
|
843
954
|
automaticallyAuth;
|
|
844
955
|
trustedRelayURLs = /* @__PURE__ */ new Set();
|
|
845
956
|
onRelayConnectionFailure;
|
|
@@ -852,6 +963,8 @@ var AbstractSimplePool = class {
|
|
|
852
963
|
this._WebSocket = opts.websocketImplementation;
|
|
853
964
|
this.enablePing = opts.enablePing;
|
|
854
965
|
this.enableReconnect = opts.enableReconnect || false;
|
|
966
|
+
if (opts.idleTimeout)
|
|
967
|
+
this.idleTimeout = opts.idleTimeout;
|
|
855
968
|
this.automaticallyAuth = opts.automaticallyAuth;
|
|
856
969
|
this.onRelayConnectionFailure = opts.onRelayConnectionFailure;
|
|
857
970
|
this.onRelayConnectionSuccess = opts.onRelayConnectionSuccess;
|
|
@@ -866,7 +979,8 @@ var AbstractSimplePool = class {
|
|
|
866
979
|
verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,
|
|
867
980
|
websocketImplementation: this._WebSocket,
|
|
868
981
|
enablePing: this.enablePing,
|
|
869
|
-
enableReconnect: this.enableReconnect
|
|
982
|
+
enableReconnect: this.enableReconnect,
|
|
983
|
+
idleTimeout: this.idleTimeout
|
|
870
984
|
});
|
|
871
985
|
relay.onclose = () => {
|
|
872
986
|
this.relays.delete(url);
|
|
@@ -1059,6 +1173,48 @@ var AbstractSimplePool = class {
|
|
|
1059
1173
|
events.sort((a, b) => b.created_at - a.created_at);
|
|
1060
1174
|
return events[0] || null;
|
|
1061
1175
|
}
|
|
1176
|
+
async countMany(relays, target, directive, params) {
|
|
1177
|
+
const filter = getCountManyFilter(target, directive);
|
|
1178
|
+
const urls = [];
|
|
1179
|
+
for (let i2 = 0; i2 < relays.length; i2++) {
|
|
1180
|
+
const url = normalizeURL(relays[i2]);
|
|
1181
|
+
if (urls.indexOf(url) === -1)
|
|
1182
|
+
urls.push(url);
|
|
1183
|
+
}
|
|
1184
|
+
const responses = await Promise.all(
|
|
1185
|
+
urls.map(async (url) => {
|
|
1186
|
+
if (this.allowConnectingToRelay?.(url, ["read", [filter]]) === false)
|
|
1187
|
+
return null;
|
|
1188
|
+
let relay;
|
|
1189
|
+
try {
|
|
1190
|
+
relay = await this.ensureRelay(url, {
|
|
1191
|
+
connectionTimeout: this.maxWaitForConnection < (params?.maxWait || 0) ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : this.maxWaitForConnection,
|
|
1192
|
+
abort: params?.abort
|
|
1193
|
+
});
|
|
1194
|
+
} catch (err) {
|
|
1195
|
+
this.onRelayConnectionFailure?.(url);
|
|
1196
|
+
return null;
|
|
1197
|
+
}
|
|
1198
|
+
this.onRelayConnectionSuccess?.(url);
|
|
1199
|
+
return relay.countWithHLL([filter], { id: params?.id }).catch(() => null);
|
|
1200
|
+
})
|
|
1201
|
+
);
|
|
1202
|
+
let count = 0;
|
|
1203
|
+
let hll;
|
|
1204
|
+
for (const response of responses) {
|
|
1205
|
+
if (!response)
|
|
1206
|
+
continue;
|
|
1207
|
+
if (response.count > count)
|
|
1208
|
+
count = response.count;
|
|
1209
|
+
if (!response.hll || response.hll.length !== 512)
|
|
1210
|
+
continue;
|
|
1211
|
+
const registers = hllDecode(response.hll);
|
|
1212
|
+
if (!registers)
|
|
1213
|
+
continue;
|
|
1214
|
+
hll = mergeHll(hll || new Uint8Array(0), registers);
|
|
1215
|
+
}
|
|
1216
|
+
return hll ? { count, hll: hllEncode(hll) } : { count };
|
|
1217
|
+
}
|
|
1062
1218
|
publish(relays, event, params) {
|
|
1063
1219
|
return relays.map(normalizeURL).map(async (url, i2, arr) => {
|
|
1064
1220
|
if (arr.indexOf(url) !== i2) {
|