nostr-tools 1.13.1 → 1.14.2

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/README.md CHANGED
@@ -108,13 +108,7 @@ let event = {
108
108
  event.id = getEventHash(event)
109
109
  event.sig = getSignature(event, sk)
110
110
 
111
- let pub = relay.publish(event)
112
- pub.on('ok', () => {
113
- console.log(`${relay.url} has accepted our event`)
114
- })
115
- pub.on('failed', reason => {
116
- console.log(`failed to publish to ${relay.url}: ${reason}`)
117
- })
111
+ await relay.publish(event)
118
112
 
119
113
  let events = await relay.list([{kinds: [0, 1]}])
120
114
  let event = await relay.get({
package/lib/esm/nostr.mjs CHANGED
@@ -211,6 +211,7 @@ var Kind = /* @__PURE__ */ ((Kind3) => {
211
211
  Kind3[Kind3["ProfileBadge"] = 30008] = "ProfileBadge";
212
212
  Kind3[Kind3["BadgeDefinition"] = 30009] = "BadgeDefinition";
213
213
  Kind3[Kind3["Article"] = 30023] = "Article";
214
+ Kind3[Kind3["FileMetadata"] = 1063] = "FileMetadata";
214
215
  return Kind3;
215
216
  })(Kind || {});
216
217
  function getBlankEvent(kind = 255 /* Blank */) {
@@ -491,12 +492,11 @@ function relayInit(url, options = {}) {
491
492
  let ok = data[2];
492
493
  let reason = data[3] || "";
493
494
  if (id2 in pubListeners) {
495
+ let { resolve: resolve2, reject: reject2 } = pubListeners[id2];
494
496
  if (ok)
495
- pubListeners[id2].ok.forEach((cb) => cb());
497
+ resolve2(null);
496
498
  else
497
- pubListeners[id2].failed.forEach((cb) => cb(reason));
498
- pubListeners[id2].ok = [];
499
- pubListeners[id2].failed = [];
499
+ reject2(new Error(reason));
500
500
  }
501
501
  return;
502
502
  }
@@ -581,27 +581,15 @@ function relayInit(url, options = {}) {
581
581
  };
582
582
  };
583
583
  function _publishEvent(event, type) {
584
- if (!event.id)
585
- throw new Error(`event ${event} has no id`);
586
- let id = event.id;
587
- trySend([type, event]);
588
- return {
589
- on: (type2, cb) => {
590
- pubListeners[id] = pubListeners[id] || {
591
- ok: [],
592
- failed: []
593
- };
594
- pubListeners[id][type2].push(cb);
595
- },
596
- off: (type2, cb) => {
597
- let listeners2 = pubListeners[id];
598
- if (!listeners2)
599
- return;
600
- let idx = listeners2[type2].indexOf(cb);
601
- if (idx >= 0)
602
- listeners2[type2].splice(idx, 1);
584
+ return new Promise((resolve, reject) => {
585
+ if (!event.id) {
586
+ reject(new Error(`event ${event} has no id`));
587
+ return;
603
588
  }
604
- };
589
+ let id = event.id;
590
+ trySend([type, event]);
591
+ pubListeners[id] = { resolve, reject };
592
+ });
605
593
  }
606
594
  return {
607
595
  url,
@@ -658,19 +646,19 @@ function relayInit(url, options = {}) {
658
646
  resolve(event);
659
647
  });
660
648
  }),
661
- publish(event) {
662
- return _publishEvent(event, "EVENT");
649
+ async publish(event) {
650
+ await _publishEvent(event, "EVENT");
663
651
  },
664
- auth(event) {
665
- return _publishEvent(event, "AUTH");
652
+ async auth(event) {
653
+ await _publishEvent(event, "AUTH");
666
654
  },
667
655
  connect,
668
656
  close() {
669
657
  listeners = newListeners();
670
658
  subListeners = {};
671
659
  pubListeners = {};
672
- if (ws.readyState === WebSocket.OPEN) {
673
- ws?.close();
660
+ if (ws?.readyState === WebSocket.OPEN) {
661
+ ws.close();
674
662
  }
675
663
  },
676
664
  get status() {
@@ -683,14 +671,17 @@ function relayInit(url, options = {}) {
683
671
  var SimplePool = class {
684
672
  _conn;
685
673
  _seenOn = {};
674
+ batchedByKey = {};
686
675
  eoseSubTimeout;
687
676
  getTimeout;
688
677
  seenOnEnabled = true;
678
+ batchInterval = 100;
689
679
  constructor(options = {}) {
690
680
  this._conn = {};
691
681
  this.eoseSubTimeout = options.eoseSubTimeout || 3400;
692
682
  this.getTimeout = options.getTimeout || 3400;
693
683
  this.seenOnEnabled = options.seenOnEnabled !== false;
684
+ this.batchInterval = options.batchInterval || 100;
694
685
  }
695
686
  close(relays) {
696
687
  relays.forEach((url) => {
@@ -735,7 +726,7 @@ var SimplePool = class {
735
726
  for (let cb of eoseListeners.values())
736
727
  cb();
737
728
  }, this.eoseSubTimeout);
738
- relays.forEach(async (relay) => {
729
+ relays.filter((r, i, a) => a.indexOf(r) == i).forEach(async (relay) => {
739
730
  let r;
740
731
  try {
741
732
  r = await this.ensureRelay(relay);
@@ -817,38 +808,54 @@ var SimplePool = class {
817
808
  });
818
809
  });
819
810
  }
820
- publish(relays, event) {
821
- const pubPromises = relays.map(async (relay) => {
822
- let r;
823
- try {
824
- r = await this.ensureRelay(relay);
825
- return r.publish(event);
826
- } catch (_) {
827
- return { on() {
828
- }, off() {
829
- } };
830
- }
831
- });
832
- const callbackMap = /* @__PURE__ */ new Map();
833
- return {
834
- on(type, cb) {
835
- relays.forEach(async (relay, i) => {
836
- let pub = await pubPromises[i];
837
- let callback = () => cb(relay);
838
- callbackMap.set(cb, callback);
839
- pub.on(type, callback);
840
- });
841
- },
842
- off(type, cb) {
843
- relays.forEach(async (_, i) => {
844
- let callback = callbackMap.get(cb);
845
- if (callback) {
846
- let pub = await pubPromises[i];
847
- pub.off(type, callback);
811
+ batchedList(batchKey, relays, filters) {
812
+ return new Promise((resolve) => {
813
+ if (!this.batchedByKey[batchKey]) {
814
+ this.batchedByKey[batchKey] = [
815
+ {
816
+ filters,
817
+ relays,
818
+ resolve,
819
+ events: []
848
820
  }
821
+ ];
822
+ setTimeout(() => {
823
+ Object.keys(this.batchedByKey).forEach(async (batchKey2) => {
824
+ const batchedRequests = this.batchedByKey[batchKey2];
825
+ const filters2 = [];
826
+ const relays2 = [];
827
+ batchedRequests.forEach((br) => {
828
+ filters2.push(...br.filters);
829
+ relays2.push(...br.relays);
830
+ });
831
+ const sub = this.sub(relays2, filters2);
832
+ sub.on("event", (event) => {
833
+ batchedRequests.forEach(
834
+ (br) => matchFilters(br.filters, event) && br.events.push(event)
835
+ );
836
+ });
837
+ sub.on("eose", () => {
838
+ sub.unsub();
839
+ batchedRequests.forEach((br) => br.resolve(br.events));
840
+ });
841
+ delete this.batchedByKey[batchKey2];
842
+ });
843
+ }, this.batchInterval);
844
+ } else {
845
+ this.batchedByKey[batchKey].push({
846
+ filters,
847
+ relays,
848
+ resolve,
849
+ events: []
849
850
  });
850
851
  }
851
- };
852
+ });
853
+ }
854
+ publish(relays, event) {
855
+ return relays.map(async (relay) => {
856
+ let r = await this.ensureRelay(relay);
857
+ return r.publish(event);
858
+ });
852
859
  }
853
860
  seenOn(id) {
854
861
  return Array.from(this._seenOn[id]?.values?.() || []);
@@ -1578,6 +1585,107 @@ function replaceAll(content, replacer) {
1578
1585
  });
1579
1586
  }
1580
1587
 
1588
+ // nip28.ts
1589
+ var nip28_exports = {};
1590
+ __export(nip28_exports, {
1591
+ channelCreateEvent: () => channelCreateEvent,
1592
+ channelHideMessageEvent: () => channelHideMessageEvent,
1593
+ channelMessageEvent: () => channelMessageEvent,
1594
+ channelMetadataEvent: () => channelMetadataEvent,
1595
+ channelMuteUserEvent: () => channelMuteUserEvent
1596
+ });
1597
+ var channelCreateEvent = (t, privateKey) => {
1598
+ let content;
1599
+ if (typeof t.content === "object") {
1600
+ content = JSON.stringify(t.content);
1601
+ } else if (typeof t.content === "string") {
1602
+ content = t.content;
1603
+ } else {
1604
+ return void 0;
1605
+ }
1606
+ return finishEvent(
1607
+ {
1608
+ kind: 40 /* ChannelCreation */,
1609
+ tags: [...t.tags ?? []],
1610
+ content,
1611
+ created_at: t.created_at
1612
+ },
1613
+ privateKey
1614
+ );
1615
+ };
1616
+ var channelMetadataEvent = (t, privateKey) => {
1617
+ let content;
1618
+ if (typeof t.content === "object") {
1619
+ content = JSON.stringify(t.content);
1620
+ } else if (typeof t.content === "string") {
1621
+ content = t.content;
1622
+ } else {
1623
+ return void 0;
1624
+ }
1625
+ return finishEvent(
1626
+ {
1627
+ kind: 41 /* ChannelMetadata */,
1628
+ tags: [["e", t.channel_create_event_id], ...t.tags ?? []],
1629
+ content,
1630
+ created_at: t.created_at
1631
+ },
1632
+ privateKey
1633
+ );
1634
+ };
1635
+ var channelMessageEvent = (t, privateKey) => {
1636
+ const tags = [["e", t.channel_create_event_id, t.relay_url, "root"]];
1637
+ if (t.reply_to_channel_message_event_id) {
1638
+ tags.push(["e", t.reply_to_channel_message_event_id, t.relay_url, "reply"]);
1639
+ }
1640
+ return finishEvent(
1641
+ {
1642
+ kind: 42 /* ChannelMessage */,
1643
+ tags: [...tags, ...t.tags ?? []],
1644
+ content: t.content,
1645
+ created_at: t.created_at
1646
+ },
1647
+ privateKey
1648
+ );
1649
+ };
1650
+ var channelHideMessageEvent = (t, privateKey) => {
1651
+ let content;
1652
+ if (typeof t.content === "object") {
1653
+ content = JSON.stringify(t.content);
1654
+ } else if (typeof t.content === "string") {
1655
+ content = t.content;
1656
+ } else {
1657
+ return void 0;
1658
+ }
1659
+ return finishEvent(
1660
+ {
1661
+ kind: 43 /* ChannelHideMessage */,
1662
+ tags: [["e", t.channel_message_event_id], ...t.tags ?? []],
1663
+ content,
1664
+ created_at: t.created_at
1665
+ },
1666
+ privateKey
1667
+ );
1668
+ };
1669
+ var channelMuteUserEvent = (t, privateKey) => {
1670
+ let content;
1671
+ if (typeof t.content === "object") {
1672
+ content = JSON.stringify(t.content);
1673
+ } else if (typeof t.content === "string") {
1674
+ content = t.content;
1675
+ } else {
1676
+ return void 0;
1677
+ }
1678
+ return finishEvent(
1679
+ {
1680
+ kind: 44 /* ChannelMuteUser */,
1681
+ tags: [["p", t.pubkey_to_mute], ...t.tags ?? []],
1682
+ content,
1683
+ created_at: t.created_at
1684
+ },
1685
+ privateKey
1686
+ );
1687
+ };
1688
+
1581
1689
  // nip39.ts
1582
1690
  var nip39_exports = {};
1583
1691
  __export(nip39_exports, {
@@ -1620,19 +1728,46 @@ var authenticate = async ({
1620
1728
  ],
1621
1729
  content: ""
1622
1730
  };
1623
- const pub = relay.auth(await sign(e));
1624
- return new Promise((resolve, reject) => {
1625
- pub.on("ok", function ok() {
1626
- pub.off("ok", ok);
1627
- resolve();
1628
- });
1629
- pub.on("failed", function fail(reason) {
1630
- pub.off("failed", fail);
1631
- reject(reason);
1632
- });
1633
- });
1731
+ return relay.auth(await sign(e));
1634
1732
  };
1635
1733
 
1734
+ // nip44.ts
1735
+ var nip44_exports = {};
1736
+ __export(nip44_exports, {
1737
+ decrypt: () => decrypt2,
1738
+ encrypt: () => encrypt2,
1739
+ getSharedSecret: () => getSharedSecret
1740
+ });
1741
+ import { base64 as base642 } from "@scure/base";
1742
+ import { randomBytes as randomBytes2 } from "@noble/hashes/utils";
1743
+ import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1";
1744
+ import { sha256 as sha2563 } from "@noble/hashes/sha256";
1745
+ import { xchacha20 } from "@noble/ciphers/chacha";
1746
+ var getSharedSecret = (privkey, pubkey) => sha2563(secp256k12.getSharedSecret(privkey, "02" + pubkey).subarray(1, 33));
1747
+ function encrypt2(key, text, v = 1) {
1748
+ if (v !== 1) {
1749
+ throw new Error("NIP44: unknown encryption version");
1750
+ }
1751
+ const nonce = randomBytes2(24);
1752
+ const plaintext = utf8Encoder.encode(text);
1753
+ const ciphertext = xchacha20(key, nonce, plaintext);
1754
+ const payload = new Uint8Array(25 + ciphertext.length);
1755
+ payload.set([v], 0);
1756
+ payload.set(nonce, 1);
1757
+ payload.set(ciphertext, 25);
1758
+ return base642.encode(payload);
1759
+ }
1760
+ function decrypt2(key, payload) {
1761
+ let data = base642.decode(payload);
1762
+ if (data[0] !== 1) {
1763
+ throw new Error(`NIP44: unknown encryption version: ${data[0]}`);
1764
+ }
1765
+ const nonce = data.slice(1, 25);
1766
+ const ciphertext = data.slice(25);
1767
+ const plaintext = xchacha20(key, nonce, ciphertext);
1768
+ return utf8Decoder.decode(plaintext);
1769
+ }
1770
+
1636
1771
  // nip57.ts
1637
1772
  var nip57_exports = {};
1638
1773
  __export(nip57_exports, {
@@ -1754,15 +1889,15 @@ function makeZapReceipt({
1754
1889
  var nip98_exports = {};
1755
1890
  __export(nip98_exports, {
1756
1891
  getToken: () => getToken,
1892
+ unpackEventFromToken: () => unpackEventFromToken,
1893
+ validateEvent: () => validateEvent2,
1757
1894
  validateToken: () => validateToken
1758
1895
  });
1759
- import { base64 as base642 } from "@scure/base";
1896
+ import { base64 as base643 } from "@scure/base";
1760
1897
  var _authorizationScheme = "Nostr ";
1761
1898
  async function getToken(loginUrl, httpMethod, sign, includeAuthorizationScheme = false) {
1762
1899
  if (!loginUrl || !httpMethod)
1763
1900
  throw new Error("Missing loginUrl or httpMethod");
1764
- if (httpMethod !== "get" /* Get */ && httpMethod !== "post" /* Post */)
1765
- throw new Error("Unknown httpMethod");
1766
1901
  const event = getBlankEvent(27235 /* HttpAuth */);
1767
1902
  event.tags = [
1768
1903
  ["u", loginUrl],
@@ -1771,18 +1906,30 @@ async function getToken(loginUrl, httpMethod, sign, includeAuthorizationScheme =
1771
1906
  event.created_at = Math.round(new Date().getTime() / 1e3);
1772
1907
  const signedEvent = await sign(event);
1773
1908
  const authorizationScheme = includeAuthorizationScheme ? _authorizationScheme : "";
1774
- return authorizationScheme + base642.encode(utf8Encoder.encode(JSON.stringify(signedEvent)));
1909
+ return authorizationScheme + base643.encode(utf8Encoder.encode(JSON.stringify(signedEvent)));
1775
1910
  }
1776
1911
  async function validateToken(token, url, method) {
1912
+ const event = await unpackEventFromToken(token).catch((error) => {
1913
+ throw error;
1914
+ });
1915
+ const valid = await validateEvent2(event, url, method).catch((error) => {
1916
+ throw error;
1917
+ });
1918
+ return valid;
1919
+ }
1920
+ async function unpackEventFromToken(token) {
1777
1921
  if (!token) {
1778
1922
  throw new Error("Missing token");
1779
1923
  }
1780
1924
  token = token.replace(_authorizationScheme, "");
1781
- const eventB64 = utf8Decoder.decode(base642.decode(token));
1925
+ const eventB64 = utf8Decoder.decode(base643.decode(token));
1782
1926
  if (!eventB64 || eventB64.length === 0 || !eventB64.startsWith("{")) {
1783
1927
  throw new Error("Invalid token");
1784
1928
  }
1785
1929
  const event = JSON.parse(eventB64);
1930
+ return event;
1931
+ }
1932
+ async function validateEvent2(event, url, method) {
1786
1933
  if (!event) {
1787
1934
  throw new Error("Invalid nostr event");
1788
1935
  }
@@ -1832,8 +1979,10 @@ export {
1832
1979
  nip25_exports as nip25,
1833
1980
  nip26_exports as nip26,
1834
1981
  nip27_exports as nip27,
1982
+ nip28_exports as nip28,
1835
1983
  nip39_exports as nip39,
1836
1984
  nip42_exports as nip42,
1985
+ nip44_exports as nip44,
1837
1986
  nip57_exports as nip57,
1838
1987
  nip98_exports as nip98,
1839
1988
  parseReferences,