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.
Files changed (74) hide show
  1. package/lib/cjs/abstract-pool.js +163 -7
  2. package/lib/cjs/abstract-pool.js.map +4 -4
  3. package/lib/cjs/abstract-relay.js +59 -6
  4. package/lib/cjs/abstract-relay.js.map +2 -2
  5. package/lib/cjs/filter.js.map +1 -1
  6. package/lib/cjs/index.js +412 -64
  7. package/lib/cjs/index.js.map +4 -4
  8. package/lib/cjs/kinds.js +196 -4
  9. package/lib/cjs/kinds.js.map +2 -2
  10. package/lib/cjs/nip17.js.map +2 -2
  11. package/lib/cjs/nip18.js.map +2 -2
  12. package/lib/cjs/nip25.js.map +1 -1
  13. package/lib/cjs/nip28.js.map +2 -2
  14. package/lib/cjs/nip42.js.map +2 -2
  15. package/lib/cjs/nip45.js +183 -0
  16. package/lib/cjs/nip45.js.map +7 -0
  17. package/lib/cjs/nip46.js +163 -7
  18. package/lib/cjs/nip46.js.map +4 -4
  19. package/lib/cjs/nip47.js.map +2 -2
  20. package/lib/cjs/nip57.js.map +1 -1
  21. package/lib/cjs/nip58.js.map +2 -2
  22. package/lib/cjs/nip59.js.map +2 -2
  23. package/lib/cjs/nip75.js.map +2 -2
  24. package/lib/cjs/nip94.js.map +2 -2
  25. package/lib/cjs/nip98.js.map +2 -2
  26. package/lib/cjs/nip99.js.map +2 -2
  27. package/lib/cjs/nipb0.js +1064 -0
  28. package/lib/cjs/nipb0.js.map +7 -0
  29. package/lib/cjs/pool.js +163 -7
  30. package/lib/cjs/pool.js.map +4 -4
  31. package/lib/cjs/relay.js +59 -6
  32. package/lib/cjs/relay.js.map +2 -2
  33. package/lib/esm/abstract-pool.js +163 -7
  34. package/lib/esm/abstract-pool.js.map +4 -4
  35. package/lib/esm/abstract-relay.js +59 -6
  36. package/lib/esm/abstract-relay.js.map +2 -2
  37. package/lib/esm/filter.js.map +1 -1
  38. package/lib/esm/index.js +388 -40
  39. package/lib/esm/index.js.map +4 -4
  40. package/lib/esm/kinds.js +196 -4
  41. package/lib/esm/kinds.js.map +2 -2
  42. package/lib/esm/nip17.js.map +2 -2
  43. package/lib/esm/nip18.js.map +2 -2
  44. package/lib/esm/nip25.js.map +1 -1
  45. package/lib/esm/nip28.js.map +2 -2
  46. package/lib/esm/nip42.js.map +2 -2
  47. package/lib/esm/nip45.js +162 -0
  48. package/lib/esm/nip45.js.map +7 -0
  49. package/lib/esm/nip46.js +163 -7
  50. package/lib/esm/nip46.js.map +4 -4
  51. package/lib/esm/nip47.js.map +2 -2
  52. package/lib/esm/nip57.js.map +1 -1
  53. package/lib/esm/nip58.js.map +2 -2
  54. package/lib/esm/nip59.js.map +2 -2
  55. package/lib/esm/nip75.js.map +2 -2
  56. package/lib/esm/nip94.js.map +2 -2
  57. package/lib/esm/nip98.js.map +2 -2
  58. package/lib/esm/nip99.js.map +2 -2
  59. package/lib/esm/nipb0.js +1049 -0
  60. package/lib/esm/nipb0.js.map +7 -0
  61. package/lib/esm/pool.js +163 -7
  62. package/lib/esm/pool.js.map +4 -4
  63. package/lib/esm/relay.js +59 -6
  64. package/lib/esm/relay.js.map +2 -2
  65. package/lib/nostr.bundle.js +361 -15
  66. package/lib/nostr.bundle.js.map +4 -4
  67. package/lib/types/abstract-pool.d.ts +10 -0
  68. package/lib/types/abstract-relay.d.ts +15 -1
  69. package/lib/types/kinds.d.ts +200 -8
  70. package/lib/types/nip45.d.ts +13 -0
  71. package/lib/types/nip45.test.d.ts +1 -0
  72. package/lib/types/nipb0.d.ts +129 -0
  73. package/lib/types/relay.d.ts +2 -2
  74. 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
- this.send('["EVENT",' + JSON.stringify(event) + "]");
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
- this.send('["COUNT","' + id + '",' + JSON.stringify(filters).substring(1));
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.count);
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) {