nostr-tools
2.20.02.21.0
~
Modified (124 files)
Index: package/lib/cjs/abstract-pool.js
===================================================================
--- package/lib/cjs/abstract-pool.js
+++ package/lib/cjs/abstract-pool.js
@@ -27,9 +27,9 @@
// core.ts
var verifiedSymbol = Symbol("verified");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try { Index: package/lib/esm/abstract-pool.js
===================================================================
--- package/lib/esm/abstract-pool.js
+++ package/lib/esm/abstract-pool.js
@@ -1,9 +1,9 @@
// core.ts
var verifiedSymbol = Symbol("verified");
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try { Index: package/lib/cjs/abstract-relay.js
===================================================================
--- package/lib/cjs/abstract-relay.js
+++ package/lib/cjs/abstract-relay.js
@@ -26,9 +26,9 @@
});
module.exports = __toCommonJS(abstract_relay_exports);
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try { Index: package/lib/esm/abstract-relay.js
===================================================================
--- package/lib/esm/abstract-relay.js
+++ package/lib/esm/abstract-relay.js
@@ -1,6 +1,6 @@
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try { Index: package/lib/cjs/index.js
===================================================================
--- package/lib/cjs/index.js
+++ package/lib/cjs/index.js
@@ -64,10 +64,10 @@
});
module.exports = __toCommonJS(nostr_tools_exports);
// pure.ts
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -106,9 +106,9 @@
});
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
var utils_exports = {};
__export(utils_exports, {
@@ -122,9 +122,9 @@
normalizeURL: () => normalizeURL,
utf8Decoder: () => utf8Decoder,
utf8Encoder: () => utf8Encoder
});
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try {
@@ -241,18 +241,18 @@
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -263,9 +263,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -278,9 +278,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey;
@@ -1434,9 +1434,9 @@
nprofileEncode: () => nprofileEncode,
npubEncode: () => npubEncode,
nsecEncode: () => nsecEncode
});
-var import_utils6 = require("@noble/hashes/utils");
+var import_utils6 = require("@noble/hashes/utils.js");
var import_base = require("@scure/base");
var NostrTypeGuard = {
isNProfile: (value) => /^nprofile1[a-z\d]+$/.test(value || ""),
isNEvent: (value) => /^nevent1[a-z\d]+$/.test(value || ""),
@@ -1704,15 +1704,15 @@
__export(nip04_exports, {
decrypt: () => decrypt,
encrypt: () => encrypt
});
-var import_utils8 = require("@noble/hashes/utils");
-var import_secp256k12 = require("@noble/curves/secp256k1");
-var import_aes = require("@noble/ciphers/aes");
+var import_utils8 = require("@noble/hashes/utils.js");
+var import_secp256k12 = require("@noble/curves/secp256k1.js");
+var import_aes = require("@noble/ciphers/aes.js");
var import_base2 = require("@scure/base");
function encrypt(secretKey, pubkey, text) {
- const privkey = secretKey instanceof Uint8Array ? (0, import_utils8.bytesToHex)(secretKey) : secretKey;
- const key = import_secp256k12.secp256k1.getSharedSecret(privkey, "02" + pubkey);
+ const privkey = secretKey instanceof Uint8Array ? secretKey : (0, import_utils8.hexToBytes)(secretKey);
+ const key = import_secp256k12.secp256k1.getSharedSecret(privkey, (0, import_utils8.hexToBytes)("02" + pubkey));
const normalizedKey = getNormalizedX(key);
let iv = Uint8Array.from((0, import_utils8.randomBytes)(16));
let plaintext = utf8Encoder.encode(text);
let ciphertext = (0, import_aes.cbc)(normalizedKey, iv).encrypt(plaintext);
@@ -1720,11 +1720,11 @@
let ivb64 = import_base2.base64.encode(new Uint8Array(iv.buffer));
return `${ctb64}?iv=${ivb64}`;
}
function decrypt(secretKey, pubkey, data) {
- const privkey = secretKey instanceof Uint8Array ? (0, import_utils8.bytesToHex)(secretKey) : secretKey;
+ const privkey = secretKey instanceof Uint8Array ? secretKey : (0, import_utils8.hexToBytes)(secretKey);
let [ctb64, ivb64] = data.split("?iv=");
- let key = import_secp256k12.secp256k1.getSharedSecret(privkey, "02" + pubkey);
+ let key = import_secp256k12.secp256k1.getSharedSecret(privkey, (0, import_utils8.hexToBytes)("02" + pubkey));
let normalizedKey = getNormalizedX(key);
let iv = import_base2.base64.decode(ivb64);
let ciphertext = import_base2.base64.decode(ctb64);
let plaintext = (0, import_aes.cbc)(normalizedKey, iv).decrypt(ciphertext);
@@ -1922,10 +1922,10 @@
fastEventHash: () => fastEventHash,
getPow: () => getPow,
minePow: () => minePow
});
-var import_utils10 = require("@noble/hashes/utils");
-var import_sha2562 = require("@noble/hashes/sha256");
+var import_utils10 = require("@noble/hashes/utils.js");
+var import_sha22 = require("@noble/hashes/sha2.js");
function getPow(hex) {
let count = 0;
for (let i2 = 0; i2 < 64; i2 += 8) {
const nibble = parseInt(hex.substring(i2, i2 + 8), 16);
@@ -1958,9 +1958,9 @@
return event;
}
function fastEventHash(evt) {
return (0, import_utils10.bytesToHex)(
- (0, import_sha2562.sha256)(utf8Encoder.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])))
+ (0, import_sha22.sha256)(utf8Encoder.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])))
);
}
// nip17.ts
@@ -1991,24 +1991,24 @@
encrypt: () => encrypt2,
getConversationKey: () => getConversationKey,
v2: () => v2
});
-var import_chacha = require("@noble/ciphers/chacha");
-var import_utils12 = require("@noble/ciphers/utils");
-var import_secp256k13 = require("@noble/curves/secp256k1");
-var import_hkdf = require("@noble/hashes/hkdf");
-var import_hmac = require("@noble/hashes/hmac");
-var import_sha2563 = require("@noble/hashes/sha256");
-var import_utils13 = require("@noble/hashes/utils");
+var import_chacha = require("@noble/ciphers/chacha.js");
+var import_utils12 = require("@noble/ciphers/utils.js");
+var import_secp256k13 = require("@noble/curves/secp256k1.js");
+var import_hkdf = require("@noble/hashes/hkdf.js");
+var import_hmac = require("@noble/hashes/hmac.js");
+var import_sha23 = require("@noble/hashes/sha2.js");
+var import_utils13 = require("@noble/hashes/utils.js");
var import_base3 = require("@scure/base");
var minPlaintextSize = 1;
var maxPlaintextSize = 65535;
function getConversationKey(privkeyA, pubkeyB) {
- const sharedX = import_secp256k13.secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
- return (0, import_hkdf.extract)(import_sha2563.sha256, sharedX, "nip44-v2");
+ const sharedX = import_secp256k13.secp256k1.getSharedSecret(privkeyA, (0, import_utils13.hexToBytes)("02" + pubkeyB)).subarray(1, 33);
+ return (0, import_hkdf.extract)(import_sha23.sha256, sharedX, utf8Encoder.encode("nip44-v2"));
}
function getMessageKeys(conversationKey, nonce) {
- const keys = (0, import_hkdf.expand)(import_sha2563.sha256, conversationKey, nonce, 76);
+ const keys = (0, import_hkdf.expand)(import_sha23.sha256, conversationKey, nonce, 76);
return {
chacha_key: keys.subarray(0, 32),
chacha_nonce: keys.subarray(32, 44),
hmac_key: keys.subarray(44, 76)
@@ -2047,9 +2047,9 @@
function hmacAad(key, message, aad) {
if (aad.length !== 32)
throw new Error("AAD associated data must be 32 bytes");
const combined = (0, import_utils13.concatBytes)(aad, message);
- return (0, import_hmac.hmac)(import_sha2563.sha256, key, combined);
+ return (0, import_hmac.hmac)(import_sha23.sha256, key, combined);
}
function decodePayload(payload) {
if (typeof payload !== "string")
throw new Error("payload must be a valid string");
@@ -2863,10 +2863,10 @@
Negentropy: () => Negentropy,
NegentropyStorageVector: () => NegentropyStorageVector,
NegentropySync: () => NegentropySync
});
-var import_utils16 = require("@noble/ciphers/utils");
-var import_sha2564 = require("@noble/hashes/sha256");
+var import_utils16 = require("@noble/hashes/utils.js");
+var import_sha24 = require("@noble/hashes/sha2.js");
var PROTOCOL_VERSION = 97;
var ID_SIZE = 32;
var FINGERPRINT_SIZE = 16;
var Mode = {
@@ -2995,9 +2995,9 @@
getFingerprint(n) {
let input = new WrappedBuffer();
input.extend(this.buf);
input.extend(encodeVarInt(n));
- let hash = (0, import_sha2564.sha256)(input.unwrap());
+ let hash = (0, import_sha24.sha256)(input.unwrap());
return hash.subarray(0, FINGERPRINT_SIZE);
}
};
var NegentropyStorageVector = class {
@@ -3370,10 +3370,10 @@
validateEventTimestamp: () => validateEventTimestamp,
validateEventUrlTag: () => validateEventUrlTag,
validateToken: () => validateToken
});
-var import_sha2565 = require("@noble/hashes/sha256");
-var import_utils17 = require("@noble/hashes/utils");
+var import_sha25 = require("@noble/hashes/sha2.js");
+var import_utils17 = require("@noble/hashes/utils.js");
var import_base5 = require("@scure/base");
var _authorizationScheme = "Nostr ";
async function getToken(loginUrl, httpMethod, sign, includeAuthorizationScheme = false, payload) {
const event = {
@@ -3436,9 +3436,9 @@
}
return methodTag.length > 0 && methodTag[1].toLowerCase() === method.toLowerCase();
}
function hashPayload(payload) {
- const hash = (0, import_sha2565.sha256)(utf8Encoder.encode(JSON.stringify(payload)));
+ const hash = (0, import_sha25.sha256)(utf8Encoder.encode(JSON.stringify(payload)));
return (0, import_utils17.bytesToHex)(hash);
}
function validateEventPayloadTag(event, payload) {
const payloadTag = event.tags.find((t) => t[0] === "payload"); Index: package/lib/esm/index.js
===================================================================
--- package/lib/esm/index.js
+++ package/lib/esm/index.js
@@ -4,10 +4,10 @@
__defProp(target, name, { get: all[name], enumerable: true });
};
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -46,9 +46,9 @@
});
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
var utils_exports = {};
__export(utils_exports, {
@@ -62,9 +62,9 @@
normalizeURL: () => normalizeURL,
utf8Decoder: () => utf8Decoder,
utf8Encoder: () => utf8Encoder
});
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try {
@@ -181,18 +181,18 @@
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -203,9 +203,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -1374,9 +1374,9 @@
nprofileEncode: () => nprofileEncode,
npubEncode: () => npubEncode,
nsecEncode: () => nsecEncode
});
-import { bytesToHex as bytesToHex3, concatBytes, hexToBytes as hexToBytes2 } from "@noble/hashes/utils";
+import { bytesToHex as bytesToHex3, concatBytes, hexToBytes as hexToBytes3 } from "@noble/hashes/utils.js";
import { bech32 } from "@scure/base";
var NostrTypeGuard = {
isNProfile: (value) => /^nprofile1[a-z\d]+$/.test(value || ""),
isNEvent: (value) => /^nevent1[a-z\d]+$/.test(value || ""),
@@ -1492,12 +1492,12 @@
function nsecEncode(key) {
return encodeBytes("nsec", key);
}
function npubEncode(hex) {
- return encodeBytes("npub", hexToBytes2(hex));
+ return encodeBytes("npub", hexToBytes3(hex));
}
function noteEncode(hex) {
- return encodeBytes("note", hexToBytes2(hex));
+ return encodeBytes("note", hexToBytes3(hex));
}
function encodeBech32(prefix, data) {
let words = bech32.toWords(data);
return bech32.encode(prefix, words, Bech32MaxSize);
@@ -1506,9 +1506,9 @@
return encodeBech32(prefix, bytes);
}
function nprofileEncode(profile) {
let data = encodeTLV({
- 0: [hexToBytes2(profile.pubkey)],
+ 0: [hexToBytes3(profile.pubkey)],
1: (profile.relays || []).map((url) => utf8Encoder.encode(url))
});
return encodeBech32("nprofile", data);
}
@@ -1517,11 +1517,11 @@
if (event.kind !== void 0) {
kindArray = integerToUint8Array(event.kind);
}
let data = encodeTLV({
- 0: [hexToBytes2(event.id)],
+ 0: [hexToBytes3(event.id)],
1: (event.relays || []).map((url) => utf8Encoder.encode(url)),
- 2: event.author ? [hexToBytes2(event.author)] : [],
+ 2: event.author ? [hexToBytes3(event.author)] : [],
3: kindArray ? [new Uint8Array(kindArray)] : []
});
return encodeBech32("nevent", data);
}
@@ -1530,9 +1530,9 @@
new DataView(kind).setUint32(0, addr.kind, false);
let data = encodeTLV({
0: [utf8Encoder.encode(addr.identifier)],
1: (addr.relays || []).map((url) => utf8Encoder.encode(url)),
- 2: [hexToBytes2(addr.pubkey)],
+ 2: [hexToBytes3(addr.pubkey)],
3: [new Uint8Array(kind)]
});
return encodeBech32("naddr", data);
}
@@ -1644,15 +1644,15 @@
__export(nip04_exports, {
decrypt: () => decrypt,
encrypt: () => encrypt
});
-import { bytesToHex as bytesToHex4, randomBytes } from "@noble/hashes/utils";
-import { secp256k1 } from "@noble/curves/secp256k1";
-import { cbc } from "@noble/ciphers/aes";
+import { hexToBytes as hexToBytes4, randomBytes } from "@noble/hashes/utils.js";
+import { secp256k1 } from "@noble/curves/secp256k1.js";
+import { cbc } from "@noble/ciphers/aes.js";
import { base64 } from "@scure/base";
function encrypt(secretKey, pubkey, text) {
- const privkey = secretKey instanceof Uint8Array ? bytesToHex4(secretKey) : secretKey;
- const key = secp256k1.getSharedSecret(privkey, "02" + pubkey);
+ const privkey = secretKey instanceof Uint8Array ? secretKey : hexToBytes4(secretKey);
+ const key = secp256k1.getSharedSecret(privkey, hexToBytes4("02" + pubkey));
const normalizedKey = getNormalizedX(key);
let iv = Uint8Array.from(randomBytes(16));
let plaintext = utf8Encoder.encode(text);
let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext);
@@ -1660,11 +1660,11 @@
let ivb64 = base64.encode(new Uint8Array(iv.buffer));
return `${ctb64}?iv=${ivb64}`;
}
function decrypt(secretKey, pubkey, data) {
- const privkey = secretKey instanceof Uint8Array ? bytesToHex4(secretKey) : secretKey;
+ const privkey = secretKey instanceof Uint8Array ? secretKey : hexToBytes4(secretKey);
let [ctb64, ivb64] = data.split("?iv=");
- let key = secp256k1.getSharedSecret(privkey, "02" + pubkey);
+ let key = secp256k1.getSharedSecret(privkey, hexToBytes4("02" + pubkey));
let normalizedKey = getNormalizedX(key);
let iv = base64.decode(ivb64);
let ciphertext = base64.decode(ctb64);
let plaintext = cbc(normalizedKey, iv).decrypt(ciphertext);
@@ -1862,10 +1862,10 @@
fastEventHash: () => fastEventHash,
getPow: () => getPow,
minePow: () => minePow
});
-import { bytesToHex as bytesToHex5 } from "@noble/hashes/utils";
-import { sha256 as sha2562 } from "@noble/hashes/sha256";
+import { bytesToHex as bytesToHex4 } from "@noble/hashes/utils.js";
+import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
function getPow(hex) {
let count = 0;
for (let i2 = 0; i2 < 64; i2 += 8) {
const nibble = parseInt(hex.substring(i2, i2 + 8), 16);
@@ -1897,9 +1897,9 @@
}
return event;
}
function fastEventHash(evt) {
- return bytesToHex5(
+ return bytesToHex4(
sha2562(utf8Encoder.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])))
);
}
@@ -1931,21 +1931,21 @@
encrypt: () => encrypt2,
getConversationKey: () => getConversationKey,
v2: () => v2
});
-import { chacha20 } from "@noble/ciphers/chacha";
-import { equalBytes } from "@noble/ciphers/utils";
-import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1";
-import { extract as hkdf_extract, expand as hkdf_expand } from "@noble/hashes/hkdf";
-import { hmac } from "@noble/hashes/hmac";
-import { sha256 as sha2563 } from "@noble/hashes/sha256";
-import { concatBytes as concatBytes2, randomBytes as randomBytes2 } from "@noble/hashes/utils";
+import { chacha20 } from "@noble/ciphers/chacha.js";
+import { equalBytes } from "@noble/ciphers/utils.js";
+import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1.js";
+import { extract as hkdf_extract, expand as hkdf_expand } from "@noble/hashes/hkdf.js";
+import { hmac } from "@noble/hashes/hmac.js";
+import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
+import { concatBytes as concatBytes2, hexToBytes as hexToBytes5, randomBytes as randomBytes2 } from "@noble/hashes/utils.js";
import { base64 as base642 } from "@scure/base";
var minPlaintextSize = 1;
var maxPlaintextSize = 65535;
function getConversationKey(privkeyA, pubkeyB) {
- const sharedX = secp256k12.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
- return hkdf_extract(sha2563, sharedX, "nip44-v2");
+ const sharedX = secp256k12.getSharedSecret(privkeyA, hexToBytes5("02" + pubkeyB)).subarray(1, 33);
+ return hkdf_extract(sha2563, sharedX, utf8Encoder.encode("nip44-v2"));
}
function getMessageKeys(conversationKey, nonce) {
const keys = hkdf_expand(sha2563, conversationKey, nonce, 76);
return {
@@ -2803,10 +2803,10 @@
Negentropy: () => Negentropy,
NegentropyStorageVector: () => NegentropyStorageVector,
NegentropySync: () => NegentropySync
});
-import { bytesToHex as bytesToHex6, hexToBytes as hexToBytes3 } from "@noble/ciphers/utils";
-import { sha256 as sha2564 } from "@noble/hashes/sha256";
+import { bytesToHex as bytesToHex5, hexToBytes as hexToBytes6 } from "@noble/hashes/utils.js";
+import { sha256 as sha2564 } from "@noble/hashes/sha2.js";
var PROTOCOL_VERSION = 97;
var ID_SIZE = 32;
var FINGERPRINT_SIZE = 16;
var Mode = {
@@ -2949,9 +2949,9 @@
}
insert(timestamp, id) {
if (this.sealed)
throw Error("already sealed");
- const idb = hexToBytes3(id);
+ const idb = hexToBytes6(id);
if (idb.byteLength !== ID_SIZE)
throw Error("bad id size for added item");
this.items.push({ timestamp, id: idb });
}
@@ -3043,12 +3043,12 @@
initiate() {
let output = new WrappedBuffer();
output.extend(new Uint8Array([PROTOCOL_VERSION]));
this.splitRange(0, this.storage.size(), this._bound(Number.MAX_VALUE), output);
- return bytesToHex6(output.unwrap());
+ return bytesToHex5(output.unwrap());
}
reconcile(queryMsg, onhave, onneed) {
- const query = new WrappedBuffer(hexToBytes3(queryMsg));
+ const query = new WrappedBuffer(hexToBytes6(queryMsg));
this.lastTimestampIn = this.lastTimestampOut = 0;
let fullOutput = new WrappedBuffer();
fullOutput.extend(new Uint8Array([PROTOCOL_VERSION]));
let protocolVersion = getByte(query);
@@ -3089,24 +3089,24 @@
let numIds = decodeVarInt(query);
let theirElems = {};
for (let i2 = 0; i2 < numIds; i2++) {
let e = getBytes(query, ID_SIZE);
- theirElems[bytesToHex6(e)] = e;
+ theirElems[bytesToHex5(e)] = e;
}
skip = true;
this.storage.iterate(lower, upper, (item) => {
let k = item.id;
- const id = bytesToHex6(k);
+ const id = bytesToHex5(k);
if (!theirElems[id]) {
onhave?.(id);
} else {
- delete theirElems[bytesToHex6(k)];
+ delete theirElems[bytesToHex5(k)];
}
return true;
});
if (onneed) {
for (let v of Object.values(theirElems)) {
- onneed(bytesToHex6(v));
+ onneed(bytesToHex5(v));
}
}
} else {
throw Error("unexpected mode");
@@ -3122,9 +3122,9 @@
}
prevIndex = upper;
prevBound = currBound;
}
- return fullOutput.length === 1 ? null : bytesToHex6(fullOutput.unwrap());
+ return fullOutput.length === 1 ? null : bytesToHex5(fullOutput.unwrap());
}
splitRange(lower, upper, upperBound, o) {
let numElems = upper - lower;
let buckets = 16;
@@ -3310,10 +3310,10 @@
validateEventTimestamp: () => validateEventTimestamp,
validateEventUrlTag: () => validateEventUrlTag,
validateToken: () => validateToken
});
-import { sha256 as sha2565 } from "@noble/hashes/sha256";
-import { bytesToHex as bytesToHex7 } from "@noble/hashes/utils";
+import { sha256 as sha2565 } from "@noble/hashes/sha2.js";
+import { bytesToHex as bytesToHex6 } from "@noble/hashes/utils.js";
import { base64 as base643 } from "@scure/base";
var _authorizationScheme = "Nostr ";
async function getToken(loginUrl, httpMethod, sign, includeAuthorizationScheme = false, payload) {
const event = {
@@ -3377,9 +3377,9 @@
return methodTag.length > 0 && methodTag[1].toLowerCase() === method.toLowerCase();
}
function hashPayload(payload) {
const hash = sha2565(utf8Encoder.encode(JSON.stringify(payload)));
- return bytesToHex7(hash);
+ return bytesToHex6(hash);
}
function validateEventPayloadTag(event, payload) {
const payloadTag = event.tags.find((t) => t[0] === "payload");
if (!payloadTag) { Index: package/lib/cjs/nip04.js
===================================================================
--- package/lib/cjs/nip04.js
+++ package/lib/cjs/nip04.js
@@ -23,22 +23,22 @@
decrypt: () => decrypt,
encrypt: () => encrypt
});
module.exports = __toCommonJS(nip04_exports);
-var import_utils2 = require("@noble/hashes/utils");
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_aes = require("@noble/ciphers/aes");
+var import_utils2 = require("@noble/hashes/utils.js");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_aes = require("@noble/ciphers/aes.js");
var import_base = require("@scure/base");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip04.ts
function encrypt(secretKey, pubkey, text) {
- const privkey = secretKey instanceof Uint8Array ? (0, import_utils2.bytesToHex)(secretKey) : secretKey;
- const key = import_secp256k1.secp256k1.getSharedSecret(privkey, "02" + pubkey);
+ const privkey = secretKey instanceof Uint8Array ? secretKey : (0, import_utils2.hexToBytes)(secretKey);
+ const key = import_secp256k1.secp256k1.getSharedSecret(privkey, (0, import_utils2.hexToBytes)("02" + pubkey));
const normalizedKey = getNormalizedX(key);
let iv = Uint8Array.from((0, import_utils2.randomBytes)(16));
let plaintext = utf8Encoder.encode(text);
let ciphertext = (0, import_aes.cbc)(normalizedKey, iv).encrypt(plaintext);
@@ -46,11 +46,11 @@
let ivb64 = import_base.base64.encode(new Uint8Array(iv.buffer));
return `${ctb64}?iv=${ivb64}`;
}
function decrypt(secretKey, pubkey, data) {
- const privkey = secretKey instanceof Uint8Array ? (0, import_utils2.bytesToHex)(secretKey) : secretKey;
+ const privkey = secretKey instanceof Uint8Array ? secretKey : (0, import_utils2.hexToBytes)(secretKey);
let [ctb64, ivb64] = data.split("?iv=");
- let key = import_secp256k1.secp256k1.getSharedSecret(privkey, "02" + pubkey);
+ let key = import_secp256k1.secp256k1.getSharedSecret(privkey, (0, import_utils2.hexToBytes)("02" + pubkey));
let normalizedKey = getNormalizedX(key);
let iv = import_base.base64.decode(ivb64);
let ciphertext = import_base.base64.decode(ctb64);
let plaintext = (0, import_aes.cbc)(normalizedKey, iv).decrypt(ciphertext); Index: package/lib/esm/nip04.js
===================================================================
--- package/lib/esm/nip04.js
+++ package/lib/esm/nip04.js
@@ -1,19 +1,19 @@
// nip04.ts
-import { bytesToHex as bytesToHex2, randomBytes } from "@noble/hashes/utils";
-import { secp256k1 } from "@noble/curves/secp256k1";
-import { cbc } from "@noble/ciphers/aes";
+import { hexToBytes as hexToBytes2, randomBytes } from "@noble/hashes/utils.js";
+import { secp256k1 } from "@noble/curves/secp256k1.js";
+import { cbc } from "@noble/ciphers/aes.js";
import { base64 } from "@scure/base";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip04.ts
function encrypt(secretKey, pubkey, text) {
- const privkey = secretKey instanceof Uint8Array ? bytesToHex2(secretKey) : secretKey;
- const key = secp256k1.getSharedSecret(privkey, "02" + pubkey);
+ const privkey = secretKey instanceof Uint8Array ? secretKey : hexToBytes2(secretKey);
+ const key = secp256k1.getSharedSecret(privkey, hexToBytes2("02" + pubkey));
const normalizedKey = getNormalizedX(key);
let iv = Uint8Array.from(randomBytes(16));
let plaintext = utf8Encoder.encode(text);
let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext);
@@ -21,11 +21,11 @@
let ivb64 = base64.encode(new Uint8Array(iv.buffer));
return `${ctb64}?iv=${ivb64}`;
}
function decrypt(secretKey, pubkey, data) {
- const privkey = secretKey instanceof Uint8Array ? bytesToHex2(secretKey) : secretKey;
+ const privkey = secretKey instanceof Uint8Array ? secretKey : hexToBytes2(secretKey);
let [ctb64, ivb64] = data.split("?iv=");
- let key = secp256k1.getSharedSecret(privkey, "02" + pubkey);
+ let key = secp256k1.getSharedSecret(privkey, hexToBytes2("02" + pubkey));
let normalizedKey = getNormalizedX(key);
let iv = base64.decode(ivb64);
let ciphertext = base64.decode(ctb64);
let plaintext = cbc(normalizedKey, iv).decrypt(ciphertext); Index: package/lib/cjs/nip06.js
===================================================================
--- package/lib/cjs/nip06.js
+++ package/lib/cjs/nip06.js
@@ -27,10 +27,10 @@
privateKeyFromSeedWords: () => privateKeyFromSeedWords,
validateWords: () => validateWords
});
module.exports = __toCommonJS(nip06_exports);
-var import_utils = require("@noble/hashes/utils");
-var import_english = require("@scure/bip39/wordlists/english");
+var import_utils = require("@noble/hashes/utils.js");
+var import_english = require("@scure/bip39/wordlists/english.js");
var import_bip39 = require("@scure/bip39");
var import_bip32 = require("@scure/bip32");
var DERIVATION_PATH = `m/44'/1237'`;
function privateKeyFromSeedWords(mnemonic, passphrase, accountIndex = 0) { Index: package/lib/esm/nip06.js
===================================================================
--- package/lib/esm/nip06.js
+++ package/lib/esm/nip06.js
@@ -1,7 +1,7 @@
// nip06.ts
-import { bytesToHex } from "@noble/hashes/utils";
-import { wordlist } from "@scure/bip39/wordlists/english";
+import { bytesToHex } from "@noble/hashes/utils.js";
+import { wordlist } from "@scure/bip39/wordlists/english.js";
import { generateMnemonic, mnemonicToSeedSync, validateMnemonic } from "@scure/bip39";
import { HDKey } from "@scure/bip32";
var DERIVATION_PATH = `m/44'/1237'`;
function privateKeyFromSeedWords(mnemonic, passphrase, accountIndex = 0) { Index: package/lib/cjs/nip13.js
===================================================================
--- package/lib/cjs/nip13.js
+++ package/lib/cjs/nip13.js
@@ -24,13 +24,13 @@
getPow: () => getPow,
minePow: () => minePow
});
module.exports = __toCommonJS(nip13_exports);
-var import_utils2 = require("@noble/hashes/utils");
-var import_sha256 = require("@noble/hashes/sha256");
+var import_utils2 = require("@noble/hashes/utils.js");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip13.ts
@@ -67,7 +67,7 @@
return event;
}
function fastEventHash(evt) {
return (0, import_utils2.bytesToHex)(
- (0, import_sha256.sha256)(utf8Encoder.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])))
+ (0, import_sha2.sha256)(utf8Encoder.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])))
);
} Index: package/lib/esm/nip13.js
===================================================================
--- package/lib/esm/nip13.js
+++ package/lib/esm/nip13.js
@@ -1,10 +1,10 @@
// nip13.ts
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
-import { sha256 } from "@noble/hashes/sha256";
+import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils.js";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip13.ts Index: package/lib/cjs/nip17.js
===================================================================
--- package/lib/cjs/nip17.js
+++ package/lib/cjs/nip17.js
@@ -27,10 +27,10 @@
});
module.exports = __toCommonJS(nip17_exports);
// pure.ts
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -61,28 +61,28 @@
return true;
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -93,9 +93,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -108,9 +108,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey;
@@ -123,24 +123,24 @@
var PrivateDirectMessage = 14;
var GiftWrap = 1059;
// nip44.ts
-var import_chacha = require("@noble/ciphers/chacha");
-var import_utils4 = require("@noble/ciphers/utils");
-var import_secp256k12 = require("@noble/curves/secp256k1");
-var import_hkdf = require("@noble/hashes/hkdf");
-var import_hmac = require("@noble/hashes/hmac");
-var import_sha2562 = require("@noble/hashes/sha256");
-var import_utils5 = require("@noble/hashes/utils");
+var import_chacha = require("@noble/ciphers/chacha.js");
+var import_utils4 = require("@noble/ciphers/utils.js");
+var import_secp256k12 = require("@noble/curves/secp256k1.js");
+var import_hkdf = require("@noble/hashes/hkdf.js");
+var import_hmac = require("@noble/hashes/hmac.js");
+var import_sha22 = require("@noble/hashes/sha2.js");
+var import_utils5 = require("@noble/hashes/utils.js");
var import_base = require("@scure/base");
var minPlaintextSize = 1;
var maxPlaintextSize = 65535;
function getConversationKey(privkeyA, pubkeyB) {
- const sharedX = import_secp256k12.secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
- return (0, import_hkdf.extract)(import_sha2562.sha256, sharedX, "nip44-v2");
+ const sharedX = import_secp256k12.secp256k1.getSharedSecret(privkeyA, (0, import_utils5.hexToBytes)("02" + pubkeyB)).subarray(1, 33);
+ return (0, import_hkdf.extract)(import_sha22.sha256, sharedX, utf8Encoder.encode("nip44-v2"));
}
function getMessageKeys(conversationKey, nonce) {
- const keys = (0, import_hkdf.expand)(import_sha2562.sha256, conversationKey, nonce, 76);
+ const keys = (0, import_hkdf.expand)(import_sha22.sha256, conversationKey, nonce, 76);
return {
chacha_key: keys.subarray(0, 32),
chacha_nonce: keys.subarray(32, 44),
hmac_key: keys.subarray(44, 76)
@@ -179,9 +179,9 @@
function hmacAad(key, message, aad) {
if (aad.length !== 32)
throw new Error("AAD associated data must be 32 bytes");
const combined = (0, import_utils5.concatBytes)(aad, message);
- return (0, import_hmac.hmac)(import_sha2562.sha256, key, combined);
+ return (0, import_hmac.hmac)(import_sha22.sha256, key, combined);
}
function decodePayload(payload) {
if (typeof payload !== "string")
throw new Error("payload must be a valid string"); Index: package/lib/esm/nip17.js
===================================================================
--- package/lib/esm/nip17.js
+++ package/lib/esm/nip17.js
@@ -1,7 +1,7 @@
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -32,28 +32,28 @@
return true;
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -64,9 +64,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -94,21 +94,21 @@
var PrivateDirectMessage = 14;
var GiftWrap = 1059;
// nip44.ts
-import { chacha20 } from "@noble/ciphers/chacha";
-import { equalBytes } from "@noble/ciphers/utils";
-import { secp256k1 } from "@noble/curves/secp256k1";
-import { extract as hkdf_extract, expand as hkdf_expand } from "@noble/hashes/hkdf";
-import { hmac } from "@noble/hashes/hmac";
-import { sha256 as sha2562 } from "@noble/hashes/sha256";
-import { concatBytes, randomBytes } from "@noble/hashes/utils";
+import { chacha20 } from "@noble/ciphers/chacha.js";
+import { equalBytes } from "@noble/ciphers/utils.js";
+import { secp256k1 } from "@noble/curves/secp256k1.js";
+import { extract as hkdf_extract, expand as hkdf_expand } from "@noble/hashes/hkdf.js";
+import { hmac } from "@noble/hashes/hmac.js";
+import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
+import { concatBytes, hexToBytes as hexToBytes3, randomBytes } from "@noble/hashes/utils.js";
import { base64 } from "@scure/base";
var minPlaintextSize = 1;
var maxPlaintextSize = 65535;
function getConversationKey(privkeyA, pubkeyB) {
- const sharedX = secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
- return hkdf_extract(sha2562, sharedX, "nip44-v2");
+ const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes3("02" + pubkeyB)).subarray(1, 33);
+ return hkdf_extract(sha2562, sharedX, utf8Encoder.encode("nip44-v2"));
}
function getMessageKeys(conversationKey, nonce) {
const keys = hkdf_expand(sha2562, conversationKey, nonce, 76);
return { Index: package/lib/cjs/nip18.js
===================================================================
--- package/lib/cjs/nip18.js
+++ package/lib/cjs/nip18.js
@@ -26,10 +26,10 @@
});
module.exports = __toCommonJS(nip18_exports);
// pure.ts
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -60,28 +60,28 @@
return true;
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -92,9 +92,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -107,9 +107,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey; Index: package/lib/esm/nip18.js
===================================================================
--- package/lib/esm/nip18.js
+++ package/lib/esm/nip18.js
@@ -1,7 +1,7 @@
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -32,28 +32,28 @@
return true;
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -64,9 +64,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false; Index: package/lib/cjs/nip19.js
===================================================================
--- package/lib/cjs/nip19.js
+++ package/lib/cjs/nip19.js
@@ -33,13 +33,13 @@
npubEncode: () => npubEncode,
nsecEncode: () => nsecEncode
});
module.exports = __toCommonJS(nip19_exports);
-var import_utils2 = require("@noble/hashes/utils");
+var import_utils2 = require("@noble/hashes/utils.js");
var import_base = require("@scure/base");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip19.ts Index: package/lib/esm/nip19.js
===================================================================
--- package/lib/esm/nip19.js
+++ package/lib/esm/nip19.js
@@ -1,10 +1,10 @@
// nip19.ts
-import { bytesToHex as bytesToHex2, concatBytes, hexToBytes as hexToBytes2 } from "@noble/hashes/utils";
+import { bytesToHex as bytesToHex2, concatBytes, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
import { bech32 } from "@scure/base";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip19.ts Index: package/lib/cjs/nip21.js
===================================================================
--- package/lib/cjs/nip21.js
+++ package/lib/cjs/nip21.js
@@ -26,13 +26,13 @@
});
module.exports = __toCommonJS(nip21_exports);
// nip19.ts
-var import_utils2 = require("@noble/hashes/utils");
+var import_utils2 = require("@noble/hashes/utils.js");
var import_base = require("@scure/base");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip19.ts Index: package/lib/esm/nip21.js
===================================================================
--- package/lib/esm/nip21.js
+++ package/lib/esm/nip21.js
@@ -1,10 +1,10 @@
// nip19.ts
-import { bytesToHex as bytesToHex2, concatBytes, hexToBytes as hexToBytes2 } from "@noble/hashes/utils";
+import { bytesToHex as bytesToHex2, concatBytes, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
import { bech32 } from "@scure/base";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip19.ts Index: package/lib/cjs/nip25.js
===================================================================
--- package/lib/cjs/nip25.js
+++ package/lib/cjs/nip25.js
@@ -25,10 +25,10 @@
});
module.exports = __toCommonJS(nip25_exports);
// pure.ts
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -59,28 +59,28 @@
return true;
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -91,9 +91,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -106,9 +106,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey; Index: package/lib/esm/nip25.js
===================================================================
--- package/lib/esm/nip25.js
+++ package/lib/esm/nip25.js
@@ -1,7 +1,7 @@
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -32,28 +32,28 @@
return true;
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -64,9 +64,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false; Index: package/lib/cjs/nip27.js
===================================================================
--- package/lib/cjs/nip27.js
+++ package/lib/cjs/nip27.js
@@ -24,13 +24,13 @@
});
module.exports = __toCommonJS(nip27_exports);
// nip19.ts
-var import_utils2 = require("@noble/hashes/utils");
+var import_utils2 = require("@noble/hashes/utils.js");
var import_base = require("@scure/base");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip19.ts Index: package/lib/esm/nip27.js
===================================================================
--- package/lib/esm/nip27.js
+++ package/lib/esm/nip27.js
@@ -1,10 +1,10 @@
// nip19.ts
-import { bytesToHex as bytesToHex2, concatBytes, hexToBytes as hexToBytes2 } from "@noble/hashes/utils";
+import { bytesToHex as bytesToHex2, concatBytes, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
import { bech32 } from "@scure/base";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip19.ts Index: package/lib/cjs/nip28.js
===================================================================
--- package/lib/cjs/nip28.js
+++ package/lib/cjs/nip28.js
@@ -28,10 +28,10 @@
});
module.exports = __toCommonJS(nip28_exports);
// pure.ts
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -62,28 +62,28 @@
return true;
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -94,9 +94,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -109,9 +109,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey; Index: package/lib/esm/nip28.js
===================================================================
--- package/lib/esm/nip28.js
+++ package/lib/esm/nip28.js
@@ -1,7 +1,7 @@
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -32,28 +32,28 @@
return true;
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -64,9 +64,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false; Index: package/lib/cjs/nip29.js
===================================================================
--- package/lib/cjs/nip29.js
+++ package/lib/cjs/nip29.js
@@ -55,13 +55,13 @@
})).json();
}
// nip19.ts
-var import_utils2 = require("@noble/hashes/utils");
+var import_utils2 = require("@noble/hashes/utils.js");
var import_base = require("@scure/base");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try { Index: package/lib/esm/nip29.js
===================================================================
--- package/lib/esm/nip29.js
+++ package/lib/esm/nip29.js
@@ -10,13 +10,13 @@
})).json();
}
// nip19.ts
-import { bytesToHex as bytesToHex2, concatBytes, hexToBytes as hexToBytes2 } from "@noble/hashes/utils";
+import { bytesToHex as bytesToHex2, concatBytes, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
import { bech32 } from "@scure/base";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try { Index: package/lib/cjs/nip44.js
===================================================================
--- package/lib/cjs/nip44.js
+++ package/lib/cjs/nip44.js
@@ -25,31 +25,31 @@
getConversationKey: () => getConversationKey,
v2: () => v2
});
module.exports = __toCommonJS(nip44_exports);
-var import_chacha = require("@noble/ciphers/chacha");
-var import_utils2 = require("@noble/ciphers/utils");
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_hkdf = require("@noble/hashes/hkdf");
-var import_hmac = require("@noble/hashes/hmac");
-var import_sha256 = require("@noble/hashes/sha256");
-var import_utils3 = require("@noble/hashes/utils");
+var import_chacha = require("@noble/ciphers/chacha.js");
+var import_utils2 = require("@noble/ciphers/utils.js");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_hkdf = require("@noble/hashes/hkdf.js");
+var import_hmac = require("@noble/hashes/hmac.js");
+var import_sha2 = require("@noble/hashes/sha2.js");
+var import_utils3 = require("@noble/hashes/utils.js");
var import_base = require("@scure/base");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip44.ts
var minPlaintextSize = 1;
var maxPlaintextSize = 65535;
function getConversationKey(privkeyA, pubkeyB) {
- const sharedX = import_secp256k1.secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
- return (0, import_hkdf.extract)(import_sha256.sha256, sharedX, "nip44-v2");
+ const sharedX = import_secp256k1.secp256k1.getSharedSecret(privkeyA, (0, import_utils3.hexToBytes)("02" + pubkeyB)).subarray(1, 33);
+ return (0, import_hkdf.extract)(import_sha2.sha256, sharedX, utf8Encoder.encode("nip44-v2"));
}
function getMessageKeys(conversationKey, nonce) {
- const keys = (0, import_hkdf.expand)(import_sha256.sha256, conversationKey, nonce, 76);
+ const keys = (0, import_hkdf.expand)(import_sha2.sha256, conversationKey, nonce, 76);
return {
chacha_key: keys.subarray(0, 32),
chacha_nonce: keys.subarray(32, 44),
hmac_key: keys.subarray(44, 76)
@@ -88,9 +88,9 @@
function hmacAad(key, message, aad) {
if (aad.length !== 32)
throw new Error("AAD associated data must be 32 bytes");
const combined = (0, import_utils3.concatBytes)(aad, message);
- return (0, import_hmac.hmac)(import_sha256.sha256, key, combined);
+ return (0, import_hmac.hmac)(import_sha2.sha256, key, combined);
}
function decodePayload(payload) {
if (typeof payload !== "string")
throw new Error("payload must be a valid string"); Index: package/lib/esm/nip44.js
===================================================================
--- package/lib/esm/nip44.js
+++ package/lib/esm/nip44.js
@@ -1,25 +1,25 @@
// nip44.ts
-import { chacha20 } from "@noble/ciphers/chacha";
-import { equalBytes } from "@noble/ciphers/utils";
-import { secp256k1 } from "@noble/curves/secp256k1";
-import { extract as hkdf_extract, expand as hkdf_expand } from "@noble/hashes/hkdf";
-import { hmac } from "@noble/hashes/hmac";
-import { sha256 } from "@noble/hashes/sha256";
-import { concatBytes, randomBytes } from "@noble/hashes/utils";
+import { chacha20 } from "@noble/ciphers/chacha.js";
+import { equalBytes } from "@noble/ciphers/utils.js";
+import { secp256k1 } from "@noble/curves/secp256k1.js";
+import { extract as hkdf_extract, expand as hkdf_expand } from "@noble/hashes/hkdf.js";
+import { hmac } from "@noble/hashes/hmac.js";
+import { sha256 } from "@noble/hashes/sha2.js";
+import { concatBytes, hexToBytes as hexToBytes2, randomBytes } from "@noble/hashes/utils.js";
import { base64 } from "@scure/base";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip44.ts
var minPlaintextSize = 1;
var maxPlaintextSize = 65535;
function getConversationKey(privkeyA, pubkeyB) {
- const sharedX = secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
- return hkdf_extract(sha256, sharedX, "nip44-v2");
+ const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes2("02" + pubkeyB)).subarray(1, 33);
+ return hkdf_extract(sha256, sharedX, utf8Encoder.encode("nip44-v2"));
}
function getMessageKeys(conversationKey, nonce) {
const keys = hkdf_expand(sha256, conversationKey, nonce, 76);
return { Index: package/lib/cjs/nip46.js
===================================================================
--- package/lib/cjs/nip46.js
+++ package/lib/cjs/nip46.js
@@ -32,10 +32,10 @@
});
module.exports = __toCommonJS(nip46_exports);
// pure.ts
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -66,12 +66,12 @@
return true;
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try {
@@ -145,18 +145,18 @@
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -167,9 +167,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -182,9 +182,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey;
@@ -192,24 +192,24 @@
var finalizeEvent = i.finalizeEvent;
var verifyEvent = i.verifyEvent;
// nip44.ts
-var import_chacha = require("@noble/ciphers/chacha");
-var import_utils4 = require("@noble/ciphers/utils");
-var import_secp256k12 = require("@noble/curves/secp256k1");
-var import_hkdf = require("@noble/hashes/hkdf");
-var import_hmac = require("@noble/hashes/hmac");
-var import_sha2562 = require("@noble/hashes/sha256");
-var import_utils5 = require("@noble/hashes/utils");
+var import_chacha = require("@noble/ciphers/chacha.js");
+var import_utils4 = require("@noble/ciphers/utils.js");
+var import_secp256k12 = require("@noble/curves/secp256k1.js");
+var import_hkdf = require("@noble/hashes/hkdf.js");
+var import_hmac = require("@noble/hashes/hmac.js");
+var import_sha22 = require("@noble/hashes/sha2.js");
+var import_utils5 = require("@noble/hashes/utils.js");
var import_base = require("@scure/base");
var minPlaintextSize = 1;
var maxPlaintextSize = 65535;
function getConversationKey(privkeyA, pubkeyB) {
- const sharedX = import_secp256k12.secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
- return (0, import_hkdf.extract)(import_sha2562.sha256, sharedX, "nip44-v2");
+ const sharedX = import_secp256k12.secp256k1.getSharedSecret(privkeyA, (0, import_utils5.hexToBytes)("02" + pubkeyB)).subarray(1, 33);
+ return (0, import_hkdf.extract)(import_sha22.sha256, sharedX, utf8Encoder.encode("nip44-v2"));
}
function getMessageKeys(conversationKey, nonce) {
- const keys = (0, import_hkdf.expand)(import_sha2562.sha256, conversationKey, nonce, 76);
+ const keys = (0, import_hkdf.expand)(import_sha22.sha256, conversationKey, nonce, 76);
return {
chacha_key: keys.subarray(0, 32),
chacha_nonce: keys.subarray(32, 44),
hmac_key: keys.subarray(44, 76)
@@ -248,9 +248,9 @@
function hmacAad(key, message, aad) {
if (aad.length !== 32)
throw new Error("AAD associated data must be 32 bytes");
const combined = (0, import_utils5.concatBytes)(aad, message);
- return (0, import_hmac.hmac)(import_sha2562.sha256, key, combined);
+ return (0, import_hmac.hmac)(import_sha22.sha256, key, combined);
}
function decodePayload(payload) {
if (typeof payload !== "string")
throw new Error("payload must be a valid string"); Index: package/lib/esm/nip46.js
===================================================================
--- package/lib/esm/nip46.js
+++ package/lib/esm/nip46.js
@@ -1,7 +1,7 @@
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -32,12 +32,12 @@
return true;
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try {
@@ -111,18 +111,18 @@
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -133,9 +133,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -158,21 +158,21 @@
var finalizeEvent = i.finalizeEvent;
var verifyEvent = i.verifyEvent;
// nip44.ts
-import { chacha20 } from "@noble/ciphers/chacha";
-import { equalBytes } from "@noble/ciphers/utils";
-import { secp256k1 } from "@noble/curves/secp256k1";
-import { extract as hkdf_extract, expand as hkdf_expand } from "@noble/hashes/hkdf";
-import { hmac } from "@noble/hashes/hmac";
-import { sha256 as sha2562 } from "@noble/hashes/sha256";
-import { concatBytes, randomBytes } from "@noble/hashes/utils";
+import { chacha20 } from "@noble/ciphers/chacha.js";
+import { equalBytes } from "@noble/ciphers/utils.js";
+import { secp256k1 } from "@noble/curves/secp256k1.js";
+import { extract as hkdf_extract, expand as hkdf_expand } from "@noble/hashes/hkdf.js";
+import { hmac } from "@noble/hashes/hmac.js";
+import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
+import { concatBytes, hexToBytes as hexToBytes3, randomBytes } from "@noble/hashes/utils.js";
import { base64 } from "@scure/base";
var minPlaintextSize = 1;
var maxPlaintextSize = 65535;
function getConversationKey(privkeyA, pubkeyB) {
- const sharedX = secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
- return hkdf_extract(sha2562, sharedX, "nip44-v2");
+ const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes3("02" + pubkeyB)).subarray(1, 33);
+ return hkdf_extract(sha2562, sharedX, utf8Encoder.encode("nip44-v2"));
}
function getMessageKeys(conversationKey, nonce) {
const keys = hkdf_expand(sha2562, conversationKey, nonce, 76);
return { Index: package/lib/cjs/nip47.js
===================================================================
--- package/lib/cjs/nip47.js
+++ package/lib/cjs/nip47.js
@@ -25,10 +25,10 @@
});
module.exports = __toCommonJS(nip47_exports);
// pure.ts
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -59,28 +59,28 @@
return true;
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -91,9 +91,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -106,9 +106,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey;
@@ -119,15 +119,15 @@
// kinds.ts
var NWCWalletRequest = 23194;
// nip04.ts
-var import_utils4 = require("@noble/hashes/utils");
-var import_secp256k12 = require("@noble/curves/secp256k1");
-var import_aes = require("@noble/ciphers/aes");
+var import_utils4 = require("@noble/hashes/utils.js");
+var import_secp256k12 = require("@noble/curves/secp256k1.js");
+var import_aes = require("@noble/ciphers/aes.js");
var import_base = require("@scure/base");
function encrypt(secretKey, pubkey, text) {
- const privkey = secretKey instanceof Uint8Array ? (0, import_utils4.bytesToHex)(secretKey) : secretKey;
- const key = import_secp256k12.secp256k1.getSharedSecret(privkey, "02" + pubkey);
+ const privkey = secretKey instanceof Uint8Array ? secretKey : (0, import_utils4.hexToBytes)(secretKey);
+ const key = import_secp256k12.secp256k1.getSharedSecret(privkey, (0, import_utils4.hexToBytes)("02" + pubkey));
const normalizedKey = getNormalizedX(key);
let iv = Uint8Array.from((0, import_utils4.randomBytes)(16));
let plaintext = utf8Encoder.encode(text);
let ciphertext = (0, import_aes.cbc)(normalizedKey, iv).encrypt(plaintext); Index: package/lib/esm/nip47.js
===================================================================
--- package/lib/esm/nip47.js
+++ package/lib/esm/nip47.js
@@ -1,7 +1,7 @@
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -32,28 +32,28 @@
return true;
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -64,9 +64,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -92,15 +92,15 @@
// kinds.ts
var NWCWalletRequest = 23194;
// nip04.ts
-import { bytesToHex as bytesToHex3, randomBytes } from "@noble/hashes/utils";
-import { secp256k1 } from "@noble/curves/secp256k1";
-import { cbc } from "@noble/ciphers/aes";
+import { hexToBytes as hexToBytes3, randomBytes } from "@noble/hashes/utils.js";
+import { secp256k1 } from "@noble/curves/secp256k1.js";
+import { cbc } from "@noble/ciphers/aes.js";
import { base64 } from "@scure/base";
function encrypt(secretKey, pubkey, text) {
- const privkey = secretKey instanceof Uint8Array ? bytesToHex3(secretKey) : secretKey;
- const key = secp256k1.getSharedSecret(privkey, "02" + pubkey);
+ const privkey = secretKey instanceof Uint8Array ? secretKey : hexToBytes3(secretKey);
+ const key = secp256k1.getSharedSecret(privkey, hexToBytes3("02" + pubkey));
const normalizedKey = getNormalizedX(key);
let iv = Uint8Array.from(randomBytes(16));
let plaintext = utf8Encoder.encode(text);
let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext); Index: package/lib/cjs/nip49.js
===================================================================
--- package/lib/cjs/nip49.js
+++ package/lib/cjs/nip49.js
@@ -23,14 +23,15 @@
decrypt: () => decrypt,
encrypt: () => encrypt
});
module.exports = __toCommonJS(nip49_exports);
-var import_scrypt = require("@noble/hashes/scrypt");
-var import_chacha = require("@noble/ciphers/chacha");
-var import_utils2 = require("@noble/hashes/utils");
+var import_base2 = require("@scure/base");
+var import_scrypt = require("@noble/hashes/scrypt.js");
+var import_chacha = require("@noble/ciphers/chacha.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// nip19.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var import_base = require("@scure/base");
var Bech32MaxSize = 5e3;
function encodeBech32(prefix, data) {
let words = import_base.bech32.toWords(data);
@@ -40,9 +41,8 @@
return encodeBech32(prefix, bytes);
}
// nip49.ts
-var import_base2 = require("@scure/base");
function encrypt(sec, password, logn = 16, ksb = 2) {
let salt = (0, import_utils2.randomBytes)(16);
let n = 2 ** logn;
let key = (0, import_scrypt.scrypt)(password.normalize("NFKC"), salt, { N: n, r: 8, p: 1, dkLen: 32 }); Index: package/lib/esm/nip49.js
===================================================================
--- package/lib/esm/nip49.js
+++ package/lib/esm/nip49.js
@@ -1,11 +1,12 @@
// nip49.ts
-import { scrypt } from "@noble/hashes/scrypt";
-import { xchacha20poly1305 } from "@noble/ciphers/chacha";
-import { concatBytes as concatBytes2, randomBytes } from "@noble/hashes/utils";
+import { bech32 as bech322 } from "@scure/base";
+import { scrypt } from "@noble/hashes/scrypt.js";
+import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
+import { concatBytes as concatBytes2, randomBytes } from "@noble/hashes/utils.js";
// nip19.ts
-import { bytesToHex, concatBytes, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, concatBytes, hexToBytes } from "@noble/hashes/utils.js";
import { bech32 } from "@scure/base";
var Bech32MaxSize = 5e3;
function encodeBech32(prefix, data) {
let words = bech32.toWords(data);
@@ -15,9 +16,8 @@
return encodeBech32(prefix, bytes);
}
// nip49.ts
-import { bech32 as bech322 } from "@scure/base";
function encrypt(sec, password, logn = 16, ksb = 2) {
let salt = randomBytes(16);
let n = 2 ** logn;
let key = scrypt(password.normalize("NFKC"), salt, { N: n, r: 8, p: 1, dkLen: 32 }); Index: package/lib/cjs/nip57.js
===================================================================
--- package/lib/cjs/nip57.js
+++ package/lib/cjs/nip57.js
@@ -30,10 +30,10 @@
module.exports = __toCommonJS(nip57_exports);
var import_base = require("@scure/base");
// pure.ts
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -64,28 +64,28 @@
return true;
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -96,9 +96,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -111,9 +111,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey; Index: package/lib/esm/nip57.js
===================================================================
--- package/lib/esm/nip57.js
+++ package/lib/esm/nip57.js
@@ -1,10 +1,10 @@
// nip57.ts
import { bech32 } from "@scure/base";
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -35,28 +35,28 @@
return true;
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -67,9 +67,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false; Index: package/lib/cjs/nip59.js
===================================================================
--- package/lib/cjs/nip59.js
+++ package/lib/cjs/nip59.js
@@ -30,31 +30,31 @@
});
module.exports = __toCommonJS(nip59_exports);
// nip44.ts
-var import_chacha = require("@noble/ciphers/chacha");
-var import_utils2 = require("@noble/ciphers/utils");
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_hkdf = require("@noble/hashes/hkdf");
-var import_hmac = require("@noble/hashes/hmac");
-var import_sha256 = require("@noble/hashes/sha256");
-var import_utils3 = require("@noble/hashes/utils");
+var import_chacha = require("@noble/ciphers/chacha.js");
+var import_utils2 = require("@noble/ciphers/utils.js");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_hkdf = require("@noble/hashes/hkdf.js");
+var import_hmac = require("@noble/hashes/hmac.js");
+var import_sha2 = require("@noble/hashes/sha2.js");
+var import_utils3 = require("@noble/hashes/utils.js");
var import_base = require("@scure/base");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip44.ts
var minPlaintextSize = 1;
var maxPlaintextSize = 65535;
function getConversationKey(privkeyA, pubkeyB) {
- const sharedX = import_secp256k1.secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
- return (0, import_hkdf.extract)(import_sha256.sha256, sharedX, "nip44-v2");
+ const sharedX = import_secp256k1.secp256k1.getSharedSecret(privkeyA, (0, import_utils3.hexToBytes)("02" + pubkeyB)).subarray(1, 33);
+ return (0, import_hkdf.extract)(import_sha2.sha256, sharedX, utf8Encoder.encode("nip44-v2"));
}
function getMessageKeys(conversationKey, nonce) {
- const keys = (0, import_hkdf.expand)(import_sha256.sha256, conversationKey, nonce, 76);
+ const keys = (0, import_hkdf.expand)(import_sha2.sha256, conversationKey, nonce, 76);
return {
chacha_key: keys.subarray(0, 32),
chacha_nonce: keys.subarray(32, 44),
hmac_key: keys.subarray(44, 76)
@@ -93,9 +93,9 @@
function hmacAad(key, message, aad) {
if (aad.length !== 32)
throw new Error("AAD associated data must be 32 bytes");
const combined = (0, import_utils3.concatBytes)(aad, message);
- return (0, import_hmac.hmac)(import_sha256.sha256, key, combined);
+ return (0, import_hmac.hmac)(import_sha2.sha256, key, combined);
}
function decodePayload(payload) {
if (typeof payload !== "string")
throw new Error("payload must be a valid string");
@@ -139,10 +139,10 @@
return unpad(padded);
}
// pure.ts
-var import_secp256k12 = require("@noble/curves/secp256k1");
-var import_utils5 = require("@noble/hashes/utils");
+var import_secp256k12 = require("@noble/curves/secp256k1.js");
+var import_utils5 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -173,21 +173,21 @@
return true;
}
// pure.ts
-var import_sha2562 = require("@noble/hashes/sha256");
+var import_sha22 = require("@noble/hashes/sha2.js");
var JS = class {
generateSecretKey() {
- return import_secp256k12.schnorr.utils.randomPrivateKey();
+ return import_secp256k12.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils5.bytesToHex)(import_secp256k12.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils5.bytesToHex)(import_secp256k12.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils5.bytesToHex)(import_secp256k12.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils5.bytesToHex)(import_secp256k12.schnorr.sign((0, import_utils5.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -198,9 +198,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k12.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k12.schnorr.verify((0, import_utils5.hexToBytes)(event.sig), (0, import_utils5.hexToBytes)(hash), (0, import_utils5.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -213,9 +213,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha2562.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha22.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils5.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey; Index: package/lib/esm/nip59.js
===================================================================
--- package/lib/esm/nip59.js
+++ package/lib/esm/nip59.js
@@ -1,25 +1,25 @@
// nip44.ts
-import { chacha20 } from "@noble/ciphers/chacha";
-import { equalBytes } from "@noble/ciphers/utils";
-import { secp256k1 } from "@noble/curves/secp256k1";
-import { extract as hkdf_extract, expand as hkdf_expand } from "@noble/hashes/hkdf";
-import { hmac } from "@noble/hashes/hmac";
-import { sha256 } from "@noble/hashes/sha256";
-import { concatBytes, randomBytes } from "@noble/hashes/utils";
+import { chacha20 } from "@noble/ciphers/chacha.js";
+import { equalBytes } from "@noble/ciphers/utils.js";
+import { secp256k1 } from "@noble/curves/secp256k1.js";
+import { extract as hkdf_extract, expand as hkdf_expand } from "@noble/hashes/hkdf.js";
+import { hmac } from "@noble/hashes/hmac.js";
+import { sha256 } from "@noble/hashes/sha2.js";
+import { concatBytes, hexToBytes as hexToBytes2, randomBytes } from "@noble/hashes/utils.js";
import { base64 } from "@scure/base";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip44.ts
var minPlaintextSize = 1;
var maxPlaintextSize = 65535;
function getConversationKey(privkeyA, pubkeyB) {
- const sharedX = secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB).subarray(1, 33);
- return hkdf_extract(sha256, sharedX, "nip44-v2");
+ const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes2("02" + pubkeyB)).subarray(1, 33);
+ return hkdf_extract(sha256, sharedX, utf8Encoder.encode("nip44-v2"));
}
function getMessageKeys(conversationKey, nonce) {
const keys = hkdf_expand(sha256, conversationKey, nonce, 76);
return {
@@ -107,10 +107,10 @@
return unpad(padded);
}
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes3 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -141,21 +141,21 @@
return true;
}
// pure.ts
-import { sha256 as sha2562 } from "@noble/hashes/sha256";
+import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes3(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -166,9 +166,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes3(event.sig), hexToBytes3(hash), hexToBytes3(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false; Index: package/lib/cjs/nip77.js
===================================================================
--- package/lib/cjs/nip77.js
+++ package/lib/cjs/nip77.js
@@ -24,10 +24,10 @@
NegentropyStorageVector: () => NegentropyStorageVector,
NegentropySync: () => NegentropySync
});
module.exports = __toCommonJS(nip77_exports);
-var import_utils = require("@noble/ciphers/utils");
-var import_sha256 = require("@noble/hashes/sha256");
+var import_utils = require("@noble/hashes/utils.js");
+var import_sha2 = require("@noble/hashes/sha2.js");
var PROTOCOL_VERSION = 97;
var ID_SIZE = 32;
var FINGERPRINT_SIZE = 16;
var Mode = {
@@ -156,9 +156,9 @@
getFingerprint(n) {
let input = new WrappedBuffer();
input.extend(this.buf);
input.extend(encodeVarInt(n));
- let hash = (0, import_sha256.sha256)(input.unwrap());
+ let hash = (0, import_sha2.sha256)(input.unwrap());
return hash.subarray(0, FINGERPRINT_SIZE);
}
};
var NegentropyStorageVector = class { Index: package/lib/esm/nip77.js
===================================================================
--- package/lib/esm/nip77.js
+++ package/lib/esm/nip77.js
@@ -1,7 +1,7 @@
// nip77.ts
-import { bytesToHex, hexToBytes } from "@noble/ciphers/utils";
-import { sha256 } from "@noble/hashes/sha256";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
+import { sha256 } from "@noble/hashes/sha2.js";
var PROTOCOL_VERSION = 97;
var ID_SIZE = 32;
var FINGERPRINT_SIZE = 16;
var Mode = { Index: package/lib/cjs/nip98.js
===================================================================
--- package/lib/cjs/nip98.js
+++ package/lib/cjs/nip98.js
@@ -31,15 +31,15 @@
validateEventUrlTag: () => validateEventUrlTag,
validateToken: () => validateToken
});
module.exports = __toCommonJS(nip98_exports);
-var import_sha2562 = require("@noble/hashes/sha256");
-var import_utils4 = require("@noble/hashes/utils");
+var import_sha22 = require("@noble/hashes/sha2.js");
+var import_utils4 = require("@noble/hashes/utils.js");
var import_base = require("@scure/base");
// pure.ts
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -70,28 +70,28 @@
return true;
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -102,9 +102,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -117,9 +117,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey;
@@ -193,9 +193,9 @@
}
return methodTag.length > 0 && methodTag[1].toLowerCase() === method.toLowerCase();
}
function hashPayload(payload) {
- const hash = (0, import_sha2562.sha256)(utf8Encoder.encode(JSON.stringify(payload)));
+ const hash = (0, import_sha22.sha256)(utf8Encoder.encode(JSON.stringify(payload)));
return (0, import_utils4.bytesToHex)(hash);
}
function validateEventPayloadTag(event, payload) {
const payloadTag = event.tags.find((t) => t[0] === "payload"); Index: package/lib/esm/nip98.js
===================================================================
--- package/lib/esm/nip98.js
+++ package/lib/esm/nip98.js
@@ -1,12 +1,12 @@
// nip98.ts
-import { sha256 as sha2562 } from "@noble/hashes/sha256";
-import { bytesToHex as bytesToHex3 } from "@noble/hashes/utils";
+import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
+import { bytesToHex as bytesToHex3 } from "@noble/hashes/utils.js";
import { base64 } from "@scure/base";
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -37,28 +37,28 @@
return true;
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -69,9 +69,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false; Index: package/lib/cjs/nipb7.js
===================================================================
--- package/lib/cjs/nipb7.js
+++ package/lib/cjs/nipb7.js
@@ -22,12 +22,12 @@
__export(nipb7_exports, {
BlossomClient: () => BlossomClient
});
module.exports = __toCommonJS(nipb7_exports);
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nipb7.ts
@@ -98,9 +98,9 @@
throw new Error(`failed to check for ${hash}: ${error}`);
}
}
async uploadBlob(file, contentType) {
- const hash = (0, import_utils.bytesToHex)((0, import_sha256.sha256)(new Uint8Array(await file.arrayBuffer())));
+ const hash = (0, import_utils.bytesToHex)((0, import_sha2.sha256)(new Uint8Array(await file.arrayBuffer())));
const actualContentType = contentType || file.type || "application/octet-stream";
const bd = await this.httpCall(
"PUT",
"upload", Index: package/lib/esm/nipb7.js
===================================================================
--- package/lib/esm/nipb7.js
+++ package/lib/esm/nipb7.js
@@ -1,9 +1,9 @@
// nipb7.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nipb7.ts File too large for inline diff
Index: package/lib/cjs/pool.js
===================================================================
--- package/lib/cjs/pool.js
+++ package/lib/cjs/pool.js
@@ -26,10 +26,10 @@
});
module.exports = __toCommonJS(pool_exports);
// pure.ts
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -60,12 +60,12 @@
return true;
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try {
@@ -139,18 +139,18 @@
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -161,9 +161,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -176,9 +176,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey; Index: package/lib/esm/pool.js
===================================================================
--- package/lib/esm/pool.js
+++ package/lib/esm/pool.js
@@ -1,7 +1,7 @@
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -32,12 +32,12 @@
return true;
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try {
@@ -111,18 +111,18 @@
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -133,9 +133,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false; Index: package/lib/cjs/pure.js
===================================================================
--- package/lib/cjs/pure.js
+++ package/lib/cjs/pure.js
@@ -30,10 +30,10 @@
verifiedSymbol: () => verifiedSymbol,
verifyEvent: () => verifyEvent
});
module.exports = __toCommonJS(pure_exports);
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -72,28 +72,28 @@
});
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -104,9 +104,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -119,9 +119,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey; Index: package/lib/esm/pure.js
===================================================================
--- package/lib/esm/pure.js
+++ package/lib/esm/pure.js
@@ -1,7 +1,7 @@
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -40,28 +40,28 @@
});
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -72,9 +72,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false; Index: package/lib/cjs/references.js
===================================================================
--- package/lib/cjs/references.js
+++ package/lib/cjs/references.js
@@ -24,13 +24,13 @@
});
module.exports = __toCommonJS(references_exports);
// nip19.ts
-var import_utils2 = require("@noble/hashes/utils");
+var import_utils2 = require("@noble/hashes/utils.js");
var import_base = require("@scure/base");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip19.ts Index: package/lib/esm/references.js
===================================================================
--- package/lib/esm/references.js
+++ package/lib/esm/references.js
@@ -1,10 +1,10 @@
// nip19.ts
-import { bytesToHex as bytesToHex2, concatBytes, hexToBytes as hexToBytes2 } from "@noble/hashes/utils";
+import { bytesToHex as bytesToHex2, concatBytes, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
import { bech32 } from "@scure/base";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// nip19.ts Index: package/lib/cjs/relay.js
===================================================================
--- package/lib/cjs/relay.js
+++ package/lib/cjs/relay.js
@@ -28,10 +28,10 @@
});
module.exports = __toCommonJS(relay_exports);
// pure.ts
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -62,12 +62,12 @@
return true;
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try {
@@ -141,18 +141,18 @@
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -163,9 +163,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -178,9 +178,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey; Index: package/lib/esm/relay.js
===================================================================
--- package/lib/esm/relay.js
+++ package/lib/esm/relay.js
@@ -1,7 +1,7 @@
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -32,12 +32,12 @@
return true;
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try {
@@ -111,18 +111,18 @@
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -133,9 +133,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false; Index: package/lib/cjs/signer.js
===================================================================
--- package/lib/cjs/signer.js
+++ package/lib/cjs/signer.js
@@ -24,10 +24,10 @@
});
module.exports = __toCommonJS(signer_exports);
// pure.ts
-var import_secp256k1 = require("@noble/curves/secp256k1");
-var import_utils2 = require("@noble/hashes/utils");
+var import_secp256k1 = require("@noble/curves/secp256k1.js");
+var import_utils2 = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -58,28 +58,28 @@
return true;
}
// pure.ts
-var import_sha256 = require("@noble/hashes/sha256");
+var import_sha2 = require("@noble/hashes/sha2.js");
// utils.ts
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return import_secp256k1.schnorr.utils.randomPrivateKey();
+ return import_secp256k1.schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign(getEventHash(event), secretKey));
+ event.sig = (0, import_utils2.bytesToHex)(import_secp256k1.schnorr.sign((0, import_utils2.hexToBytes)(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -90,9 +90,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = import_secp256k1.schnorr.verify((0, import_utils2.hexToBytes)(event.sig), (0, import_utils2.hexToBytes)(hash), (0, import_utils2.hexToBytes)(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
@@ -105,9 +105,9 @@
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
- let eventHash = (0, import_sha256.sha256)(utf8Encoder.encode(serializeEvent(event)));
+ let eventHash = (0, import_sha2.sha256)(utf8Encoder.encode(serializeEvent(event)));
return (0, import_utils2.bytesToHex)(eventHash);
}
var i = new JS();
var generateSecretKey = i.generateSecretKey; Index: package/lib/esm/signer.js
===================================================================
--- package/lib/esm/signer.js
+++ package/lib/esm/signer.js
@@ -1,7 +1,7 @@
// pure.ts
-import { schnorr } from "@noble/curves/secp256k1";
-import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
+import { schnorr } from "@noble/curves/secp256k1.js";
+import { bytesToHex as bytesToHex2, hexToBytes as hexToBytes2 } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object;
@@ -32,28 +32,28 @@
return true;
}
// pure.ts
-import { sha256 } from "@noble/hashes/sha256";
+import { sha256 } from "@noble/hashes/sha2.js";
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
// pure.ts
var JS = class {
generateSecretKey() {
- return schnorr.utils.randomPrivateKey();
+ return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex2(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
- event.sig = bytesToHex2(schnorr.sign(getEventHash(event), secretKey));
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
@@ -64,9 +64,9 @@
event[verifiedSymbol] = false;
return false;
}
try {
- const valid = schnorr.verify(event.sig, hash, event.pubkey);
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false; Index: package/lib/cjs/utils.js
===================================================================
--- package/lib/cjs/utils.js
+++ package/lib/cjs/utils.js
@@ -31,9 +31,9 @@
utf8Decoder: () => utf8Decoder,
utf8Encoder: () => utf8Encoder
});
module.exports = __toCommonJS(utils_exports);
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try { Index: package/lib/esm/utils.js
===================================================================
--- package/lib/esm/utils.js
+++ package/lib/esm/utils.js
@@ -1,6 +1,6 @@
// utils.ts
-import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
+import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
var utf8Decoder = new TextDecoder("utf-8");
var utf8Encoder = new TextEncoder();
function normalizeURL(url) {
try { Index: package/lib/cjs/wasm.js
===================================================================
--- package/lib/cjs/wasm.js
+++ package/lib/cjs/wasm.js
@@ -29,9 +29,9 @@
verifiedSymbol: () => verifiedSymbol,
verifyEvent: () => verifyEvent
});
module.exports = __toCommonJS(wasm_exports);
-var import_utils = require("@noble/hashes/utils");
+var import_utils = require("@noble/hashes/utils.js");
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object; Index: package/lib/esm/wasm.js
===================================================================
--- package/lib/esm/wasm.js
+++ package/lib/esm/wasm.js
@@ -1,6 +1,6 @@
// wasm.ts
-import { bytesToHex } from "@noble/hashes/utils";
+import { bytesToHex } from "@noble/hashes/utils.js";
// core.ts
var verifiedSymbol = Symbol("verified");
var isRecord = (obj) => obj instanceof Object; Index: package/package.json
===================================================================
--- package/package.json
+++ package/package.json
@@ -1,8 +1,8 @@
{
"type": "module",
"name": "nostr-tools",
- "version": "2.20.0",
+ "version": "2.21.0",
"description": "Tools for making a Nostr client.",
"repository": {
"type": "git",
"url": "https://github.com/nbd-wtf/nostr-tools.git"
@@ -235,14 +235,14 @@
}
},
"license": "Unlicense",
"dependencies": {
- "@noble/ciphers": "^0.5.1",
- "@noble/curves": "1.2.0",
- "@noble/hashes": "1.3.1",
- "@scure/base": "1.1.1",
- "@scure/bip32": "1.3.1",
- "@scure/bip39": "1.2.1",
+ "@noble/ciphers": "npm:@jsr/[email protected]",
+ "@noble/curves": "npm:@jsr/[email protected]",
+ "@noble/hashes": "npm:@jsr/[email protected]",
+ "@scure/base": "npm:@jsr/[email protected]",
+ "@scure/bip32": "npm:@jsr/[email protected]",
+ "@scure/bip39": "npm:@jsr/[email protected]",
"nostr-wasm": "0.1.0"
},
"peerDependencies": {
"typescript": ">=5.0.0" Index: package/lib/cjs/abstract-pool.js.map
===================================================================
--- package/lib/cjs/abstract-pool.js.map
+++ package/lib/cjs/abstract-pool.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../abstract-pool.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts", "../../helpers.ts", "../../abstract-relay.ts"],
- "sourcesContent": ["/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n"],
+ "sourcesContent": ["/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n"],
"mappings": "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",
"names": ["target", "reason"]
} Index: package/lib/esm/abstract-pool.js.map
===================================================================
--- package/lib/esm/abstract-pool.js.map
+++ package/lib/esm/abstract-pool.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../core.ts", "../../utils.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts", "../../helpers.ts", "../../abstract-relay.ts", "../../abstract-pool.ts"],
- "sourcesContent": ["export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n"],
+ "sourcesContent": ["export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n"],
"mappings": "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",
"names": ["target", "reason"]
} Index: package/lib/cjs/abstract-relay.js.map
===================================================================
--- package/lib/cjs/abstract-relay.js.map
+++ package/lib/cjs/abstract-relay.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../abstract-relay.ts", "../../utils.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts", "../../helpers.ts"],
- "sourcesContent": ["/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n"],
+ "sourcesContent": ["/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n"],
"mappings": "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",
"names": ["target"]
} Index: package/lib/esm/abstract-relay.js.map
===================================================================
--- package/lib/esm/abstract-relay.js.map
+++ package/lib/esm/abstract-relay.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../utils.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts", "../../helpers.ts", "../../abstract-relay.ts"],
- "sourcesContent": ["import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n"],
+ "sourcesContent": ["import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n"],
"mappings": "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",
"names": ["target"]
} File too large for inline diff
File too large for inline diff
Index: package/lib/cjs/nip04.js.map
===================================================================
--- package/lib/cjs/nip04.js.map
+++ package/lib/cjs/nip04.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip04.ts", "../../utils.ts"],
- "sourcesContent": ["import { bytesToHex, randomBytes } from '@noble/hashes/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { cbc } from '@noble/ciphers/aes'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport function encrypt(secretKey: string | Uint8Array, pubkey: string, text: string): string {\n const privkey: string = secretKey instanceof Uint8Array ? bytesToHex(secretKey) : secretKey\n const key = secp256k1.getSharedSecret(privkey, '02' + pubkey)\n const normalizedKey = getNormalizedX(key)\n\n let iv = Uint8Array.from(randomBytes(16))\n let plaintext = utf8Encoder.encode(text)\n\n let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext)\n\n let ctb64 = base64.encode(new Uint8Array(ciphertext))\n let ivb64 = base64.encode(new Uint8Array(iv.buffer))\n\n return `${ctb64}?iv=${ivb64}`\n}\n\nexport function decrypt(secretKey: string | Uint8Array, pubkey: string, data: string): string {\n const privkey: string = secretKey instanceof Uint8Array ? bytesToHex(secretKey) : secretKey\n let [ctb64, ivb64] = data.split('?iv=')\n let key = secp256k1.getSharedSecret(privkey, '02' + pubkey)\n let normalizedKey = getNormalizedX(key)\n\n let iv = base64.decode(ivb64)\n let ciphertext = base64.decode(ctb64)\n\n let plaintext = cbc(normalizedKey, iv).decrypt(ciphertext)\n\n return utf8Decoder.decode(plaintext)\n}\n\nfunction getNormalizedX(key: Uint8Array): Uint8Array {\n return key.slice(1, 33)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,gBAAwC;AACxC,uBAA0B;AAC1B,iBAAoB;AACpB,kBAAuB;;;ACEvB,mBAAuC;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;ADIjD,SAAS,QAAQ,WAAgC,QAAgB,MAAsB;AAC5F,QAAM,UAAkB,qBAAqB,iBAAa,0BAAW,SAAS,IAAI;AAClF,QAAM,MAAM,2BAAU,gBAAgB,SAAS,OAAO,MAAM;AAC5D,QAAM,gBAAgB,eAAe,GAAG;AAExC,MAAI,KAAK,WAAW,SAAK,2BAAY,EAAE,CAAC;AACxC,MAAI,YAAY,YAAY,OAAO,IAAI;AAEvC,MAAI,iBAAa,gBAAI,eAAe,EAAE,EAAE,QAAQ,SAAS;AAEzD,MAAI,QAAQ,mBAAO,OAAO,IAAI,WAAW,UAAU,CAAC;AACpD,MAAI,QAAQ,mBAAO,OAAO,IAAI,WAAW,GAAG,MAAM,CAAC;AAEnD,SAAO,GAAG,YAAY;AACxB;AAEO,SAAS,QAAQ,WAAgC,QAAgB,MAAsB;AAC5F,QAAM,UAAkB,qBAAqB,iBAAa,0BAAW,SAAS,IAAI;AAClF,MAAI,CAAC,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AACtC,MAAI,MAAM,2BAAU,gBAAgB,SAAS,OAAO,MAAM;AAC1D,MAAI,gBAAgB,eAAe,GAAG;AAEtC,MAAI,KAAK,mBAAO,OAAO,KAAK;AAC5B,MAAI,aAAa,mBAAO,OAAO,KAAK;AAEpC,MAAI,gBAAY,gBAAI,eAAe,EAAE,EAAE,QAAQ,UAAU;AAEzD,SAAO,YAAY,OAAO,SAAS;AACrC;AAEA,SAAS,eAAe,KAA6B;AACnD,SAAO,IAAI,MAAM,GAAG,EAAE;AACxB;",
+ "sourcesContent": ["import { hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { cbc } from '@noble/ciphers/aes.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport function encrypt(secretKey: string | Uint8Array, pubkey: string, text: string): string {\n const privkey: Uint8Array = secretKey instanceof Uint8Array ? secretKey : hexToBytes(secretKey)\n const key = secp256k1.getSharedSecret(privkey, hexToBytes('02' + pubkey))\n const normalizedKey = getNormalizedX(key)\n\n let iv = Uint8Array.from(randomBytes(16))\n let plaintext = utf8Encoder.encode(text)\n\n let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext)\n\n let ctb64 = base64.encode(new Uint8Array(ciphertext))\n let ivb64 = base64.encode(new Uint8Array(iv.buffer))\n\n return `${ctb64}?iv=${ivb64}`\n}\n\nexport function decrypt(secretKey: string | Uint8Array, pubkey: string, data: string): string {\n const privkey: Uint8Array = secretKey instanceof Uint8Array ? secretKey : hexToBytes(secretKey)\n let [ctb64, ivb64] = data.split('?iv=')\n let key = secp256k1.getSharedSecret(privkey, hexToBytes('02' + pubkey))\n let normalizedKey = getNormalizedX(key)\n\n let iv = base64.decode(ivb64)\n let ciphertext = base64.decode(ctb64)\n\n let plaintext = cbc(normalizedKey, iv).decrypt(ciphertext)\n\n return utf8Decoder.decode(plaintext)\n}\n\nfunction getNormalizedX(key: Uint8Array): Uint8Array {\n return key.slice(1, 33)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,gBAAwC;AACxC,uBAA0B;AAC1B,iBAAoB;AACpB,kBAAuB;;;ACEvB,mBAAuC;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;ADIjD,SAAS,QAAQ,WAAgC,QAAgB,MAAsB;AAC5F,QAAM,UAAsB,qBAAqB,aAAa,gBAAY,0BAAW,SAAS;AAC9F,QAAM,MAAM,2BAAU,gBAAgB,aAAS,0BAAW,OAAO,MAAM,CAAC;AACxE,QAAM,gBAAgB,eAAe,GAAG;AAExC,MAAI,KAAK,WAAW,SAAK,2BAAY,EAAE,CAAC;AACxC,MAAI,YAAY,YAAY,OAAO,IAAI;AAEvC,MAAI,iBAAa,gBAAI,eAAe,EAAE,EAAE,QAAQ,SAAS;AAEzD,MAAI,QAAQ,mBAAO,OAAO,IAAI,WAAW,UAAU,CAAC;AACpD,MAAI,QAAQ,mBAAO,OAAO,IAAI,WAAW,GAAG,MAAM,CAAC;AAEnD,SAAO,GAAG,YAAY;AACxB;AAEO,SAAS,QAAQ,WAAgC,QAAgB,MAAsB;AAC5F,QAAM,UAAsB,qBAAqB,aAAa,gBAAY,0BAAW,SAAS;AAC9F,MAAI,CAAC,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AACtC,MAAI,MAAM,2BAAU,gBAAgB,aAAS,0BAAW,OAAO,MAAM,CAAC;AACtE,MAAI,gBAAgB,eAAe,GAAG;AAEtC,MAAI,KAAK,mBAAO,OAAO,KAAK;AAC5B,MAAI,aAAa,mBAAO,OAAO,KAAK;AAEpC,MAAI,gBAAY,gBAAI,eAAe,EAAE,EAAE,QAAQ,UAAU;AAEzD,SAAO,YAAY,OAAO,SAAS;AACrC;AAEA,SAAS,eAAe,KAA6B;AACnD,SAAO,IAAI,MAAM,GAAG,EAAE;AACxB;",
"names": ["import_utils"]
} Index: package/lib/esm/nip04.js.map
===================================================================
--- package/lib/esm/nip04.js.map
+++ package/lib/esm/nip04.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip04.ts", "../../utils.ts"],
- "sourcesContent": ["import { bytesToHex, randomBytes } from '@noble/hashes/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { cbc } from '@noble/ciphers/aes'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport function encrypt(secretKey: string | Uint8Array, pubkey: string, text: string): string {\n const privkey: string = secretKey instanceof Uint8Array ? bytesToHex(secretKey) : secretKey\n const key = secp256k1.getSharedSecret(privkey, '02' + pubkey)\n const normalizedKey = getNormalizedX(key)\n\n let iv = Uint8Array.from(randomBytes(16))\n let plaintext = utf8Encoder.encode(text)\n\n let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext)\n\n let ctb64 = base64.encode(new Uint8Array(ciphertext))\n let ivb64 = base64.encode(new Uint8Array(iv.buffer))\n\n return `${ctb64}?iv=${ivb64}`\n}\n\nexport function decrypt(secretKey: string | Uint8Array, pubkey: string, data: string): string {\n const privkey: string = secretKey instanceof Uint8Array ? bytesToHex(secretKey) : secretKey\n let [ctb64, ivb64] = data.split('?iv=')\n let key = secp256k1.getSharedSecret(privkey, '02' + pubkey)\n let normalizedKey = getNormalizedX(key)\n\n let iv = base64.decode(ivb64)\n let ciphertext = base64.decode(ctb64)\n\n let plaintext = cbc(normalizedKey, iv).decrypt(ciphertext)\n\n return utf8Decoder.decode(plaintext)\n}\n\nfunction getNormalizedX(key: Uint8Array): Uint8Array {\n return key.slice(1, 33)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": ";AAAA,SAAS,cAAAA,aAAY,mBAAmB;AACxC,SAAS,iBAAiB;AAC1B,SAAS,WAAW;AACpB,SAAS,cAAc;;;ACEvB,SAAS,YAAY,kBAAkB;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;ADIjD,SAAS,QAAQ,WAAgC,QAAgB,MAAsB;AAC5F,QAAM,UAAkB,qBAAqB,aAAaC,YAAW,SAAS,IAAI;AAClF,QAAM,MAAM,UAAU,gBAAgB,SAAS,OAAO,MAAM;AAC5D,QAAM,gBAAgB,eAAe,GAAG;AAExC,MAAI,KAAK,WAAW,KAAK,YAAY,EAAE,CAAC;AACxC,MAAI,YAAY,YAAY,OAAO,IAAI;AAEvC,MAAI,aAAa,IAAI,eAAe,EAAE,EAAE,QAAQ,SAAS;AAEzD,MAAI,QAAQ,OAAO,OAAO,IAAI,WAAW,UAAU,CAAC;AACpD,MAAI,QAAQ,OAAO,OAAO,IAAI,WAAW,GAAG,MAAM,CAAC;AAEnD,SAAO,GAAG,YAAY;AACxB;AAEO,SAAS,QAAQ,WAAgC,QAAgB,MAAsB;AAC5F,QAAM,UAAkB,qBAAqB,aAAaA,YAAW,SAAS,IAAI;AAClF,MAAI,CAAC,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AACtC,MAAI,MAAM,UAAU,gBAAgB,SAAS,OAAO,MAAM;AAC1D,MAAI,gBAAgB,eAAe,GAAG;AAEtC,MAAI,KAAK,OAAO,OAAO,KAAK;AAC5B,MAAI,aAAa,OAAO,OAAO,KAAK;AAEpC,MAAI,YAAY,IAAI,eAAe,EAAE,EAAE,QAAQ,UAAU;AAEzD,SAAO,YAAY,OAAO,SAAS;AACrC;AAEA,SAAS,eAAe,KAA6B;AACnD,SAAO,IAAI,MAAM,GAAG,EAAE;AACxB;",
- "names": ["bytesToHex", "bytesToHex"]
+ "sourcesContent": ["import { hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { cbc } from '@noble/ciphers/aes.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport function encrypt(secretKey: string | Uint8Array, pubkey: string, text: string): string {\n const privkey: Uint8Array = secretKey instanceof Uint8Array ? secretKey : hexToBytes(secretKey)\n const key = secp256k1.getSharedSecret(privkey, hexToBytes('02' + pubkey))\n const normalizedKey = getNormalizedX(key)\n\n let iv = Uint8Array.from(randomBytes(16))\n let plaintext = utf8Encoder.encode(text)\n\n let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext)\n\n let ctb64 = base64.encode(new Uint8Array(ciphertext))\n let ivb64 = base64.encode(new Uint8Array(iv.buffer))\n\n return `${ctb64}?iv=${ivb64}`\n}\n\nexport function decrypt(secretKey: string | Uint8Array, pubkey: string, data: string): string {\n const privkey: Uint8Array = secretKey instanceof Uint8Array ? secretKey : hexToBytes(secretKey)\n let [ctb64, ivb64] = data.split('?iv=')\n let key = secp256k1.getSharedSecret(privkey, hexToBytes('02' + pubkey))\n let normalizedKey = getNormalizedX(key)\n\n let iv = base64.decode(ivb64)\n let ciphertext = base64.decode(ctb64)\n\n let plaintext = cbc(normalizedKey, iv).decrypt(ciphertext)\n\n return utf8Decoder.decode(plaintext)\n}\n\nfunction getNormalizedX(key: Uint8Array): Uint8Array {\n return key.slice(1, 33)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": ";AAAA,SAAS,cAAAA,aAAY,mBAAmB;AACxC,SAAS,iBAAiB;AAC1B,SAAS,WAAW;AACpB,SAAS,cAAc;;;ACEvB,SAAS,YAAY,kBAAkB;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;ADIjD,SAAS,QAAQ,WAAgC,QAAgB,MAAsB;AAC5F,QAAM,UAAsB,qBAAqB,aAAa,YAAYC,YAAW,SAAS;AAC9F,QAAM,MAAM,UAAU,gBAAgB,SAASA,YAAW,OAAO,MAAM,CAAC;AACxE,QAAM,gBAAgB,eAAe,GAAG;AAExC,MAAI,KAAK,WAAW,KAAK,YAAY,EAAE,CAAC;AACxC,MAAI,YAAY,YAAY,OAAO,IAAI;AAEvC,MAAI,aAAa,IAAI,eAAe,EAAE,EAAE,QAAQ,SAAS;AAEzD,MAAI,QAAQ,OAAO,OAAO,IAAI,WAAW,UAAU,CAAC;AACpD,MAAI,QAAQ,OAAO,OAAO,IAAI,WAAW,GAAG,MAAM,CAAC;AAEnD,SAAO,GAAG,YAAY;AACxB;AAEO,SAAS,QAAQ,WAAgC,QAAgB,MAAsB;AAC5F,QAAM,UAAsB,qBAAqB,aAAa,YAAYA,YAAW,SAAS;AAC9F,MAAI,CAAC,OAAO,KAAK,IAAI,KAAK,MAAM,MAAM;AACtC,MAAI,MAAM,UAAU,gBAAgB,SAASA,YAAW,OAAO,MAAM,CAAC;AACtE,MAAI,gBAAgB,eAAe,GAAG;AAEtC,MAAI,KAAK,OAAO,OAAO,KAAK;AAC5B,MAAI,aAAa,OAAO,OAAO,KAAK;AAEpC,MAAI,YAAY,IAAI,eAAe,EAAE,EAAE,QAAQ,UAAU;AAEzD,SAAO,YAAY,OAAO,SAAS;AACrC;AAEA,SAAS,eAAe,KAA6B;AACnD,SAAO,IAAI,MAAM,GAAG,EAAE;AACxB;",
+ "names": ["hexToBytes", "hexToBytes"]
} Index: package/lib/cjs/nip06.js.map
===================================================================
--- package/lib/cjs/nip06.js.map
+++ package/lib/cjs/nip06.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip06.ts"],
- "sourcesContent": ["import { bytesToHex } from '@noble/hashes/utils'\nimport { wordlist } from '@scure/bip39/wordlists/english'\nimport { generateMnemonic, mnemonicToSeedSync, validateMnemonic } from '@scure/bip39'\nimport { HDKey } from '@scure/bip32'\n\nconst DERIVATION_PATH = `m/44'/1237'`\n\nexport function privateKeyFromSeedWords(mnemonic: string, passphrase?: string, accountIndex = 0): Uint8Array {\n let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n let privateKey = root.derive(`${DERIVATION_PATH}/${accountIndex}'/0/0`).privateKey\n if (!privateKey) throw new Error('could not derive private key')\n return privateKey\n}\n\nexport function accountFromSeedWords(\n mnemonic: string,\n passphrase?: string,\n accountIndex = 0,\n): {\n privateKey: Uint8Array\n publicKey: string\n} {\n const root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n const seed = root.derive(`${DERIVATION_PATH}/${accountIndex}'/0/0`)\n const publicKey = bytesToHex(seed.publicKey!.slice(1))\n const privateKey = seed.privateKey\n if (!privateKey || !publicKey) {\n throw new Error('could not derive key pair')\n }\n return { privateKey, publicKey }\n}\n\nexport function extendedKeysFromSeedWords(\n mnemonic: string,\n passphrase?: string,\n extendedAccountIndex = 0,\n): {\n privateExtendedKey: string\n publicExtendedKey: string\n} {\n let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n let seed = root.derive(`${DERIVATION_PATH}/${extendedAccountIndex}'`)\n let privateExtendedKey = seed.privateExtendedKey\n let publicExtendedKey = seed.publicExtendedKey\n if (!privateExtendedKey && !publicExtendedKey) throw new Error('could not derive extended key pair')\n return { privateExtendedKey, publicExtendedKey }\n}\n\nexport function accountFromExtendedKey(\n base58key: string,\n accountIndex = 0,\n): {\n privateKey?: Uint8Array\n publicKey: string\n} {\n let extendedKey = HDKey.fromExtendedKey(base58key)\n let version = base58key.slice(0, 4)\n let child = extendedKey.deriveChild(0).deriveChild(accountIndex)\n let publicKey = bytesToHex(child.publicKey!.slice(1))\n if (!publicKey) throw new Error('could not derive public key')\n if (version === 'xprv') {\n let privateKey = child.privateKey!\n if (!privateKey) throw new Error('could not derive private key')\n return { privateKey, publicKey }\n }\n return { publicKey }\n}\n\nexport function generateSeedWords(): string {\n return generateMnemonic(wordlist)\n}\n\nexport function validateWords(words: string): boolean {\n return validateMnemonic(words, wordlist)\n}\n"],
+ "sourcesContent": ["import { bytesToHex } from '@noble/hashes/utils.js'\nimport { wordlist } from '@scure/bip39/wordlists/english.js'\nimport { generateMnemonic, mnemonicToSeedSync, validateMnemonic } from '@scure/bip39'\nimport { HDKey } from '@scure/bip32'\n\nconst DERIVATION_PATH = `m/44'/1237'`\n\nexport function privateKeyFromSeedWords(mnemonic: string, passphrase?: string, accountIndex = 0): Uint8Array {\n let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n let privateKey = root.derive(`${DERIVATION_PATH}/${accountIndex}'/0/0`).privateKey\n if (!privateKey) throw new Error('could not derive private key')\n return privateKey\n}\n\nexport function accountFromSeedWords(\n mnemonic: string,\n passphrase?: string,\n accountIndex = 0,\n): {\n privateKey: Uint8Array\n publicKey: string\n} {\n const root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n const seed = root.derive(`${DERIVATION_PATH}/${accountIndex}'/0/0`)\n const publicKey = bytesToHex(seed.publicKey!.slice(1))\n const privateKey = seed.privateKey\n if (!privateKey || !publicKey) {\n throw new Error('could not derive key pair')\n }\n return { privateKey, publicKey }\n}\n\nexport function extendedKeysFromSeedWords(\n mnemonic: string,\n passphrase?: string,\n extendedAccountIndex = 0,\n): {\n privateExtendedKey: string\n publicExtendedKey: string\n} {\n let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n let seed = root.derive(`${DERIVATION_PATH}/${extendedAccountIndex}'`)\n let privateExtendedKey = seed.privateExtendedKey\n let publicExtendedKey = seed.publicExtendedKey\n if (!privateExtendedKey && !publicExtendedKey) throw new Error('could not derive extended key pair')\n return { privateExtendedKey, publicExtendedKey }\n}\n\nexport function accountFromExtendedKey(\n base58key: string,\n accountIndex = 0,\n): {\n privateKey?: Uint8Array\n publicKey: string\n} {\n let extendedKey = HDKey.fromExtendedKey(base58key)\n let version = base58key.slice(0, 4)\n let child = extendedKey.deriveChild(0).deriveChild(accountIndex)\n let publicKey = bytesToHex(child.publicKey!.slice(1))\n if (!publicKey) throw new Error('could not derive public key')\n if (version === 'xprv') {\n let privateKey = child.privateKey!\n if (!privateKey) throw new Error('could not derive private key')\n return { privateKey, publicKey }\n }\n return { publicKey }\n}\n\nexport function generateSeedWords(): string {\n return generateMnemonic(wordlist)\n}\n\nexport function validateWords(words: string): boolean {\n return validateMnemonic(words, wordlist)\n}\n"],
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA2B;AAC3B,qBAAyB;AACzB,mBAAuE;AACvE,mBAAsB;AAEtB,IAAM,kBAAkB;AAEjB,SAAS,wBAAwB,UAAkB,YAAqB,eAAe,GAAe;AAC3G,MAAI,OAAO,mBAAM,mBAAe,iCAAmB,UAAU,UAAU,CAAC;AACxE,MAAI,aAAa,KAAK,OAAO,GAAG,mBAAmB,mBAAmB,EAAE;AACxE,MAAI,CAAC;AAAY,UAAM,IAAI,MAAM,8BAA8B;AAC/D,SAAO;AACT;AAEO,SAAS,qBACd,UACA,YACA,eAAe,GAIf;AACA,QAAM,OAAO,mBAAM,mBAAe,iCAAmB,UAAU,UAAU,CAAC;AAC1E,QAAM,OAAO,KAAK,OAAO,GAAG,mBAAmB,mBAAmB;AAClE,QAAM,gBAAY,yBAAW,KAAK,UAAW,MAAM,CAAC,CAAC;AACrD,QAAM,aAAa,KAAK;AACxB,MAAI,CAAC,cAAc,CAAC,WAAW;AAC7B,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AACA,SAAO,EAAE,YAAY,UAAU;AACjC;AAEO,SAAS,0BACd,UACA,YACA,uBAAuB,GAIvB;AACA,MAAI,OAAO,mBAAM,mBAAe,iCAAmB,UAAU,UAAU,CAAC;AACxE,MAAI,OAAO,KAAK,OAAO,GAAG,mBAAmB,uBAAuB;AACpE,MAAI,qBAAqB,KAAK;AAC9B,MAAI,oBAAoB,KAAK;AAC7B,MAAI,CAAC,sBAAsB,CAAC;AAAmB,UAAM,IAAI,MAAM,oCAAoC;AACnG,SAAO,EAAE,oBAAoB,kBAAkB;AACjD;AAEO,SAAS,uBACd,WACA,eAAe,GAIf;AACA,MAAI,cAAc,mBAAM,gBAAgB,SAAS;AACjD,MAAI,UAAU,UAAU,MAAM,GAAG,CAAC;AAClC,MAAI,QAAQ,YAAY,YAAY,CAAC,EAAE,YAAY,YAAY;AAC/D,MAAI,gBAAY,yBAAW,MAAM,UAAW,MAAM,CAAC,CAAC;AACpD,MAAI,CAAC;AAAW,UAAM,IAAI,MAAM,6BAA6B;AAC7D,MAAI,YAAY,QAAQ;AACtB,QAAI,aAAa,MAAM;AACvB,QAAI,CAAC;AAAY,YAAM,IAAI,MAAM,8BAA8B;AAC/D,WAAO,EAAE,YAAY,UAAU;AAAA,EACjC;AACA,SAAO,EAAE,UAAU;AACrB;AAEO,SAAS,oBAA4B;AAC1C,aAAO,+BAAiB,uBAAQ;AAClC;AAEO,SAAS,cAAc,OAAwB;AACpD,aAAO,+BAAiB,OAAO,uBAAQ;AACzC;",
"names": []
} Index: package/lib/esm/nip06.js.map
===================================================================
--- package/lib/esm/nip06.js.map
+++ package/lib/esm/nip06.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip06.ts"],
- "sourcesContent": ["import { bytesToHex } from '@noble/hashes/utils'\nimport { wordlist } from '@scure/bip39/wordlists/english'\nimport { generateMnemonic, mnemonicToSeedSync, validateMnemonic } from '@scure/bip39'\nimport { HDKey } from '@scure/bip32'\n\nconst DERIVATION_PATH = `m/44'/1237'`\n\nexport function privateKeyFromSeedWords(mnemonic: string, passphrase?: string, accountIndex = 0): Uint8Array {\n let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n let privateKey = root.derive(`${DERIVATION_PATH}/${accountIndex}'/0/0`).privateKey\n if (!privateKey) throw new Error('could not derive private key')\n return privateKey\n}\n\nexport function accountFromSeedWords(\n mnemonic: string,\n passphrase?: string,\n accountIndex = 0,\n): {\n privateKey: Uint8Array\n publicKey: string\n} {\n const root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n const seed = root.derive(`${DERIVATION_PATH}/${accountIndex}'/0/0`)\n const publicKey = bytesToHex(seed.publicKey!.slice(1))\n const privateKey = seed.privateKey\n if (!privateKey || !publicKey) {\n throw new Error('could not derive key pair')\n }\n return { privateKey, publicKey }\n}\n\nexport function extendedKeysFromSeedWords(\n mnemonic: string,\n passphrase?: string,\n extendedAccountIndex = 0,\n): {\n privateExtendedKey: string\n publicExtendedKey: string\n} {\n let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n let seed = root.derive(`${DERIVATION_PATH}/${extendedAccountIndex}'`)\n let privateExtendedKey = seed.privateExtendedKey\n let publicExtendedKey = seed.publicExtendedKey\n if (!privateExtendedKey && !publicExtendedKey) throw new Error('could not derive extended key pair')\n return { privateExtendedKey, publicExtendedKey }\n}\n\nexport function accountFromExtendedKey(\n base58key: string,\n accountIndex = 0,\n): {\n privateKey?: Uint8Array\n publicKey: string\n} {\n let extendedKey = HDKey.fromExtendedKey(base58key)\n let version = base58key.slice(0, 4)\n let child = extendedKey.deriveChild(0).deriveChild(accountIndex)\n let publicKey = bytesToHex(child.publicKey!.slice(1))\n if (!publicKey) throw new Error('could not derive public key')\n if (version === 'xprv') {\n let privateKey = child.privateKey!\n if (!privateKey) throw new Error('could not derive private key')\n return { privateKey, publicKey }\n }\n return { publicKey }\n}\n\nexport function generateSeedWords(): string {\n return generateMnemonic(wordlist)\n}\n\nexport function validateWords(words: string): boolean {\n return validateMnemonic(words, wordlist)\n}\n"],
+ "sourcesContent": ["import { bytesToHex } from '@noble/hashes/utils.js'\nimport { wordlist } from '@scure/bip39/wordlists/english.js'\nimport { generateMnemonic, mnemonicToSeedSync, validateMnemonic } from '@scure/bip39'\nimport { HDKey } from '@scure/bip32'\n\nconst DERIVATION_PATH = `m/44'/1237'`\n\nexport function privateKeyFromSeedWords(mnemonic: string, passphrase?: string, accountIndex = 0): Uint8Array {\n let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n let privateKey = root.derive(`${DERIVATION_PATH}/${accountIndex}'/0/0`).privateKey\n if (!privateKey) throw new Error('could not derive private key')\n return privateKey\n}\n\nexport function accountFromSeedWords(\n mnemonic: string,\n passphrase?: string,\n accountIndex = 0,\n): {\n privateKey: Uint8Array\n publicKey: string\n} {\n const root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n const seed = root.derive(`${DERIVATION_PATH}/${accountIndex}'/0/0`)\n const publicKey = bytesToHex(seed.publicKey!.slice(1))\n const privateKey = seed.privateKey\n if (!privateKey || !publicKey) {\n throw new Error('could not derive key pair')\n }\n return { privateKey, publicKey }\n}\n\nexport function extendedKeysFromSeedWords(\n mnemonic: string,\n passphrase?: string,\n extendedAccountIndex = 0,\n): {\n privateExtendedKey: string\n publicExtendedKey: string\n} {\n let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n let seed = root.derive(`${DERIVATION_PATH}/${extendedAccountIndex}'`)\n let privateExtendedKey = seed.privateExtendedKey\n let publicExtendedKey = seed.publicExtendedKey\n if (!privateExtendedKey && !publicExtendedKey) throw new Error('could not derive extended key pair')\n return { privateExtendedKey, publicExtendedKey }\n}\n\nexport function accountFromExtendedKey(\n base58key: string,\n accountIndex = 0,\n): {\n privateKey?: Uint8Array\n publicKey: string\n} {\n let extendedKey = HDKey.fromExtendedKey(base58key)\n let version = base58key.slice(0, 4)\n let child = extendedKey.deriveChild(0).deriveChild(accountIndex)\n let publicKey = bytesToHex(child.publicKey!.slice(1))\n if (!publicKey) throw new Error('could not derive public key')\n if (version === 'xprv') {\n let privateKey = child.privateKey!\n if (!privateKey) throw new Error('could not derive private key')\n return { privateKey, publicKey }\n }\n return { publicKey }\n}\n\nexport function generateSeedWords(): string {\n return generateMnemonic(wordlist)\n}\n\nexport function validateWords(words: string): boolean {\n return validateMnemonic(words, wordlist)\n}\n"],
"mappings": ";AAAA,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,kBAAkB,oBAAoB,wBAAwB;AACvE,SAAS,aAAa;AAEtB,IAAM,kBAAkB;AAEjB,SAAS,wBAAwB,UAAkB,YAAqB,eAAe,GAAe;AAC3G,MAAI,OAAO,MAAM,eAAe,mBAAmB,UAAU,UAAU,CAAC;AACxE,MAAI,aAAa,KAAK,OAAO,GAAG,mBAAmB,mBAAmB,EAAE;AACxE,MAAI,CAAC;AAAY,UAAM,IAAI,MAAM,8BAA8B;AAC/D,SAAO;AACT;AAEO,SAAS,qBACd,UACA,YACA,eAAe,GAIf;AACA,QAAM,OAAO,MAAM,eAAe,mBAAmB,UAAU,UAAU,CAAC;AAC1E,QAAM,OAAO,KAAK,OAAO,GAAG,mBAAmB,mBAAmB;AAClE,QAAM,YAAY,WAAW,KAAK,UAAW,MAAM,CAAC,CAAC;AACrD,QAAM,aAAa,KAAK;AACxB,MAAI,CAAC,cAAc,CAAC,WAAW;AAC7B,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AACA,SAAO,EAAE,YAAY,UAAU;AACjC;AAEO,SAAS,0BACd,UACA,YACA,uBAAuB,GAIvB;AACA,MAAI,OAAO,MAAM,eAAe,mBAAmB,UAAU,UAAU,CAAC;AACxE,MAAI,OAAO,KAAK,OAAO,GAAG,mBAAmB,uBAAuB;AACpE,MAAI,qBAAqB,KAAK;AAC9B,MAAI,oBAAoB,KAAK;AAC7B,MAAI,CAAC,sBAAsB,CAAC;AAAmB,UAAM,IAAI,MAAM,oCAAoC;AACnG,SAAO,EAAE,oBAAoB,kBAAkB;AACjD;AAEO,SAAS,uBACd,WACA,eAAe,GAIf;AACA,MAAI,cAAc,MAAM,gBAAgB,SAAS;AACjD,MAAI,UAAU,UAAU,MAAM,GAAG,CAAC;AAClC,MAAI,QAAQ,YAAY,YAAY,CAAC,EAAE,YAAY,YAAY;AAC/D,MAAI,YAAY,WAAW,MAAM,UAAW,MAAM,CAAC,CAAC;AACpD,MAAI,CAAC;AAAW,UAAM,IAAI,MAAM,6BAA6B;AAC7D,MAAI,YAAY,QAAQ;AACtB,QAAI,aAAa,MAAM;AACvB,QAAI,CAAC;AAAY,YAAM,IAAI,MAAM,8BAA8B;AAC/D,WAAO,EAAE,YAAY,UAAU;AAAA,EACjC;AACA,SAAO,EAAE,UAAU;AACrB;AAEO,SAAS,oBAA4B;AAC1C,SAAO,iBAAiB,QAAQ;AAClC;AAEO,SAAS,cAAc,OAAwB;AACpD,SAAO,iBAAiB,OAAO,QAAQ;AACzC;",
"names": []
} Index: package/lib/cjs/nip13.js.map
===================================================================
--- package/lib/cjs/nip13.js.map
+++ package/lib/cjs/nip13.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip13.ts", "../../utils.ts"],
- "sourcesContent": ["import { bytesToHex } from '@noble/hashes/utils'\nimport { type UnsignedEvent, type Event } from './pure.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\n/** Get POW difficulty from a Nostr hex ID. */\nexport function getPow(hex: string): number {\n let count = 0\n\n for (let i = 0; i < 64; i += 8) {\n const nibble = parseInt(hex.substring(i, i + 8), 16)\n if (nibble === 0) {\n count += 32\n } else {\n count += Math.clz32(nibble)\n break\n }\n }\n\n return count\n}\n\n/**\n * Mine an event with the desired POW. This function mutates the event.\n * Note that this operation is synchronous and should be run in a worker context to avoid blocking the main thread.\n */\nexport function minePow(unsigned: UnsignedEvent, difficulty: number): Omit<Event, 'sig'> {\n let count = 0\n\n const event = unsigned as Omit<Event, 'sig'>\n const tag = ['nonce', count.toString(), difficulty.toString()]\n\n event.tags.push(tag)\n\n while (true) {\n const now = Math.floor(new Date().getTime() / 1000)\n\n if (now !== event.created_at) {\n count = 0\n event.created_at = now\n }\n\n tag[1] = (++count).toString()\n\n event.id = fastEventHash(event)\n\n if (getPow(event.id) >= difficulty) {\n break\n }\n }\n\n return event\n}\n\nexport function fastEventHash(evt: UnsignedEvent): string {\n return bytesToHex(\n sha256(utf8Encoder.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]))),\n )\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,gBAA2B;AAE3B,oBAAuB;;;ACGvB,mBAAuC;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;ADIjD,SAAS,OAAO,KAAqB;AAC1C,MAAI,QAAQ;AAEZ,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK,GAAG;AAC9B,UAAM,SAAS,SAAS,IAAI,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE;AACnD,QAAI,WAAW,GAAG;AAChB,eAAS;AAAA,IACX,OAAO;AACL,eAAS,KAAK,MAAM,MAAM;AAC1B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,QAAQ,UAAyB,YAAwC;AACvF,MAAI,QAAQ;AAEZ,QAAM,QAAQ;AACd,QAAM,MAAM,CAAC,SAAS,MAAM,SAAS,GAAG,WAAW,SAAS,CAAC;AAE7D,QAAM,KAAK,KAAK,GAAG;AAEnB,SAAO,MAAM;AACX,UAAM,MAAM,KAAK,MAAM,IAAI,KAAK,EAAE,QAAQ,IAAI,GAAI;AAElD,QAAI,QAAQ,MAAM,YAAY;AAC5B,cAAQ;AACR,YAAM,aAAa;AAAA,IACrB;AAEA,QAAI,MAAM,EAAE,OAAO,SAAS;AAE5B,UAAM,KAAK,cAAc,KAAK;AAE9B,QAAI,OAAO,MAAM,EAAE,KAAK,YAAY;AAClC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,cAAc,KAA4B;AACxD,aAAO;AAAA,QACL,sBAAO,YAAY,OAAO,KAAK,UAAU,CAAC,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC;AAAA,EAC7G;AACF;",
+ "sourcesContent": ["import { bytesToHex } from '@noble/hashes/utils.js'\nimport { type UnsignedEvent, type Event } from './pure.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\n/** Get POW difficulty from a Nostr hex ID. */\nexport function getPow(hex: string): number {\n let count = 0\n\n for (let i = 0; i < 64; i += 8) {\n const nibble = parseInt(hex.substring(i, i + 8), 16)\n if (nibble === 0) {\n count += 32\n } else {\n count += Math.clz32(nibble)\n break\n }\n }\n\n return count\n}\n\n/**\n * Mine an event with the desired POW. This function mutates the event.\n * Note that this operation is synchronous and should be run in a worker context to avoid blocking the main thread.\n */\nexport function minePow(unsigned: UnsignedEvent, difficulty: number): Omit<Event, 'sig'> {\n let count = 0\n\n const event = unsigned as Omit<Event, 'sig'>\n const tag = ['nonce', count.toString(), difficulty.toString()]\n\n event.tags.push(tag)\n\n while (true) {\n const now = Math.floor(new Date().getTime() / 1000)\n\n if (now !== event.created_at) {\n count = 0\n event.created_at = now\n }\n\n tag[1] = (++count).toString()\n\n event.id = fastEventHash(event)\n\n if (getPow(event.id) >= difficulty) {\n break\n }\n }\n\n return event\n}\n\nexport function fastEventHash(evt: UnsignedEvent): string {\n return bytesToHex(\n sha256(utf8Encoder.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]))),\n )\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,gBAA2B;AAE3B,kBAAuB;;;ACGvB,mBAAuC;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;ADIjD,SAAS,OAAO,KAAqB;AAC1C,MAAI,QAAQ;AAEZ,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK,GAAG;AAC9B,UAAM,SAAS,SAAS,IAAI,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE;AACnD,QAAI,WAAW,GAAG;AAChB,eAAS;AAAA,IACX,OAAO;AACL,eAAS,KAAK,MAAM,MAAM;AAC1B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,QAAQ,UAAyB,YAAwC;AACvF,MAAI,QAAQ;AAEZ,QAAM,QAAQ;AACd,QAAM,MAAM,CAAC,SAAS,MAAM,SAAS,GAAG,WAAW,SAAS,CAAC;AAE7D,QAAM,KAAK,KAAK,GAAG;AAEnB,SAAO,MAAM;AACX,UAAM,MAAM,KAAK,MAAM,IAAI,KAAK,EAAE,QAAQ,IAAI,GAAI;AAElD,QAAI,QAAQ,MAAM,YAAY;AAC5B,cAAQ;AACR,YAAM,aAAa;AAAA,IACrB;AAEA,QAAI,MAAM,EAAE,OAAO,SAAS;AAE5B,UAAM,KAAK,cAAc,KAAK;AAE9B,QAAI,OAAO,MAAM,EAAE,KAAK,YAAY;AAClC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,cAAc,KAA4B;AACxD,aAAO;AAAA,QACL,oBAAO,YAAY,OAAO,KAAK,UAAU,CAAC,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC;AAAA,EAC7G;AACF;",
"names": ["import_utils"]
} Index: package/lib/esm/nip13.js.map
===================================================================
--- package/lib/esm/nip13.js.map
+++ package/lib/esm/nip13.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip13.ts", "../../utils.ts"],
- "sourcesContent": ["import { bytesToHex } from '@noble/hashes/utils'\nimport { type UnsignedEvent, type Event } from './pure.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\n/** Get POW difficulty from a Nostr hex ID. */\nexport function getPow(hex: string): number {\n let count = 0\n\n for (let i = 0; i < 64; i += 8) {\n const nibble = parseInt(hex.substring(i, i + 8), 16)\n if (nibble === 0) {\n count += 32\n } else {\n count += Math.clz32(nibble)\n break\n }\n }\n\n return count\n}\n\n/**\n * Mine an event with the desired POW. This function mutates the event.\n * Note that this operation is synchronous and should be run in a worker context to avoid blocking the main thread.\n */\nexport function minePow(unsigned: UnsignedEvent, difficulty: number): Omit<Event, 'sig'> {\n let count = 0\n\n const event = unsigned as Omit<Event, 'sig'>\n const tag = ['nonce', count.toString(), difficulty.toString()]\n\n event.tags.push(tag)\n\n while (true) {\n const now = Math.floor(new Date().getTime() / 1000)\n\n if (now !== event.created_at) {\n count = 0\n event.created_at = now\n }\n\n tag[1] = (++count).toString()\n\n event.id = fastEventHash(event)\n\n if (getPow(event.id) >= difficulty) {\n break\n }\n }\n\n return event\n}\n\nexport function fastEventHash(evt: UnsignedEvent): string {\n return bytesToHex(\n sha256(utf8Encoder.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]))),\n )\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "sourcesContent": ["import { bytesToHex } from '@noble/hashes/utils.js'\nimport { type UnsignedEvent, type Event } from './pure.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\n/** Get POW difficulty from a Nostr hex ID. */\nexport function getPow(hex: string): number {\n let count = 0\n\n for (let i = 0; i < 64; i += 8) {\n const nibble = parseInt(hex.substring(i, i + 8), 16)\n if (nibble === 0) {\n count += 32\n } else {\n count += Math.clz32(nibble)\n break\n }\n }\n\n return count\n}\n\n/**\n * Mine an event with the desired POW. This function mutates the event.\n * Note that this operation is synchronous and should be run in a worker context to avoid blocking the main thread.\n */\nexport function minePow(unsigned: UnsignedEvent, difficulty: number): Omit<Event, 'sig'> {\n let count = 0\n\n const event = unsigned as Omit<Event, 'sig'>\n const tag = ['nonce', count.toString(), difficulty.toString()]\n\n event.tags.push(tag)\n\n while (true) {\n const now = Math.floor(new Date().getTime() / 1000)\n\n if (now !== event.created_at) {\n count = 0\n event.created_at = now\n }\n\n tag[1] = (++count).toString()\n\n event.id = fastEventHash(event)\n\n if (getPow(event.id) >= difficulty) {\n break\n }\n }\n\n return event\n}\n\nexport function fastEventHash(evt: UnsignedEvent): string {\n return bytesToHex(\n sha256(utf8Encoder.encode(JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]))),\n )\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
"mappings": ";AAAA,SAAS,cAAAA,mBAAkB;AAE3B,SAAS,cAAc;;;ACGvB,SAAS,YAAY,kBAAkB;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;ADIjD,SAAS,OAAO,KAAqB;AAC1C,MAAI,QAAQ;AAEZ,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK,GAAG;AAC9B,UAAM,SAAS,SAAS,IAAI,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE;AACnD,QAAI,WAAW,GAAG;AAChB,eAAS;AAAA,IACX,OAAO;AACL,eAAS,KAAK,MAAM,MAAM;AAC1B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,QAAQ,UAAyB,YAAwC;AACvF,MAAI,QAAQ;AAEZ,QAAM,QAAQ;AACd,QAAM,MAAM,CAAC,SAAS,MAAM,SAAS,GAAG,WAAW,SAAS,CAAC;AAE7D,QAAM,KAAK,KAAK,GAAG;AAEnB,SAAO,MAAM;AACX,UAAM,MAAM,KAAK,MAAM,IAAI,KAAK,EAAE,QAAQ,IAAI,GAAI;AAElD,QAAI,QAAQ,MAAM,YAAY;AAC5B,cAAQ;AACR,YAAM,aAAa;AAAA,IACrB;AAEA,QAAI,MAAM,EAAE,OAAO,SAAS;AAE5B,UAAM,KAAK,cAAc,KAAK;AAE9B,QAAI,OAAO,MAAM,EAAE,KAAK,YAAY;AAClC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,cAAc,KAA4B;AACxD,SAAOC;AAAA,IACL,OAAO,YAAY,OAAO,KAAK,UAAU,CAAC,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC;AAAA,EAC7G;AACF;",
"names": ["bytesToHex", "bytesToHex"]
} Index: package/lib/cjs/nip17.js.map
===================================================================
--- package/lib/cjs/nip17.js.map
+++ package/lib/cjs/nip17.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip17.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../nip44.ts", "../../nip59.ts"],
- "sourcesContent": ["import { PrivateDirectMessage } from './kinds.ts'\nimport { EventTemplate, NostrEvent, getPublicKey } from './pure.ts'\nimport * as nip59 from './nip59.ts'\n\ntype Recipient = {\n publicKey: string\n relayUrl?: string\n}\n\ntype ReplyTo = {\n eventId: string\n relayUrl?: string\n}\n\nfunction createEvent(\n recipients: Recipient | Recipient[],\n message: string,\n conversationTitle?: string,\n replyTo?: ReplyTo,\n): EventTemplate {\n const baseEvent: EventTemplate = {\n created_at: Math.ceil(Date.now() / 1000),\n kind: PrivateDirectMessage,\n tags: [],\n content: message,\n }\n\n const recipientsArray = Array.isArray(recipients) ? recipients : [recipients]\n\n recipientsArray.forEach(({ publicKey, relayUrl }) => {\n baseEvent.tags.push(relayUrl ? ['p', publicKey, relayUrl] : ['p', publicKey])\n })\n\n if (replyTo) {\n baseEvent.tags.push(['e', replyTo.eventId, replyTo.relayUrl || '', 'reply'])\n }\n\n if (conversationTitle) {\n baseEvent.tags.push(['subject', conversationTitle])\n }\n\n return baseEvent\n}\n\nexport function wrapEvent(\n senderPrivateKey: Uint8Array,\n recipient: Recipient,\n message: string,\n conversationTitle?: string,\n replyTo?: ReplyTo,\n): NostrEvent {\n const event = createEvent(recipient, message, conversationTitle, replyTo)\n return nip59.wrapEvent(event, senderPrivateKey, recipient.publicKey)\n}\n\nexport function wrapManyEvents(\n senderPrivateKey: Uint8Array,\n recipients: Recipient[],\n message: string,\n conversationTitle?: string,\n replyTo?: ReplyTo,\n): NostrEvent[] {\n if (!recipients || recipients.length === 0) {\n throw new Error('At least one recipient is required.')\n }\n\n const senderPublicKey = getPublicKey(senderPrivateKey)\n\n // wrap the event for the sender and then for each recipient\n return [{ publicKey: senderPublicKey }, ...recipients].map(recipient =>\n wrapEvent(senderPrivateKey, recipient, message, conversationTitle, replyTo),\n )\n}\n\nexport const unwrapEvent = nip59.unwrapEvent\n\nexport const unwrapManyEvents = nip59.unwrapManyEvents\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { chacha20 } from '@noble/ciphers/chacha'\nimport { equalBytes } from '@noble/ciphers/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf'\nimport { hmac } from '@noble/hashes/hmac'\nimport { sha256 } from '@noble/hashes/sha256'\nimport { concatBytes, randomBytes } from '@noble/hashes/utils'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, 'nip44-v2')\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import { EventTemplate, UnsignedEvent, NostrEvent } from './core.ts'\nimport { getConversationKey, decrypt, encrypt } from './nip44.ts'\nimport { getEventHash, generateSecretKey, finalizeEvent, getPublicKey } from './pure.ts'\nimport { Seal, GiftWrap } from './kinds.ts'\n\ntype Rumor = UnsignedEvent & { id: string }\n\nconst TWO_DAYS = 2 * 24 * 60 * 60\n\nconst now = () => Math.round(Date.now() / 1000)\nconst randomNow = () => Math.round(now() - Math.random() * TWO_DAYS)\n\nconst nip44ConversationKey = (privateKey: Uint8Array, publicKey: string) => getConversationKey(privateKey, publicKey)\n\nconst nip44Encrypt = (data: EventTemplate, privateKey: Uint8Array, publicKey: string) =>\n encrypt(JSON.stringify(data), nip44ConversationKey(privateKey, publicKey))\n\nconst nip44Decrypt = (data: NostrEvent, privateKey: Uint8Array) =>\n JSON.parse(decrypt(data.content, nip44ConversationKey(privateKey, data.pubkey)))\n\nexport function createRumor(event: Partial<UnsignedEvent>, privateKey: Uint8Array): Rumor {\n const rumor = {\n created_at: now(),\n content: '',\n tags: [],\n ...event,\n pubkey: getPublicKey(privateKey),\n } as any\n\n rumor.id = getEventHash(rumor)\n\n return rumor as Rumor\n}\n\nexport function createSeal(rumor: Rumor, privateKey: Uint8Array, recipientPublicKey: string): NostrEvent {\n return finalizeEvent(\n {\n kind: Seal,\n content: nip44Encrypt(rumor, privateKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [],\n },\n privateKey,\n )\n}\n\nexport function createWrap(seal: NostrEvent, recipientPublicKey: string): NostrEvent {\n const randomKey = generateSecretKey()\n\n return finalizeEvent(\n {\n kind: GiftWrap,\n content: nip44Encrypt(seal, randomKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [['p', recipientPublicKey]],\n },\n randomKey,\n ) as NostrEvent\n}\n\nexport function wrapEvent(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientPublicKey: string,\n): NostrEvent {\n const rumor = createRumor(event, senderPrivateKey)\n\n const seal = createSeal(rumor, senderPrivateKey, recipientPublicKey)\n return createWrap(seal, recipientPublicKey)\n}\n\nexport function wrapManyEvents(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientsPublicKeys: string[],\n): NostrEvent[] {\n if (!recipientsPublicKeys || recipientsPublicKeys.length === 0) {\n throw new Error('At least one recipient is required.')\n }\n\n const senderPublicKey = getPublicKey(senderPrivateKey)\n\n const wrappeds = [wrapEvent(event, senderPrivateKey, senderPublicKey)]\n\n recipientsPublicKeys.forEach(recipientPublicKey => {\n wrappeds.push(wrapEvent(event, senderPrivateKey, recipientPublicKey))\n })\n\n return wrappeds\n}\n\nexport function unwrapEvent(wrap: NostrEvent, recipientPrivateKey: Uint8Array): Rumor {\n const unwrappedSeal = nip44Decrypt(wrap, recipientPrivateKey)\n return nip44Decrypt(unwrappedSeal, recipientPrivateKey)\n}\n\nexport function unwrapManyEvents(wrappedEvents: NostrEvent[], recipientPrivateKey: Uint8Array): Rumor[] {\n let unwrappedEvents: Rumor[] = []\n\n wrappedEvents.forEach(e => {\n unwrappedEvents.push(unwrapEvent(e, recipientPrivateKey))\n })\n\n unwrappedEvents.sort((a, b) => a.created_at - b.created_at)\n\n return unwrappedEvents\n}\n"],
- "mappings": "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",
- "names": ["unwrapEvent", "unwrapManyEvents", "wrapEvent", "import_utils", "i", "import_utils", "import_secp256k1", "import_sha256", "hkdf_extract", "hkdf_expand", "wrapEvent", "unwrapEvent", "unwrapManyEvents"]
+ "sourcesContent": ["import { PrivateDirectMessage } from './kinds.ts'\nimport { EventTemplate, NostrEvent, getPublicKey } from './pure.ts'\nimport * as nip59 from './nip59.ts'\n\ntype Recipient = {\n publicKey: string\n relayUrl?: string\n}\n\ntype ReplyTo = {\n eventId: string\n relayUrl?: string\n}\n\nfunction createEvent(\n recipients: Recipient | Recipient[],\n message: string,\n conversationTitle?: string,\n replyTo?: ReplyTo,\n): EventTemplate {\n const baseEvent: EventTemplate = {\n created_at: Math.ceil(Date.now() / 1000),\n kind: PrivateDirectMessage,\n tags: [],\n content: message,\n }\n\n const recipientsArray = Array.isArray(recipients) ? recipients : [recipients]\n\n recipientsArray.forEach(({ publicKey, relayUrl }) => {\n baseEvent.tags.push(relayUrl ? ['p', publicKey, relayUrl] : ['p', publicKey])\n })\n\n if (replyTo) {\n baseEvent.tags.push(['e', replyTo.eventId, replyTo.relayUrl || '', 'reply'])\n }\n\n if (conversationTitle) {\n baseEvent.tags.push(['subject', conversationTitle])\n }\n\n return baseEvent\n}\n\nexport function wrapEvent(\n senderPrivateKey: Uint8Array,\n recipient: Recipient,\n message: string,\n conversationTitle?: string,\n replyTo?: ReplyTo,\n): NostrEvent {\n const event = createEvent(recipient, message, conversationTitle, replyTo)\n return nip59.wrapEvent(event, senderPrivateKey, recipient.publicKey)\n}\n\nexport function wrapManyEvents(\n senderPrivateKey: Uint8Array,\n recipients: Recipient[],\n message: string,\n conversationTitle?: string,\n replyTo?: ReplyTo,\n): NostrEvent[] {\n if (!recipients || recipients.length === 0) {\n throw new Error('At least one recipient is required.')\n }\n\n const senderPublicKey = getPublicKey(senderPrivateKey)\n\n // wrap the event for the sender and then for each recipient\n return [{ publicKey: senderPublicKey }, ...recipients].map(recipient =>\n wrapEvent(senderPrivateKey, recipient, message, conversationTitle, replyTo),\n )\n}\n\nexport const unwrapEvent = nip59.unwrapEvent\n\nexport const unwrapManyEvents = nip59.unwrapManyEvents\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { chacha20 } from '@noble/ciphers/chacha.js'\nimport { equalBytes } from '@noble/ciphers/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf.js'\nimport { hmac } from '@noble/hashes/hmac.js'\nimport { sha256 } from '@noble/hashes/sha2.js'\nimport { concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes('02' + pubkeyB)).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, utf8Encoder.encode('nip44-v2'))\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import { EventTemplate, UnsignedEvent, NostrEvent } from './core.ts'\nimport { getConversationKey, decrypt, encrypt } from './nip44.ts'\nimport { getEventHash, generateSecretKey, finalizeEvent, getPublicKey } from './pure.ts'\nimport { Seal, GiftWrap } from './kinds.ts'\n\ntype Rumor = UnsignedEvent & { id: string }\n\nconst TWO_DAYS = 2 * 24 * 60 * 60\n\nconst now = () => Math.round(Date.now() / 1000)\nconst randomNow = () => Math.round(now() - Math.random() * TWO_DAYS)\n\nconst nip44ConversationKey = (privateKey: Uint8Array, publicKey: string) => getConversationKey(privateKey, publicKey)\n\nconst nip44Encrypt = (data: EventTemplate, privateKey: Uint8Array, publicKey: string) =>\n encrypt(JSON.stringify(data), nip44ConversationKey(privateKey, publicKey))\n\nconst nip44Decrypt = (data: NostrEvent, privateKey: Uint8Array) =>\n JSON.parse(decrypt(data.content, nip44ConversationKey(privateKey, data.pubkey)))\n\nexport function createRumor(event: Partial<UnsignedEvent>, privateKey: Uint8Array): Rumor {\n const rumor = {\n created_at: now(),\n content: '',\n tags: [],\n ...event,\n pubkey: getPublicKey(privateKey),\n } as any\n\n rumor.id = getEventHash(rumor)\n\n return rumor as Rumor\n}\n\nexport function createSeal(rumor: Rumor, privateKey: Uint8Array, recipientPublicKey: string): NostrEvent {\n return finalizeEvent(\n {\n kind: Seal,\n content: nip44Encrypt(rumor, privateKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [],\n },\n privateKey,\n )\n}\n\nexport function createWrap(seal: NostrEvent, recipientPublicKey: string): NostrEvent {\n const randomKey = generateSecretKey()\n\n return finalizeEvent(\n {\n kind: GiftWrap,\n content: nip44Encrypt(seal, randomKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [['p', recipientPublicKey]],\n },\n randomKey,\n ) as NostrEvent\n}\n\nexport function wrapEvent(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientPublicKey: string,\n): NostrEvent {\n const rumor = createRumor(event, senderPrivateKey)\n\n const seal = createSeal(rumor, senderPrivateKey, recipientPublicKey)\n return createWrap(seal, recipientPublicKey)\n}\n\nexport function wrapManyEvents(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientsPublicKeys: string[],\n): NostrEvent[] {\n if (!recipientsPublicKeys || recipientsPublicKeys.length === 0) {\n throw new Error('At least one recipient is required.')\n }\n\n const senderPublicKey = getPublicKey(senderPrivateKey)\n\n const wrappeds = [wrapEvent(event, senderPrivateKey, senderPublicKey)]\n\n recipientsPublicKeys.forEach(recipientPublicKey => {\n wrappeds.push(wrapEvent(event, senderPrivateKey, recipientPublicKey))\n })\n\n return wrappeds\n}\n\nexport function unwrapEvent(wrap: NostrEvent, recipientPrivateKey: Uint8Array): Rumor {\n const unwrappedSeal = nip44Decrypt(wrap, recipientPrivateKey)\n return nip44Decrypt(unwrappedSeal, recipientPrivateKey)\n}\n\nexport function unwrapManyEvents(wrappedEvents: NostrEvent[], recipientPrivateKey: Uint8Array): Rumor[] {\n let unwrappedEvents: Rumor[] = []\n\n wrappedEvents.forEach(e => {\n unwrappedEvents.push(unwrapEvent(e, recipientPrivateKey))\n })\n\n unwrappedEvents.sort((a, b) => a.created_at - b.created_at)\n\n return unwrappedEvents\n}\n"],
+ "mappings": "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",
+ "names": ["unwrapEvent", "unwrapManyEvents", "wrapEvent", "import_utils", "i", "import_utils", "import_secp256k1", "import_sha2", "hkdf_extract", "hkdf_expand", "wrapEvent", "unwrapEvent", "unwrapManyEvents"]
} Index: package/lib/esm/nip17.js.map
===================================================================
--- package/lib/esm/nip17.js.map
+++ package/lib/esm/nip17.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../nip44.ts", "../../nip59.ts", "../../nip17.ts"],
- "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { chacha20 } from '@noble/ciphers/chacha'\nimport { equalBytes } from '@noble/ciphers/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf'\nimport { hmac } from '@noble/hashes/hmac'\nimport { sha256 } from '@noble/hashes/sha256'\nimport { concatBytes, randomBytes } from '@noble/hashes/utils'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, 'nip44-v2')\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import { EventTemplate, UnsignedEvent, NostrEvent } from './core.ts'\nimport { getConversationKey, decrypt, encrypt } from './nip44.ts'\nimport { getEventHash, generateSecretKey, finalizeEvent, getPublicKey } from './pure.ts'\nimport { Seal, GiftWrap } from './kinds.ts'\n\ntype Rumor = UnsignedEvent & { id: string }\n\nconst TWO_DAYS = 2 * 24 * 60 * 60\n\nconst now = () => Math.round(Date.now() / 1000)\nconst randomNow = () => Math.round(now() - Math.random() * TWO_DAYS)\n\nconst nip44ConversationKey = (privateKey: Uint8Array, publicKey: string) => getConversationKey(privateKey, publicKey)\n\nconst nip44Encrypt = (data: EventTemplate, privateKey: Uint8Array, publicKey: string) =>\n encrypt(JSON.stringify(data), nip44ConversationKey(privateKey, publicKey))\n\nconst nip44Decrypt = (data: NostrEvent, privateKey: Uint8Array) =>\n JSON.parse(decrypt(data.content, nip44ConversationKey(privateKey, data.pubkey)))\n\nexport function createRumor(event: Partial<UnsignedEvent>, privateKey: Uint8Array): Rumor {\n const rumor = {\n created_at: now(),\n content: '',\n tags: [],\n ...event,\n pubkey: getPublicKey(privateKey),\n } as any\n\n rumor.id = getEventHash(rumor)\n\n return rumor as Rumor\n}\n\nexport function createSeal(rumor: Rumor, privateKey: Uint8Array, recipientPublicKey: string): NostrEvent {\n return finalizeEvent(\n {\n kind: Seal,\n content: nip44Encrypt(rumor, privateKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [],\n },\n privateKey,\n )\n}\n\nexport function createWrap(seal: NostrEvent, recipientPublicKey: string): NostrEvent {\n const randomKey = generateSecretKey()\n\n return finalizeEvent(\n {\n kind: GiftWrap,\n content: nip44Encrypt(seal, randomKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [['p', recipientPublicKey]],\n },\n randomKey,\n ) as NostrEvent\n}\n\nexport function wrapEvent(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientPublicKey: string,\n): NostrEvent {\n const rumor = createRumor(event, senderPrivateKey)\n\n const seal = createSeal(rumor, senderPrivateKey, recipientPublicKey)\n return createWrap(seal, recipientPublicKey)\n}\n\nexport function wrapManyEvents(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientsPublicKeys: string[],\n): NostrEvent[] {\n if (!recipientsPublicKeys || recipientsPublicKeys.length === 0) {\n throw new Error('At least one recipient is required.')\n }\n\n const senderPublicKey = getPublicKey(senderPrivateKey)\n\n const wrappeds = [wrapEvent(event, senderPrivateKey, senderPublicKey)]\n\n recipientsPublicKeys.forEach(recipientPublicKey => {\n wrappeds.push(wrapEvent(event, senderPrivateKey, recipientPublicKey))\n })\n\n return wrappeds\n}\n\nexport function unwrapEvent(wrap: NostrEvent, recipientPrivateKey: Uint8Array): Rumor {\n const unwrappedSeal = nip44Decrypt(wrap, recipientPrivateKey)\n return nip44Decrypt(unwrappedSeal, recipientPrivateKey)\n}\n\nexport function unwrapManyEvents(wrappedEvents: NostrEvent[], recipientPrivateKey: Uint8Array): Rumor[] {\n let unwrappedEvents: Rumor[] = []\n\n wrappedEvents.forEach(e => {\n unwrappedEvents.push(unwrapEvent(e, recipientPrivateKey))\n })\n\n unwrappedEvents.sort((a, b) => a.created_at - b.created_at)\n\n return unwrappedEvents\n}\n", "import { PrivateDirectMessage } from './kinds.ts'\nimport { EventTemplate, NostrEvent, getPublicKey } from './pure.ts'\nimport * as nip59 from './nip59.ts'\n\ntype Recipient = {\n publicKey: string\n relayUrl?: string\n}\n\ntype ReplyTo = {\n eventId: string\n relayUrl?: string\n}\n\nfunction createEvent(\n recipients: Recipient | Recipient[],\n message: string,\n conversationTitle?: string,\n replyTo?: ReplyTo,\n): EventTemplate {\n const baseEvent: EventTemplate = {\n created_at: Math.ceil(Date.now() / 1000),\n kind: PrivateDirectMessage,\n tags: [],\n content: message,\n }\n\n const recipientsArray = Array.isArray(recipients) ? recipients : [recipients]\n\n recipientsArray.forEach(({ publicKey, relayUrl }) => {\n baseEvent.tags.push(relayUrl ? ['p', publicKey, relayUrl] : ['p', publicKey])\n })\n\n if (replyTo) {\n baseEvent.tags.push(['e', replyTo.eventId, replyTo.relayUrl || '', 'reply'])\n }\n\n if (conversationTitle) {\n baseEvent.tags.push(['subject', conversationTitle])\n }\n\n return baseEvent\n}\n\nexport function wrapEvent(\n senderPrivateKey: Uint8Array,\n recipient: Recipient,\n message: string,\n conversationTitle?: string,\n replyTo?: ReplyTo,\n): NostrEvent {\n const event = createEvent(recipient, message, conversationTitle, replyTo)\n return nip59.wrapEvent(event, senderPrivateKey, recipient.publicKey)\n}\n\nexport function wrapManyEvents(\n senderPrivateKey: Uint8Array,\n recipients: Recipient[],\n message: string,\n conversationTitle?: string,\n replyTo?: ReplyTo,\n): NostrEvent[] {\n if (!recipients || recipients.length === 0) {\n throw new Error('At least one recipient is required.')\n }\n\n const senderPublicKey = getPublicKey(senderPrivateKey)\n\n // wrap the event for the sender and then for each recipient\n return [{ publicKey: senderPublicKey }, ...recipients].map(recipient =>\n wrapEvent(senderPrivateKey, recipient, message, conversationTitle, replyTo),\n )\n}\n\nexport const unwrapEvent = nip59.unwrapEvent\n\nexport const unwrapManyEvents = nip59.unwrapManyEvents\n"],
- "mappings": "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",
- "names": ["bytesToHex", "i", "bytesToHex", "sha256", "sha256", "wrapEvent", "unwrapEvent", "unwrapManyEvents"]
+ "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { chacha20 } from '@noble/ciphers/chacha.js'\nimport { equalBytes } from '@noble/ciphers/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf.js'\nimport { hmac } from '@noble/hashes/hmac.js'\nimport { sha256 } from '@noble/hashes/sha2.js'\nimport { concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes('02' + pubkeyB)).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, utf8Encoder.encode('nip44-v2'))\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import { EventTemplate, UnsignedEvent, NostrEvent } from './core.ts'\nimport { getConversationKey, decrypt, encrypt } from './nip44.ts'\nimport { getEventHash, generateSecretKey, finalizeEvent, getPublicKey } from './pure.ts'\nimport { Seal, GiftWrap } from './kinds.ts'\n\ntype Rumor = UnsignedEvent & { id: string }\n\nconst TWO_DAYS = 2 * 24 * 60 * 60\n\nconst now = () => Math.round(Date.now() / 1000)\nconst randomNow = () => Math.round(now() - Math.random() * TWO_DAYS)\n\nconst nip44ConversationKey = (privateKey: Uint8Array, publicKey: string) => getConversationKey(privateKey, publicKey)\n\nconst nip44Encrypt = (data: EventTemplate, privateKey: Uint8Array, publicKey: string) =>\n encrypt(JSON.stringify(data), nip44ConversationKey(privateKey, publicKey))\n\nconst nip44Decrypt = (data: NostrEvent, privateKey: Uint8Array) =>\n JSON.parse(decrypt(data.content, nip44ConversationKey(privateKey, data.pubkey)))\n\nexport function createRumor(event: Partial<UnsignedEvent>, privateKey: Uint8Array): Rumor {\n const rumor = {\n created_at: now(),\n content: '',\n tags: [],\n ...event,\n pubkey: getPublicKey(privateKey),\n } as any\n\n rumor.id = getEventHash(rumor)\n\n return rumor as Rumor\n}\n\nexport function createSeal(rumor: Rumor, privateKey: Uint8Array, recipientPublicKey: string): NostrEvent {\n return finalizeEvent(\n {\n kind: Seal,\n content: nip44Encrypt(rumor, privateKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [],\n },\n privateKey,\n )\n}\n\nexport function createWrap(seal: NostrEvent, recipientPublicKey: string): NostrEvent {\n const randomKey = generateSecretKey()\n\n return finalizeEvent(\n {\n kind: GiftWrap,\n content: nip44Encrypt(seal, randomKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [['p', recipientPublicKey]],\n },\n randomKey,\n ) as NostrEvent\n}\n\nexport function wrapEvent(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientPublicKey: string,\n): NostrEvent {\n const rumor = createRumor(event, senderPrivateKey)\n\n const seal = createSeal(rumor, senderPrivateKey, recipientPublicKey)\n return createWrap(seal, recipientPublicKey)\n}\n\nexport function wrapManyEvents(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientsPublicKeys: string[],\n): NostrEvent[] {\n if (!recipientsPublicKeys || recipientsPublicKeys.length === 0) {\n throw new Error('At least one recipient is required.')\n }\n\n const senderPublicKey = getPublicKey(senderPrivateKey)\n\n const wrappeds = [wrapEvent(event, senderPrivateKey, senderPublicKey)]\n\n recipientsPublicKeys.forEach(recipientPublicKey => {\n wrappeds.push(wrapEvent(event, senderPrivateKey, recipientPublicKey))\n })\n\n return wrappeds\n}\n\nexport function unwrapEvent(wrap: NostrEvent, recipientPrivateKey: Uint8Array): Rumor {\n const unwrappedSeal = nip44Decrypt(wrap, recipientPrivateKey)\n return nip44Decrypt(unwrappedSeal, recipientPrivateKey)\n}\n\nexport function unwrapManyEvents(wrappedEvents: NostrEvent[], recipientPrivateKey: Uint8Array): Rumor[] {\n let unwrappedEvents: Rumor[] = []\n\n wrappedEvents.forEach(e => {\n unwrappedEvents.push(unwrapEvent(e, recipientPrivateKey))\n })\n\n unwrappedEvents.sort((a, b) => a.created_at - b.created_at)\n\n return unwrappedEvents\n}\n", "import { PrivateDirectMessage } from './kinds.ts'\nimport { EventTemplate, NostrEvent, getPublicKey } from './pure.ts'\nimport * as nip59 from './nip59.ts'\n\ntype Recipient = {\n publicKey: string\n relayUrl?: string\n}\n\ntype ReplyTo = {\n eventId: string\n relayUrl?: string\n}\n\nfunction createEvent(\n recipients: Recipient | Recipient[],\n message: string,\n conversationTitle?: string,\n replyTo?: ReplyTo,\n): EventTemplate {\n const baseEvent: EventTemplate = {\n created_at: Math.ceil(Date.now() / 1000),\n kind: PrivateDirectMessage,\n tags: [],\n content: message,\n }\n\n const recipientsArray = Array.isArray(recipients) ? recipients : [recipients]\n\n recipientsArray.forEach(({ publicKey, relayUrl }) => {\n baseEvent.tags.push(relayUrl ? ['p', publicKey, relayUrl] : ['p', publicKey])\n })\n\n if (replyTo) {\n baseEvent.tags.push(['e', replyTo.eventId, replyTo.relayUrl || '', 'reply'])\n }\n\n if (conversationTitle) {\n baseEvent.tags.push(['subject', conversationTitle])\n }\n\n return baseEvent\n}\n\nexport function wrapEvent(\n senderPrivateKey: Uint8Array,\n recipient: Recipient,\n message: string,\n conversationTitle?: string,\n replyTo?: ReplyTo,\n): NostrEvent {\n const event = createEvent(recipient, message, conversationTitle, replyTo)\n return nip59.wrapEvent(event, senderPrivateKey, recipient.publicKey)\n}\n\nexport function wrapManyEvents(\n senderPrivateKey: Uint8Array,\n recipients: Recipient[],\n message: string,\n conversationTitle?: string,\n replyTo?: ReplyTo,\n): NostrEvent[] {\n if (!recipients || recipients.length === 0) {\n throw new Error('At least one recipient is required.')\n }\n\n const senderPublicKey = getPublicKey(senderPrivateKey)\n\n // wrap the event for the sender and then for each recipient\n return [{ publicKey: senderPublicKey }, ...recipients].map(recipient =>\n wrapEvent(senderPrivateKey, recipient, message, conversationTitle, replyTo),\n )\n}\n\nexport const unwrapEvent = nip59.unwrapEvent\n\nexport const unwrapManyEvents = nip59.unwrapManyEvents\n"],
+ "mappings": "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",
+ "names": ["bytesToHex", "hexToBytes", "i", "bytesToHex", "hexToBytes", "sha256", "hexToBytes", "hexToBytes", "sha256", "wrapEvent", "unwrapEvent", "unwrapManyEvents"]
} Index: package/lib/cjs/nip18.js.map
===================================================================
--- package/lib/cjs/nip18.js.map
+++ package/lib/cjs/nip18.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip18.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts"],
- "sourcesContent": ["import { GenericRepost, Repost, ShortTextNote } from './kinds.ts'\nimport { EventPointer } from './nip19.ts'\nimport { Event, finalizeEvent, verifyEvent } from './pure.ts'\n\nexport type RepostEventTemplate = {\n /**\n * Pass only non-nip18 tags if you have to.\n * Nip18 tags ('e' and 'p' tags pointing to the reposted event) will be added automatically.\n */\n tags?: string[][]\n\n /**\n * Pass an empty string to NOT include the stringified JSON of the reposted event.\n * Any other content will be ignored and replaced with the stringified JSON of the reposted event.\n * @default Stringified JSON of the reposted event\n */\n content?: ''\n\n created_at: number\n}\n\nexport function finishRepostEvent(\n t: RepostEventTemplate,\n reposted: Event,\n relayUrl: string,\n privateKey: Uint8Array,\n): Event {\n let kind: Repost | GenericRepost\n const tags = [...(t.tags ?? []), ['e', reposted.id, relayUrl], ['p', reposted.pubkey]]\n if (reposted.kind === ShortTextNote) {\n kind = Repost\n } else {\n kind = GenericRepost\n tags.push(['k', String(reposted.kind)])\n }\n\n return finalizeEvent(\n {\n kind,\n tags,\n content: t.content === '' || reposted.tags?.find(tag => tag[0] === '-') ? '' : JSON.stringify(reposted),\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport function getRepostedEventPointer(event: Event): undefined | EventPointer {\n if (![Repost, GenericRepost].includes(event.kind)) {\n return undefined\n }\n\n let lastETag: undefined | string[]\n let lastPTag: undefined | string[]\n\n for (let i = event.tags.length - 1; i >= 0 && (lastETag === undefined || lastPTag === undefined); i--) {\n const tag = event.tags[i]\n if (tag.length >= 2) {\n if (tag[0] === 'e' && lastETag === undefined) {\n lastETag = tag\n } else if (tag[0] === 'p' && lastPTag === undefined) {\n lastPTag = tag\n }\n }\n }\n\n if (lastETag === undefined) {\n return undefined\n }\n\n return {\n id: lastETag[1],\n relays: [lastETag[2], lastPTag?.[2]].filter((x): x is string => typeof x === 'string'),\n author: lastPTag?.[1],\n }\n}\n\nexport type GetRepostedEventOptions = {\n skipVerification?: boolean\n}\n\nexport function getRepostedEvent(event: Event, { skipVerification }: GetRepostedEventOptions = {}): undefined | Event {\n const pointer = getRepostedEventPointer(event)\n\n if (pointer === undefined || event.content === '') {\n return undefined\n }\n\n let repostedEvent: undefined | Event\n\n try {\n repostedEvent = JSON.parse(event.content) as Event\n } catch (error) {\n return undefined\n }\n\n if (repostedEvent.id !== pointer.id) {\n return undefined\n }\n\n if (!skipVerification && !verifyEvent(repostedEvent)) {\n return undefined\n }\n\n return repostedEvent\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,uBAAwB;AACxB,IAAAA,gBAA2B;;;ACOpB,IAAM,iBAAiB,OAAO,UAAU;AAsB/C,IAAM,WAAW,CAAC,QAAiD,eAAe;AAE3E,SAAS,cAAiB,OAAsC;AACrE,MAAI,CAAC,SAAS,KAAK;AAAG,WAAO;AAC7B,MAAI,OAAO,MAAM,SAAS;AAAU,WAAO;AAC3C,MAAI,OAAO,MAAM,YAAY;AAAU,WAAO;AAC9C,MAAI,OAAO,MAAM,eAAe;AAAU,WAAO;AACjD,MAAI,OAAO,MAAM,WAAW;AAAU,WAAO;AAC7C,MAAI,CAAC,MAAM,OAAO,MAAM,gBAAgB;AAAG,WAAO;AAElD,MAAI,CAAC,MAAM,QAAQ,MAAM,IAAI;AAAG,WAAO;AACvC,WAASC,KAAI,GAAGA,KAAI,MAAM,KAAK,QAAQA,MAAK;AAC1C,QAAI,MAAM,MAAM,KAAKA;AACrB,QAAI,CAAC,MAAM,QAAQ,GAAG;AAAG,aAAO;AAChC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAI,OAAO,IAAI,OAAO;AAAU,eAAO;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AACT;;;AD/CA,oBAAuB;;;AEEvB,mBAAuC;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;AFIxD,IAAM,KAAN,MAA0B;AAAA,EACxB,oBAAgC;AAC9B,WAAO,yBAAQ,MAAM,iBAAiB;AAAA,EACxC;AAAA,EACA,aAAa,WAA+B;AAC1C,eAAO,0BAAW,yBAAQ,aAAa,SAAS,CAAC;AAAA,EACnD;AAAA,EACA,cAAc,GAAkB,WAAsC;AACpE,UAAM,QAAQ;AACd,UAAM,aAAS,0BAAW,yBAAQ,aAAa,SAAS,CAAC;AACzD,UAAM,KAAK,aAAa,KAAK;AAC7B,UAAM,UAAM,0BAAW,yBAAQ,KAAK,aAAa,KAAK,GAAG,SAAS,CAAC;AACnE,UAAM,kBAAkB;AACxB,WAAO;AAAA,EACT;AAAA,EACA,YAAY,OAAsC;AAChD,QAAI,OAAO,MAAM,oBAAoB;AAAW,aAAO,MAAM;AAE7D,UAAM,OAAO,aAAa,KAAK;AAC/B,QAAI,SAAS,MAAM,IAAI;AACrB,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,QAAQ,yBAAQ,OAAO,MAAM,KAAK,MAAM,MAAM,MAAM;AAC1D,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT,SAAS,KAAP;AACA,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,eAAe,KAA4B;AACzD,MAAI,CAAC,cAAc,GAAG;AAAG,UAAM,IAAI,MAAM,wDAAwD;AACjG,SAAO,KAAK,UAAU,CAAC,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,CAAC;AACxF;AAEO,SAAS,aAAa,OAA8B;AACzD,MAAI,gBAAY,sBAAO,YAAY,OAAO,eAAe,KAAK,CAAC,CAAC;AAChE,aAAO,0BAAW,SAAS;AAC7B;AAEA,IAAM,IAAQ,IAAI,GAAG;AAEd,IAAM,oBAAoB,EAAE;AAC5B,IAAM,eAAe,EAAE;AACvB,IAAM,gBAAgB,EAAE;AACxB,IAAM,cAAc,EAAE;;;AGhBtB,IAAM,gBAAgB;AAUtB,IAAM,SAAS;AAgBf,IAAM,gBAAgB;;;AJ9CtB,SAAS,kBACd,GACA,UACA,UACA,YACO;AACP,MAAI;AACJ,QAAM,OAAO,CAAC,GAAI,EAAE,QAAQ,CAAC,GAAI,CAAC,KAAK,SAAS,IAAI,QAAQ,GAAG,CAAC,KAAK,SAAS,MAAM,CAAC;AACrF,MAAI,SAAS,SAAS,eAAe;AACnC,WAAO;AAAA,EACT,OAAO;AACL,WAAO;AACP,SAAK,KAAK,CAAC,KAAK,OAAO,SAAS,IAAI,CAAC,CAAC;AAAA,EACxC;AAEA,SAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA;AAAA,MACA,SAAS,EAAE,YAAY,MAAM,SAAS,MAAM,KAAK,SAAO,IAAI,OAAO,GAAG,IAAI,KAAK,KAAK,UAAU,QAAQ;AAAA,MACtG,YAAY,EAAE;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,wBAAwB,OAAwC;AAC9E,MAAI,CAAC,CAAC,QAAQ,aAAa,EAAE,SAAS,MAAM,IAAI,GAAG;AACjD,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AAEJ,WAASC,KAAI,MAAM,KAAK,SAAS,GAAGA,MAAK,MAAM,aAAa,UAAa,aAAa,SAAYA,MAAK;AACrG,UAAM,MAAM,MAAM,KAAKA;AACvB,QAAI,IAAI,UAAU,GAAG;AACnB,UAAI,IAAI,OAAO,OAAO,aAAa,QAAW;AAC5C,mBAAW;AAAA,MACb,WAAW,IAAI,OAAO,OAAO,aAAa,QAAW;AACnD,mBAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAEA,MAAI,aAAa,QAAW;AAC1B,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,IAAI,SAAS;AAAA,IACb,QAAQ,CAAC,SAAS,IAAI,WAAW,EAAE,EAAE,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ;AAAA,IACrF,QAAQ,WAAW;AAAA,EACrB;AACF;AAMO,SAAS,iBAAiB,OAAc,EAAE,iBAAiB,IAA6B,CAAC,GAAsB;AACpH,QAAM,UAAU,wBAAwB,KAAK;AAE7C,MAAI,YAAY,UAAa,MAAM,YAAY,IAAI;AACjD,WAAO;AAAA,EACT;AAEA,MAAI;AAEJ,MAAI;AACF,oBAAgB,KAAK,MAAM,MAAM,OAAO;AAAA,EAC1C,SAAS,OAAP;AACA,WAAO;AAAA,EACT;AAEA,MAAI,cAAc,OAAO,QAAQ,IAAI;AACnC,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,oBAAoB,CAAC,YAAY,aAAa,GAAG;AACpD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;",
+ "sourcesContent": ["import { GenericRepost, Repost, ShortTextNote } from './kinds.ts'\nimport { EventPointer } from './nip19.ts'\nimport { Event, finalizeEvent, verifyEvent } from './pure.ts'\n\nexport type RepostEventTemplate = {\n /**\n * Pass only non-nip18 tags if you have to.\n * Nip18 tags ('e' and 'p' tags pointing to the reposted event) will be added automatically.\n */\n tags?: string[][]\n\n /**\n * Pass an empty string to NOT include the stringified JSON of the reposted event.\n * Any other content will be ignored and replaced with the stringified JSON of the reposted event.\n * @default Stringified JSON of the reposted event\n */\n content?: ''\n\n created_at: number\n}\n\nexport function finishRepostEvent(\n t: RepostEventTemplate,\n reposted: Event,\n relayUrl: string,\n privateKey: Uint8Array,\n): Event {\n let kind: Repost | GenericRepost\n const tags = [...(t.tags ?? []), ['e', reposted.id, relayUrl], ['p', reposted.pubkey]]\n if (reposted.kind === ShortTextNote) {\n kind = Repost\n } else {\n kind = GenericRepost\n tags.push(['k', String(reposted.kind)])\n }\n\n return finalizeEvent(\n {\n kind,\n tags,\n content: t.content === '' || reposted.tags?.find(tag => tag[0] === '-') ? '' : JSON.stringify(reposted),\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport function getRepostedEventPointer(event: Event): undefined | EventPointer {\n if (![Repost, GenericRepost].includes(event.kind)) {\n return undefined\n }\n\n let lastETag: undefined | string[]\n let lastPTag: undefined | string[]\n\n for (let i = event.tags.length - 1; i >= 0 && (lastETag === undefined || lastPTag === undefined); i--) {\n const tag = event.tags[i]\n if (tag.length >= 2) {\n if (tag[0] === 'e' && lastETag === undefined) {\n lastETag = tag\n } else if (tag[0] === 'p' && lastPTag === undefined) {\n lastPTag = tag\n }\n }\n }\n\n if (lastETag === undefined) {\n return undefined\n }\n\n return {\n id: lastETag[1],\n relays: [lastETag[2], lastPTag?.[2]].filter((x): x is string => typeof x === 'string'),\n author: lastPTag?.[1],\n }\n}\n\nexport type GetRepostedEventOptions = {\n skipVerification?: boolean\n}\n\nexport function getRepostedEvent(event: Event, { skipVerification }: GetRepostedEventOptions = {}): undefined | Event {\n const pointer = getRepostedEventPointer(event)\n\n if (pointer === undefined || event.content === '') {\n return undefined\n }\n\n let repostedEvent: undefined | Event\n\n try {\n repostedEvent = JSON.parse(event.content) as Event\n } catch (error) {\n return undefined\n }\n\n if (repostedEvent.id !== pointer.id) {\n return undefined\n }\n\n if (!skipVerification && !verifyEvent(repostedEvent)) {\n return undefined\n }\n\n return repostedEvent\n}\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
+ "mappings": "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",
"names": ["import_utils", "i", "i"]
} Index: package/lib/esm/nip18.js.map
===================================================================
--- package/lib/esm/nip18.js.map
+++ package/lib/esm/nip18.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../nip18.ts"],
- "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { GenericRepost, Repost, ShortTextNote } from './kinds.ts'\nimport { EventPointer } from './nip19.ts'\nimport { Event, finalizeEvent, verifyEvent } from './pure.ts'\n\nexport type RepostEventTemplate = {\n /**\n * Pass only non-nip18 tags if you have to.\n * Nip18 tags ('e' and 'p' tags pointing to the reposted event) will be added automatically.\n */\n tags?: string[][]\n\n /**\n * Pass an empty string to NOT include the stringified JSON of the reposted event.\n * Any other content will be ignored and replaced with the stringified JSON of the reposted event.\n * @default Stringified JSON of the reposted event\n */\n content?: ''\n\n created_at: number\n}\n\nexport function finishRepostEvent(\n t: RepostEventTemplate,\n reposted: Event,\n relayUrl: string,\n privateKey: Uint8Array,\n): Event {\n let kind: Repost | GenericRepost\n const tags = [...(t.tags ?? []), ['e', reposted.id, relayUrl], ['p', reposted.pubkey]]\n if (reposted.kind === ShortTextNote) {\n kind = Repost\n } else {\n kind = GenericRepost\n tags.push(['k', String(reposted.kind)])\n }\n\n return finalizeEvent(\n {\n kind,\n tags,\n content: t.content === '' || reposted.tags?.find(tag => tag[0] === '-') ? '' : JSON.stringify(reposted),\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport function getRepostedEventPointer(event: Event): undefined | EventPointer {\n if (![Repost, GenericRepost].includes(event.kind)) {\n return undefined\n }\n\n let lastETag: undefined | string[]\n let lastPTag: undefined | string[]\n\n for (let i = event.tags.length - 1; i >= 0 && (lastETag === undefined || lastPTag === undefined); i--) {\n const tag = event.tags[i]\n if (tag.length >= 2) {\n if (tag[0] === 'e' && lastETag === undefined) {\n lastETag = tag\n } else if (tag[0] === 'p' && lastPTag === undefined) {\n lastPTag = tag\n }\n }\n }\n\n if (lastETag === undefined) {\n return undefined\n }\n\n return {\n id: lastETag[1],\n relays: [lastETag[2], lastPTag?.[2]].filter((x): x is string => typeof x === 'string'),\n author: lastPTag?.[1],\n }\n}\n\nexport type GetRepostedEventOptions = {\n skipVerification?: boolean\n}\n\nexport function getRepostedEvent(event: Event, { skipVerification }: GetRepostedEventOptions = {}): undefined | Event {\n const pointer = getRepostedEventPointer(event)\n\n if (pointer === undefined || event.content === '') {\n return undefined\n }\n\n let repostedEvent: undefined | Event\n\n try {\n repostedEvent = JSON.parse(event.content) as Event\n } catch (error) {\n return undefined\n }\n\n if (repostedEvent.id !== pointer.id) {\n return undefined\n }\n\n if (!skipVerification && !verifyEvent(repostedEvent)) {\n return undefined\n }\n\n return repostedEvent\n}\n"],
- "mappings": "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",
- "names": ["bytesToHex", "i", "bytesToHex", "i"]
+ "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { GenericRepost, Repost, ShortTextNote } from './kinds.ts'\nimport { EventPointer } from './nip19.ts'\nimport { Event, finalizeEvent, verifyEvent } from './pure.ts'\n\nexport type RepostEventTemplate = {\n /**\n * Pass only non-nip18 tags if you have to.\n * Nip18 tags ('e' and 'p' tags pointing to the reposted event) will be added automatically.\n */\n tags?: string[][]\n\n /**\n * Pass an empty string to NOT include the stringified JSON of the reposted event.\n * Any other content will be ignored and replaced with the stringified JSON of the reposted event.\n * @default Stringified JSON of the reposted event\n */\n content?: ''\n\n created_at: number\n}\n\nexport function finishRepostEvent(\n t: RepostEventTemplate,\n reposted: Event,\n relayUrl: string,\n privateKey: Uint8Array,\n): Event {\n let kind: Repost | GenericRepost\n const tags = [...(t.tags ?? []), ['e', reposted.id, relayUrl], ['p', reposted.pubkey]]\n if (reposted.kind === ShortTextNote) {\n kind = Repost\n } else {\n kind = GenericRepost\n tags.push(['k', String(reposted.kind)])\n }\n\n return finalizeEvent(\n {\n kind,\n tags,\n content: t.content === '' || reposted.tags?.find(tag => tag[0] === '-') ? '' : JSON.stringify(reposted),\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport function getRepostedEventPointer(event: Event): undefined | EventPointer {\n if (![Repost, GenericRepost].includes(event.kind)) {\n return undefined\n }\n\n let lastETag: undefined | string[]\n let lastPTag: undefined | string[]\n\n for (let i = event.tags.length - 1; i >= 0 && (lastETag === undefined || lastPTag === undefined); i--) {\n const tag = event.tags[i]\n if (tag.length >= 2) {\n if (tag[0] === 'e' && lastETag === undefined) {\n lastETag = tag\n } else if (tag[0] === 'p' && lastPTag === undefined) {\n lastPTag = tag\n }\n }\n }\n\n if (lastETag === undefined) {\n return undefined\n }\n\n return {\n id: lastETag[1],\n relays: [lastETag[2], lastPTag?.[2]].filter((x): x is string => typeof x === 'string'),\n author: lastPTag?.[1],\n }\n}\n\nexport type GetRepostedEventOptions = {\n skipVerification?: boolean\n}\n\nexport function getRepostedEvent(event: Event, { skipVerification }: GetRepostedEventOptions = {}): undefined | Event {\n const pointer = getRepostedEventPointer(event)\n\n if (pointer === undefined || event.content === '') {\n return undefined\n }\n\n let repostedEvent: undefined | Event\n\n try {\n repostedEvent = JSON.parse(event.content) as Event\n } catch (error) {\n return undefined\n }\n\n if (repostedEvent.id !== pointer.id) {\n return undefined\n }\n\n if (!skipVerification && !verifyEvent(repostedEvent)) {\n return undefined\n }\n\n return repostedEvent\n}\n"],
+ "mappings": "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",
+ "names": ["bytesToHex", "hexToBytes", "i", "bytesToHex", "hexToBytes", "i"]
} Index: package/lib/cjs/nip19.js.map
===================================================================
--- package/lib/cjs/nip19.js.map
+++ package/lib/cjs/nip19.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip19.ts", "../../utils.ts"],
- "sourcesContent": ["import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": "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",
"names": ["import_utils"]
} Index: package/lib/esm/nip19.js.map
===================================================================
--- package/lib/esm/nip19.js.map
+++ package/lib/esm/nip19.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip19.ts", "../../utils.ts"],
- "sourcesContent": ["import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": ";AAAA,SAAS,cAAAA,aAAY,aAAa,cAAAC,mBAAkB;AACpD,SAAS,cAAc;;;ACIvB,SAAS,YAAY,kBAAkB;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;ADUjD,IAAM,iBAAiB;AAAA,EAC5B,YAAY,CAAC,UAA6C,sBAAsB,KAAK,SAAS,EAAE;AAAA,EAChG,UAAU,CAAC,UAA2C,oBAAoB,KAAK,SAAS,EAAE;AAAA,EAC1F,SAAS,CAAC,UAA0C,mBAAmB,KAAK,SAAS,EAAE;AAAA,EACvF,QAAQ,CAAC,UAAyC,qBAAqB,KAAK,SAAS,EAAE;AAAA,EACvF,QAAQ,CAAC,UAAyC,qBAAqB,KAAK,SAAS,EAAE;AAAA,EACvF,QAAQ,CAAC,UAAyC,kBAAkB,KAAK,SAAS,EAAE;AAAA,EACpF,aAAa,CAAC,UAA8C,uBAAuB,KAAK,SAAS,EAAE;AACrG;AAEO,IAAM,gBAAgB;AAMtB,IAAM,eAAe;AAE5B,SAAS,oBAAoB,QAAgB;AAE3C,QAAM,aAAa,IAAI,WAAW,CAAC;AAGnC,aAAW,KAAM,UAAU,KAAM;AACjC,aAAW,KAAM,UAAU,KAAM;AACjC,aAAW,KAAM,UAAU,IAAK;AAChC,aAAW,KAAK,SAAS;AAEzB,SAAO;AACT;AAqBO,SAAS,eAAe,WAAgF;AAC7G,MAAI;AACF,QAAI,UAAU,WAAW,QAAQ;AAAG,kBAAY,UAAU,UAAU,CAAC;AACrE,WAAO,OAAO,SAAS;AAAA,EACzB,SAAS,MAAP;AACA,WAAO,EAAE,MAAM,WAAW,MAAM,KAAK;AAAA,EACvC;AACF;AAyCO,SAAS,OAAO,MAA6B;AAClD,MAAI,EAAE,QAAQ,MAAM,IAAI,OAAO,OAAO,MAAM,aAAa;AACzD,MAAI,OAAO,IAAI,WAAW,OAAO,UAAU,KAAK,CAAC;AAEjD,UAAQ,QAAQ;AAAA,IACd,KAAK,YAAY;AACf,UAAI,MAAM,SAAS,IAAI;AACvB,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,4BAA4B;AAC9D,UAAI,IAAI,GAAG,GAAG,WAAW;AAAI,cAAM,IAAI,MAAM,0BAA0B;AAEvE,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,QAAQC,YAAW,IAAI,GAAG,EAAE;AAAA,UAC5B,QAAQ,IAAI,KAAK,IAAI,GAAG,IAAI,OAAK,YAAY,OAAO,CAAC,CAAC,IAAI,CAAC;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,UAAI,MAAM,SAAS,IAAI;AACvB,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,0BAA0B;AAC5D,UAAI,IAAI,GAAG,GAAG,WAAW;AAAI,cAAM,IAAI,MAAM,0BAA0B;AACvE,UAAI,IAAI,MAAM,IAAI,GAAG,GAAG,WAAW;AAAI,cAAM,IAAI,MAAM,0BAA0B;AACjF,UAAI,IAAI,MAAM,IAAI,GAAG,GAAG,WAAW;AAAG,cAAM,IAAI,MAAM,yBAAyB;AAE/E,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,IAAIA,YAAW,IAAI,GAAG,EAAE;AAAA,UACxB,QAAQ,IAAI,KAAK,IAAI,GAAG,IAAI,OAAK,YAAY,OAAO,CAAC,CAAC,IAAI,CAAC;AAAA,UAC3D,QAAQ,IAAI,KAAK,KAAKA,YAAW,IAAI,GAAG,EAAE,IAAI;AAAA,UAC9C,MAAM,IAAI,KAAK,KAAK,SAASA,YAAW,IAAI,GAAG,EAAE,GAAG,EAAE,IAAI;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,SAAS;AACZ,UAAI,MAAM,SAAS,IAAI;AACvB,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,yBAAyB;AAC3D,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,yBAAyB;AAC3D,UAAI,IAAI,GAAG,GAAG,WAAW;AAAI,cAAM,IAAI,MAAM,0BAA0B;AACvE,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,yBAAyB;AAC3D,UAAI,IAAI,GAAG,GAAG,WAAW;AAAG,cAAM,IAAI,MAAM,yBAAyB;AAErE,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,YAAY,YAAY,OAAO,IAAI,GAAG,EAAE;AAAA,UACxC,QAAQA,YAAW,IAAI,GAAG,EAAE;AAAA,UAC5B,MAAM,SAASA,YAAW,IAAI,GAAG,EAAE,GAAG,EAAE;AAAA,UACxC,QAAQ,IAAI,KAAK,IAAI,GAAG,IAAI,OAAK,YAAY,OAAO,CAAC,CAAC,IAAI,CAAC;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK;AACH,aAAO,EAAE,MAAM,QAAQ,KAAK;AAAA,IAE9B,KAAK;AAAA,IACL,KAAK;AACH,aAAO,EAAE,MAAM,QAAQ,MAAMA,YAAW,IAAI,EAAE;AAAA,IAEhD;AACE,YAAM,IAAI,MAAM,kBAAkB,QAAQ;AAAA,EAC9C;AACF;AAIA,SAAS,SAAS,MAAuB;AACvC,MAAI,SAAc,CAAC;AACnB,MAAI,OAAO;AACX,SAAO,KAAK,SAAS,GAAG;AACtB,QAAI,IAAI,KAAK;AACb,QAAI,IAAI,KAAK;AACb,QAAI,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC;AAC3B,WAAO,KAAK,MAAM,IAAI,CAAC;AACvB,QAAI,EAAE,SAAS;AAAG,YAAM,IAAI,MAAM,kCAAkC,GAAG;AACvE,WAAO,KAAK,OAAO,MAAM,CAAC;AAC1B,WAAO,GAAG,KAAK,CAAC;AAAA,EAClB;AACA,SAAO;AACT;AAEO,SAAS,WAAW,KAAuB;AAChD,SAAO,YAAY,QAAQ,GAAG;AAChC;AAEO,SAAS,WAAW,KAAmB;AAC5C,SAAO,YAAY,QAAQC,YAAW,GAAG,CAAC;AAC5C;AAEO,SAAS,WAAW,KAAmB;AAC5C,SAAO,YAAY,QAAQA,YAAW,GAAG,CAAC;AAC5C;AAEA,SAAS,aAAoC,QAAgB,MAAyC;AACpG,MAAI,QAAQ,OAAO,QAAQ,IAAI;AAC/B,SAAO,OAAO,OAAO,QAAQ,OAAO,aAAa;AACnD;AAEO,SAAS,YAAmC,QAAgB,OAA0C;AAC3G,SAAO,aAAa,QAAQ,KAAK;AACnC;AAEO,SAAS,eAAe,SAAmC;AAChE,MAAI,OAAO,UAAU;AAAA,IACnB,GAAG,CAACA,YAAW,QAAQ,MAAM,CAAC;AAAA,IAC9B,IAAI,QAAQ,UAAU,CAAC,GAAG,IAAI,SAAO,YAAY,OAAO,GAAG,CAAC;AAAA,EAC9D,CAAC;AACD,SAAO,aAAa,YAAY,IAAI;AACtC;AAEO,SAAS,aAAa,OAA6B;AACxD,MAAI;AACJ,MAAI,MAAM,SAAS,QAAW;AAC5B,gBAAY,oBAAoB,MAAM,IAAI;AAAA,EAC5C;AAEA,MAAI,OAAO,UAAU;AAAA,IACnB,GAAG,CAACA,YAAW,MAAM,EAAE,CAAC;AAAA,IACxB,IAAI,MAAM,UAAU,CAAC,GAAG,IAAI,SAAO,YAAY,OAAO,GAAG,CAAC;AAAA,IAC1D,GAAG,MAAM,SAAS,CAACA,YAAW,MAAM,MAAM,CAAC,IAAI,CAAC;AAAA,IAChD,GAAG,YAAY,CAAC,IAAI,WAAW,SAAS,CAAC,IAAI,CAAC;AAAA,EAChD,CAAC;AAED,SAAO,aAAa,UAAU,IAAI;AACpC;AAEO,SAAS,YAAY,MAA6B;AACvD,MAAI,OAAO,IAAI,YAAY,CAAC;AAC5B,MAAI,SAAS,IAAI,EAAE,UAAU,GAAG,KAAK,MAAM,KAAK;AAEhD,MAAI,OAAO,UAAU;AAAA,IACnB,GAAG,CAAC,YAAY,OAAO,KAAK,UAAU,CAAC;AAAA,IACvC,IAAI,KAAK,UAAU,CAAC,GAAG,IAAI,SAAO,YAAY,OAAO,GAAG,CAAC;AAAA,IACzD,GAAG,CAACA,YAAW,KAAK,MAAM,CAAC;AAAA,IAC3B,GAAG,CAAC,IAAI,WAAW,IAAI,CAAC;AAAA,EAC1B,CAAC;AACD,SAAO,aAAa,SAAS,IAAI;AACnC;AAEA,SAAS,UAAU,KAAsB;AACvC,MAAI,UAAwB,CAAC;AAE7B,SAAO,QAAQ,GAAG,EACf,QAAQ,EACR,QAAQ,CAAC,CAAC,GAAG,EAAE,MAAM;AACpB,OAAG,QAAQ,OAAK;AACd,UAAI,QAAQ,IAAI,WAAW,EAAE,SAAS,CAAC;AACvC,YAAM,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC;AAC1B,YAAM,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC;AACvB,YAAM,IAAI,GAAG,CAAC;AACd,cAAQ,KAAK,KAAK;AAAA,IACpB,CAAC;AAAA,EACH,CAAC;AAEH,SAAO,YAAY,GAAG,OAAO;AAC/B;",
+ "sourcesContent": ["import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": "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",
"names": ["bytesToHex", "hexToBytes", "bytesToHex", "hexToBytes"]
} Index: package/lib/cjs/nip21.js.map
===================================================================
--- package/lib/cjs/nip21.js.map
+++ package/lib/cjs/nip21.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip21.ts", "../../nip19.ts", "../../utils.ts"],
- "sourcesContent": ["import { AddressPointer, BECH32_REGEX, decode, EventPointer, ProfilePointer } from './nip19.ts'\n\n/** Nostr URI regex, eg `nostr:npub1...` */\nexport const NOSTR_URI_REGEX: RegExp = new RegExp(`nostr:(${BECH32_REGEX.source})`)\n\n/** Test whether the value is a Nostr URI. */\nexport function test(value: unknown): value is `nostr:${string}` {\n return typeof value === 'string' && new RegExp(`^${NOSTR_URI_REGEX.source}$`).test(value)\n}\n\n/** Parsed Nostr URI data. */\nexport interface NostrURI {\n /** Full URI including the `nostr:` protocol. */\n uri: `nostr:${string}`\n /** The bech32-encoded data (eg `npub1...`). */\n value: string\n /** Decoded bech32 string, according to NIP-19. */\n decoded:\n | {\n type: 'nevent'\n data: EventPointer\n }\n | {\n type: 'nprofile'\n data: ProfilePointer\n }\n | {\n type: 'naddr'\n data: AddressPointer\n }\n | {\n type: 'npub'\n data: string\n }\n | {\n type: 'nsec'\n data: Uint8Array\n }\n | {\n type: 'note'\n data: string\n }\n}\n\n/** Parse and decode a Nostr URI. */\nexport function parse(uri: string): NostrURI {\n const match = uri.match(new RegExp(`^${NOSTR_URI_REGEX.source}$`))\n if (!match) throw new Error(`Invalid Nostr URI: ${uri}`)\n return {\n uri: match[0] as `nostr:${string}`,\n value: match[1],\n decoded: decode(match[1]),\n }\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { AddressPointer, BECH32_REGEX, decode, EventPointer, ProfilePointer } from './nip19.ts'\n\n/** Nostr URI regex, eg `nostr:npub1...` */\nexport const NOSTR_URI_REGEX: RegExp = new RegExp(`nostr:(${BECH32_REGEX.source})`)\n\n/** Test whether the value is a Nostr URI. */\nexport function test(value: unknown): value is `nostr:${string}` {\n return typeof value === 'string' && new RegExp(`^${NOSTR_URI_REGEX.source}$`).test(value)\n}\n\n/** Parsed Nostr URI data. */\nexport interface NostrURI {\n /** Full URI including the `nostr:` protocol. */\n uri: `nostr:${string}`\n /** The bech32-encoded data (eg `npub1...`). */\n value: string\n /** Decoded bech32 string, according to NIP-19. */\n decoded:\n | {\n type: 'nevent'\n data: EventPointer\n }\n | {\n type: 'nprofile'\n data: ProfilePointer\n }\n | {\n type: 'naddr'\n data: AddressPointer\n }\n | {\n type: 'npub'\n data: string\n }\n | {\n type: 'nsec'\n data: Uint8Array\n }\n | {\n type: 'note'\n data: string\n }\n}\n\n/** Parse and decode a Nostr URI. */\nexport function parse(uri: string): NostrURI {\n const match = uri.match(new RegExp(`^${NOSTR_URI_REGEX.source}$`))\n if (!match) throw new Error(`Invalid Nostr URI: ${uri}`)\n return {\n uri: match[0] as `nostr:${string}`,\n value: match[1],\n decoded: decode(match[1]),\n }\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,gBAAoD;AACpD,kBAAuB;;;ACIvB,mBAAuC;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;ADoBjD,IAAM,gBAAgB;AAMtB,IAAM,eAAe;AAkFrB,SAAS,OAAO,MAA6B;AAClD,MAAI,EAAE,QAAQ,MAAM,IAAI,mBAAO,OAAO,MAA+B,aAAa;AAClF,MAAI,OAAO,IAAI,WAAW,mBAAO,UAAU,KAAK,CAAC;AAEjD,UAAQ,QAAQ;AAAA,IACd,KAAK,YAAY;AACf,UAAI,MAAM,SAAS,IAAI;AACvB,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,4BAA4B;AAC9D,UAAI,IAAI,GAAG,GAAG,WAAW;AAAI,cAAM,IAAI,MAAM,0BAA0B;AAEvE,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,YAAQ,0BAAW,IAAI,GAAG,EAAE;AAAA,UAC5B,QAAQ,IAAI,KAAK,IAAI,GAAG,IAAI,OAAK,YAAY,OAAO,CAAC,CAAC,IAAI,CAAC;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,UAAI,MAAM,SAAS,IAAI;AACvB,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,0BAA0B;AAC5D,UAAI,IAAI,GAAG,GAAG,WAAW;AAAI,cAAM,IAAI,MAAM,0BAA0B;AACvE,UAAI,IAAI,MAAM,IAAI,GAAG,GAAG,WAAW;AAAI,cAAM,IAAI,MAAM,0BAA0B;AACjF,UAAI,IAAI,MAAM,IAAI,GAAG,GAAG,WAAW;AAAG,cAAM,IAAI,MAAM,yBAAyB;AAE/E,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,QAAI,0BAAW,IAAI,GAAG,EAAE;AAAA,UACxB,QAAQ,IAAI,KAAK,IAAI,GAAG,IAAI,OAAK,YAAY,OAAO,CAAC,CAAC,IAAI,CAAC;AAAA,UAC3D,QAAQ,IAAI,KAAK,SAAK,0BAAW,IAAI,GAAG,EAAE,IAAI;AAAA,UAC9C,MAAM,IAAI,KAAK,KAAK,aAAS,0BAAW,IAAI,GAAG,EAAE,GAAG,EAAE,IAAI;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,SAAS;AACZ,UAAI,MAAM,SAAS,IAAI;AACvB,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,yBAAyB;AAC3D,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,yBAAyB;AAC3D,UAAI,IAAI,GAAG,GAAG,WAAW;AAAI,cAAM,IAAI,MAAM,0BAA0B;AACvE,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,yBAAyB;AAC3D,UAAI,IAAI,GAAG,GAAG,WAAW;AAAG,cAAM,IAAI,MAAM,yBAAyB;AAErE,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,YAAY,YAAY,OAAO,IAAI,GAAG,EAAE;AAAA,UACxC,YAAQ,0BAAW,IAAI,GAAG,EAAE;AAAA,UAC5B,MAAM,aAAS,0BAAW,IAAI,GAAG,EAAE,GAAG,EAAE;AAAA,UACxC,QAAQ,IAAI,KAAK,IAAI,GAAG,IAAI,OAAK,YAAY,OAAO,CAAC,CAAC,IAAI,CAAC;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK;AACH,aAAO,EAAE,MAAM,QAAQ,KAAK;AAAA,IAE9B,KAAK;AAAA,IACL,KAAK;AACH,aAAO,EAAE,MAAM,QAAQ,UAAM,0BAAW,IAAI,EAAE;AAAA,IAEhD;AACE,YAAM,IAAI,MAAM,kBAAkB,QAAQ;AAAA,EAC9C;AACF;AAIA,SAAS,SAAS,MAAuB;AACvC,MAAI,SAAc,CAAC;AACnB,MAAI,OAAO;AACX,SAAO,KAAK,SAAS,GAAG;AACtB,QAAI,IAAI,KAAK;AACb,QAAI,IAAI,KAAK;AACb,QAAI,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC;AAC3B,WAAO,KAAK,MAAM,IAAI,CAAC;AACvB,QAAI,EAAE,SAAS;AAAG,YAAM,IAAI,MAAM,kCAAkC,GAAG;AACvE,WAAO,KAAK,OAAO,MAAM,CAAC;AAC1B,WAAO,GAAG,KAAK,CAAC;AAAA,EAClB;AACA,SAAO;AACT;;;AD9LO,IAAM,kBAA0B,IAAI,OAAO,UAAU,aAAa,SAAS;AAG3E,SAAS,KAAK,OAA4C;AAC/D,SAAO,OAAO,UAAU,YAAY,IAAI,OAAO,IAAI,gBAAgB,SAAS,EAAE,KAAK,KAAK;AAC1F;AAqCO,SAAS,MAAM,KAAuB;AAC3C,QAAM,QAAQ,IAAI,MAAM,IAAI,OAAO,IAAI,gBAAgB,SAAS,CAAC;AACjE,MAAI,CAAC;AAAO,UAAM,IAAI,MAAM,sBAAsB,KAAK;AACvD,SAAO;AAAA,IACL,KAAK,MAAM;AAAA,IACX,OAAO,MAAM;AAAA,IACb,SAAS,OAAO,MAAM,EAAE;AAAA,EAC1B;AACF;",
"names": ["import_utils"]
} Index: package/lib/esm/nip21.js.map
===================================================================
--- package/lib/esm/nip21.js.map
+++ package/lib/esm/nip21.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip19.ts", "../../utils.ts", "../../nip21.ts"],
- "sourcesContent": ["import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { AddressPointer, BECH32_REGEX, decode, EventPointer, ProfilePointer } from './nip19.ts'\n\n/** Nostr URI regex, eg `nostr:npub1...` */\nexport const NOSTR_URI_REGEX: RegExp = new RegExp(`nostr:(${BECH32_REGEX.source})`)\n\n/** Test whether the value is a Nostr URI. */\nexport function test(value: unknown): value is `nostr:${string}` {\n return typeof value === 'string' && new RegExp(`^${NOSTR_URI_REGEX.source}$`).test(value)\n}\n\n/** Parsed Nostr URI data. */\nexport interface NostrURI {\n /** Full URI including the `nostr:` protocol. */\n uri: `nostr:${string}`\n /** The bech32-encoded data (eg `npub1...`). */\n value: string\n /** Decoded bech32 string, according to NIP-19. */\n decoded:\n | {\n type: 'nevent'\n data: EventPointer\n }\n | {\n type: 'nprofile'\n data: ProfilePointer\n }\n | {\n type: 'naddr'\n data: AddressPointer\n }\n | {\n type: 'npub'\n data: string\n }\n | {\n type: 'nsec'\n data: Uint8Array\n }\n | {\n type: 'note'\n data: string\n }\n}\n\n/** Parse and decode a Nostr URI. */\nexport function parse(uri: string): NostrURI {\n const match = uri.match(new RegExp(`^${NOSTR_URI_REGEX.source}$`))\n if (!match) throw new Error(`Invalid Nostr URI: ${uri}`)\n return {\n uri: match[0] as `nostr:${string}`,\n value: match[1],\n decoded: decode(match[1]),\n }\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { AddressPointer, BECH32_REGEX, decode, EventPointer, ProfilePointer } from './nip19.ts'\n\n/** Nostr URI regex, eg `nostr:npub1...` */\nexport const NOSTR_URI_REGEX: RegExp = new RegExp(`nostr:(${BECH32_REGEX.source})`)\n\n/** Test whether the value is a Nostr URI. */\nexport function test(value: unknown): value is `nostr:${string}` {\n return typeof value === 'string' && new RegExp(`^${NOSTR_URI_REGEX.source}$`).test(value)\n}\n\n/** Parsed Nostr URI data. */\nexport interface NostrURI {\n /** Full URI including the `nostr:` protocol. */\n uri: `nostr:${string}`\n /** The bech32-encoded data (eg `npub1...`). */\n value: string\n /** Decoded bech32 string, according to NIP-19. */\n decoded:\n | {\n type: 'nevent'\n data: EventPointer\n }\n | {\n type: 'nprofile'\n data: ProfilePointer\n }\n | {\n type: 'naddr'\n data: AddressPointer\n }\n | {\n type: 'npub'\n data: string\n }\n | {\n type: 'nsec'\n data: Uint8Array\n }\n | {\n type: 'note'\n data: string\n }\n}\n\n/** Parse and decode a Nostr URI. */\nexport function parse(uri: string): NostrURI {\n const match = uri.match(new RegExp(`^${NOSTR_URI_REGEX.source}$`))\n if (!match) throw new Error(`Invalid Nostr URI: ${uri}`)\n return {\n uri: match[0] as `nostr:${string}`,\n value: match[1],\n decoded: decode(match[1]),\n }\n}\n"],
+ "mappings": "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",
"names": ["bytesToHex", "hexToBytes", "bytesToHex"]
} Index: package/lib/cjs/nip25.js.map
===================================================================
--- package/lib/cjs/nip25.js.map
+++ package/lib/cjs/nip25.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip25.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts"],
- "sourcesContent": ["import { Event, finalizeEvent } from './pure.ts'\nimport { Reaction } from './kinds.ts'\n\nimport type { EventPointer } from './nip19.ts'\n\nexport type ReactionEventTemplate = {\n /**\n * Pass only non-nip25 tags if you have to. Nip25 tags ('e' and 'p' tags from reacted event) will be added automatically.\n */\n tags?: string[][]\n\n /**\n * @default '+'\n */\n content?: string\n\n created_at: number\n}\n\nexport function finishReactionEvent(t: ReactionEventTemplate, reacted: Event, privateKey: Uint8Array): Event {\n const inheritedTags = reacted.tags.filter(tag => tag.length >= 2 && (tag[0] === 'e' || tag[0] === 'p'))\n\n return finalizeEvent(\n {\n ...t,\n kind: Reaction,\n tags: [...(t.tags ?? []), ...inheritedTags, ['e', reacted.id], ['p', reacted.pubkey]],\n content: t.content ?? '+',\n },\n privateKey,\n )\n}\n\nexport function getReactedEventPointer(event: Event): undefined | EventPointer {\n if (event.kind !== Reaction) {\n return undefined\n }\n\n let lastETag: undefined | string[]\n let lastPTag: undefined | string[]\n\n for (let i = event.tags.length - 1; i >= 0 && (lastETag === undefined || lastPTag === undefined); i--) {\n const tag = event.tags[i]\n if (tag.length >= 2) {\n if (tag[0] === 'e' && lastETag === undefined) {\n lastETag = tag\n } else if (tag[0] === 'p' && lastPTag === undefined) {\n lastPTag = tag\n }\n }\n }\n\n if (lastETag === undefined || lastPTag === undefined) {\n return undefined\n }\n\n return {\n id: lastETag[1],\n relays: [lastETag[2], lastPTag[2]].filter(x => x !== undefined),\n author: lastPTag[1],\n }\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
- "mappings": "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",
+ "sourcesContent": ["import { Event, finalizeEvent } from './pure.ts'\nimport { Reaction } from './kinds.ts'\n\nimport type { EventPointer } from './nip19.ts'\n\nexport type ReactionEventTemplate = {\n /**\n * Pass only non-nip25 tags if you have to. Nip25 tags ('e' and 'p' tags from reacted event) will be added automatically.\n */\n tags?: string[][]\n\n /**\n * @default '+'\n */\n content?: string\n\n created_at: number\n}\n\nexport function finishReactionEvent(t: ReactionEventTemplate, reacted: Event, privateKey: Uint8Array): Event {\n const inheritedTags = reacted.tags.filter(tag => tag.length >= 2 && (tag[0] === 'e' || tag[0] === 'p'))\n\n return finalizeEvent(\n {\n ...t,\n kind: Reaction,\n tags: [...(t.tags ?? []), ...inheritedTags, ['e', reacted.id], ['p', reacted.pubkey]],\n content: t.content ?? '+',\n },\n privateKey,\n )\n}\n\nexport function getReactedEventPointer(event: Event): undefined | EventPointer {\n if (event.kind !== Reaction) {\n return undefined\n }\n\n let lastETag: undefined | string[]\n let lastPTag: undefined | string[]\n\n for (let i = event.tags.length - 1; i >= 0 && (lastETag === undefined || lastPTag === undefined); i--) {\n const tag = event.tags[i]\n if (tag.length >= 2) {\n if (tag[0] === 'e' && lastETag === undefined) {\n lastETag = tag\n } else if (tag[0] === 'p' && lastPTag === undefined) {\n lastPTag = tag\n }\n }\n }\n\n if (lastETag === undefined || lastPTag === undefined) {\n return undefined\n }\n\n return {\n id: lastETag[1],\n relays: [lastETag[2], lastPTag[2]].filter(x => x !== undefined),\n author: lastPTag[1],\n }\n}\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
+ "mappings": "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",
"names": ["import_utils", "i", "i"]
} Index: package/lib/esm/nip25.js.map
===================================================================
--- package/lib/esm/nip25.js.map
+++ package/lib/esm/nip25.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../nip25.ts"],
- "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event, finalizeEvent } from './pure.ts'\nimport { Reaction } from './kinds.ts'\n\nimport type { EventPointer } from './nip19.ts'\n\nexport type ReactionEventTemplate = {\n /**\n * Pass only non-nip25 tags if you have to. Nip25 tags ('e' and 'p' tags from reacted event) will be added automatically.\n */\n tags?: string[][]\n\n /**\n * @default '+'\n */\n content?: string\n\n created_at: number\n}\n\nexport function finishReactionEvent(t: ReactionEventTemplate, reacted: Event, privateKey: Uint8Array): Event {\n const inheritedTags = reacted.tags.filter(tag => tag.length >= 2 && (tag[0] === 'e' || tag[0] === 'p'))\n\n return finalizeEvent(\n {\n ...t,\n kind: Reaction,\n tags: [...(t.tags ?? []), ...inheritedTags, ['e', reacted.id], ['p', reacted.pubkey]],\n content: t.content ?? '+',\n },\n privateKey,\n )\n}\n\nexport function getReactedEventPointer(event: Event): undefined | EventPointer {\n if (event.kind !== Reaction) {\n return undefined\n }\n\n let lastETag: undefined | string[]\n let lastPTag: undefined | string[]\n\n for (let i = event.tags.length - 1; i >= 0 && (lastETag === undefined || lastPTag === undefined); i--) {\n const tag = event.tags[i]\n if (tag.length >= 2) {\n if (tag[0] === 'e' && lastETag === undefined) {\n lastETag = tag\n } else if (tag[0] === 'p' && lastPTag === undefined) {\n lastPTag = tag\n }\n }\n }\n\n if (lastETag === undefined || lastPTag === undefined) {\n return undefined\n }\n\n return {\n id: lastETag[1],\n relays: [lastETag[2], lastPTag[2]].filter(x => x !== undefined),\n author: lastPTag[1],\n }\n}\n"],
- "mappings": "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",
- "names": ["bytesToHex", "i", "bytesToHex", "i"]
+ "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event, finalizeEvent } from './pure.ts'\nimport { Reaction } from './kinds.ts'\n\nimport type { EventPointer } from './nip19.ts'\n\nexport type ReactionEventTemplate = {\n /**\n * Pass only non-nip25 tags if you have to. Nip25 tags ('e' and 'p' tags from reacted event) will be added automatically.\n */\n tags?: string[][]\n\n /**\n * @default '+'\n */\n content?: string\n\n created_at: number\n}\n\nexport function finishReactionEvent(t: ReactionEventTemplate, reacted: Event, privateKey: Uint8Array): Event {\n const inheritedTags = reacted.tags.filter(tag => tag.length >= 2 && (tag[0] === 'e' || tag[0] === 'p'))\n\n return finalizeEvent(\n {\n ...t,\n kind: Reaction,\n tags: [...(t.tags ?? []), ...inheritedTags, ['e', reacted.id], ['p', reacted.pubkey]],\n content: t.content ?? '+',\n },\n privateKey,\n )\n}\n\nexport function getReactedEventPointer(event: Event): undefined | EventPointer {\n if (event.kind !== Reaction) {\n return undefined\n }\n\n let lastETag: undefined | string[]\n let lastPTag: undefined | string[]\n\n for (let i = event.tags.length - 1; i >= 0 && (lastETag === undefined || lastPTag === undefined); i--) {\n const tag = event.tags[i]\n if (tag.length >= 2) {\n if (tag[0] === 'e' && lastETag === undefined) {\n lastETag = tag\n } else if (tag[0] === 'p' && lastPTag === undefined) {\n lastPTag = tag\n }\n }\n }\n\n if (lastETag === undefined || lastPTag === undefined) {\n return undefined\n }\n\n return {\n id: lastETag[1],\n relays: [lastETag[2], lastPTag[2]].filter(x => x !== undefined),\n author: lastPTag[1],\n }\n}\n"],
+ "mappings": "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",
+ "names": ["bytesToHex", "hexToBytes", "i", "bytesToHex", "hexToBytes", "i"]
} Index: package/lib/cjs/nip27.js.map
===================================================================
--- package/lib/cjs/nip27.js.map
+++ package/lib/cjs/nip27.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip27.ts", "../../nip19.ts", "../../utils.ts"],
- "sourcesContent": ["import { NostrEvent } from './core.ts'\nimport { AddressPointer, EventPointer, ProfilePointer, decode } from './nip19.ts'\n\nexport type Block =\n | {\n type: 'text'\n text: string\n }\n | {\n type: 'reference'\n pointer: ProfilePointer | AddressPointer | EventPointer\n }\n | {\n type: 'url'\n url: string\n }\n | {\n type: 'relay'\n url: string\n }\n | {\n type: 'image'\n url: string\n }\n | {\n type: 'video'\n url: string\n }\n | {\n type: 'audio'\n url: string\n }\n | {\n type: 'emoji'\n shortcode: string\n url: string\n }\n | {\n type: 'hashtag'\n value: string\n }\n\nconst noCharacter = /\\W/m\nconst noURLCharacter = /[^\\w\\/] |[^\\w\\/]$|$|,| /m\nconst MAX_HASHTAG_LENGTH = 42\n\nexport function* parse(content: string | NostrEvent): Iterable<Block> {\n let emojis: { type: 'emoji'; shortcode: string; url: string }[] = []\n if (typeof content !== 'string') {\n for (let i = 0; i < content.tags.length; i++) {\n const tag = content.tags[i]\n if (tag[0] === 'emoji' && tag.length >= 3) {\n emojis.push({ type: 'emoji', shortcode: tag[1], url: tag[2] })\n }\n }\n content = content.content\n }\n\n const max = content.length\n let prevIndex = 0\n let index = 0\n mainloop: while (index < max) {\n const u = content.indexOf(':', index)\n const h = content.indexOf('#', index)\n if (u === -1 && h === -1) {\n // reached end\n break mainloop\n }\n\n if (u === -1 || (h >= 0 && h < u)) {\n // parse hashtag\n if (h === 0 || content[h - 1] === ' ') {\n const m = content.slice(h + 1, h + MAX_HASHTAG_LENGTH).match(noCharacter)\n const end = m ? h + 1 + m.index! : max\n yield { type: 'text', text: content.slice(prevIndex, h) }\n yield { type: 'hashtag', value: content.slice(h + 1, end) }\n index = end\n prevIndex = index\n continue mainloop\n }\n\n // ignore this, it is nothing\n index = h + 1\n continue mainloop\n }\n\n // otherwise parse things that have an \":\"\n if (content.slice(u - 5, u) === 'nostr') {\n const m = content.slice(u + 60).match(noCharacter)\n const end = m ? u + 60 + m.index! : max\n try {\n let pointer: ProfilePointer | AddressPointer | EventPointer\n let { data, type } = decode(content.slice(u + 1, end))\n\n switch (type) {\n case 'npub':\n pointer = { pubkey: data } as ProfilePointer\n break\n case 'note':\n pointer = { id: data } as EventPointer\n break\n case 'nsec':\n // ignore this, treat it as not a valid uri\n index = end + 1\n continue\n default:\n pointer = data as any\n }\n\n if (prevIndex !== u - 5) {\n yield { type: 'text', text: content.slice(prevIndex, u - 5) }\n }\n yield { type: 'reference', pointer }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid nostr uri\n index = u + 1\n continue mainloop\n }\n } else if (content.slice(u - 5, u) === 'https' || content.slice(u - 4, u) === 'http') {\n const m = content.slice(u + 4).match(noURLCharacter)\n const end = m ? u + 4 + m.index! : max\n const prefixLen = content[u - 1] === 's' ? 5 : 4\n try {\n let url = new URL(content.slice(u - prefixLen, end))\n if (url.hostname.indexOf('.') === -1) {\n throw new Error('invalid url')\n }\n\n if (prevIndex !== u - prefixLen) {\n yield { type: 'text', text: content.slice(prevIndex, u - prefixLen) }\n }\n\n if (/\\.(png|jpe?g|gif|webp|heic|svg)$/i.test(url.pathname)) {\n yield { type: 'image', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n if (/\\.(mp4|avi|webm|mkv|mov)$/i.test(url.pathname)) {\n yield { type: 'video', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n if (/\\.(mp3|aac|ogg|opus|wav|flac)$/i.test(url.pathname)) {\n yield { type: 'audio', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n\n yield { type: 'url', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid url\n index = end + 1\n continue mainloop\n }\n } else if (content.slice(u - 3, u) === 'wss' || content.slice(u - 2, u) === 'ws') {\n const m = content.slice(u + 4).match(noURLCharacter)\n const end = m ? u + 4 + m.index! : max\n const prefixLen = content[u - 1] === 's' ? 3 : 2\n try {\n let url = new URL(content.slice(u - prefixLen, end))\n if (url.hostname.indexOf('.') === -1) {\n throw new Error('invalid ws url')\n }\n\n if (prevIndex !== u - prefixLen) {\n yield { type: 'text', text: content.slice(prevIndex, u - prefixLen) }\n }\n yield { type: 'relay', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid url\n index = end + 1\n continue mainloop\n }\n } else {\n // try to parse an emoji shortcode\n for (let e = 0; e < emojis.length; e++) {\n const emoji = emojis[e]\n if (\n content[u + emoji.shortcode.length + 1] === ':' &&\n content.slice(u + 1, u + emoji.shortcode.length + 1) === emoji.shortcode\n ) {\n // found an emoji\n if (prevIndex !== u) {\n yield { type: 'text', text: content.slice(prevIndex, u) }\n }\n yield emoji\n index = u + emoji.shortcode.length + 2\n prevIndex = index\n continue mainloop\n }\n }\n\n // ignore this, it is nothing\n index = u + 1\n continue mainloop\n }\n }\n\n if (prevIndex !== max) {\n yield { type: 'text', text: content.slice(prevIndex) }\n }\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,gBAAoD;AACpD,kBAAuB;;;ACIvB,mBAAuC;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;ADoBjD,IAAM,gBAAgB;AAwFtB,SAAS,OAAO,MAA6B;AAClD,MAAI,EAAE,QAAQ,MAAM,IAAI,mBAAO,OAAO,MAAM,aAAa;AACzD,MAAI,OAAO,IAAI,WAAW,mBAAO,UAAU,KAAK,CAAC;AAEjD,UAAQ,QAAQ;AAAA,IACd,KAAK,YAAY;AACf,UAAI,MAAM,SAAS,IAAI;AACvB,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,4BAA4B;AAC9D,UAAI,IAAI,GAAG,GAAG,WAAW;AAAI,cAAM,IAAI,MAAM,0BAA0B;AAEvE,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,YAAQ,0BAAW,IAAI,GAAG,EAAE;AAAA,UAC5B,QAAQ,IAAI,KAAK,IAAI,GAAG,IAAI,OAAK,YAAY,OAAO,CAAC,CAAC,IAAI,CAAC;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAAA,IACA,KAAK,UAAU;AACb,UAAI,MAAM,SAAS,IAAI;AACvB,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,0BAA0B;AAC5D,UAAI,IAAI,GAAG,GAAG,WAAW;AAAI,cAAM,IAAI,MAAM,0BAA0B;AACvE,UAAI,IAAI,MAAM,IAAI,GAAG,GAAG,WAAW;AAAI,cAAM,IAAI,MAAM,0BAA0B;AACjF,UAAI,IAAI,MAAM,IAAI,GAAG,GAAG,WAAW;AAAG,cAAM,IAAI,MAAM,yBAAyB;AAE/E,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,QAAI,0BAAW,IAAI,GAAG,EAAE;AAAA,UACxB,QAAQ,IAAI,KAAK,IAAI,GAAG,IAAI,OAAK,YAAY,OAAO,CAAC,CAAC,IAAI,CAAC;AAAA,UAC3D,QAAQ,IAAI,KAAK,SAAK,0BAAW,IAAI,GAAG,EAAE,IAAI;AAAA,UAC9C,MAAM,IAAI,KAAK,KAAK,aAAS,0BAAW,IAAI,GAAG,EAAE,GAAG,EAAE,IAAI;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK,SAAS;AACZ,UAAI,MAAM,SAAS,IAAI;AACvB,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,yBAAyB;AAC3D,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,yBAAyB;AAC3D,UAAI,IAAI,GAAG,GAAG,WAAW;AAAI,cAAM,IAAI,MAAM,0BAA0B;AACvE,UAAI,CAAC,IAAI,KAAK;AAAI,cAAM,IAAI,MAAM,yBAAyB;AAC3D,UAAI,IAAI,GAAG,GAAG,WAAW;AAAG,cAAM,IAAI,MAAM,yBAAyB;AAErE,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM;AAAA,UACJ,YAAY,YAAY,OAAO,IAAI,GAAG,EAAE;AAAA,UACxC,YAAQ,0BAAW,IAAI,GAAG,EAAE;AAAA,UAC5B,MAAM,aAAS,0BAAW,IAAI,GAAG,EAAE,GAAG,EAAE;AAAA,UACxC,QAAQ,IAAI,KAAK,IAAI,GAAG,IAAI,OAAK,YAAY,OAAO,CAAC,CAAC,IAAI,CAAC;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAAA,IAEA,KAAK;AACH,aAAO,EAAE,MAAM,QAAQ,KAAK;AAAA,IAE9B,KAAK;AAAA,IACL,KAAK;AACH,aAAO,EAAE,MAAM,QAAQ,UAAM,0BAAW,IAAI,EAAE;AAAA,IAEhD;AACE,YAAM,IAAI,MAAM,kBAAkB,QAAQ;AAAA,EAC9C;AACF;AAIA,SAAS,SAAS,MAAuB;AACvC,MAAI,SAAc,CAAC;AACnB,MAAI,OAAO;AACX,SAAO,KAAK,SAAS,GAAG;AACtB,QAAI,IAAI,KAAK;AACb,QAAI,IAAI,KAAK;AACb,QAAI,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC;AAC3B,WAAO,KAAK,MAAM,IAAI,CAAC;AACvB,QAAI,EAAE,SAAS;AAAG,YAAM,IAAI,MAAM,kCAAkC,GAAG;AACvE,WAAO,KAAK,OAAO,MAAM,CAAC;AAC1B,WAAO,GAAG,KAAK,CAAC;AAAA,EAClB;AACA,SAAO;AACT;;;ADvJA,IAAM,cAAc;AACpB,IAAM,iBAAiB;AACvB,IAAM,qBAAqB;AAEpB,UAAU,MAAM,SAA+C;AACpE,MAAI,SAA8D,CAAC;AACnE,MAAI,OAAO,YAAY,UAAU;AAC/B,aAAS,IAAI,GAAG,IAAI,QAAQ,KAAK,QAAQ,KAAK;AAC5C,YAAM,MAAM,QAAQ,KAAK;AACzB,UAAI,IAAI,OAAO,WAAW,IAAI,UAAU,GAAG;AACzC,eAAO,KAAK,EAAE,MAAM,SAAS,WAAW,IAAI,IAAI,KAAK,IAAI,GAAG,CAAC;AAAA,MAC/D;AAAA,IACF;AACA,cAAU,QAAQ;AAAA,EACpB;AAEA,QAAM,MAAM,QAAQ;AACpB,MAAI,YAAY;AAChB,MAAI,QAAQ;AACZ;AAAU,WAAO,QAAQ,KAAK;AAC5B,YAAM,IAAI,QAAQ,QAAQ,KAAK,KAAK;AACpC,YAAM,IAAI,QAAQ,QAAQ,KAAK,KAAK;AACpC,UAAI,MAAM,MAAM,MAAM,IAAI;AAExB,cAAM;AAAA,MACR;AAEA,UAAI,MAAM,MAAO,KAAK,KAAK,IAAI,GAAI;AAEjC,YAAI,MAAM,KAAK,QAAQ,IAAI,OAAO,KAAK;AACrC,gBAAM,IAAI,QAAQ,MAAM,IAAI,GAAG,IAAI,kBAAkB,EAAE,MAAM,WAAW;AACxE,gBAAM,MAAM,IAAI,IAAI,IAAI,EAAE,QAAS;AACnC,gBAAM,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,WAAW,CAAC,EAAE;AACxD,gBAAM,EAAE,MAAM,WAAW,OAAO,QAAQ,MAAM,IAAI,GAAG,GAAG,EAAE;AAC1D,kBAAQ;AACR,sBAAY;AACZ,mBAAS;AAAA,QACX;AAGA,gBAAQ,IAAI;AACZ,iBAAS;AAAA,MACX;AAGA,UAAI,QAAQ,MAAM,IAAI,GAAG,CAAC,MAAM,SAAS;AACvC,cAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,EAAE,MAAM,WAAW;AACjD,cAAM,MAAM,IAAI,IAAI,KAAK,EAAE,QAAS;AACpC,YAAI;AACF,cAAI;AACJ,cAAI,EAAE,MAAM,KAAK,IAAI,OAAO,QAAQ,MAAM,IAAI,GAAG,GAAG,CAAC;AAErD,kBAAQ,MAAM;AAAA,YACZ,KAAK;AACH,wBAAU,EAAE,QAAQ,KAAK;AACzB;AAAA,YACF,KAAK;AACH,wBAAU,EAAE,IAAI,KAAK;AACrB;AAAA,YACF,KAAK;AAEH,sBAAQ,MAAM;AACd;AAAA,YACF;AACE,wBAAU;AAAA,UACd;AAEA,cAAI,cAAc,IAAI,GAAG;AACvB,kBAAM,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,WAAW,IAAI,CAAC,EAAE;AAAA,UAC9D;AACA,gBAAM,EAAE,MAAM,aAAa,QAAQ;AACnC,kBAAQ;AACR,sBAAY;AACZ,mBAAS;AAAA,QACX,SAAS,MAAP;AAEA,kBAAQ,IAAI;AACZ,mBAAS;AAAA,QACX;AAAA,MACF,WAAW,QAAQ,MAAM,IAAI,GAAG,CAAC,MAAM,WAAW,QAAQ,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ;AACpF,cAAM,IAAI,QAAQ,MAAM,IAAI,CAAC,EAAE,MAAM,cAAc;AACnD,cAAM,MAAM,IAAI,IAAI,IAAI,EAAE,QAAS;AACnC,cAAM,YAAY,QAAQ,IAAI,OAAO,MAAM,IAAI;AAC/C,YAAI;AACF,cAAI,MAAM,IAAI,IAAI,QAAQ,MAAM,IAAI,WAAW,GAAG,CAAC;AACnD,cAAI,IAAI,SAAS,QAAQ,GAAG,MAAM,IAAI;AACpC,kBAAM,IAAI,MAAM,aAAa;AAAA,UAC/B;AAEA,cAAI,cAAc,IAAI,WAAW;AAC/B,kBAAM,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,WAAW,IAAI,SAAS,EAAE;AAAA,UACtE;AAEA,cAAI,oCAAoC,KAAK,IAAI,QAAQ,GAAG;AAC1D,kBAAM,EAAE,MAAM,SAAS,KAAK,IAAI,SAAS,EAAE;AAC3C,oBAAQ;AACR,wBAAY;AACZ,qBAAS;AAAA,UACX;AACA,cAAI,6BAA6B,KAAK,IAAI,QAAQ,GAAG;AACnD,kBAAM,EAAE,MAAM,SAAS,KAAK,IAAI,SAAS,EAAE;AAC3C,oBAAQ;AACR,wBAAY;AACZ,qBAAS;AAAA,UACX;AACA,cAAI,kCAAkC,KAAK,IAAI,QAAQ,GAAG;AACxD,kBAAM,EAAE,MAAM,SAAS,KAAK,IAAI,SAAS,EAAE;AAC3C,oBAAQ;AACR,wBAAY;AACZ,qBAAS;AAAA,UACX;AAEA,gBAAM,EAAE,MAAM,OAAO,KAAK,IAAI,SAAS,EAAE;AACzC,kBAAQ;AACR,sBAAY;AACZ,mBAAS;AAAA,QACX,SAAS,MAAP;AAEA,kBAAQ,MAAM;AACd,mBAAS;AAAA,QACX;AAAA,MACF,WAAW,QAAQ,MAAM,IAAI,GAAG,CAAC,MAAM,SAAS,QAAQ,MAAM,IAAI,GAAG,CAAC,MAAM,MAAM;AAChF,cAAM,IAAI,QAAQ,MAAM,IAAI,CAAC,EAAE,MAAM,cAAc;AACnD,cAAM,MAAM,IAAI,IAAI,IAAI,EAAE,QAAS;AACnC,cAAM,YAAY,QAAQ,IAAI,OAAO,MAAM,IAAI;AAC/C,YAAI;AACF,cAAI,MAAM,IAAI,IAAI,QAAQ,MAAM,IAAI,WAAW,GAAG,CAAC;AACnD,cAAI,IAAI,SAAS,QAAQ,GAAG,MAAM,IAAI;AACpC,kBAAM,IAAI,MAAM,gBAAgB;AAAA,UAClC;AAEA,cAAI,cAAc,IAAI,WAAW;AAC/B,kBAAM,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,WAAW,IAAI,SAAS,EAAE;AAAA,UACtE;AACA,gBAAM,EAAE,MAAM,SAAS,KAAK,IAAI,SAAS,EAAE;AAC3C,kBAAQ;AACR,sBAAY;AACZ,mBAAS;AAAA,QACX,SAAS,MAAP;AAEA,kBAAQ,MAAM;AACd,mBAAS;AAAA,QACX;AAAA,MACF,OAAO;AAEL,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,gBAAM,QAAQ,OAAO;AACrB,cACE,QAAQ,IAAI,MAAM,UAAU,SAAS,OAAO,OAC5C,QAAQ,MAAM,IAAI,GAAG,IAAI,MAAM,UAAU,SAAS,CAAC,MAAM,MAAM,WAC/D;AAEA,gBAAI,cAAc,GAAG;AACnB,oBAAM,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,WAAW,CAAC,EAAE;AAAA,YAC1D;AACA,kBAAM;AACN,oBAAQ,IAAI,MAAM,UAAU,SAAS;AACrC,wBAAY;AACZ,qBAAS;AAAA,UACX;AAAA,QACF;AAGA,gBAAQ,IAAI;AACZ,iBAAS;AAAA,MACX;AAAA,IACF;AAEA,MAAI,cAAc,KAAK;AACrB,UAAM,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,SAAS,EAAE;AAAA,EACvD;AACF;",
+ "sourcesContent": ["import { NostrEvent } from './core.ts'\nimport { AddressPointer, EventPointer, ProfilePointer, decode } from './nip19.ts'\n\nexport type Block =\n | {\n type: 'text'\n text: string\n }\n | {\n type: 'reference'\n pointer: ProfilePointer | AddressPointer | EventPointer\n }\n | {\n type: 'url'\n url: string\n }\n | {\n type: 'relay'\n url: string\n }\n | {\n type: 'image'\n url: string\n }\n | {\n type: 'video'\n url: string\n }\n | {\n type: 'audio'\n url: string\n }\n | {\n type: 'emoji'\n shortcode: string\n url: string\n }\n | {\n type: 'hashtag'\n value: string\n }\n\nconst noCharacter = /\\W/m\nconst noURLCharacter = /[^\\w\\/] |[^\\w\\/]$|$|,| /m\nconst MAX_HASHTAG_LENGTH = 42\n\nexport function* parse(content: string | NostrEvent): Iterable<Block> {\n let emojis: { type: 'emoji'; shortcode: string; url: string }[] = []\n if (typeof content !== 'string') {\n for (let i = 0; i < content.tags.length; i++) {\n const tag = content.tags[i]\n if (tag[0] === 'emoji' && tag.length >= 3) {\n emojis.push({ type: 'emoji', shortcode: tag[1], url: tag[2] })\n }\n }\n content = content.content\n }\n\n const max = content.length\n let prevIndex = 0\n let index = 0\n mainloop: while (index < max) {\n const u = content.indexOf(':', index)\n const h = content.indexOf('#', index)\n if (u === -1 && h === -1) {\n // reached end\n break mainloop\n }\n\n if (u === -1 || (h >= 0 && h < u)) {\n // parse hashtag\n if (h === 0 || content[h - 1] === ' ') {\n const m = content.slice(h + 1, h + MAX_HASHTAG_LENGTH).match(noCharacter)\n const end = m ? h + 1 + m.index! : max\n yield { type: 'text', text: content.slice(prevIndex, h) }\n yield { type: 'hashtag', value: content.slice(h + 1, end) }\n index = end\n prevIndex = index\n continue mainloop\n }\n\n // ignore this, it is nothing\n index = h + 1\n continue mainloop\n }\n\n // otherwise parse things that have an \":\"\n if (content.slice(u - 5, u) === 'nostr') {\n const m = content.slice(u + 60).match(noCharacter)\n const end = m ? u + 60 + m.index! : max\n try {\n let pointer: ProfilePointer | AddressPointer | EventPointer\n let { data, type } = decode(content.slice(u + 1, end))\n\n switch (type) {\n case 'npub':\n pointer = { pubkey: data } as ProfilePointer\n break\n case 'note':\n pointer = { id: data } as EventPointer\n break\n case 'nsec':\n // ignore this, treat it as not a valid uri\n index = end + 1\n continue\n default:\n pointer = data as any\n }\n\n if (prevIndex !== u - 5) {\n yield { type: 'text', text: content.slice(prevIndex, u - 5) }\n }\n yield { type: 'reference', pointer }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid nostr uri\n index = u + 1\n continue mainloop\n }\n } else if (content.slice(u - 5, u) === 'https' || content.slice(u - 4, u) === 'http') {\n const m = content.slice(u + 4).match(noURLCharacter)\n const end = m ? u + 4 + m.index! : max\n const prefixLen = content[u - 1] === 's' ? 5 : 4\n try {\n let url = new URL(content.slice(u - prefixLen, end))\n if (url.hostname.indexOf('.') === -1) {\n throw new Error('invalid url')\n }\n\n if (prevIndex !== u - prefixLen) {\n yield { type: 'text', text: content.slice(prevIndex, u - prefixLen) }\n }\n\n if (/\\.(png|jpe?g|gif|webp|heic|svg)$/i.test(url.pathname)) {\n yield { type: 'image', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n if (/\\.(mp4|avi|webm|mkv|mov)$/i.test(url.pathname)) {\n yield { type: 'video', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n if (/\\.(mp3|aac|ogg|opus|wav|flac)$/i.test(url.pathname)) {\n yield { type: 'audio', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n\n yield { type: 'url', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid url\n index = end + 1\n continue mainloop\n }\n } else if (content.slice(u - 3, u) === 'wss' || content.slice(u - 2, u) === 'ws') {\n const m = content.slice(u + 4).match(noURLCharacter)\n const end = m ? u + 4 + m.index! : max\n const prefixLen = content[u - 1] === 's' ? 3 : 2\n try {\n let url = new URL(content.slice(u - prefixLen, end))\n if (url.hostname.indexOf('.') === -1) {\n throw new Error('invalid ws url')\n }\n\n if (prevIndex !== u - prefixLen) {\n yield { type: 'text', text: content.slice(prevIndex, u - prefixLen) }\n }\n yield { type: 'relay', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid url\n index = end + 1\n continue mainloop\n }\n } else {\n // try to parse an emoji shortcode\n for (let e = 0; e < emojis.length; e++) {\n const emoji = emojis[e]\n if (\n content[u + emoji.shortcode.length + 1] === ':' &&\n content.slice(u + 1, u + emoji.shortcode.length + 1) === emoji.shortcode\n ) {\n // found an emoji\n if (prevIndex !== u) {\n yield { type: 'text', text: content.slice(prevIndex, u) }\n }\n yield emoji\n index = u + emoji.shortcode.length + 2\n prevIndex = index\n continue mainloop\n }\n }\n\n // ignore this, it is nothing\n index = u + 1\n continue mainloop\n }\n }\n\n if (prevIndex !== max) {\n yield { type: 'text', text: content.slice(prevIndex) }\n }\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": "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",
"names": ["import_utils"]
} Index: package/lib/esm/nip27.js.map
===================================================================
--- package/lib/esm/nip27.js.map
+++ package/lib/esm/nip27.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip19.ts", "../../utils.ts", "../../nip27.ts"],
- "sourcesContent": ["import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent } from './core.ts'\nimport { AddressPointer, EventPointer, ProfilePointer, decode } from './nip19.ts'\n\nexport type Block =\n | {\n type: 'text'\n text: string\n }\n | {\n type: 'reference'\n pointer: ProfilePointer | AddressPointer | EventPointer\n }\n | {\n type: 'url'\n url: string\n }\n | {\n type: 'relay'\n url: string\n }\n | {\n type: 'image'\n url: string\n }\n | {\n type: 'video'\n url: string\n }\n | {\n type: 'audio'\n url: string\n }\n | {\n type: 'emoji'\n shortcode: string\n url: string\n }\n | {\n type: 'hashtag'\n value: string\n }\n\nconst noCharacter = /\\W/m\nconst noURLCharacter = /[^\\w\\/] |[^\\w\\/]$|$|,| /m\nconst MAX_HASHTAG_LENGTH = 42\n\nexport function* parse(content: string | NostrEvent): Iterable<Block> {\n let emojis: { type: 'emoji'; shortcode: string; url: string }[] = []\n if (typeof content !== 'string') {\n for (let i = 0; i < content.tags.length; i++) {\n const tag = content.tags[i]\n if (tag[0] === 'emoji' && tag.length >= 3) {\n emojis.push({ type: 'emoji', shortcode: tag[1], url: tag[2] })\n }\n }\n content = content.content\n }\n\n const max = content.length\n let prevIndex = 0\n let index = 0\n mainloop: while (index < max) {\n const u = content.indexOf(':', index)\n const h = content.indexOf('#', index)\n if (u === -1 && h === -1) {\n // reached end\n break mainloop\n }\n\n if (u === -1 || (h >= 0 && h < u)) {\n // parse hashtag\n if (h === 0 || content[h - 1] === ' ') {\n const m = content.slice(h + 1, h + MAX_HASHTAG_LENGTH).match(noCharacter)\n const end = m ? h + 1 + m.index! : max\n yield { type: 'text', text: content.slice(prevIndex, h) }\n yield { type: 'hashtag', value: content.slice(h + 1, end) }\n index = end\n prevIndex = index\n continue mainloop\n }\n\n // ignore this, it is nothing\n index = h + 1\n continue mainloop\n }\n\n // otherwise parse things that have an \":\"\n if (content.slice(u - 5, u) === 'nostr') {\n const m = content.slice(u + 60).match(noCharacter)\n const end = m ? u + 60 + m.index! : max\n try {\n let pointer: ProfilePointer | AddressPointer | EventPointer\n let { data, type } = decode(content.slice(u + 1, end))\n\n switch (type) {\n case 'npub':\n pointer = { pubkey: data } as ProfilePointer\n break\n case 'note':\n pointer = { id: data } as EventPointer\n break\n case 'nsec':\n // ignore this, treat it as not a valid uri\n index = end + 1\n continue\n default:\n pointer = data as any\n }\n\n if (prevIndex !== u - 5) {\n yield { type: 'text', text: content.slice(prevIndex, u - 5) }\n }\n yield { type: 'reference', pointer }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid nostr uri\n index = u + 1\n continue mainloop\n }\n } else if (content.slice(u - 5, u) === 'https' || content.slice(u - 4, u) === 'http') {\n const m = content.slice(u + 4).match(noURLCharacter)\n const end = m ? u + 4 + m.index! : max\n const prefixLen = content[u - 1] === 's' ? 5 : 4\n try {\n let url = new URL(content.slice(u - prefixLen, end))\n if (url.hostname.indexOf('.') === -1) {\n throw new Error('invalid url')\n }\n\n if (prevIndex !== u - prefixLen) {\n yield { type: 'text', text: content.slice(prevIndex, u - prefixLen) }\n }\n\n if (/\\.(png|jpe?g|gif|webp|heic|svg)$/i.test(url.pathname)) {\n yield { type: 'image', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n if (/\\.(mp4|avi|webm|mkv|mov)$/i.test(url.pathname)) {\n yield { type: 'video', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n if (/\\.(mp3|aac|ogg|opus|wav|flac)$/i.test(url.pathname)) {\n yield { type: 'audio', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n\n yield { type: 'url', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid url\n index = end + 1\n continue mainloop\n }\n } else if (content.slice(u - 3, u) === 'wss' || content.slice(u - 2, u) === 'ws') {\n const m = content.slice(u + 4).match(noURLCharacter)\n const end = m ? u + 4 + m.index! : max\n const prefixLen = content[u - 1] === 's' ? 3 : 2\n try {\n let url = new URL(content.slice(u - prefixLen, end))\n if (url.hostname.indexOf('.') === -1) {\n throw new Error('invalid ws url')\n }\n\n if (prevIndex !== u - prefixLen) {\n yield { type: 'text', text: content.slice(prevIndex, u - prefixLen) }\n }\n yield { type: 'relay', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid url\n index = end + 1\n continue mainloop\n }\n } else {\n // try to parse an emoji shortcode\n for (let e = 0; e < emojis.length; e++) {\n const emoji = emojis[e]\n if (\n content[u + emoji.shortcode.length + 1] === ':' &&\n content.slice(u + 1, u + emoji.shortcode.length + 1) === emoji.shortcode\n ) {\n // found an emoji\n if (prevIndex !== u) {\n yield { type: 'text', text: content.slice(prevIndex, u) }\n }\n yield emoji\n index = u + emoji.shortcode.length + 2\n prevIndex = index\n continue mainloop\n }\n }\n\n // ignore this, it is nothing\n index = u + 1\n continue mainloop\n }\n }\n\n if (prevIndex !== max) {\n yield { type: 'text', text: content.slice(prevIndex) }\n }\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent } from './core.ts'\nimport { AddressPointer, EventPointer, ProfilePointer, decode } from './nip19.ts'\n\nexport type Block =\n | {\n type: 'text'\n text: string\n }\n | {\n type: 'reference'\n pointer: ProfilePointer | AddressPointer | EventPointer\n }\n | {\n type: 'url'\n url: string\n }\n | {\n type: 'relay'\n url: string\n }\n | {\n type: 'image'\n url: string\n }\n | {\n type: 'video'\n url: string\n }\n | {\n type: 'audio'\n url: string\n }\n | {\n type: 'emoji'\n shortcode: string\n url: string\n }\n | {\n type: 'hashtag'\n value: string\n }\n\nconst noCharacter = /\\W/m\nconst noURLCharacter = /[^\\w\\/] |[^\\w\\/]$|$|,| /m\nconst MAX_HASHTAG_LENGTH = 42\n\nexport function* parse(content: string | NostrEvent): Iterable<Block> {\n let emojis: { type: 'emoji'; shortcode: string; url: string }[] = []\n if (typeof content !== 'string') {\n for (let i = 0; i < content.tags.length; i++) {\n const tag = content.tags[i]\n if (tag[0] === 'emoji' && tag.length >= 3) {\n emojis.push({ type: 'emoji', shortcode: tag[1], url: tag[2] })\n }\n }\n content = content.content\n }\n\n const max = content.length\n let prevIndex = 0\n let index = 0\n mainloop: while (index < max) {\n const u = content.indexOf(':', index)\n const h = content.indexOf('#', index)\n if (u === -1 && h === -1) {\n // reached end\n break mainloop\n }\n\n if (u === -1 || (h >= 0 && h < u)) {\n // parse hashtag\n if (h === 0 || content[h - 1] === ' ') {\n const m = content.slice(h + 1, h + MAX_HASHTAG_LENGTH).match(noCharacter)\n const end = m ? h + 1 + m.index! : max\n yield { type: 'text', text: content.slice(prevIndex, h) }\n yield { type: 'hashtag', value: content.slice(h + 1, end) }\n index = end\n prevIndex = index\n continue mainloop\n }\n\n // ignore this, it is nothing\n index = h + 1\n continue mainloop\n }\n\n // otherwise parse things that have an \":\"\n if (content.slice(u - 5, u) === 'nostr') {\n const m = content.slice(u + 60).match(noCharacter)\n const end = m ? u + 60 + m.index! : max\n try {\n let pointer: ProfilePointer | AddressPointer | EventPointer\n let { data, type } = decode(content.slice(u + 1, end))\n\n switch (type) {\n case 'npub':\n pointer = { pubkey: data } as ProfilePointer\n break\n case 'note':\n pointer = { id: data } as EventPointer\n break\n case 'nsec':\n // ignore this, treat it as not a valid uri\n index = end + 1\n continue\n default:\n pointer = data as any\n }\n\n if (prevIndex !== u - 5) {\n yield { type: 'text', text: content.slice(prevIndex, u - 5) }\n }\n yield { type: 'reference', pointer }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid nostr uri\n index = u + 1\n continue mainloop\n }\n } else if (content.slice(u - 5, u) === 'https' || content.slice(u - 4, u) === 'http') {\n const m = content.slice(u + 4).match(noURLCharacter)\n const end = m ? u + 4 + m.index! : max\n const prefixLen = content[u - 1] === 's' ? 5 : 4\n try {\n let url = new URL(content.slice(u - prefixLen, end))\n if (url.hostname.indexOf('.') === -1) {\n throw new Error('invalid url')\n }\n\n if (prevIndex !== u - prefixLen) {\n yield { type: 'text', text: content.slice(prevIndex, u - prefixLen) }\n }\n\n if (/\\.(png|jpe?g|gif|webp|heic|svg)$/i.test(url.pathname)) {\n yield { type: 'image', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n if (/\\.(mp4|avi|webm|mkv|mov)$/i.test(url.pathname)) {\n yield { type: 'video', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n if (/\\.(mp3|aac|ogg|opus|wav|flac)$/i.test(url.pathname)) {\n yield { type: 'audio', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n }\n\n yield { type: 'url', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid url\n index = end + 1\n continue mainloop\n }\n } else if (content.slice(u - 3, u) === 'wss' || content.slice(u - 2, u) === 'ws') {\n const m = content.slice(u + 4).match(noURLCharacter)\n const end = m ? u + 4 + m.index! : max\n const prefixLen = content[u - 1] === 's' ? 3 : 2\n try {\n let url = new URL(content.slice(u - prefixLen, end))\n if (url.hostname.indexOf('.') === -1) {\n throw new Error('invalid ws url')\n }\n\n if (prevIndex !== u - prefixLen) {\n yield { type: 'text', text: content.slice(prevIndex, u - prefixLen) }\n }\n yield { type: 'relay', url: url.toString() }\n index = end\n prevIndex = index\n continue mainloop\n } catch (_err) {\n // ignore this, not a valid url\n index = end + 1\n continue mainloop\n }\n } else {\n // try to parse an emoji shortcode\n for (let e = 0; e < emojis.length; e++) {\n const emoji = emojis[e]\n if (\n content[u + emoji.shortcode.length + 1] === ':' &&\n content.slice(u + 1, u + emoji.shortcode.length + 1) === emoji.shortcode\n ) {\n // found an emoji\n if (prevIndex !== u) {\n yield { type: 'text', text: content.slice(prevIndex, u) }\n }\n yield emoji\n index = u + emoji.shortcode.length + 2\n prevIndex = index\n continue mainloop\n }\n }\n\n // ignore this, it is nothing\n index = u + 1\n continue mainloop\n }\n }\n\n if (prevIndex !== max) {\n yield { type: 'text', text: content.slice(prevIndex) }\n }\n}\n"],
+ "mappings": "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",
"names": ["bytesToHex", "hexToBytes", "bytesToHex"]
} Index: package/lib/cjs/nip28.js.map
===================================================================
--- package/lib/cjs/nip28.js.map
+++ package/lib/cjs/nip28.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip28.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts"],
- "sourcesContent": ["import { Event, finalizeEvent } from './pure.ts'\nimport {\n ChannelCreation,\n ChannelHideMessage,\n ChannelMessage,\n ChannelMetadata as KindChannelMetadata,\n ChannelMuteUser,\n} from './kinds.ts'\n\nexport interface ChannelMetadata {\n name: string\n about: string\n picture: string\n}\n\nexport interface ChannelCreateEventTemplate {\n /* JSON string containing ChannelMetadata as defined for Kind 40 and 41 in nip-28. */\n content: string | ChannelMetadata\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMetadataEventTemplate {\n channel_create_event_id: string\n /* JSON string containing ChannelMetadata as defined for Kind 40 and 41 in nip-28. */\n content: string | ChannelMetadata\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMessageEventTemplate {\n channel_create_event_id: string\n reply_to_channel_message_event_id?: string\n relay_url: string\n content: string\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelHideMessageEventTemplate {\n channel_message_event_id: string\n content: string | { reason: string }\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMuteUserEventTemplate {\n content: string | { reason: string }\n created_at: number\n pubkey_to_mute: string\n tags?: string[][]\n}\n\nexport const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelCreation,\n tags: [...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMetadataEvent = (t: ChannelMetadataEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: KindChannelMetadata,\n tags: [['e', t.channel_create_event_id], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey: Uint8Array): Event => {\n const tags = [['e', t.channel_create_event_id, t.relay_url, 'root']]\n\n if (t.reply_to_channel_message_event_id) {\n tags.push(['e', t.reply_to_channel_message_event_id, t.relay_url, 'reply'])\n }\n\n return finalizeEvent(\n {\n kind: ChannelMessage,\n tags: [...tags, ...(t.tags ?? [])],\n content: t.content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\n/* \"e\" tag should be the kind 42 event to hide */\nexport const channelHideMessageEvent = (\n t: ChannelHideMessageEventTemplate,\n privateKey: Uint8Array,\n): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelHideMessage,\n tags: [['e', t.channel_message_event_id], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMuteUserEvent = (t: ChannelMuteUserEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelMuteUser,\n tags: [['p', t.pubkey_to_mute], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
- "mappings": "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",
+ "sourcesContent": ["import { Event, finalizeEvent } from './pure.ts'\nimport {\n ChannelCreation,\n ChannelHideMessage,\n ChannelMessage,\n ChannelMetadata as KindChannelMetadata,\n ChannelMuteUser,\n} from './kinds.ts'\n\nexport interface ChannelMetadata {\n name: string\n about: string\n picture: string\n}\n\nexport interface ChannelCreateEventTemplate {\n /* JSON string containing ChannelMetadata as defined for Kind 40 and 41 in nip-28. */\n content: string | ChannelMetadata\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMetadataEventTemplate {\n channel_create_event_id: string\n /* JSON string containing ChannelMetadata as defined for Kind 40 and 41 in nip-28. */\n content: string | ChannelMetadata\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMessageEventTemplate {\n channel_create_event_id: string\n reply_to_channel_message_event_id?: string\n relay_url: string\n content: string\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelHideMessageEventTemplate {\n channel_message_event_id: string\n content: string | { reason: string }\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMuteUserEventTemplate {\n content: string | { reason: string }\n created_at: number\n pubkey_to_mute: string\n tags?: string[][]\n}\n\nexport const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelCreation,\n tags: [...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMetadataEvent = (t: ChannelMetadataEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: KindChannelMetadata,\n tags: [['e', t.channel_create_event_id], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey: Uint8Array): Event => {\n const tags = [['e', t.channel_create_event_id, t.relay_url, 'root']]\n\n if (t.reply_to_channel_message_event_id) {\n tags.push(['e', t.reply_to_channel_message_event_id, t.relay_url, 'reply'])\n }\n\n return finalizeEvent(\n {\n kind: ChannelMessage,\n tags: [...tags, ...(t.tags ?? [])],\n content: t.content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\n/* \"e\" tag should be the kind 42 event to hide */\nexport const channelHideMessageEvent = (\n t: ChannelHideMessageEventTemplate,\n privateKey: Uint8Array,\n): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelHideMessage,\n tags: [['e', t.channel_message_event_id], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMuteUserEvent = (t: ChannelMuteUserEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelMuteUser,\n tags: [['p', t.pubkey_to_mute], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
+ "mappings": "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",
"names": ["import_utils", "i"]
} Index: package/lib/esm/nip28.js.map
===================================================================
--- package/lib/esm/nip28.js.map
+++ package/lib/esm/nip28.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../nip28.ts"],
- "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event, finalizeEvent } from './pure.ts'\nimport {\n ChannelCreation,\n ChannelHideMessage,\n ChannelMessage,\n ChannelMetadata as KindChannelMetadata,\n ChannelMuteUser,\n} from './kinds.ts'\n\nexport interface ChannelMetadata {\n name: string\n about: string\n picture: string\n}\n\nexport interface ChannelCreateEventTemplate {\n /* JSON string containing ChannelMetadata as defined for Kind 40 and 41 in nip-28. */\n content: string | ChannelMetadata\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMetadataEventTemplate {\n channel_create_event_id: string\n /* JSON string containing ChannelMetadata as defined for Kind 40 and 41 in nip-28. */\n content: string | ChannelMetadata\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMessageEventTemplate {\n channel_create_event_id: string\n reply_to_channel_message_event_id?: string\n relay_url: string\n content: string\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelHideMessageEventTemplate {\n channel_message_event_id: string\n content: string | { reason: string }\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMuteUserEventTemplate {\n content: string | { reason: string }\n created_at: number\n pubkey_to_mute: string\n tags?: string[][]\n}\n\nexport const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelCreation,\n tags: [...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMetadataEvent = (t: ChannelMetadataEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: KindChannelMetadata,\n tags: [['e', t.channel_create_event_id], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey: Uint8Array): Event => {\n const tags = [['e', t.channel_create_event_id, t.relay_url, 'root']]\n\n if (t.reply_to_channel_message_event_id) {\n tags.push(['e', t.reply_to_channel_message_event_id, t.relay_url, 'reply'])\n }\n\n return finalizeEvent(\n {\n kind: ChannelMessage,\n tags: [...tags, ...(t.tags ?? [])],\n content: t.content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\n/* \"e\" tag should be the kind 42 event to hide */\nexport const channelHideMessageEvent = (\n t: ChannelHideMessageEventTemplate,\n privateKey: Uint8Array,\n): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelHideMessage,\n tags: [['e', t.channel_message_event_id], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMuteUserEvent = (t: ChannelMuteUserEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelMuteUser,\n tags: [['p', t.pubkey_to_mute], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n"],
- "mappings": "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",
- "names": ["bytesToHex", "i", "bytesToHex"]
+ "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event, finalizeEvent } from './pure.ts'\nimport {\n ChannelCreation,\n ChannelHideMessage,\n ChannelMessage,\n ChannelMetadata as KindChannelMetadata,\n ChannelMuteUser,\n} from './kinds.ts'\n\nexport interface ChannelMetadata {\n name: string\n about: string\n picture: string\n}\n\nexport interface ChannelCreateEventTemplate {\n /* JSON string containing ChannelMetadata as defined for Kind 40 and 41 in nip-28. */\n content: string | ChannelMetadata\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMetadataEventTemplate {\n channel_create_event_id: string\n /* JSON string containing ChannelMetadata as defined for Kind 40 and 41 in nip-28. */\n content: string | ChannelMetadata\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMessageEventTemplate {\n channel_create_event_id: string\n reply_to_channel_message_event_id?: string\n relay_url: string\n content: string\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelHideMessageEventTemplate {\n channel_message_event_id: string\n content: string | { reason: string }\n created_at: number\n tags?: string[][]\n}\n\nexport interface ChannelMuteUserEventTemplate {\n content: string | { reason: string }\n created_at: number\n pubkey_to_mute: string\n tags?: string[][]\n}\n\nexport const channelCreateEvent = (t: ChannelCreateEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelCreation,\n tags: [...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMetadataEvent = (t: ChannelMetadataEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: KindChannelMetadata,\n tags: [['e', t.channel_create_event_id], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMessageEvent = (t: ChannelMessageEventTemplate, privateKey: Uint8Array): Event => {\n const tags = [['e', t.channel_create_event_id, t.relay_url, 'root']]\n\n if (t.reply_to_channel_message_event_id) {\n tags.push(['e', t.reply_to_channel_message_event_id, t.relay_url, 'reply'])\n }\n\n return finalizeEvent(\n {\n kind: ChannelMessage,\n tags: [...tags, ...(t.tags ?? [])],\n content: t.content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\n/* \"e\" tag should be the kind 42 event to hide */\nexport const channelHideMessageEvent = (\n t: ChannelHideMessageEventTemplate,\n privateKey: Uint8Array,\n): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelHideMessage,\n tags: [['e', t.channel_message_event_id], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n\nexport const channelMuteUserEvent = (t: ChannelMuteUserEventTemplate, privateKey: Uint8Array): Event | undefined => {\n let content: string\n if (typeof t.content === 'object') {\n content = JSON.stringify(t.content)\n } else if (typeof t.content === 'string') {\n content = t.content\n } else {\n return undefined\n }\n\n return finalizeEvent(\n {\n kind: ChannelMuteUser,\n tags: [['p', t.pubkey_to_mute], ...(t.tags ?? [])],\n content: content,\n created_at: t.created_at,\n },\n privateKey,\n )\n}\n"],
+ "mappings": ";AAAA,SAAS,eAAe;AACxB,SAAS,cAAAA,aAAY,cAAAC,mBAAkB;;;ACOhC,IAAM,iBAAiB,OAAO,UAAU;AAsB/C,IAAM,WAAW,CAAC,QAAiD,eAAe;AAE3E,SAAS,cAAiB,OAAsC;AACrE,MAAI,CAAC,SAAS,KAAK;AAAG,WAAO;AAC7B,MAAI,OAAO,MAAM,SAAS;AAAU,WAAO;AAC3C,MAAI,OAAO,MAAM,YAAY;AAAU,WAAO;AAC9C,MAAI,OAAO,MAAM,eAAe;AAAU,WAAO;AACjD,MAAI,OAAO,MAAM,WAAW;AAAU,WAAO;AAC7C,MAAI,CAAC,MAAM,OAAO,MAAM,gBAAgB;AAAG,WAAO;AAElD,MAAI,CAAC,MAAM,QAAQ,MAAM,IAAI;AAAG,WAAO;AACvC,WAASC,KAAI,GAAGA,KAAI,MAAM,KAAK,QAAQA,MAAK;AAC1C,QAAI,MAAM,MAAM,KAAKA;AACrB,QAAI,CAAC,MAAM,QAAQ,GAAG;AAAG,aAAO;AAChC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAI,OAAO,IAAI,OAAO;AAAU,eAAO;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AACT;;;AD/CA,SAAS,cAAc;;;AEEvB,SAAS,YAAY,kBAAkB;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;AFIxD,IAAM,KAAN,MAA0B;AAAA,EACxB,oBAAgC;AAC9B,WAAO,QAAQ,MAAM,gBAAgB;AAAA,EACvC;AAAA,EACA,aAAa,WAA+B;AAC1C,WAAOC,YAAW,QAAQ,aAAa,SAAS,CAAC;AAAA,EACnD;AAAA,EACA,cAAc,GAAkB,WAAsC;AACpE,UAAM,QAAQ;AACd,UAAM,SAASA,YAAW,QAAQ,aAAa,SAAS,CAAC;AACzD,UAAM,KAAK,aAAa,KAAK;AAC7B,UAAM,MAAMA,YAAW,QAAQ,KAAKC,YAAW,aAAa,KAAK,CAAC,GAAG,SAAS,CAAC;AAC/E,UAAM,kBAAkB;AACxB,WAAO;AAAA,EACT;AAAA,EACA,YAAY,OAAsC;AAChD,QAAI,OAAO,MAAM,oBAAoB;AAAW,aAAO,MAAM;AAE7D,UAAM,OAAO,aAAa,KAAK;AAC/B,QAAI,SAAS,MAAM,IAAI;AACrB,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,QAAQ,QAAQ,OAAOA,YAAW,MAAM,GAAG,GAAGA,YAAW,IAAI,GAAGA,YAAW,MAAM,MAAM,CAAC;AAC9F,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT,SAAS,KAAP;AACA,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,eAAe,KAA4B;AACzD,MAAI,CAAC,cAAc,GAAG;AAAG,UAAM,IAAI,MAAM,wDAAwD;AACjG,SAAO,KAAK,UAAU,CAAC,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,CAAC;AACxF;AAEO,SAAS,aAAa,OAA8B;AACzD,MAAI,YAAY,OAAO,YAAY,OAAO,eAAe,KAAK,CAAC,CAAC;AAChE,SAAOD,YAAW,SAAS;AAC7B;AAEA,IAAM,IAAQ,IAAI,GAAG;AAEd,IAAM,oBAAoB,EAAE;AAC5B,IAAM,eAAe,EAAE;AACvB,IAAM,gBAAgB,EAAE;AACxB,IAAM,cAAc,EAAE;;;AGkBtB,IAAM,kBAAkB;AAExB,IAAM,kBAAkB;AAExB,IAAM,iBAAiB;AAEvB,IAAM,qBAAqB;AAE3B,IAAM,kBAAkB;;;AC9BxB,IAAM,qBAAqB,CAAC,GAA+B,eAA8C;AAC9G,MAAI;AACJ,MAAI,OAAO,EAAE,YAAY,UAAU;AACjC,cAAU,KAAK,UAAU,EAAE,OAAO;AAAA,EACpC,WAAW,OAAO,EAAE,YAAY,UAAU;AACxC,cAAU,EAAE;AAAA,EACd,OAAO;AACL,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,MAAM,CAAC,GAAI,EAAE,QAAQ,CAAC,CAAE;AAAA,MACxB;AAAA,MACA,YAAY,EAAE;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;AAEO,IAAM,uBAAuB,CAAC,GAAiC,eAA8C;AAClH,MAAI;AACJ,MAAI,OAAO,EAAE,YAAY,UAAU;AACjC,cAAU,KAAK,UAAU,EAAE,OAAO;AAAA,EACpC,WAAW,OAAO,EAAE,YAAY,UAAU;AACxC,cAAU,EAAE;AAAA,EACd,OAAO;AACL,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,MAAM,CAAC,CAAC,KAAK,EAAE,uBAAuB,GAAG,GAAI,EAAE,QAAQ,CAAC,CAAE;AAAA,MAC1D;AAAA,MACA,YAAY,EAAE;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;AAEO,IAAM,sBAAsB,CAAC,GAAgC,eAAkC;AACpG,QAAM,OAAO,CAAC,CAAC,KAAK,EAAE,yBAAyB,EAAE,WAAW,MAAM,CAAC;AAEnE,MAAI,EAAE,mCAAmC;AACvC,SAAK,KAAK,CAAC,KAAK,EAAE,mCAAmC,EAAE,WAAW,OAAO,CAAC;AAAA,EAC5E;AAEA,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,MAAM,CAAC,GAAG,MAAM,GAAI,EAAE,QAAQ,CAAC,CAAE;AAAA,MACjC,SAAS,EAAE;AAAA,MACX,YAAY,EAAE;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;AAGO,IAAM,0BAA0B,CACrC,GACA,eACsB;AACtB,MAAI;AACJ,MAAI,OAAO,EAAE,YAAY,UAAU;AACjC,cAAU,KAAK,UAAU,EAAE,OAAO;AAAA,EACpC,WAAW,OAAO,EAAE,YAAY,UAAU;AACxC,cAAU,EAAE;AAAA,EACd,OAAO;AACL,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,MAAM,CAAC,CAAC,KAAK,EAAE,wBAAwB,GAAG,GAAI,EAAE,QAAQ,CAAC,CAAE;AAAA,MAC3D;AAAA,MACA,YAAY,EAAE;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;AAEO,IAAM,uBAAuB,CAAC,GAAiC,eAA8C;AAClH,MAAI;AACJ,MAAI,OAAO,EAAE,YAAY,UAAU;AACjC,cAAU,KAAK,UAAU,EAAE,OAAO;AAAA,EACpC,WAAW,OAAO,EAAE,YAAY,UAAU;AACxC,cAAU,EAAE;AAAA,EACd,OAAO;AACL,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,MAAM,CAAC,CAAC,KAAK,EAAE,cAAc,GAAG,GAAI,EAAE,QAAQ,CAAC,CAAE;AAAA,MACjD;AAAA,MACA,YAAY,EAAE;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AACF;",
+ "names": ["bytesToHex", "hexToBytes", "i", "bytesToHex", "hexToBytes"]
} Index: package/lib/cjs/nip29.js.map
===================================================================
--- package/lib/cjs/nip29.js.map
+++ package/lib/cjs/nip29.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip29.ts", "../../nip11.ts", "../../nip19.ts", "../../utils.ts"],
- "sourcesContent": ["import { AbstractSimplePool } from './abstract-pool.ts'\nimport { Subscription } from './abstract-relay.ts'\nimport type { Event, EventTemplate } from './core.ts'\nimport { fetchRelayInformation, RelayInformation } from './nip11.ts'\nimport { decode, NostrTypeGuard } from './nip19.ts'\nimport { normalizeURL } from './utils.ts'\n\n/**\n * Represents a NIP29 group.\n */\nexport type Group = {\n relay: string\n metadata: GroupMetadata\n admins?: GroupAdmin[]\n members?: GroupMember[]\n reference: GroupReference\n}\n\n/**\n * Represents the metadata for a NIP29 group.\n */\nexport type GroupMetadata = {\n id: string\n pubkey: string\n name?: string\n picture?: string\n about?: string\n isPublic?: boolean\n isOpen?: boolean\n}\n\n/**\n * Represents a NIP29 group reference.\n */\nexport type GroupReference = {\n id: string\n host: string\n}\n\n/**\n * Represents a NIP29 group member.\n */\nexport type GroupMember = {\n pubkey: string\n label?: string\n}\n\n/**\n * Represents a NIP29 group admin.\n */\nexport type GroupAdmin = {\n pubkey: string\n label?: string\n permissions: GroupAdminPermission[]\n}\n\n/**\n * Represents the permissions that a NIP29 group admin can have.\n */\nexport enum GroupAdminPermission {\n /** @deprecated use PutUser instead */\n AddUser = 'add-user',\n EditMetadata = 'edit-metadata',\n DeleteEvent = 'delete-event',\n RemoveUser = 'remove-user',\n /** @deprecated removed from NIP */\n AddPermission = 'add-permission',\n /** @deprecated removed from NIP */\n RemovePermission = 'remove-permission',\n /** @deprecated removed from NIP */\n EditGroupStatus = 'edit-group-status',\n PutUser = 'put-user',\n CreateGroup = 'create-group',\n DeleteGroup = 'delete-group',\n CreateInvite = 'create-invite',\n}\n\n/**\n * Generates a group metadata event template.\n *\n * @param group - The group object.\n * @returns An event template with the generated group metadata that can be signed later.\n */\nexport function generateGroupMetadataEventTemplate(group: Group): EventTemplate {\n const tags: string[][] = [['d', group.metadata.id]]\n group.metadata.name && tags.push(['name', group.metadata.name])\n group.metadata.picture && tags.push(['picture', group.metadata.picture])\n group.metadata.about && tags.push(['about', group.metadata.about])\n group.metadata.isPublic && tags.push(['public'])\n group.metadata.isOpen && tags.push(['open'])\n\n return {\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n kind: 39000,\n tags,\n }\n}\n\n/**\n * Validates a group metadata event.\n *\n * @param event - The event to validate.\n * @returns A boolean indicating whether the event is valid.\n */\nexport function validateGroupMetadataEvent(event: Event): boolean {\n if (event.kind !== 39000) return false\n\n if (!event.pubkey) return false\n\n const requiredTags = ['d'] as const\n for (const tag of requiredTags) {\n if (!event.tags.find(([t]) => t == tag)) return false\n }\n\n return true\n}\n\n/**\n * Generates an event template for group admins.\n *\n * @param group - The group object.\n * @param admins - An array of group admins.\n * @returns The generated event template with the group admins that can be signed later.\n */\nexport function generateGroupAdminsEventTemplate(group: Group, admins: GroupAdmin[]): EventTemplate {\n const tags: string[][] = [['d', group.metadata.id]]\n for (const admin of admins) {\n tags.push(['p', admin.pubkey, admin.label || '', ...admin.permissions])\n }\n\n return {\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n kind: 39001,\n tags,\n }\n}\n\n/**\n * Validates a group admins event.\n *\n * @param event - The event to validate.\n * @returns True if the event is valid, false otherwise.\n */\nexport function validateGroupAdminsEvent(event: Event): boolean {\n if (event.kind !== 39001) return false\n\n const requiredTags = ['d'] as const\n for (const tag of requiredTags) {\n if (!event.tags.find(([t]) => t == tag)) return false\n }\n\n // validate permissions\n for (const [tag, _value, _label, ...permissions] of event.tags) {\n if (tag !== 'p') continue\n\n for (let i = 0; i < permissions.length; i += 1) {\n if (typeof permissions[i] !== 'string') return false\n\n // validate permission name from the GroupAdminPermission enum\n if (!Object.values(GroupAdminPermission).includes(permissions[i] as GroupAdminPermission)) return false\n }\n }\n\n return true\n}\n\n/**\n * Generates an event template for a group with its members.\n *\n * @param group - The group object.\n * @param members - An array of group members.\n * @returns The generated event template with the group members that can be signed later.\n */\nexport function generateGroupMembersEventTemplate(group: Group, members: GroupMember[]): EventTemplate {\n const tags: string[][] = [['d', group.metadata.id]]\n for (const member of members) {\n tags.push(['p', member.pubkey, member.label || ''])\n }\n\n return {\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n kind: 39002,\n tags,\n }\n}\n\n/**\n * Validates a group members event.\n *\n * @param event - The event to validate.\n * @returns Returns `true` if the event is a valid group members event, `false` otherwise.\n */\nexport function validateGroupMembersEvent(event: Event): boolean {\n if (event.kind !== 39002) return false\n\n const requiredTags = ['d'] as const\n for (const tag of requiredTags) {\n if (!event.tags.find(([t]) => t == tag)) return false\n }\n\n return true\n}\n\n/**\n * Returns the normalized relay URL based on the provided group reference.\n *\n * @param groupReference - The group reference object containing the host.\n * @returns The normalized relay URL.\n */\nexport function getNormalizedRelayURLByGroupReference(groupReference: GroupReference): string {\n return normalizeURL(groupReference.host)\n}\n\n/**\n * Fetches relay information by group reference.\n *\n * @param groupReference The group reference.\n * @returns A promise that resolves to the relay information.\n */\nexport async function fetchRelayInformationByGroupReference(groupReference: GroupReference): Promise<RelayInformation> {\n const normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n\n return fetchRelayInformation(normalizedRelayURL)\n}\n\n/**\n * Fetches the group metadata event from the specified pool.\n * If the normalizedRelayURL is not provided, it will be obtained using the groupReference.\n * If the relayInformation is not provided, it will be fetched using the normalizedRelayURL.\n *\n * @param {Object} options - The options object.\n * @param {AbstractSimplePool} options.pool - The pool to fetch the group metadata event from.\n * @param {GroupReference} options.groupReference - The reference to the group.\n * @param {string} [options.normalizedRelayURL] - The normalized URL of the relay.\n * @param {RelayInformation} [options.relayInformation] - The relay information object.\n * @returns {Promise<Event>} The group metadata event that can be parsed later to get the group metadata object.\n * @throws {Error} If the group is not found on the specified relay.\n */\nexport async function fetchGroupMetadataEvent({\n pool,\n groupReference,\n relayInformation,\n normalizedRelayURL,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Event> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const groupMetadataEvent = await pool.get([normalizedRelayURL], {\n kinds: [39000],\n authors: [relayInformation.pubkey],\n '#d': [groupReference.id],\n })\n\n if (!groupMetadataEvent) throw new Error(`group '${groupReference.id}' not found on ${normalizedRelayURL}`)\n\n return groupMetadataEvent\n}\n\n/**\n * Parses a group metadata event and returns the corresponding GroupMetadata object.\n *\n * @param event - The event to parse.\n * @returns The parsed GroupMetadata object.\n * @throws An error if the group metadata event is invalid.\n */\nexport function parseGroupMetadataEvent(event: Event): GroupMetadata {\n if (!validateGroupMetadataEvent(event)) throw new Error('invalid group metadata event')\n\n const metadata: GroupMetadata = {\n id: '',\n pubkey: event.pubkey,\n }\n\n for (const [tag, value] of event.tags) {\n switch (tag) {\n case 'd':\n metadata.id = value\n break\n case 'name':\n metadata.name = value\n break\n case 'picture':\n metadata.picture = value\n break\n case 'about':\n metadata.about = value\n break\n case 'public':\n metadata.isPublic = true\n break\n case 'open':\n metadata.isOpen = true\n break\n }\n }\n\n return metadata\n}\n\n/**\n * Fetches the group admins event from the specified pool.\n * If the normalizedRelayURL is not provided, it will be obtained from the groupReference.\n * If the relayInformation is not provided, it will be fetched using the normalizedRelayURL.\n *\n * @param {Object} options - The options object.\n * @param {AbstractSimplePool} options.pool - The pool to fetch the group admins event from.\n * @param {GroupReference} options.groupReference - The reference to the group.\n * @param {string} [options.normalizedRelayURL] - The normalized relay URL.\n * @param {RelayInformation} [options.relayInformation] - The relay information.\n * @returns {Promise<Event>} The group admins event that can be parsed later to get the group admins object.\n * @throws {Error} If the group admins event is not found on the specified relay.\n */\nexport async function fetchGroupAdminsEvent({\n pool,\n groupReference,\n relayInformation,\n normalizedRelayURL,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Event> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const groupAdminsEvent = await pool.get([normalizedRelayURL], {\n kinds: [39001],\n authors: [relayInformation.pubkey],\n '#d': [groupReference.id],\n })\n\n if (!groupAdminsEvent) throw new Error(`admins for group '${groupReference.id}' not found on ${normalizedRelayURL}`)\n\n return groupAdminsEvent\n}\n\n/**\n * Parses a group admins event and returns an array of GroupAdmin objects.\n *\n * @param event - The event to parse.\n * @returns An array of GroupAdmin objects.\n * @throws Throws an error if the group admins event is invalid.\n */\nexport function parseGroupAdminsEvent(event: Event): GroupAdmin[] {\n if (!validateGroupAdminsEvent(event)) throw new Error('invalid group admins event')\n\n const admins: GroupAdmin[] = []\n\n for (const [tag, value, label, ...permissions] of event.tags) {\n if (tag !== 'p') continue\n\n admins.push({\n pubkey: value,\n label,\n permissions: permissions as GroupAdminPermission[],\n })\n }\n\n return admins\n}\n\n/**\n * Fetches the group members event from the specified relay.\n * If the normalizedRelayURL is not provided, it will be obtained using the groupReference.\n * If the relayInformation is not provided, it will be fetched using the normalizedRelayURL.\n *\n * @param {Object} options - The options object.\n * @param {AbstractSimplePool} options.pool - The pool object.\n * @param {GroupReference} options.groupReference - The group reference object.\n * @param {string} [options.normalizedRelayURL] - The normalized relay URL.\n * @param {RelayInformation} [options.relayInformation] - The relay information object.\n * @returns {Promise<Event>} The group members event that can be parsed later to get the group members object.\n * @throws {Error} If the group members event is not found.\n */\nexport async function fetchGroupMembersEvent({\n pool,\n groupReference,\n relayInformation,\n normalizedRelayURL,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Event> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const groupMembersEvent = await pool.get([normalizedRelayURL], {\n kinds: [39002],\n authors: [relayInformation.pubkey],\n '#d': [groupReference.id],\n })\n\n if (!groupMembersEvent) throw new Error(`members for group '${groupReference.id}' not found on ${normalizedRelayURL}`)\n\n return groupMembersEvent\n}\n\n/**\n * Parses a group members event and returns an array of GroupMember objects.\n * @param event - The event to parse.\n * @returns An array of GroupMember objects.\n * @throws Throws an error if the group members event is invalid.\n */\nexport function parseGroupMembersEvent(event: Event): GroupMember[] {\n if (!validateGroupMembersEvent(event)) throw new Error('invalid group members event')\n\n const members: GroupMember[] = []\n\n for (const [tag, value, label] of event.tags) {\n if (tag !== 'p') continue\n\n members.push({\n pubkey: value,\n label,\n })\n }\n\n return members\n}\n\n/**\n * Fetches and parses the group metadata event, group admins event, and group members event from the specified pool.\n * If the normalized relay URL is not provided, it will be obtained using the group reference.\n * If the relay information is not provided, it will be fetched using the normalized relay URL.\n *\n * @param {Object} options - The options for loading the group.\n * @param {AbstractSimplePool} options.pool - The pool to load the group from.\n * @param {GroupReference} options.groupReference - The reference of the group to load.\n * @param {string} [options.normalizedRelayURL] - The normalized URL of the relay to use.\n * @param {RelayInformation} [options.relayInformation] - The relay information to use.\n * @returns {Promise<Group>} A promise that resolves to the loaded group.\n */\nexport async function loadGroup({\n pool,\n groupReference,\n normalizedRelayURL,\n relayInformation,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Group> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const metadataEvent = await fetchGroupMetadataEvent({ pool, groupReference, normalizedRelayURL, relayInformation })\n const metadata = parseGroupMetadataEvent(metadataEvent)\n\n const adminsEvent = await fetchGroupAdminsEvent({ pool, groupReference, normalizedRelayURL, relayInformation })\n const admins = parseGroupAdminsEvent(adminsEvent)\n\n const membersEvent = await fetchGroupMembersEvent({ pool, groupReference, normalizedRelayURL, relayInformation })\n const members = parseGroupMembersEvent(membersEvent)\n\n const group: Group = {\n relay: normalizedRelayURL,\n metadata,\n admins,\n members,\n reference: groupReference,\n }\n\n return group\n}\n\n/**\n * Loads a group from the specified pool using the provided group code.\n *\n * @param {AbstractSimplePool} pool - The pool to load the group from.\n * @param {string} code - The code representing the group.\n * @returns {Promise<Group>} - A promise that resolves to the loaded group.\n * @throws {Error} - If the group code is invalid.\n */\nexport async function loadGroupFromCode(pool: AbstractSimplePool, code: string): Promise<Group> {\n const groupReference = parseGroupCode(code)\n\n if (!groupReference) throw new Error('invalid group code')\n\n return loadGroup({ pool, groupReference })\n}\n\n/**\n * Parses a group code and returns a GroupReference object.\n *\n * @param code The group code to parse.\n * @returns A GroupReference object if the code is valid, otherwise null.\n */\nexport function parseGroupCode(code: string): null | GroupReference {\n if (NostrTypeGuard.isNAddr(code)) {\n try {\n let { data } = decode(code)\n\n let { relays, identifier } = data\n if (!relays || relays.length === 0) return null\n\n let host = relays![0]\n if (host.startsWith('wss://')) {\n host = host.slice(6)\n }\n return { host, id: identifier }\n } catch (err) {\n return null\n }\n } else if (code.split(\"'\").length === 2) {\n let spl = code.split(\"'\")\n return { host: spl[0], id: spl[1] }\n }\n\n return null\n}\n\n/**\n * Encodes a group reference into a string.\n *\n * @param gr - The group reference to encode.\n * @returns The encoded group reference as a string.\n */\nexport function encodeGroupReference(gr: GroupReference): string {\n const { host, id } = gr\n const normalizedHost = host.replace(/^(https?:\\/\\/|wss?:\\/\\/)/, '')\n\n return `${normalizedHost}'${id}`\n}\n\n/**\n * Subscribes to relay groups metadata events and calls the provided event handler function\n * when an event is received.\n *\n * @param {Object} options - The options for subscribing to relay groups metadata events.\n * @param {AbstractSimplePool} options.pool - The pool to subscribe to.\n * @param {string} options.relayURL - The URL of the relay.\n * @param {Function} options.onError - The error handler function.\n * @param {Function} options.onEvent - The event handler function.\n * @param {Function} [options.onConnect] - The connect handler function.\n * @returns {Function} - A function to close the subscription\n */\nexport function subscribeRelayGroupsMetadataEvents({\n pool,\n relayURL,\n onError,\n onEvent,\n onConnect,\n}: {\n pool: AbstractSimplePool\n relayURL: string\n onError: (err: Error) => void\n onEvent: (event: Event) => void\n onConnect?: () => void\n}): () => void {\n let sub: Subscription\n\n const normalizedRelayURL = normalizeURL(relayURL)\n\n fetchRelayInformation(normalizedRelayURL)\n .then(async info => {\n const abstractedRelay = await pool.ensureRelay(normalizedRelayURL)\n\n onConnect?.()\n\n sub = abstractedRelay.prepareSubscription(\n [\n {\n kinds: [39000],\n limit: 50,\n authors: [info.pubkey],\n },\n ],\n {\n onevent(event: Event) {\n onEvent(event)\n },\n },\n )\n })\n .catch(err => {\n sub.close()\n\n onError(err)\n })\n\n return () => sub.close()\n}\n", "var _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any): void {\n _fetch = fetchImplementation\n}\n\nexport async function fetchRelayInformation(url: string): Promise<RelayInformation> {\n return (await (\n await fetch(url.replace('ws://', 'http://').replace('wss://', 'https://'), {\n headers: { Accept: 'application/nostr+json' },\n })\n ).json()) as RelayInformation\n}\n\n/**\n * ## Relay Information Document\n\n * Relays may provide server metadata to clients to inform\n * them of capabilities, administrative contacts, and\n * various server attributes. This is made available as a\n * JSON document over HTTP, on the same URI as the relay's\n * websocket.\n\n * Any field may be omitted, and clients MUST ignore any\n * additional fields they do not understand. Relays MUST\n * accept CORS requests by sending\n * `Access-Control-Allow-Origin`,\n * `Access-Control-Allow-Headers`, and\n * `Access-Control-Allow-Methods` headers.\n * @param name string identifying relay\n * @param description string with detailed information\n * @param pubkey administrative contact pubkey\n * @param contact: administrative alternate contact\n * @param supported_nips a list of NIP numbers supported by\n * the relay\n * @param software identifying relay software URL\n * @param version string version identifier\n */\nexport interface BasicRelayInformation {\n // string identifying relay\n name: string\n description: string\n pubkey: string\n contact: string\n supported_nips: number[]\n software: string\n version: string\n // limitation?: Limitations<A, P>\n}\n\n/**\n * * ## Extra Fields\n\n * * ### Server Limitations\n\n * These are limitations imposed by the relay on clients.\n * Your client should expect that requests which exceed\n * these practical_ limitations are rejected or fail immediately.\n * @param max_message_length this is the maximum number of\n * bytes for incoming JSON that the relay will attempt to\n * decode and act upon. When you send large subscriptions,\n * you will be limited by this value. It also effectively\n * limits the maximum size of any event. Value is calculated\n * from `[` to `]` and is after UTF-8 serialization (so some\n * unicode characters will cost 2-3 bytes). It is equal to\n * the maximum size of the WebSocket message frame.\n * @param max_subscriptions total number of subscriptions\n * that may be active on a single websocket connection to\n * this relay. It's possible that authenticated clients with\n * a (paid) relationship to the relay may have higher limits.\n * @param max_filters maximum number of filter values in\n * each subscription. Must be one or higher.\n * @param max_limit the relay server will clamp each\n * filter's `limit` value to this number.\n * This means the client won't be able to get more than this\n * number of events from a single subscription filter. This\n * clamping is typically done silently by the relay, but\n * with this number, you can know that there are additional\n * results if you narrowed your filter's time range or other\n * parameters.\n * @param max_subid_length maximum length of subscription id as a\n * string.\n * @param min_prefix for `authors` and `ids` filters which\n * are to match against a hex prefix, you must provide at\n * least this many hex digits in the prefix.\n * @param max_event_tags in any event, this is the maximum\n * number of elements in the `tags` list.\n * @param max_content_length maximum number of characters in\n * the `content` field of any event. This is a count of\n * unicode characters. After serializing into JSON it may be\n * larger (in bytes), and is still subject to the\n * max_message_length`, if defined.\n * @param min_pow_difficulty new events will require at\n * least this difficulty of PoW, based on [NIP-13](13.md),\n * or they will be rejected by this server.\n * @param auth_required this relay requires [NIP-42](42.md)\n * authentication to happen before a new connection may\n * perform any other action. Even if set to False,\n * authentication may be required for specific actions.\n * @param restricted_writes: this relay requires some kind\n * of condition to be fulfilled in order to accept events\n * (not necessarily, but including\n * @param payment_required this relay requires payment\n * before a new connection may perform any action.\n * @param created_at_lower_limit: 'created_at' lower limit\n * @param created_at_upper_limit: 'created_at' upper limit\n */\nexport interface Limitations {\n max_message_length: number\n max_subscriptions: number\n max_filters: number\n max_limit: number\n max_subid_length: number\n min_prefix: number\n max_event_tags: number\n max_content_length: number\n min_pow_difficulty: number\n auth_required: boolean\n payment_required: boolean\n created_at_lower_limit: number\n created_at_upper_limit: number\n restricted_writes: boolean\n}\n\nexport interface RetentionDetails {\n kinds: (number | number[])[]\n time?: number | null\n count?: number | null\n}\ntype AnyRetentionDetails = RetentionDetails\n/**\n * ### Event Retention\n\n * There may be a cost associated with storing data forever,\n * so relays may wish to state retention times. The values\n * stated here are defaults for unauthenticated users and\n * visitors. Paid users would likely have other policies.\n\n * Retention times are given in seconds, with `null`\n * indicating infinity. If zero is provided, this means the\n * event will not be stored at all, and preferably an error\n * will be provided when those are received.\n * ```json\n{\n...\n \"retention\": [\n { \"kinds\": [0, 1, [5, 7], [40, 49]], \"time\": 3600 },\n { \"kinds\": [[40000, 49999]], \"time\": 100 },\n { \"kinds\": [[30000, 39999]], \"count\": 1000 },\n { \"time\": 3600, \"count\": 10000 }\n ]\n...\n}\n```\n * @param retention is a list of specifications: each will\n * apply to either all kinds, or a subset of kinds. Ranges\n * may be specified for the kind field as a tuple of\n * inclusive start and end values. Events of indicated kind\n * (or all) are then limited to a `count` and/or time\n * period.\n\n * It is possible to effectively blacklist Nostr-based\n * protocols that rely on a specific `kind` number, by\n * giving a retention time of zero for those `kind` values.\n * While that is unfortunate, it does allow clients to\n * discover servers that will support their protocol quickly\n * via a single HTTP fetch.\n\n * There is no need to specify retention times for\n * _ephemeral events_ as defined in [NIP-16](16.md) since\n * they are not retained.\n */\nexport interface Retention {\n retention: AnyRetentionDetails[]\n}\n\n/**\n * Some relays may be governed by the arbitrary laws of a\n * nation state. This may limit what content can be stored\n * in cleartext on those relays. All clients are encouraged\n * to use encryption to work around this limitation.\n\n * It is not possible to describe the limitations of each\n * country's laws and policies which themselves are\n * typically vague and constantly shifting.\n\n * Therefore, this field allows the relay operator to\n * indicate which countries' laws might end up being\n * enforced on them, and then indirectly on their users'\n * content.\n\n * Users should be able to avoid relays in countries they\n * don't like, and/or select relays in more favourable\n * zones. Exposing this flexibility is up to the client\n * software.\n\n * @param relay_countries a list of two-level ISO country\n * codes (ISO 3166-1 alpha-2) whose laws and policies may\n * affect this relay. `EU` may be used for European Union\n * countries.\n\n * Remember that a relay may be hosted in a country which is\n * not the country of the legal entities who own the relay,\n * so it's very likely a number of countries are involved.\n */\nexport interface ContentLimitations {\n relay_countries: string[]\n}\n\n/**\n * ### Community Preferences\n\n * For public text notes at least, a relay may try to foster\n * a local community. This would encourage users to follow\n * the global feed on that relay, in addition to their usual\n * individual follows. To support this goal, relays MAY\n * specify some of the following values.\n\n * @param language_tags is an ordered list of [IETF\n * language\n * tags](https://en.wikipedia.org/wiki/IETF_language_tag\n * indicating the major languages spoken on the relay.\n * @param tags is a list of limitations on the topics to be\n * discussed. For example `sfw-only` indicates that only\n * \"Safe For Work\" content is encouraged on this relay. This\n * relies on assumptions of what the \"work\" \"community\"\n * feels \"safe\" talking about. In time, a common set of tags\n * may emerge that allow users to find relays that suit\n * their needs, and client software will be able to parse\n * these tags easily. The `bitcoin-only` tag indicates that\n * any _altcoin_, _\"crypto\"_ or _blockchain_ comments will\n * be ridiculed without mercy.\n * @param posting_policy is a link to a human-readable page\n * which specifies the community policies for the relay. In\n * cases where `sfw-only` is True, it's important to link to\n * a page which gets into the specifics of your posting\n * policy.\n\n * The `description` field should be used to describe your\n * community goals and values, in brief. The\n * `posting_policy` is for additional detail and legal\n * terms. Use the `tags` field to signify limitations on\n * content, or topics to be discussed, which could be\n * machine processed by appropriate client software.\n */\nexport interface CommunityPreferences {\n language_tags: string[]\n tags: string[]\n posting_policy: string\n}\n\nexport interface Amount {\n amount: number\n unit: 'msat'\n}\nexport interface PublicationAmount extends Amount {\n kinds: number[]\n}\nexport interface Subscription extends Amount {\n period: number\n}\nexport interface Fees {\n admission: Amount[]\n subscription: Subscription[]\n publication: PublicationAmount[]\n}\n/**\n * Relays that require payments may want to expose their fee\n * schedules.\n */\nexport interface PayToRelay {\n payments_url: string\n fees: Fees\n}\n\n/**\n * A URL pointing to an image to be used as an icon for the\n * relay. Recommended to be squared in shape.\n */\nexport interface Icon {\n icon: string\n}\n\nexport type RelayInformation = BasicRelayInformation &\n Partial<Retention> & {\n limitation?: Partial<Limitations>\n } & Partial<ContentLimitations> &\n Partial<CommunityPreferences> &\n Partial<PayToRelay> &\n Partial<Icon>\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { AbstractSimplePool } from './abstract-pool.ts'\nimport { Subscription } from './abstract-relay.ts'\nimport type { Event, EventTemplate } from './core.ts'\nimport { fetchRelayInformation, RelayInformation } from './nip11.ts'\nimport { decode, NostrTypeGuard } from './nip19.ts'\nimport { normalizeURL } from './utils.ts'\n\n/**\n * Represents a NIP29 group.\n */\nexport type Group = {\n relay: string\n metadata: GroupMetadata\n admins?: GroupAdmin[]\n members?: GroupMember[]\n reference: GroupReference\n}\n\n/**\n * Represents the metadata for a NIP29 group.\n */\nexport type GroupMetadata = {\n id: string\n pubkey: string\n name?: string\n picture?: string\n about?: string\n isPublic?: boolean\n isOpen?: boolean\n}\n\n/**\n * Represents a NIP29 group reference.\n */\nexport type GroupReference = {\n id: string\n host: string\n}\n\n/**\n * Represents a NIP29 group member.\n */\nexport type GroupMember = {\n pubkey: string\n label?: string\n}\n\n/**\n * Represents a NIP29 group admin.\n */\nexport type GroupAdmin = {\n pubkey: string\n label?: string\n permissions: GroupAdminPermission[]\n}\n\n/**\n * Represents the permissions that a NIP29 group admin can have.\n */\nexport enum GroupAdminPermission {\n /** @deprecated use PutUser instead */\n AddUser = 'add-user',\n EditMetadata = 'edit-metadata',\n DeleteEvent = 'delete-event',\n RemoveUser = 'remove-user',\n /** @deprecated removed from NIP */\n AddPermission = 'add-permission',\n /** @deprecated removed from NIP */\n RemovePermission = 'remove-permission',\n /** @deprecated removed from NIP */\n EditGroupStatus = 'edit-group-status',\n PutUser = 'put-user',\n CreateGroup = 'create-group',\n DeleteGroup = 'delete-group',\n CreateInvite = 'create-invite',\n}\n\n/**\n * Generates a group metadata event template.\n *\n * @param group - The group object.\n * @returns An event template with the generated group metadata that can be signed later.\n */\nexport function generateGroupMetadataEventTemplate(group: Group): EventTemplate {\n const tags: string[][] = [['d', group.metadata.id]]\n group.metadata.name && tags.push(['name', group.metadata.name])\n group.metadata.picture && tags.push(['picture', group.metadata.picture])\n group.metadata.about && tags.push(['about', group.metadata.about])\n group.metadata.isPublic && tags.push(['public'])\n group.metadata.isOpen && tags.push(['open'])\n\n return {\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n kind: 39000,\n tags,\n }\n}\n\n/**\n * Validates a group metadata event.\n *\n * @param event - The event to validate.\n * @returns A boolean indicating whether the event is valid.\n */\nexport function validateGroupMetadataEvent(event: Event): boolean {\n if (event.kind !== 39000) return false\n\n if (!event.pubkey) return false\n\n const requiredTags = ['d'] as const\n for (const tag of requiredTags) {\n if (!event.tags.find(([t]) => t == tag)) return false\n }\n\n return true\n}\n\n/**\n * Generates an event template for group admins.\n *\n * @param group - The group object.\n * @param admins - An array of group admins.\n * @returns The generated event template with the group admins that can be signed later.\n */\nexport function generateGroupAdminsEventTemplate(group: Group, admins: GroupAdmin[]): EventTemplate {\n const tags: string[][] = [['d', group.metadata.id]]\n for (const admin of admins) {\n tags.push(['p', admin.pubkey, admin.label || '', ...admin.permissions])\n }\n\n return {\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n kind: 39001,\n tags,\n }\n}\n\n/**\n * Validates a group admins event.\n *\n * @param event - The event to validate.\n * @returns True if the event is valid, false otherwise.\n */\nexport function validateGroupAdminsEvent(event: Event): boolean {\n if (event.kind !== 39001) return false\n\n const requiredTags = ['d'] as const\n for (const tag of requiredTags) {\n if (!event.tags.find(([t]) => t == tag)) return false\n }\n\n // validate permissions\n for (const [tag, _value, _label, ...permissions] of event.tags) {\n if (tag !== 'p') continue\n\n for (let i = 0; i < permissions.length; i += 1) {\n if (typeof permissions[i] !== 'string') return false\n\n // validate permission name from the GroupAdminPermission enum\n if (!Object.values(GroupAdminPermission).includes(permissions[i] as GroupAdminPermission)) return false\n }\n }\n\n return true\n}\n\n/**\n * Generates an event template for a group with its members.\n *\n * @param group - The group object.\n * @param members - An array of group members.\n * @returns The generated event template with the group members that can be signed later.\n */\nexport function generateGroupMembersEventTemplate(group: Group, members: GroupMember[]): EventTemplate {\n const tags: string[][] = [['d', group.metadata.id]]\n for (const member of members) {\n tags.push(['p', member.pubkey, member.label || ''])\n }\n\n return {\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n kind: 39002,\n tags,\n }\n}\n\n/**\n * Validates a group members event.\n *\n * @param event - The event to validate.\n * @returns Returns `true` if the event is a valid group members event, `false` otherwise.\n */\nexport function validateGroupMembersEvent(event: Event): boolean {\n if (event.kind !== 39002) return false\n\n const requiredTags = ['d'] as const\n for (const tag of requiredTags) {\n if (!event.tags.find(([t]) => t == tag)) return false\n }\n\n return true\n}\n\n/**\n * Returns the normalized relay URL based on the provided group reference.\n *\n * @param groupReference - The group reference object containing the host.\n * @returns The normalized relay URL.\n */\nexport function getNormalizedRelayURLByGroupReference(groupReference: GroupReference): string {\n return normalizeURL(groupReference.host)\n}\n\n/**\n * Fetches relay information by group reference.\n *\n * @param groupReference The group reference.\n * @returns A promise that resolves to the relay information.\n */\nexport async function fetchRelayInformationByGroupReference(groupReference: GroupReference): Promise<RelayInformation> {\n const normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n\n return fetchRelayInformation(normalizedRelayURL)\n}\n\n/**\n * Fetches the group metadata event from the specified pool.\n * If the normalizedRelayURL is not provided, it will be obtained using the groupReference.\n * If the relayInformation is not provided, it will be fetched using the normalizedRelayURL.\n *\n * @param {Object} options - The options object.\n * @param {AbstractSimplePool} options.pool - The pool to fetch the group metadata event from.\n * @param {GroupReference} options.groupReference - The reference to the group.\n * @param {string} [options.normalizedRelayURL] - The normalized URL of the relay.\n * @param {RelayInformation} [options.relayInformation] - The relay information object.\n * @returns {Promise<Event>} The group metadata event that can be parsed later to get the group metadata object.\n * @throws {Error} If the group is not found on the specified relay.\n */\nexport async function fetchGroupMetadataEvent({\n pool,\n groupReference,\n relayInformation,\n normalizedRelayURL,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Event> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const groupMetadataEvent = await pool.get([normalizedRelayURL], {\n kinds: [39000],\n authors: [relayInformation.pubkey],\n '#d': [groupReference.id],\n })\n\n if (!groupMetadataEvent) throw new Error(`group '${groupReference.id}' not found on ${normalizedRelayURL}`)\n\n return groupMetadataEvent\n}\n\n/**\n * Parses a group metadata event and returns the corresponding GroupMetadata object.\n *\n * @param event - The event to parse.\n * @returns The parsed GroupMetadata object.\n * @throws An error if the group metadata event is invalid.\n */\nexport function parseGroupMetadataEvent(event: Event): GroupMetadata {\n if (!validateGroupMetadataEvent(event)) throw new Error('invalid group metadata event')\n\n const metadata: GroupMetadata = {\n id: '',\n pubkey: event.pubkey,\n }\n\n for (const [tag, value] of event.tags) {\n switch (tag) {\n case 'd':\n metadata.id = value\n break\n case 'name':\n metadata.name = value\n break\n case 'picture':\n metadata.picture = value\n break\n case 'about':\n metadata.about = value\n break\n case 'public':\n metadata.isPublic = true\n break\n case 'open':\n metadata.isOpen = true\n break\n }\n }\n\n return metadata\n}\n\n/**\n * Fetches the group admins event from the specified pool.\n * If the normalizedRelayURL is not provided, it will be obtained from the groupReference.\n * If the relayInformation is not provided, it will be fetched using the normalizedRelayURL.\n *\n * @param {Object} options - The options object.\n * @param {AbstractSimplePool} options.pool - The pool to fetch the group admins event from.\n * @param {GroupReference} options.groupReference - The reference to the group.\n * @param {string} [options.normalizedRelayURL] - The normalized relay URL.\n * @param {RelayInformation} [options.relayInformation] - The relay information.\n * @returns {Promise<Event>} The group admins event that can be parsed later to get the group admins object.\n * @throws {Error} If the group admins event is not found on the specified relay.\n */\nexport async function fetchGroupAdminsEvent({\n pool,\n groupReference,\n relayInformation,\n normalizedRelayURL,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Event> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const groupAdminsEvent = await pool.get([normalizedRelayURL], {\n kinds: [39001],\n authors: [relayInformation.pubkey],\n '#d': [groupReference.id],\n })\n\n if (!groupAdminsEvent) throw new Error(`admins for group '${groupReference.id}' not found on ${normalizedRelayURL}`)\n\n return groupAdminsEvent\n}\n\n/**\n * Parses a group admins event and returns an array of GroupAdmin objects.\n *\n * @param event - The event to parse.\n * @returns An array of GroupAdmin objects.\n * @throws Throws an error if the group admins event is invalid.\n */\nexport function parseGroupAdminsEvent(event: Event): GroupAdmin[] {\n if (!validateGroupAdminsEvent(event)) throw new Error('invalid group admins event')\n\n const admins: GroupAdmin[] = []\n\n for (const [tag, value, label, ...permissions] of event.tags) {\n if (tag !== 'p') continue\n\n admins.push({\n pubkey: value,\n label,\n permissions: permissions as GroupAdminPermission[],\n })\n }\n\n return admins\n}\n\n/**\n * Fetches the group members event from the specified relay.\n * If the normalizedRelayURL is not provided, it will be obtained using the groupReference.\n * If the relayInformation is not provided, it will be fetched using the normalizedRelayURL.\n *\n * @param {Object} options - The options object.\n * @param {AbstractSimplePool} options.pool - The pool object.\n * @param {GroupReference} options.groupReference - The group reference object.\n * @param {string} [options.normalizedRelayURL] - The normalized relay URL.\n * @param {RelayInformation} [options.relayInformation] - The relay information object.\n * @returns {Promise<Event>} The group members event that can be parsed later to get the group members object.\n * @throws {Error} If the group members event is not found.\n */\nexport async function fetchGroupMembersEvent({\n pool,\n groupReference,\n relayInformation,\n normalizedRelayURL,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Event> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const groupMembersEvent = await pool.get([normalizedRelayURL], {\n kinds: [39002],\n authors: [relayInformation.pubkey],\n '#d': [groupReference.id],\n })\n\n if (!groupMembersEvent) throw new Error(`members for group '${groupReference.id}' not found on ${normalizedRelayURL}`)\n\n return groupMembersEvent\n}\n\n/**\n * Parses a group members event and returns an array of GroupMember objects.\n * @param event - The event to parse.\n * @returns An array of GroupMember objects.\n * @throws Throws an error if the group members event is invalid.\n */\nexport function parseGroupMembersEvent(event: Event): GroupMember[] {\n if (!validateGroupMembersEvent(event)) throw new Error('invalid group members event')\n\n const members: GroupMember[] = []\n\n for (const [tag, value, label] of event.tags) {\n if (tag !== 'p') continue\n\n members.push({\n pubkey: value,\n label,\n })\n }\n\n return members\n}\n\n/**\n * Fetches and parses the group metadata event, group admins event, and group members event from the specified pool.\n * If the normalized relay URL is not provided, it will be obtained using the group reference.\n * If the relay information is not provided, it will be fetched using the normalized relay URL.\n *\n * @param {Object} options - The options for loading the group.\n * @param {AbstractSimplePool} options.pool - The pool to load the group from.\n * @param {GroupReference} options.groupReference - The reference of the group to load.\n * @param {string} [options.normalizedRelayURL] - The normalized URL of the relay to use.\n * @param {RelayInformation} [options.relayInformation] - The relay information to use.\n * @returns {Promise<Group>} A promise that resolves to the loaded group.\n */\nexport async function loadGroup({\n pool,\n groupReference,\n normalizedRelayURL,\n relayInformation,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Group> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const metadataEvent = await fetchGroupMetadataEvent({ pool, groupReference, normalizedRelayURL, relayInformation })\n const metadata = parseGroupMetadataEvent(metadataEvent)\n\n const adminsEvent = await fetchGroupAdminsEvent({ pool, groupReference, normalizedRelayURL, relayInformation })\n const admins = parseGroupAdminsEvent(adminsEvent)\n\n const membersEvent = await fetchGroupMembersEvent({ pool, groupReference, normalizedRelayURL, relayInformation })\n const members = parseGroupMembersEvent(membersEvent)\n\n const group: Group = {\n relay: normalizedRelayURL,\n metadata,\n admins,\n members,\n reference: groupReference,\n }\n\n return group\n}\n\n/**\n * Loads a group from the specified pool using the provided group code.\n *\n * @param {AbstractSimplePool} pool - The pool to load the group from.\n * @param {string} code - The code representing the group.\n * @returns {Promise<Group>} - A promise that resolves to the loaded group.\n * @throws {Error} - If the group code is invalid.\n */\nexport async function loadGroupFromCode(pool: AbstractSimplePool, code: string): Promise<Group> {\n const groupReference = parseGroupCode(code)\n\n if (!groupReference) throw new Error('invalid group code')\n\n return loadGroup({ pool, groupReference })\n}\n\n/**\n * Parses a group code and returns a GroupReference object.\n *\n * @param code The group code to parse.\n * @returns A GroupReference object if the code is valid, otherwise null.\n */\nexport function parseGroupCode(code: string): null | GroupReference {\n if (NostrTypeGuard.isNAddr(code)) {\n try {\n let { data } = decode(code)\n\n let { relays, identifier } = data\n if (!relays || relays.length === 0) return null\n\n let host = relays![0]\n if (host.startsWith('wss://')) {\n host = host.slice(6)\n }\n return { host, id: identifier }\n } catch (err) {\n return null\n }\n } else if (code.split(\"'\").length === 2) {\n let spl = code.split(\"'\")\n return { host: spl[0], id: spl[1] }\n }\n\n return null\n}\n\n/**\n * Encodes a group reference into a string.\n *\n * @param gr - The group reference to encode.\n * @returns The encoded group reference as a string.\n */\nexport function encodeGroupReference(gr: GroupReference): string {\n const { host, id } = gr\n const normalizedHost = host.replace(/^(https?:\\/\\/|wss?:\\/\\/)/, '')\n\n return `${normalizedHost}'${id}`\n}\n\n/**\n * Subscribes to relay groups metadata events and calls the provided event handler function\n * when an event is received.\n *\n * @param {Object} options - The options for subscribing to relay groups metadata events.\n * @param {AbstractSimplePool} options.pool - The pool to subscribe to.\n * @param {string} options.relayURL - The URL of the relay.\n * @param {Function} options.onError - The error handler function.\n * @param {Function} options.onEvent - The event handler function.\n * @param {Function} [options.onConnect] - The connect handler function.\n * @returns {Function} - A function to close the subscription\n */\nexport function subscribeRelayGroupsMetadataEvents({\n pool,\n relayURL,\n onError,\n onEvent,\n onConnect,\n}: {\n pool: AbstractSimplePool\n relayURL: string\n onError: (err: Error) => void\n onEvent: (event: Event) => void\n onConnect?: () => void\n}): () => void {\n let sub: Subscription\n\n const normalizedRelayURL = normalizeURL(relayURL)\n\n fetchRelayInformation(normalizedRelayURL)\n .then(async info => {\n const abstractedRelay = await pool.ensureRelay(normalizedRelayURL)\n\n onConnect?.()\n\n sub = abstractedRelay.prepareSubscription(\n [\n {\n kinds: [39000],\n limit: 50,\n authors: [info.pubkey],\n },\n ],\n {\n onevent(event: Event) {\n onEvent(event)\n },\n },\n )\n })\n .catch(err => {\n sub.close()\n\n onError(err)\n })\n\n return () => sub.close()\n}\n", "var _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any): void {\n _fetch = fetchImplementation\n}\n\nexport async function fetchRelayInformation(url: string): Promise<RelayInformation> {\n return (await (\n await fetch(url.replace('ws://', 'http://').replace('wss://', 'https://'), {\n headers: { Accept: 'application/nostr+json' },\n })\n ).json()) as RelayInformation\n}\n\n/**\n * ## Relay Information Document\n\n * Relays may provide server metadata to clients to inform\n * them of capabilities, administrative contacts, and\n * various server attributes. This is made available as a\n * JSON document over HTTP, on the same URI as the relay's\n * websocket.\n\n * Any field may be omitted, and clients MUST ignore any\n * additional fields they do not understand. Relays MUST\n * accept CORS requests by sending\n * `Access-Control-Allow-Origin`,\n * `Access-Control-Allow-Headers`, and\n * `Access-Control-Allow-Methods` headers.\n * @param name string identifying relay\n * @param description string with detailed information\n * @param pubkey administrative contact pubkey\n * @param contact: administrative alternate contact\n * @param supported_nips a list of NIP numbers supported by\n * the relay\n * @param software identifying relay software URL\n * @param version string version identifier\n */\nexport interface BasicRelayInformation {\n // string identifying relay\n name: string\n description: string\n pubkey: string\n contact: string\n supported_nips: number[]\n software: string\n version: string\n // limitation?: Limitations<A, P>\n}\n\n/**\n * * ## Extra Fields\n\n * * ### Server Limitations\n\n * These are limitations imposed by the relay on clients.\n * Your client should expect that requests which exceed\n * these practical_ limitations are rejected or fail immediately.\n * @param max_message_length this is the maximum number of\n * bytes for incoming JSON that the relay will attempt to\n * decode and act upon. When you send large subscriptions,\n * you will be limited by this value. It also effectively\n * limits the maximum size of any event. Value is calculated\n * from `[` to `]` and is after UTF-8 serialization (so some\n * unicode characters will cost 2-3 bytes). It is equal to\n * the maximum size of the WebSocket message frame.\n * @param max_subscriptions total number of subscriptions\n * that may be active on a single websocket connection to\n * this relay. It's possible that authenticated clients with\n * a (paid) relationship to the relay may have higher limits.\n * @param max_filters maximum number of filter values in\n * each subscription. Must be one or higher.\n * @param max_limit the relay server will clamp each\n * filter's `limit` value to this number.\n * This means the client won't be able to get more than this\n * number of events from a single subscription filter. This\n * clamping is typically done silently by the relay, but\n * with this number, you can know that there are additional\n * results if you narrowed your filter's time range or other\n * parameters.\n * @param max_subid_length maximum length of subscription id as a\n * string.\n * @param min_prefix for `authors` and `ids` filters which\n * are to match against a hex prefix, you must provide at\n * least this many hex digits in the prefix.\n * @param max_event_tags in any event, this is the maximum\n * number of elements in the `tags` list.\n * @param max_content_length maximum number of characters in\n * the `content` field of any event. This is a count of\n * unicode characters. After serializing into JSON it may be\n * larger (in bytes), and is still subject to the\n * max_message_length`, if defined.\n * @param min_pow_difficulty new events will require at\n * least this difficulty of PoW, based on [NIP-13](13.md),\n * or they will be rejected by this server.\n * @param auth_required this relay requires [NIP-42](42.md)\n * authentication to happen before a new connection may\n * perform any other action. Even if set to False,\n * authentication may be required for specific actions.\n * @param restricted_writes: this relay requires some kind\n * of condition to be fulfilled in order to accept events\n * (not necessarily, but including\n * @param payment_required this relay requires payment\n * before a new connection may perform any action.\n * @param created_at_lower_limit: 'created_at' lower limit\n * @param created_at_upper_limit: 'created_at' upper limit\n */\nexport interface Limitations {\n max_message_length: number\n max_subscriptions: number\n max_filters: number\n max_limit: number\n max_subid_length: number\n min_prefix: number\n max_event_tags: number\n max_content_length: number\n min_pow_difficulty: number\n auth_required: boolean\n payment_required: boolean\n created_at_lower_limit: number\n created_at_upper_limit: number\n restricted_writes: boolean\n}\n\nexport interface RetentionDetails {\n kinds: (number | number[])[]\n time?: number | null\n count?: number | null\n}\ntype AnyRetentionDetails = RetentionDetails\n/**\n * ### Event Retention\n\n * There may be a cost associated with storing data forever,\n * so relays may wish to state retention times. The values\n * stated here are defaults for unauthenticated users and\n * visitors. Paid users would likely have other policies.\n\n * Retention times are given in seconds, with `null`\n * indicating infinity. If zero is provided, this means the\n * event will not be stored at all, and preferably an error\n * will be provided when those are received.\n * ```json\n{\n...\n \"retention\": [\n { \"kinds\": [0, 1, [5, 7], [40, 49]], \"time\": 3600 },\n { \"kinds\": [[40000, 49999]], \"time\": 100 },\n { \"kinds\": [[30000, 39999]], \"count\": 1000 },\n { \"time\": 3600, \"count\": 10000 }\n ]\n...\n}\n```\n * @param retention is a list of specifications: each will\n * apply to either all kinds, or a subset of kinds. Ranges\n * may be specified for the kind field as a tuple of\n * inclusive start and end values. Events of indicated kind\n * (or all) are then limited to a `count` and/or time\n * period.\n\n * It is possible to effectively blacklist Nostr-based\n * protocols that rely on a specific `kind` number, by\n * giving a retention time of zero for those `kind` values.\n * While that is unfortunate, it does allow clients to\n * discover servers that will support their protocol quickly\n * via a single HTTP fetch.\n\n * There is no need to specify retention times for\n * _ephemeral events_ as defined in [NIP-16](16.md) since\n * they are not retained.\n */\nexport interface Retention {\n retention: AnyRetentionDetails[]\n}\n\n/**\n * Some relays may be governed by the arbitrary laws of a\n * nation state. This may limit what content can be stored\n * in cleartext on those relays. All clients are encouraged\n * to use encryption to work around this limitation.\n\n * It is not possible to describe the limitations of each\n * country's laws and policies which themselves are\n * typically vague and constantly shifting.\n\n * Therefore, this field allows the relay operator to\n * indicate which countries' laws might end up being\n * enforced on them, and then indirectly on their users'\n * content.\n\n * Users should be able to avoid relays in countries they\n * don't like, and/or select relays in more favourable\n * zones. Exposing this flexibility is up to the client\n * software.\n\n * @param relay_countries a list of two-level ISO country\n * codes (ISO 3166-1 alpha-2) whose laws and policies may\n * affect this relay. `EU` may be used for European Union\n * countries.\n\n * Remember that a relay may be hosted in a country which is\n * not the country of the legal entities who own the relay,\n * so it's very likely a number of countries are involved.\n */\nexport interface ContentLimitations {\n relay_countries: string[]\n}\n\n/**\n * ### Community Preferences\n\n * For public text notes at least, a relay may try to foster\n * a local community. This would encourage users to follow\n * the global feed on that relay, in addition to their usual\n * individual follows. To support this goal, relays MAY\n * specify some of the following values.\n\n * @param language_tags is an ordered list of [IETF\n * language\n * tags](https://en.wikipedia.org/wiki/IETF_language_tag\n * indicating the major languages spoken on the relay.\n * @param tags is a list of limitations on the topics to be\n * discussed. For example `sfw-only` indicates that only\n * \"Safe For Work\" content is encouraged on this relay. This\n * relies on assumptions of what the \"work\" \"community\"\n * feels \"safe\" talking about. In time, a common set of tags\n * may emerge that allow users to find relays that suit\n * their needs, and client software will be able to parse\n * these tags easily. The `bitcoin-only` tag indicates that\n * any _altcoin_, _\"crypto\"_ or _blockchain_ comments will\n * be ridiculed without mercy.\n * @param posting_policy is a link to a human-readable page\n * which specifies the community policies for the relay. In\n * cases where `sfw-only` is True, it's important to link to\n * a page which gets into the specifics of your posting\n * policy.\n\n * The `description` field should be used to describe your\n * community goals and values, in brief. The\n * `posting_policy` is for additional detail and legal\n * terms. Use the `tags` field to signify limitations on\n * content, or topics to be discussed, which could be\n * machine processed by appropriate client software.\n */\nexport interface CommunityPreferences {\n language_tags: string[]\n tags: string[]\n posting_policy: string\n}\n\nexport interface Amount {\n amount: number\n unit: 'msat'\n}\nexport interface PublicationAmount extends Amount {\n kinds: number[]\n}\nexport interface Subscription extends Amount {\n period: number\n}\nexport interface Fees {\n admission: Amount[]\n subscription: Subscription[]\n publication: PublicationAmount[]\n}\n/**\n * Relays that require payments may want to expose their fee\n * schedules.\n */\nexport interface PayToRelay {\n payments_url: string\n fees: Fees\n}\n\n/**\n * A URL pointing to an image to be used as an icon for the\n * relay. Recommended to be squared in shape.\n */\nexport interface Icon {\n icon: string\n}\n\nexport type RelayInformation = BasicRelayInformation &\n Partial<Retention> & {\n limitation?: Partial<Limitations>\n } & Partial<ContentLimitations> &\n Partial<CommunityPreferences> &\n Partial<PayToRelay> &\n Partial<Icon>\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": "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",
"names": ["import_utils", "GroupAdminPermission"]
} Index: package/lib/esm/nip29.js.map
===================================================================
--- package/lib/esm/nip29.js.map
+++ package/lib/esm/nip29.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip11.ts", "../../nip19.ts", "../../utils.ts", "../../nip29.ts"],
- "sourcesContent": ["var _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any): void {\n _fetch = fetchImplementation\n}\n\nexport async function fetchRelayInformation(url: string): Promise<RelayInformation> {\n return (await (\n await fetch(url.replace('ws://', 'http://').replace('wss://', 'https://'), {\n headers: { Accept: 'application/nostr+json' },\n })\n ).json()) as RelayInformation\n}\n\n/**\n * ## Relay Information Document\n\n * Relays may provide server metadata to clients to inform\n * them of capabilities, administrative contacts, and\n * various server attributes. This is made available as a\n * JSON document over HTTP, on the same URI as the relay's\n * websocket.\n\n * Any field may be omitted, and clients MUST ignore any\n * additional fields they do not understand. Relays MUST\n * accept CORS requests by sending\n * `Access-Control-Allow-Origin`,\n * `Access-Control-Allow-Headers`, and\n * `Access-Control-Allow-Methods` headers.\n * @param name string identifying relay\n * @param description string with detailed information\n * @param pubkey administrative contact pubkey\n * @param contact: administrative alternate contact\n * @param supported_nips a list of NIP numbers supported by\n * the relay\n * @param software identifying relay software URL\n * @param version string version identifier\n */\nexport interface BasicRelayInformation {\n // string identifying relay\n name: string\n description: string\n pubkey: string\n contact: string\n supported_nips: number[]\n software: string\n version: string\n // limitation?: Limitations<A, P>\n}\n\n/**\n * * ## Extra Fields\n\n * * ### Server Limitations\n\n * These are limitations imposed by the relay on clients.\n * Your client should expect that requests which exceed\n * these practical_ limitations are rejected or fail immediately.\n * @param max_message_length this is the maximum number of\n * bytes for incoming JSON that the relay will attempt to\n * decode and act upon. When you send large subscriptions,\n * you will be limited by this value. It also effectively\n * limits the maximum size of any event. Value is calculated\n * from `[` to `]` and is after UTF-8 serialization (so some\n * unicode characters will cost 2-3 bytes). It is equal to\n * the maximum size of the WebSocket message frame.\n * @param max_subscriptions total number of subscriptions\n * that may be active on a single websocket connection to\n * this relay. It's possible that authenticated clients with\n * a (paid) relationship to the relay may have higher limits.\n * @param max_filters maximum number of filter values in\n * each subscription. Must be one or higher.\n * @param max_limit the relay server will clamp each\n * filter's `limit` value to this number.\n * This means the client won't be able to get more than this\n * number of events from a single subscription filter. This\n * clamping is typically done silently by the relay, but\n * with this number, you can know that there are additional\n * results if you narrowed your filter's time range or other\n * parameters.\n * @param max_subid_length maximum length of subscription id as a\n * string.\n * @param min_prefix for `authors` and `ids` filters which\n * are to match against a hex prefix, you must provide at\n * least this many hex digits in the prefix.\n * @param max_event_tags in any event, this is the maximum\n * number of elements in the `tags` list.\n * @param max_content_length maximum number of characters in\n * the `content` field of any event. This is a count of\n * unicode characters. After serializing into JSON it may be\n * larger (in bytes), and is still subject to the\n * max_message_length`, if defined.\n * @param min_pow_difficulty new events will require at\n * least this difficulty of PoW, based on [NIP-13](13.md),\n * or they will be rejected by this server.\n * @param auth_required this relay requires [NIP-42](42.md)\n * authentication to happen before a new connection may\n * perform any other action. Even if set to False,\n * authentication may be required for specific actions.\n * @param restricted_writes: this relay requires some kind\n * of condition to be fulfilled in order to accept events\n * (not necessarily, but including\n * @param payment_required this relay requires payment\n * before a new connection may perform any action.\n * @param created_at_lower_limit: 'created_at' lower limit\n * @param created_at_upper_limit: 'created_at' upper limit\n */\nexport interface Limitations {\n max_message_length: number\n max_subscriptions: number\n max_filters: number\n max_limit: number\n max_subid_length: number\n min_prefix: number\n max_event_tags: number\n max_content_length: number\n min_pow_difficulty: number\n auth_required: boolean\n payment_required: boolean\n created_at_lower_limit: number\n created_at_upper_limit: number\n restricted_writes: boolean\n}\n\nexport interface RetentionDetails {\n kinds: (number | number[])[]\n time?: number | null\n count?: number | null\n}\ntype AnyRetentionDetails = RetentionDetails\n/**\n * ### Event Retention\n\n * There may be a cost associated with storing data forever,\n * so relays may wish to state retention times. The values\n * stated here are defaults for unauthenticated users and\n * visitors. Paid users would likely have other policies.\n\n * Retention times are given in seconds, with `null`\n * indicating infinity. If zero is provided, this means the\n * event will not be stored at all, and preferably an error\n * will be provided when those are received.\n * ```json\n{\n...\n \"retention\": [\n { \"kinds\": [0, 1, [5, 7], [40, 49]], \"time\": 3600 },\n { \"kinds\": [[40000, 49999]], \"time\": 100 },\n { \"kinds\": [[30000, 39999]], \"count\": 1000 },\n { \"time\": 3600, \"count\": 10000 }\n ]\n...\n}\n```\n * @param retention is a list of specifications: each will\n * apply to either all kinds, or a subset of kinds. Ranges\n * may be specified for the kind field as a tuple of\n * inclusive start and end values. Events of indicated kind\n * (or all) are then limited to a `count` and/or time\n * period.\n\n * It is possible to effectively blacklist Nostr-based\n * protocols that rely on a specific `kind` number, by\n * giving a retention time of zero for those `kind` values.\n * While that is unfortunate, it does allow clients to\n * discover servers that will support their protocol quickly\n * via a single HTTP fetch.\n\n * There is no need to specify retention times for\n * _ephemeral events_ as defined in [NIP-16](16.md) since\n * they are not retained.\n */\nexport interface Retention {\n retention: AnyRetentionDetails[]\n}\n\n/**\n * Some relays may be governed by the arbitrary laws of a\n * nation state. This may limit what content can be stored\n * in cleartext on those relays. All clients are encouraged\n * to use encryption to work around this limitation.\n\n * It is not possible to describe the limitations of each\n * country's laws and policies which themselves are\n * typically vague and constantly shifting.\n\n * Therefore, this field allows the relay operator to\n * indicate which countries' laws might end up being\n * enforced on them, and then indirectly on their users'\n * content.\n\n * Users should be able to avoid relays in countries they\n * don't like, and/or select relays in more favourable\n * zones. Exposing this flexibility is up to the client\n * software.\n\n * @param relay_countries a list of two-level ISO country\n * codes (ISO 3166-1 alpha-2) whose laws and policies may\n * affect this relay. `EU` may be used for European Union\n * countries.\n\n * Remember that a relay may be hosted in a country which is\n * not the country of the legal entities who own the relay,\n * so it's very likely a number of countries are involved.\n */\nexport interface ContentLimitations {\n relay_countries: string[]\n}\n\n/**\n * ### Community Preferences\n\n * For public text notes at least, a relay may try to foster\n * a local community. This would encourage users to follow\n * the global feed on that relay, in addition to their usual\n * individual follows. To support this goal, relays MAY\n * specify some of the following values.\n\n * @param language_tags is an ordered list of [IETF\n * language\n * tags](https://en.wikipedia.org/wiki/IETF_language_tag\n * indicating the major languages spoken on the relay.\n * @param tags is a list of limitations on the topics to be\n * discussed. For example `sfw-only` indicates that only\n * \"Safe For Work\" content is encouraged on this relay. This\n * relies on assumptions of what the \"work\" \"community\"\n * feels \"safe\" talking about. In time, a common set of tags\n * may emerge that allow users to find relays that suit\n * their needs, and client software will be able to parse\n * these tags easily. The `bitcoin-only` tag indicates that\n * any _altcoin_, _\"crypto\"_ or _blockchain_ comments will\n * be ridiculed without mercy.\n * @param posting_policy is a link to a human-readable page\n * which specifies the community policies for the relay. In\n * cases where `sfw-only` is True, it's important to link to\n * a page which gets into the specifics of your posting\n * policy.\n\n * The `description` field should be used to describe your\n * community goals and values, in brief. The\n * `posting_policy` is for additional detail and legal\n * terms. Use the `tags` field to signify limitations on\n * content, or topics to be discussed, which could be\n * machine processed by appropriate client software.\n */\nexport interface CommunityPreferences {\n language_tags: string[]\n tags: string[]\n posting_policy: string\n}\n\nexport interface Amount {\n amount: number\n unit: 'msat'\n}\nexport interface PublicationAmount extends Amount {\n kinds: number[]\n}\nexport interface Subscription extends Amount {\n period: number\n}\nexport interface Fees {\n admission: Amount[]\n subscription: Subscription[]\n publication: PublicationAmount[]\n}\n/**\n * Relays that require payments may want to expose their fee\n * schedules.\n */\nexport interface PayToRelay {\n payments_url: string\n fees: Fees\n}\n\n/**\n * A URL pointing to an image to be used as an icon for the\n * relay. Recommended to be squared in shape.\n */\nexport interface Icon {\n icon: string\n}\n\nexport type RelayInformation = BasicRelayInformation &\n Partial<Retention> & {\n limitation?: Partial<Limitations>\n } & Partial<ContentLimitations> &\n Partial<CommunityPreferences> &\n Partial<PayToRelay> &\n Partial<Icon>\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { AbstractSimplePool } from './abstract-pool.ts'\nimport { Subscription } from './abstract-relay.ts'\nimport type { Event, EventTemplate } from './core.ts'\nimport { fetchRelayInformation, RelayInformation } from './nip11.ts'\nimport { decode, NostrTypeGuard } from './nip19.ts'\nimport { normalizeURL } from './utils.ts'\n\n/**\n * Represents a NIP29 group.\n */\nexport type Group = {\n relay: string\n metadata: GroupMetadata\n admins?: GroupAdmin[]\n members?: GroupMember[]\n reference: GroupReference\n}\n\n/**\n * Represents the metadata for a NIP29 group.\n */\nexport type GroupMetadata = {\n id: string\n pubkey: string\n name?: string\n picture?: string\n about?: string\n isPublic?: boolean\n isOpen?: boolean\n}\n\n/**\n * Represents a NIP29 group reference.\n */\nexport type GroupReference = {\n id: string\n host: string\n}\n\n/**\n * Represents a NIP29 group member.\n */\nexport type GroupMember = {\n pubkey: string\n label?: string\n}\n\n/**\n * Represents a NIP29 group admin.\n */\nexport type GroupAdmin = {\n pubkey: string\n label?: string\n permissions: GroupAdminPermission[]\n}\n\n/**\n * Represents the permissions that a NIP29 group admin can have.\n */\nexport enum GroupAdminPermission {\n /** @deprecated use PutUser instead */\n AddUser = 'add-user',\n EditMetadata = 'edit-metadata',\n DeleteEvent = 'delete-event',\n RemoveUser = 'remove-user',\n /** @deprecated removed from NIP */\n AddPermission = 'add-permission',\n /** @deprecated removed from NIP */\n RemovePermission = 'remove-permission',\n /** @deprecated removed from NIP */\n EditGroupStatus = 'edit-group-status',\n PutUser = 'put-user',\n CreateGroup = 'create-group',\n DeleteGroup = 'delete-group',\n CreateInvite = 'create-invite',\n}\n\n/**\n * Generates a group metadata event template.\n *\n * @param group - The group object.\n * @returns An event template with the generated group metadata that can be signed later.\n */\nexport function generateGroupMetadataEventTemplate(group: Group): EventTemplate {\n const tags: string[][] = [['d', group.metadata.id]]\n group.metadata.name && tags.push(['name', group.metadata.name])\n group.metadata.picture && tags.push(['picture', group.metadata.picture])\n group.metadata.about && tags.push(['about', group.metadata.about])\n group.metadata.isPublic && tags.push(['public'])\n group.metadata.isOpen && tags.push(['open'])\n\n return {\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n kind: 39000,\n tags,\n }\n}\n\n/**\n * Validates a group metadata event.\n *\n * @param event - The event to validate.\n * @returns A boolean indicating whether the event is valid.\n */\nexport function validateGroupMetadataEvent(event: Event): boolean {\n if (event.kind !== 39000) return false\n\n if (!event.pubkey) return false\n\n const requiredTags = ['d'] as const\n for (const tag of requiredTags) {\n if (!event.tags.find(([t]) => t == tag)) return false\n }\n\n return true\n}\n\n/**\n * Generates an event template for group admins.\n *\n * @param group - The group object.\n * @param admins - An array of group admins.\n * @returns The generated event template with the group admins that can be signed later.\n */\nexport function generateGroupAdminsEventTemplate(group: Group, admins: GroupAdmin[]): EventTemplate {\n const tags: string[][] = [['d', group.metadata.id]]\n for (const admin of admins) {\n tags.push(['p', admin.pubkey, admin.label || '', ...admin.permissions])\n }\n\n return {\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n kind: 39001,\n tags,\n }\n}\n\n/**\n * Validates a group admins event.\n *\n * @param event - The event to validate.\n * @returns True if the event is valid, false otherwise.\n */\nexport function validateGroupAdminsEvent(event: Event): boolean {\n if (event.kind !== 39001) return false\n\n const requiredTags = ['d'] as const\n for (const tag of requiredTags) {\n if (!event.tags.find(([t]) => t == tag)) return false\n }\n\n // validate permissions\n for (const [tag, _value, _label, ...permissions] of event.tags) {\n if (tag !== 'p') continue\n\n for (let i = 0; i < permissions.length; i += 1) {\n if (typeof permissions[i] !== 'string') return false\n\n // validate permission name from the GroupAdminPermission enum\n if (!Object.values(GroupAdminPermission).includes(permissions[i] as GroupAdminPermission)) return false\n }\n }\n\n return true\n}\n\n/**\n * Generates an event template for a group with its members.\n *\n * @param group - The group object.\n * @param members - An array of group members.\n * @returns The generated event template with the group members that can be signed later.\n */\nexport function generateGroupMembersEventTemplate(group: Group, members: GroupMember[]): EventTemplate {\n const tags: string[][] = [['d', group.metadata.id]]\n for (const member of members) {\n tags.push(['p', member.pubkey, member.label || ''])\n }\n\n return {\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n kind: 39002,\n tags,\n }\n}\n\n/**\n * Validates a group members event.\n *\n * @param event - The event to validate.\n * @returns Returns `true` if the event is a valid group members event, `false` otherwise.\n */\nexport function validateGroupMembersEvent(event: Event): boolean {\n if (event.kind !== 39002) return false\n\n const requiredTags = ['d'] as const\n for (const tag of requiredTags) {\n if (!event.tags.find(([t]) => t == tag)) return false\n }\n\n return true\n}\n\n/**\n * Returns the normalized relay URL based on the provided group reference.\n *\n * @param groupReference - The group reference object containing the host.\n * @returns The normalized relay URL.\n */\nexport function getNormalizedRelayURLByGroupReference(groupReference: GroupReference): string {\n return normalizeURL(groupReference.host)\n}\n\n/**\n * Fetches relay information by group reference.\n *\n * @param groupReference The group reference.\n * @returns A promise that resolves to the relay information.\n */\nexport async function fetchRelayInformationByGroupReference(groupReference: GroupReference): Promise<RelayInformation> {\n const normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n\n return fetchRelayInformation(normalizedRelayURL)\n}\n\n/**\n * Fetches the group metadata event from the specified pool.\n * If the normalizedRelayURL is not provided, it will be obtained using the groupReference.\n * If the relayInformation is not provided, it will be fetched using the normalizedRelayURL.\n *\n * @param {Object} options - The options object.\n * @param {AbstractSimplePool} options.pool - The pool to fetch the group metadata event from.\n * @param {GroupReference} options.groupReference - The reference to the group.\n * @param {string} [options.normalizedRelayURL] - The normalized URL of the relay.\n * @param {RelayInformation} [options.relayInformation] - The relay information object.\n * @returns {Promise<Event>} The group metadata event that can be parsed later to get the group metadata object.\n * @throws {Error} If the group is not found on the specified relay.\n */\nexport async function fetchGroupMetadataEvent({\n pool,\n groupReference,\n relayInformation,\n normalizedRelayURL,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Event> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const groupMetadataEvent = await pool.get([normalizedRelayURL], {\n kinds: [39000],\n authors: [relayInformation.pubkey],\n '#d': [groupReference.id],\n })\n\n if (!groupMetadataEvent) throw new Error(`group '${groupReference.id}' not found on ${normalizedRelayURL}`)\n\n return groupMetadataEvent\n}\n\n/**\n * Parses a group metadata event and returns the corresponding GroupMetadata object.\n *\n * @param event - The event to parse.\n * @returns The parsed GroupMetadata object.\n * @throws An error if the group metadata event is invalid.\n */\nexport function parseGroupMetadataEvent(event: Event): GroupMetadata {\n if (!validateGroupMetadataEvent(event)) throw new Error('invalid group metadata event')\n\n const metadata: GroupMetadata = {\n id: '',\n pubkey: event.pubkey,\n }\n\n for (const [tag, value] of event.tags) {\n switch (tag) {\n case 'd':\n metadata.id = value\n break\n case 'name':\n metadata.name = value\n break\n case 'picture':\n metadata.picture = value\n break\n case 'about':\n metadata.about = value\n break\n case 'public':\n metadata.isPublic = true\n break\n case 'open':\n metadata.isOpen = true\n break\n }\n }\n\n return metadata\n}\n\n/**\n * Fetches the group admins event from the specified pool.\n * If the normalizedRelayURL is not provided, it will be obtained from the groupReference.\n * If the relayInformation is not provided, it will be fetched using the normalizedRelayURL.\n *\n * @param {Object} options - The options object.\n * @param {AbstractSimplePool} options.pool - The pool to fetch the group admins event from.\n * @param {GroupReference} options.groupReference - The reference to the group.\n * @param {string} [options.normalizedRelayURL] - The normalized relay URL.\n * @param {RelayInformation} [options.relayInformation] - The relay information.\n * @returns {Promise<Event>} The group admins event that can be parsed later to get the group admins object.\n * @throws {Error} If the group admins event is not found on the specified relay.\n */\nexport async function fetchGroupAdminsEvent({\n pool,\n groupReference,\n relayInformation,\n normalizedRelayURL,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Event> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const groupAdminsEvent = await pool.get([normalizedRelayURL], {\n kinds: [39001],\n authors: [relayInformation.pubkey],\n '#d': [groupReference.id],\n })\n\n if (!groupAdminsEvent) throw new Error(`admins for group '${groupReference.id}' not found on ${normalizedRelayURL}`)\n\n return groupAdminsEvent\n}\n\n/**\n * Parses a group admins event and returns an array of GroupAdmin objects.\n *\n * @param event - The event to parse.\n * @returns An array of GroupAdmin objects.\n * @throws Throws an error if the group admins event is invalid.\n */\nexport function parseGroupAdminsEvent(event: Event): GroupAdmin[] {\n if (!validateGroupAdminsEvent(event)) throw new Error('invalid group admins event')\n\n const admins: GroupAdmin[] = []\n\n for (const [tag, value, label, ...permissions] of event.tags) {\n if (tag !== 'p') continue\n\n admins.push({\n pubkey: value,\n label,\n permissions: permissions as GroupAdminPermission[],\n })\n }\n\n return admins\n}\n\n/**\n * Fetches the group members event from the specified relay.\n * If the normalizedRelayURL is not provided, it will be obtained using the groupReference.\n * If the relayInformation is not provided, it will be fetched using the normalizedRelayURL.\n *\n * @param {Object} options - The options object.\n * @param {AbstractSimplePool} options.pool - The pool object.\n * @param {GroupReference} options.groupReference - The group reference object.\n * @param {string} [options.normalizedRelayURL] - The normalized relay URL.\n * @param {RelayInformation} [options.relayInformation] - The relay information object.\n * @returns {Promise<Event>} The group members event that can be parsed later to get the group members object.\n * @throws {Error} If the group members event is not found.\n */\nexport async function fetchGroupMembersEvent({\n pool,\n groupReference,\n relayInformation,\n normalizedRelayURL,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Event> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const groupMembersEvent = await pool.get([normalizedRelayURL], {\n kinds: [39002],\n authors: [relayInformation.pubkey],\n '#d': [groupReference.id],\n })\n\n if (!groupMembersEvent) throw new Error(`members for group '${groupReference.id}' not found on ${normalizedRelayURL}`)\n\n return groupMembersEvent\n}\n\n/**\n * Parses a group members event and returns an array of GroupMember objects.\n * @param event - The event to parse.\n * @returns An array of GroupMember objects.\n * @throws Throws an error if the group members event is invalid.\n */\nexport function parseGroupMembersEvent(event: Event): GroupMember[] {\n if (!validateGroupMembersEvent(event)) throw new Error('invalid group members event')\n\n const members: GroupMember[] = []\n\n for (const [tag, value, label] of event.tags) {\n if (tag !== 'p') continue\n\n members.push({\n pubkey: value,\n label,\n })\n }\n\n return members\n}\n\n/**\n * Fetches and parses the group metadata event, group admins event, and group members event from the specified pool.\n * If the normalized relay URL is not provided, it will be obtained using the group reference.\n * If the relay information is not provided, it will be fetched using the normalized relay URL.\n *\n * @param {Object} options - The options for loading the group.\n * @param {AbstractSimplePool} options.pool - The pool to load the group from.\n * @param {GroupReference} options.groupReference - The reference of the group to load.\n * @param {string} [options.normalizedRelayURL] - The normalized URL of the relay to use.\n * @param {RelayInformation} [options.relayInformation] - The relay information to use.\n * @returns {Promise<Group>} A promise that resolves to the loaded group.\n */\nexport async function loadGroup({\n pool,\n groupReference,\n normalizedRelayURL,\n relayInformation,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Group> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const metadataEvent = await fetchGroupMetadataEvent({ pool, groupReference, normalizedRelayURL, relayInformation })\n const metadata = parseGroupMetadataEvent(metadataEvent)\n\n const adminsEvent = await fetchGroupAdminsEvent({ pool, groupReference, normalizedRelayURL, relayInformation })\n const admins = parseGroupAdminsEvent(adminsEvent)\n\n const membersEvent = await fetchGroupMembersEvent({ pool, groupReference, normalizedRelayURL, relayInformation })\n const members = parseGroupMembersEvent(membersEvent)\n\n const group: Group = {\n relay: normalizedRelayURL,\n metadata,\n admins,\n members,\n reference: groupReference,\n }\n\n return group\n}\n\n/**\n * Loads a group from the specified pool using the provided group code.\n *\n * @param {AbstractSimplePool} pool - The pool to load the group from.\n * @param {string} code - The code representing the group.\n * @returns {Promise<Group>} - A promise that resolves to the loaded group.\n * @throws {Error} - If the group code is invalid.\n */\nexport async function loadGroupFromCode(pool: AbstractSimplePool, code: string): Promise<Group> {\n const groupReference = parseGroupCode(code)\n\n if (!groupReference) throw new Error('invalid group code')\n\n return loadGroup({ pool, groupReference })\n}\n\n/**\n * Parses a group code and returns a GroupReference object.\n *\n * @param code The group code to parse.\n * @returns A GroupReference object if the code is valid, otherwise null.\n */\nexport function parseGroupCode(code: string): null | GroupReference {\n if (NostrTypeGuard.isNAddr(code)) {\n try {\n let { data } = decode(code)\n\n let { relays, identifier } = data\n if (!relays || relays.length === 0) return null\n\n let host = relays![0]\n if (host.startsWith('wss://')) {\n host = host.slice(6)\n }\n return { host, id: identifier }\n } catch (err) {\n return null\n }\n } else if (code.split(\"'\").length === 2) {\n let spl = code.split(\"'\")\n return { host: spl[0], id: spl[1] }\n }\n\n return null\n}\n\n/**\n * Encodes a group reference into a string.\n *\n * @param gr - The group reference to encode.\n * @returns The encoded group reference as a string.\n */\nexport function encodeGroupReference(gr: GroupReference): string {\n const { host, id } = gr\n const normalizedHost = host.replace(/^(https?:\\/\\/|wss?:\\/\\/)/, '')\n\n return `${normalizedHost}'${id}`\n}\n\n/**\n * Subscribes to relay groups metadata events and calls the provided event handler function\n * when an event is received.\n *\n * @param {Object} options - The options for subscribing to relay groups metadata events.\n * @param {AbstractSimplePool} options.pool - The pool to subscribe to.\n * @param {string} options.relayURL - The URL of the relay.\n * @param {Function} options.onError - The error handler function.\n * @param {Function} options.onEvent - The event handler function.\n * @param {Function} [options.onConnect] - The connect handler function.\n * @returns {Function} - A function to close the subscription\n */\nexport function subscribeRelayGroupsMetadataEvents({\n pool,\n relayURL,\n onError,\n onEvent,\n onConnect,\n}: {\n pool: AbstractSimplePool\n relayURL: string\n onError: (err: Error) => void\n onEvent: (event: Event) => void\n onConnect?: () => void\n}): () => void {\n let sub: Subscription\n\n const normalizedRelayURL = normalizeURL(relayURL)\n\n fetchRelayInformation(normalizedRelayURL)\n .then(async info => {\n const abstractedRelay = await pool.ensureRelay(normalizedRelayURL)\n\n onConnect?.()\n\n sub = abstractedRelay.prepareSubscription(\n [\n {\n kinds: [39000],\n limit: 50,\n authors: [info.pubkey],\n },\n ],\n {\n onevent(event: Event) {\n onEvent(event)\n },\n },\n )\n })\n .catch(err => {\n sub.close()\n\n onError(err)\n })\n\n return () => sub.close()\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["var _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any): void {\n _fetch = fetchImplementation\n}\n\nexport async function fetchRelayInformation(url: string): Promise<RelayInformation> {\n return (await (\n await fetch(url.replace('ws://', 'http://').replace('wss://', 'https://'), {\n headers: { Accept: 'application/nostr+json' },\n })\n ).json()) as RelayInformation\n}\n\n/**\n * ## Relay Information Document\n\n * Relays may provide server metadata to clients to inform\n * them of capabilities, administrative contacts, and\n * various server attributes. This is made available as a\n * JSON document over HTTP, on the same URI as the relay's\n * websocket.\n\n * Any field may be omitted, and clients MUST ignore any\n * additional fields they do not understand. Relays MUST\n * accept CORS requests by sending\n * `Access-Control-Allow-Origin`,\n * `Access-Control-Allow-Headers`, and\n * `Access-Control-Allow-Methods` headers.\n * @param name string identifying relay\n * @param description string with detailed information\n * @param pubkey administrative contact pubkey\n * @param contact: administrative alternate contact\n * @param supported_nips a list of NIP numbers supported by\n * the relay\n * @param software identifying relay software URL\n * @param version string version identifier\n */\nexport interface BasicRelayInformation {\n // string identifying relay\n name: string\n description: string\n pubkey: string\n contact: string\n supported_nips: number[]\n software: string\n version: string\n // limitation?: Limitations<A, P>\n}\n\n/**\n * * ## Extra Fields\n\n * * ### Server Limitations\n\n * These are limitations imposed by the relay on clients.\n * Your client should expect that requests which exceed\n * these practical_ limitations are rejected or fail immediately.\n * @param max_message_length this is the maximum number of\n * bytes for incoming JSON that the relay will attempt to\n * decode and act upon. When you send large subscriptions,\n * you will be limited by this value. It also effectively\n * limits the maximum size of any event. Value is calculated\n * from `[` to `]` and is after UTF-8 serialization (so some\n * unicode characters will cost 2-3 bytes). It is equal to\n * the maximum size of the WebSocket message frame.\n * @param max_subscriptions total number of subscriptions\n * that may be active on a single websocket connection to\n * this relay. It's possible that authenticated clients with\n * a (paid) relationship to the relay may have higher limits.\n * @param max_filters maximum number of filter values in\n * each subscription. Must be one or higher.\n * @param max_limit the relay server will clamp each\n * filter's `limit` value to this number.\n * This means the client won't be able to get more than this\n * number of events from a single subscription filter. This\n * clamping is typically done silently by the relay, but\n * with this number, you can know that there are additional\n * results if you narrowed your filter's time range or other\n * parameters.\n * @param max_subid_length maximum length of subscription id as a\n * string.\n * @param min_prefix for `authors` and `ids` filters which\n * are to match against a hex prefix, you must provide at\n * least this many hex digits in the prefix.\n * @param max_event_tags in any event, this is the maximum\n * number of elements in the `tags` list.\n * @param max_content_length maximum number of characters in\n * the `content` field of any event. This is a count of\n * unicode characters. After serializing into JSON it may be\n * larger (in bytes), and is still subject to the\n * max_message_length`, if defined.\n * @param min_pow_difficulty new events will require at\n * least this difficulty of PoW, based on [NIP-13](13.md),\n * or they will be rejected by this server.\n * @param auth_required this relay requires [NIP-42](42.md)\n * authentication to happen before a new connection may\n * perform any other action. Even if set to False,\n * authentication may be required for specific actions.\n * @param restricted_writes: this relay requires some kind\n * of condition to be fulfilled in order to accept events\n * (not necessarily, but including\n * @param payment_required this relay requires payment\n * before a new connection may perform any action.\n * @param created_at_lower_limit: 'created_at' lower limit\n * @param created_at_upper_limit: 'created_at' upper limit\n */\nexport interface Limitations {\n max_message_length: number\n max_subscriptions: number\n max_filters: number\n max_limit: number\n max_subid_length: number\n min_prefix: number\n max_event_tags: number\n max_content_length: number\n min_pow_difficulty: number\n auth_required: boolean\n payment_required: boolean\n created_at_lower_limit: number\n created_at_upper_limit: number\n restricted_writes: boolean\n}\n\nexport interface RetentionDetails {\n kinds: (number | number[])[]\n time?: number | null\n count?: number | null\n}\ntype AnyRetentionDetails = RetentionDetails\n/**\n * ### Event Retention\n\n * There may be a cost associated with storing data forever,\n * so relays may wish to state retention times. The values\n * stated here are defaults for unauthenticated users and\n * visitors. Paid users would likely have other policies.\n\n * Retention times are given in seconds, with `null`\n * indicating infinity. If zero is provided, this means the\n * event will not be stored at all, and preferably an error\n * will be provided when those are received.\n * ```json\n{\n...\n \"retention\": [\n { \"kinds\": [0, 1, [5, 7], [40, 49]], \"time\": 3600 },\n { \"kinds\": [[40000, 49999]], \"time\": 100 },\n { \"kinds\": [[30000, 39999]], \"count\": 1000 },\n { \"time\": 3600, \"count\": 10000 }\n ]\n...\n}\n```\n * @param retention is a list of specifications: each will\n * apply to either all kinds, or a subset of kinds. Ranges\n * may be specified for the kind field as a tuple of\n * inclusive start and end values. Events of indicated kind\n * (or all) are then limited to a `count` and/or time\n * period.\n\n * It is possible to effectively blacklist Nostr-based\n * protocols that rely on a specific `kind` number, by\n * giving a retention time of zero for those `kind` values.\n * While that is unfortunate, it does allow clients to\n * discover servers that will support their protocol quickly\n * via a single HTTP fetch.\n\n * There is no need to specify retention times for\n * _ephemeral events_ as defined in [NIP-16](16.md) since\n * they are not retained.\n */\nexport interface Retention {\n retention: AnyRetentionDetails[]\n}\n\n/**\n * Some relays may be governed by the arbitrary laws of a\n * nation state. This may limit what content can be stored\n * in cleartext on those relays. All clients are encouraged\n * to use encryption to work around this limitation.\n\n * It is not possible to describe the limitations of each\n * country's laws and policies which themselves are\n * typically vague and constantly shifting.\n\n * Therefore, this field allows the relay operator to\n * indicate which countries' laws might end up being\n * enforced on them, and then indirectly on their users'\n * content.\n\n * Users should be able to avoid relays in countries they\n * don't like, and/or select relays in more favourable\n * zones. Exposing this flexibility is up to the client\n * software.\n\n * @param relay_countries a list of two-level ISO country\n * codes (ISO 3166-1 alpha-2) whose laws and policies may\n * affect this relay. `EU` may be used for European Union\n * countries.\n\n * Remember that a relay may be hosted in a country which is\n * not the country of the legal entities who own the relay,\n * so it's very likely a number of countries are involved.\n */\nexport interface ContentLimitations {\n relay_countries: string[]\n}\n\n/**\n * ### Community Preferences\n\n * For public text notes at least, a relay may try to foster\n * a local community. This would encourage users to follow\n * the global feed on that relay, in addition to their usual\n * individual follows. To support this goal, relays MAY\n * specify some of the following values.\n\n * @param language_tags is an ordered list of [IETF\n * language\n * tags](https://en.wikipedia.org/wiki/IETF_language_tag\n * indicating the major languages spoken on the relay.\n * @param tags is a list of limitations on the topics to be\n * discussed. For example `sfw-only` indicates that only\n * \"Safe For Work\" content is encouraged on this relay. This\n * relies on assumptions of what the \"work\" \"community\"\n * feels \"safe\" talking about. In time, a common set of tags\n * may emerge that allow users to find relays that suit\n * their needs, and client software will be able to parse\n * these tags easily. The `bitcoin-only` tag indicates that\n * any _altcoin_, _\"crypto\"_ or _blockchain_ comments will\n * be ridiculed without mercy.\n * @param posting_policy is a link to a human-readable page\n * which specifies the community policies for the relay. In\n * cases where `sfw-only` is True, it's important to link to\n * a page which gets into the specifics of your posting\n * policy.\n\n * The `description` field should be used to describe your\n * community goals and values, in brief. The\n * `posting_policy` is for additional detail and legal\n * terms. Use the `tags` field to signify limitations on\n * content, or topics to be discussed, which could be\n * machine processed by appropriate client software.\n */\nexport interface CommunityPreferences {\n language_tags: string[]\n tags: string[]\n posting_policy: string\n}\n\nexport interface Amount {\n amount: number\n unit: 'msat'\n}\nexport interface PublicationAmount extends Amount {\n kinds: number[]\n}\nexport interface Subscription extends Amount {\n period: number\n}\nexport interface Fees {\n admission: Amount[]\n subscription: Subscription[]\n publication: PublicationAmount[]\n}\n/**\n * Relays that require payments may want to expose their fee\n * schedules.\n */\nexport interface PayToRelay {\n payments_url: string\n fees: Fees\n}\n\n/**\n * A URL pointing to an image to be used as an icon for the\n * relay. Recommended to be squared in shape.\n */\nexport interface Icon {\n icon: string\n}\n\nexport type RelayInformation = BasicRelayInformation &\n Partial<Retention> & {\n limitation?: Partial<Limitations>\n } & Partial<ContentLimitations> &\n Partial<CommunityPreferences> &\n Partial<PayToRelay> &\n Partial<Icon>\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { AbstractSimplePool } from './abstract-pool.ts'\nimport { Subscription } from './abstract-relay.ts'\nimport type { Event, EventTemplate } from './core.ts'\nimport { fetchRelayInformation, RelayInformation } from './nip11.ts'\nimport { decode, NostrTypeGuard } from './nip19.ts'\nimport { normalizeURL } from './utils.ts'\n\n/**\n * Represents a NIP29 group.\n */\nexport type Group = {\n relay: string\n metadata: GroupMetadata\n admins?: GroupAdmin[]\n members?: GroupMember[]\n reference: GroupReference\n}\n\n/**\n * Represents the metadata for a NIP29 group.\n */\nexport type GroupMetadata = {\n id: string\n pubkey: string\n name?: string\n picture?: string\n about?: string\n isPublic?: boolean\n isOpen?: boolean\n}\n\n/**\n * Represents a NIP29 group reference.\n */\nexport type GroupReference = {\n id: string\n host: string\n}\n\n/**\n * Represents a NIP29 group member.\n */\nexport type GroupMember = {\n pubkey: string\n label?: string\n}\n\n/**\n * Represents a NIP29 group admin.\n */\nexport type GroupAdmin = {\n pubkey: string\n label?: string\n permissions: GroupAdminPermission[]\n}\n\n/**\n * Represents the permissions that a NIP29 group admin can have.\n */\nexport enum GroupAdminPermission {\n /** @deprecated use PutUser instead */\n AddUser = 'add-user',\n EditMetadata = 'edit-metadata',\n DeleteEvent = 'delete-event',\n RemoveUser = 'remove-user',\n /** @deprecated removed from NIP */\n AddPermission = 'add-permission',\n /** @deprecated removed from NIP */\n RemovePermission = 'remove-permission',\n /** @deprecated removed from NIP */\n EditGroupStatus = 'edit-group-status',\n PutUser = 'put-user',\n CreateGroup = 'create-group',\n DeleteGroup = 'delete-group',\n CreateInvite = 'create-invite',\n}\n\n/**\n * Generates a group metadata event template.\n *\n * @param group - The group object.\n * @returns An event template with the generated group metadata that can be signed later.\n */\nexport function generateGroupMetadataEventTemplate(group: Group): EventTemplate {\n const tags: string[][] = [['d', group.metadata.id]]\n group.metadata.name && tags.push(['name', group.metadata.name])\n group.metadata.picture && tags.push(['picture', group.metadata.picture])\n group.metadata.about && tags.push(['about', group.metadata.about])\n group.metadata.isPublic && tags.push(['public'])\n group.metadata.isOpen && tags.push(['open'])\n\n return {\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n kind: 39000,\n tags,\n }\n}\n\n/**\n * Validates a group metadata event.\n *\n * @param event - The event to validate.\n * @returns A boolean indicating whether the event is valid.\n */\nexport function validateGroupMetadataEvent(event: Event): boolean {\n if (event.kind !== 39000) return false\n\n if (!event.pubkey) return false\n\n const requiredTags = ['d'] as const\n for (const tag of requiredTags) {\n if (!event.tags.find(([t]) => t == tag)) return false\n }\n\n return true\n}\n\n/**\n * Generates an event template for group admins.\n *\n * @param group - The group object.\n * @param admins - An array of group admins.\n * @returns The generated event template with the group admins that can be signed later.\n */\nexport function generateGroupAdminsEventTemplate(group: Group, admins: GroupAdmin[]): EventTemplate {\n const tags: string[][] = [['d', group.metadata.id]]\n for (const admin of admins) {\n tags.push(['p', admin.pubkey, admin.label || '', ...admin.permissions])\n }\n\n return {\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n kind: 39001,\n tags,\n }\n}\n\n/**\n * Validates a group admins event.\n *\n * @param event - The event to validate.\n * @returns True if the event is valid, false otherwise.\n */\nexport function validateGroupAdminsEvent(event: Event): boolean {\n if (event.kind !== 39001) return false\n\n const requiredTags = ['d'] as const\n for (const tag of requiredTags) {\n if (!event.tags.find(([t]) => t == tag)) return false\n }\n\n // validate permissions\n for (const [tag, _value, _label, ...permissions] of event.tags) {\n if (tag !== 'p') continue\n\n for (let i = 0; i < permissions.length; i += 1) {\n if (typeof permissions[i] !== 'string') return false\n\n // validate permission name from the GroupAdminPermission enum\n if (!Object.values(GroupAdminPermission).includes(permissions[i] as GroupAdminPermission)) return false\n }\n }\n\n return true\n}\n\n/**\n * Generates an event template for a group with its members.\n *\n * @param group - The group object.\n * @param members - An array of group members.\n * @returns The generated event template with the group members that can be signed later.\n */\nexport function generateGroupMembersEventTemplate(group: Group, members: GroupMember[]): EventTemplate {\n const tags: string[][] = [['d', group.metadata.id]]\n for (const member of members) {\n tags.push(['p', member.pubkey, member.label || ''])\n }\n\n return {\n content: '',\n created_at: Math.floor(Date.now() / 1000),\n kind: 39002,\n tags,\n }\n}\n\n/**\n * Validates a group members event.\n *\n * @param event - The event to validate.\n * @returns Returns `true` if the event is a valid group members event, `false` otherwise.\n */\nexport function validateGroupMembersEvent(event: Event): boolean {\n if (event.kind !== 39002) return false\n\n const requiredTags = ['d'] as const\n for (const tag of requiredTags) {\n if (!event.tags.find(([t]) => t == tag)) return false\n }\n\n return true\n}\n\n/**\n * Returns the normalized relay URL based on the provided group reference.\n *\n * @param groupReference - The group reference object containing the host.\n * @returns The normalized relay URL.\n */\nexport function getNormalizedRelayURLByGroupReference(groupReference: GroupReference): string {\n return normalizeURL(groupReference.host)\n}\n\n/**\n * Fetches relay information by group reference.\n *\n * @param groupReference The group reference.\n * @returns A promise that resolves to the relay information.\n */\nexport async function fetchRelayInformationByGroupReference(groupReference: GroupReference): Promise<RelayInformation> {\n const normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n\n return fetchRelayInformation(normalizedRelayURL)\n}\n\n/**\n * Fetches the group metadata event from the specified pool.\n * If the normalizedRelayURL is not provided, it will be obtained using the groupReference.\n * If the relayInformation is not provided, it will be fetched using the normalizedRelayURL.\n *\n * @param {Object} options - The options object.\n * @param {AbstractSimplePool} options.pool - The pool to fetch the group metadata event from.\n * @param {GroupReference} options.groupReference - The reference to the group.\n * @param {string} [options.normalizedRelayURL] - The normalized URL of the relay.\n * @param {RelayInformation} [options.relayInformation] - The relay information object.\n * @returns {Promise<Event>} The group metadata event that can be parsed later to get the group metadata object.\n * @throws {Error} If the group is not found on the specified relay.\n */\nexport async function fetchGroupMetadataEvent({\n pool,\n groupReference,\n relayInformation,\n normalizedRelayURL,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Event> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const groupMetadataEvent = await pool.get([normalizedRelayURL], {\n kinds: [39000],\n authors: [relayInformation.pubkey],\n '#d': [groupReference.id],\n })\n\n if (!groupMetadataEvent) throw new Error(`group '${groupReference.id}' not found on ${normalizedRelayURL}`)\n\n return groupMetadataEvent\n}\n\n/**\n * Parses a group metadata event and returns the corresponding GroupMetadata object.\n *\n * @param event - The event to parse.\n * @returns The parsed GroupMetadata object.\n * @throws An error if the group metadata event is invalid.\n */\nexport function parseGroupMetadataEvent(event: Event): GroupMetadata {\n if (!validateGroupMetadataEvent(event)) throw new Error('invalid group metadata event')\n\n const metadata: GroupMetadata = {\n id: '',\n pubkey: event.pubkey,\n }\n\n for (const [tag, value] of event.tags) {\n switch (tag) {\n case 'd':\n metadata.id = value\n break\n case 'name':\n metadata.name = value\n break\n case 'picture':\n metadata.picture = value\n break\n case 'about':\n metadata.about = value\n break\n case 'public':\n metadata.isPublic = true\n break\n case 'open':\n metadata.isOpen = true\n break\n }\n }\n\n return metadata\n}\n\n/**\n * Fetches the group admins event from the specified pool.\n * If the normalizedRelayURL is not provided, it will be obtained from the groupReference.\n * If the relayInformation is not provided, it will be fetched using the normalizedRelayURL.\n *\n * @param {Object} options - The options object.\n * @param {AbstractSimplePool} options.pool - The pool to fetch the group admins event from.\n * @param {GroupReference} options.groupReference - The reference to the group.\n * @param {string} [options.normalizedRelayURL] - The normalized relay URL.\n * @param {RelayInformation} [options.relayInformation] - The relay information.\n * @returns {Promise<Event>} The group admins event that can be parsed later to get the group admins object.\n * @throws {Error} If the group admins event is not found on the specified relay.\n */\nexport async function fetchGroupAdminsEvent({\n pool,\n groupReference,\n relayInformation,\n normalizedRelayURL,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Event> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const groupAdminsEvent = await pool.get([normalizedRelayURL], {\n kinds: [39001],\n authors: [relayInformation.pubkey],\n '#d': [groupReference.id],\n })\n\n if (!groupAdminsEvent) throw new Error(`admins for group '${groupReference.id}' not found on ${normalizedRelayURL}`)\n\n return groupAdminsEvent\n}\n\n/**\n * Parses a group admins event and returns an array of GroupAdmin objects.\n *\n * @param event - The event to parse.\n * @returns An array of GroupAdmin objects.\n * @throws Throws an error if the group admins event is invalid.\n */\nexport function parseGroupAdminsEvent(event: Event): GroupAdmin[] {\n if (!validateGroupAdminsEvent(event)) throw new Error('invalid group admins event')\n\n const admins: GroupAdmin[] = []\n\n for (const [tag, value, label, ...permissions] of event.tags) {\n if (tag !== 'p') continue\n\n admins.push({\n pubkey: value,\n label,\n permissions: permissions as GroupAdminPermission[],\n })\n }\n\n return admins\n}\n\n/**\n * Fetches the group members event from the specified relay.\n * If the normalizedRelayURL is not provided, it will be obtained using the groupReference.\n * If the relayInformation is not provided, it will be fetched using the normalizedRelayURL.\n *\n * @param {Object} options - The options object.\n * @param {AbstractSimplePool} options.pool - The pool object.\n * @param {GroupReference} options.groupReference - The group reference object.\n * @param {string} [options.normalizedRelayURL] - The normalized relay URL.\n * @param {RelayInformation} [options.relayInformation] - The relay information object.\n * @returns {Promise<Event>} The group members event that can be parsed later to get the group members object.\n * @throws {Error} If the group members event is not found.\n */\nexport async function fetchGroupMembersEvent({\n pool,\n groupReference,\n relayInformation,\n normalizedRelayURL,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Event> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const groupMembersEvent = await pool.get([normalizedRelayURL], {\n kinds: [39002],\n authors: [relayInformation.pubkey],\n '#d': [groupReference.id],\n })\n\n if (!groupMembersEvent) throw new Error(`members for group '${groupReference.id}' not found on ${normalizedRelayURL}`)\n\n return groupMembersEvent\n}\n\n/**\n * Parses a group members event and returns an array of GroupMember objects.\n * @param event - The event to parse.\n * @returns An array of GroupMember objects.\n * @throws Throws an error if the group members event is invalid.\n */\nexport function parseGroupMembersEvent(event: Event): GroupMember[] {\n if (!validateGroupMembersEvent(event)) throw new Error('invalid group members event')\n\n const members: GroupMember[] = []\n\n for (const [tag, value, label] of event.tags) {\n if (tag !== 'p') continue\n\n members.push({\n pubkey: value,\n label,\n })\n }\n\n return members\n}\n\n/**\n * Fetches and parses the group metadata event, group admins event, and group members event from the specified pool.\n * If the normalized relay URL is not provided, it will be obtained using the group reference.\n * If the relay information is not provided, it will be fetched using the normalized relay URL.\n *\n * @param {Object} options - The options for loading the group.\n * @param {AbstractSimplePool} options.pool - The pool to load the group from.\n * @param {GroupReference} options.groupReference - The reference of the group to load.\n * @param {string} [options.normalizedRelayURL] - The normalized URL of the relay to use.\n * @param {RelayInformation} [options.relayInformation] - The relay information to use.\n * @returns {Promise<Group>} A promise that resolves to the loaded group.\n */\nexport async function loadGroup({\n pool,\n groupReference,\n normalizedRelayURL,\n relayInformation,\n}: {\n pool: AbstractSimplePool\n groupReference: GroupReference\n normalizedRelayURL?: string\n relayInformation?: RelayInformation\n}): Promise<Group> {\n if (!normalizedRelayURL) {\n normalizedRelayURL = getNormalizedRelayURLByGroupReference(groupReference)\n }\n\n if (!relayInformation) {\n relayInformation = await fetchRelayInformation(normalizedRelayURL)\n }\n\n const metadataEvent = await fetchGroupMetadataEvent({ pool, groupReference, normalizedRelayURL, relayInformation })\n const metadata = parseGroupMetadataEvent(metadataEvent)\n\n const adminsEvent = await fetchGroupAdminsEvent({ pool, groupReference, normalizedRelayURL, relayInformation })\n const admins = parseGroupAdminsEvent(adminsEvent)\n\n const membersEvent = await fetchGroupMembersEvent({ pool, groupReference, normalizedRelayURL, relayInformation })\n const members = parseGroupMembersEvent(membersEvent)\n\n const group: Group = {\n relay: normalizedRelayURL,\n metadata,\n admins,\n members,\n reference: groupReference,\n }\n\n return group\n}\n\n/**\n * Loads a group from the specified pool using the provided group code.\n *\n * @param {AbstractSimplePool} pool - The pool to load the group from.\n * @param {string} code - The code representing the group.\n * @returns {Promise<Group>} - A promise that resolves to the loaded group.\n * @throws {Error} - If the group code is invalid.\n */\nexport async function loadGroupFromCode(pool: AbstractSimplePool, code: string): Promise<Group> {\n const groupReference = parseGroupCode(code)\n\n if (!groupReference) throw new Error('invalid group code')\n\n return loadGroup({ pool, groupReference })\n}\n\n/**\n * Parses a group code and returns a GroupReference object.\n *\n * @param code The group code to parse.\n * @returns A GroupReference object if the code is valid, otherwise null.\n */\nexport function parseGroupCode(code: string): null | GroupReference {\n if (NostrTypeGuard.isNAddr(code)) {\n try {\n let { data } = decode(code)\n\n let { relays, identifier } = data\n if (!relays || relays.length === 0) return null\n\n let host = relays![0]\n if (host.startsWith('wss://')) {\n host = host.slice(6)\n }\n return { host, id: identifier }\n } catch (err) {\n return null\n }\n } else if (code.split(\"'\").length === 2) {\n let spl = code.split(\"'\")\n return { host: spl[0], id: spl[1] }\n }\n\n return null\n}\n\n/**\n * Encodes a group reference into a string.\n *\n * @param gr - The group reference to encode.\n * @returns The encoded group reference as a string.\n */\nexport function encodeGroupReference(gr: GroupReference): string {\n const { host, id } = gr\n const normalizedHost = host.replace(/^(https?:\\/\\/|wss?:\\/\\/)/, '')\n\n return `${normalizedHost}'${id}`\n}\n\n/**\n * Subscribes to relay groups metadata events and calls the provided event handler function\n * when an event is received.\n *\n * @param {Object} options - The options for subscribing to relay groups metadata events.\n * @param {AbstractSimplePool} options.pool - The pool to subscribe to.\n * @param {string} options.relayURL - The URL of the relay.\n * @param {Function} options.onError - The error handler function.\n * @param {Function} options.onEvent - The event handler function.\n * @param {Function} [options.onConnect] - The connect handler function.\n * @returns {Function} - A function to close the subscription\n */\nexport function subscribeRelayGroupsMetadataEvents({\n pool,\n relayURL,\n onError,\n onEvent,\n onConnect,\n}: {\n pool: AbstractSimplePool\n relayURL: string\n onError: (err: Error) => void\n onEvent: (event: Event) => void\n onConnect?: () => void\n}): () => void {\n let sub: Subscription\n\n const normalizedRelayURL = normalizeURL(relayURL)\n\n fetchRelayInformation(normalizedRelayURL)\n .then(async info => {\n const abstractedRelay = await pool.ensureRelay(normalizedRelayURL)\n\n onConnect?.()\n\n sub = abstractedRelay.prepareSubscription(\n [\n {\n kinds: [39000],\n limit: 50,\n authors: [info.pubkey],\n },\n ],\n {\n onevent(event: Event) {\n onEvent(event)\n },\n },\n )\n })\n .catch(err => {\n sub.close()\n\n onError(err)\n })\n\n return () => sub.close()\n}\n"],
+ "mappings": "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",
"names": ["bytesToHex", "hexToBytes", "bytesToHex", "GroupAdminPermission"]
} Index: package/lib/cjs/nip44.js.map
===================================================================
--- package/lib/cjs/nip44.js.map
+++ package/lib/cjs/nip44.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip44.ts", "../../utils.ts"],
- "sourcesContent": ["import { chacha20 } from '@noble/ciphers/chacha'\nimport { equalBytes } from '@noble/ciphers/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf'\nimport { hmac } from '@noble/hashes/hmac'\nimport { sha256 } from '@noble/hashes/sha256'\nimport { concatBytes, randomBytes } from '@noble/hashes/utils'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, 'nip44-v2')\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { chacha20 } from '@noble/ciphers/chacha.js'\nimport { equalBytes } from '@noble/ciphers/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf.js'\nimport { hmac } from '@noble/hashes/hmac.js'\nimport { sha256 } from '@noble/hashes/sha2.js'\nimport { concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes('02' + pubkeyB)).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, utf8Encoder.encode('nip44-v2'))\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": "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",
"names": ["import_utils", "hkdf_extract", "hkdf_expand"]
} Index: package/lib/esm/nip44.js.map
===================================================================
--- package/lib/esm/nip44.js.map
+++ package/lib/esm/nip44.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip44.ts", "../../utils.ts"],
- "sourcesContent": ["import { chacha20 } from '@noble/ciphers/chacha'\nimport { equalBytes } from '@noble/ciphers/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf'\nimport { hmac } from '@noble/hashes/hmac'\nimport { sha256 } from '@noble/hashes/sha256'\nimport { concatBytes, randomBytes } from '@noble/hashes/utils'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, 'nip44-v2')\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": "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",
- "names": []
+ "sourcesContent": ["import { chacha20 } from '@noble/ciphers/chacha.js'\nimport { equalBytes } from '@noble/ciphers/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf.js'\nimport { hmac } from '@noble/hashes/hmac.js'\nimport { sha256 } from '@noble/hashes/sha2.js'\nimport { concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes('02' + pubkeyB)).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, utf8Encoder.encode('nip44-v2'))\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": "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",
+ "names": ["hexToBytes", "hexToBytes"]
} Index: package/lib/cjs/nip46.js.map
===================================================================
--- package/lib/cjs/nip46.js.map
+++ package/lib/cjs/nip46.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip46.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../nip44.ts", "../../nip05.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts", "../../helpers.ts", "../../abstract-relay.ts", "../../abstract-pool.ts", "../../pool.ts"],
- "sourcesContent": ["import { EventTemplate, NostrEvent, VerifiedEvent } from './core.ts'\nimport { generateSecretKey, finalizeEvent, getPublicKey, verifyEvent } from './pure.ts'\nimport { AbstractSimplePool, SubCloser } from './abstract-pool.ts'\nimport { getConversationKey, decrypt, encrypt } from './nip44.ts'\nimport { NIP05_REGEX } from './nip05.ts'\nimport { SimplePool } from './pool.ts'\nimport { Handlerinformation, NostrConnect } from './kinds.ts'\nimport { Signer } from './signer.ts'\n\nvar _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any) {\n _fetch = fetchImplementation\n}\n\nexport const BUNKER_REGEX = /^bunker:\\/\\/([0-9a-f]{64})\\??([?\\/\\w:.=&%-]*)$/\nconst EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\nexport type BunkerPointer = {\n relays: string[]\n pubkey: string\n secret: null | string\n}\n\nexport function toBunkerURL(bunkerPointer: BunkerPointer): string {\n let bunkerURL = new URL(`bunker://${bunkerPointer.pubkey}`)\n bunkerPointer.relays.forEach(relay => {\n bunkerURL.searchParams.append('relay', relay)\n })\n if (bunkerPointer.secret) {\n bunkerURL.searchParams.set('secret', bunkerPointer.secret)\n }\n return bunkerURL.toString()\n}\n\n/** This takes either a bunker:// URL or a [email protected] NIP-05 identifier\n and returns a BunkerPointer -- or null in case of error */\nexport async function parseBunkerInput(input: string): Promise<BunkerPointer | null> {\n let match = input.match(BUNKER_REGEX)\n if (match) {\n try {\n const pubkey = match[1]\n const qs = new URLSearchParams(match[2])\n return {\n pubkey,\n relays: qs.getAll('relay'),\n secret: qs.get('secret'),\n }\n } catch (_err) {\n /* just move to the next case */\n }\n }\n\n return queryBunkerProfile(input)\n}\n\nexport async function queryBunkerProfile(nip05: string): Promise<BunkerPointer | null> {\n const match = nip05.match(NIP05_REGEX)\n if (!match) return null\n\n const [_, name = '_', domain] = match\n\n try {\n const url = `https://${domain}/.well-known/nostr.json?name=${name}`\n const res = await (await _fetch(url, { redirect: 'error' })).json()\n\n let pubkey = res.names[name]\n let relays = res.nip46[pubkey] || []\n\n return { pubkey, relays, secret: null }\n } catch (_err) {\n return null\n }\n}\n\nexport type NostrConnectParams = {\n clientPubkey: string\n relays: string[]\n secret: string\n perms?: string[]\n name?: string\n url?: string\n image?: string\n}\n\nexport function createNostrConnectURI(params: NostrConnectParams): string {\n const queryParams = new URLSearchParams()\n\n params.relays.forEach(relay => {\n queryParams.append('relay', relay)\n })\n\n queryParams.append('secret', params.secret)\n\n if (params.perms && params.perms.length > 0) {\n queryParams.append('perms', params.perms.join(','))\n }\n if (params.name) {\n queryParams.append('name', params.name)\n }\n if (params.url) {\n queryParams.append('url', params.url)\n }\n if (params.image) {\n queryParams.append('image', params.image)\n }\n\n return `nostrconnect://${params.clientPubkey}?${queryParams.toString()}`\n}\n\nexport type BunkerSignerParams = {\n pool?: AbstractSimplePool\n onauth?: (url: string) => void\n}\n\nexport class BunkerSigner implements Signer {\n private params: BunkerSignerParams\n private pool: AbstractSimplePool\n private subCloser: SubCloser | undefined\n private isOpen: boolean\n private serial: number\n private idPrefix: string\n private listeners: {\n [id: string]: {\n resolve: (_: string) => void\n reject: (_: string) => void\n }\n }\n private waitingForAuth: { [id: string]: boolean }\n private secretKey: Uint8Array\n // If the client initiates the connection, the two variables below can be filled in later.\n private conversationKey!: Uint8Array\n public bp!: BunkerPointer\n\n private cachedPubKey: string | undefined\n\n /**\n * Creates a new instance of the Nip46 class.\n * @param relays - An array of relay addresses.\n * @param remotePubkey - An optional remote public key. This is the key you want to sign as.\n * @param secretKey - An optional key pair.\n */\n private constructor(clientSecretKey: Uint8Array, params: BunkerSignerParams) {\n this.params = params\n this.pool = params.pool || new SimplePool()\n this.secretKey = clientSecretKey\n this.isOpen = false\n this.idPrefix = Math.random().toString(36).substring(7)\n this.serial = 0\n this.listeners = {}\n this.waitingForAuth = {}\n }\n\n /**\n * [Factory Method 1] Creates a Signer using bunker information (bunker:// URL or NIP-05).\n * This method is used when the public key of the bunker is known in advance.\n */\n public static fromBunker(\n clientSecretKey: Uint8Array,\n bp: BunkerPointer,\n params: BunkerSignerParams = {},\n ): BunkerSigner {\n if (bp.relays.length === 0) {\n throw new Error('no relays specified for this bunker')\n }\n\n const signer = new BunkerSigner(clientSecretKey, params)\n\n signer.conversationKey = getConversationKey(clientSecretKey, bp.pubkey)\n signer.bp = bp\n\n signer.setupSubscription()\n return signer\n }\n\n /**\n * [Factory Method 2] Creates a Signer using a nostrconnect:// URI generated by the client.\n * In this method, the bunker initiates the connection by scanning the URI.\n */\n public static async fromURI(\n clientSecretKey: Uint8Array,\n connectionURI: string,\n bunkerParams: BunkerSignerParams = {},\n maxWaitOrAbort: number | AbortSignal = 300_000,\n ): Promise<BunkerSigner> {\n const signer = new BunkerSigner(clientSecretKey, bunkerParams)\n const uri = new URL(connectionURI)\n const clientPubkey = getPublicKey(clientSecretKey)\n\n return new Promise((resolve, reject) => {\n let success = false\n const sub = signer.pool.subscribe(\n uri.searchParams.getAll('relay'),\n {\n kinds: [NostrConnect],\n '#p': [clientPubkey],\n limit: 0,\n },\n {\n onevent: async (event: NostrEvent) => {\n try {\n const tempConvKey = getConversationKey(clientSecretKey, event.pubkey)\n const decryptedContent = decrypt(event.content, tempConvKey)\n\n const response = JSON.parse(decryptedContent)\n\n if (response.result === uri.searchParams.get('secret')) {\n sub.close()\n\n signer.bp = {\n pubkey: event.pubkey,\n relays: uri.searchParams.getAll('relay'),\n secret: uri.searchParams.get('secret'),\n }\n signer.conversationKey = getConversationKey(clientSecretKey, event.pubkey)\n signer.setupSubscription()\n\n success = true\n await Promise.race([new Promise(resolve => setTimeout(resolve, 1000)), signer.switchRelays()])\n resolve(signer)\n }\n } catch (e) {\n console.warn('failed to process potential connection event', e)\n }\n },\n onclose: () => {\n if (!success) reject(new Error('subscription closed before connection was established.'))\n },\n maxWait: typeof maxWaitOrAbort === 'number' ? maxWaitOrAbort : undefined,\n abort: typeof maxWaitOrAbort !== 'number' ? maxWaitOrAbort : undefined,\n },\n )\n })\n }\n\n private setupSubscription() {\n const listeners = this.listeners\n const waitingForAuth = this.waitingForAuth\n const convKey = this.conversationKey\n\n this.subCloser = this.pool.subscribe(\n this.bp.relays,\n {\n kinds: [NostrConnect],\n authors: [this.bp.pubkey],\n '#p': [getPublicKey(this.secretKey)],\n limit: 0,\n },\n {\n onevent: async (event: NostrEvent) => {\n const o = JSON.parse(decrypt(event.content, convKey))\n const { id, result, error } = o\n\n if (result === 'auth_url' && waitingForAuth[id]) {\n delete waitingForAuth[id]\n\n if (this.params.onauth) {\n this.params.onauth(error)\n } else {\n console.warn(\n `nostr-tools/nip46: remote signer ${this.bp.pubkey} tried to send an \"auth_url\"='${error}' but there was no onauth() callback configured.`,\n )\n }\n return\n }\n\n let handler = listeners[id]\n if (handler) {\n if (error) handler.reject(error)\n else if (result) handler.resolve(result)\n delete listeners[id]\n }\n },\n onclose: () => {\n this.subCloser = undefined\n },\n },\n )\n this.isOpen = true\n }\n\n async switchRelays(): Promise<boolean> {\n try {\n const switchResp = await this.sendRequest('switch_relays', [])\n let relays = JSON.parse(switchResp) as string[] | null\n if (!relays) return false\n if (JSON.stringify(relays.sort()) === JSON.stringify(this.bp.relays)) return false\n\n this.bp.relays = relays\n let previousCloser = this.subCloser!\n setTimeout(() => {\n previousCloser.close()\n }, 5000)\n\n this.subCloser = undefined\n this.setupSubscription()\n return true\n } catch {\n return false\n }\n }\n\n // closes the subscription -- this object can't be used anymore after this\n async close() {\n this.isOpen = false\n this.subCloser!.close()\n }\n\n async sendRequest(method: string, params: string[]): Promise<string> {\n return new Promise(async (resolve, reject) => {\n try {\n if (!this.isOpen) throw new Error('this signer is not open anymore, create a new one')\n if (!this.subCloser) this.setupSubscription()\n\n this.serial++\n const id = `${this.idPrefix}-${this.serial}`\n\n const encryptedContent = encrypt(JSON.stringify({ id, method, params }), this.conversationKey)\n\n // the request event\n const verifiedEvent: VerifiedEvent = finalizeEvent(\n {\n kind: NostrConnect,\n tags: [['p', this.bp.pubkey]],\n content: encryptedContent,\n created_at: Math.floor(Date.now() / 1000),\n },\n this.secretKey,\n )\n\n // setup callback listener\n this.listeners[id] = { resolve, reject }\n this.waitingForAuth[id] = true\n\n // publish the event\n await Promise.any(this.pool.publish(this.bp.relays, verifiedEvent))\n } catch (err) {\n reject(err)\n }\n })\n }\n\n /**\n * Calls the \"connect\" method on the bunker.\n * The promise will be rejected if the response is not \"pong\".\n */\n async ping(): Promise<void> {\n let resp = await this.sendRequest('ping', [])\n if (resp !== 'pong') throw new Error(`result is not pong: ${resp}`)\n }\n\n /**\n * Calls the \"connect\" method on the bunker.\n */\n async connect(): Promise<void> {\n await this.sendRequest('connect', [this.bp.pubkey, this.bp.secret || ''])\n }\n\n /**\n * Calls the \"get_public_key\" method on the bunker.\n * (before we would return the public key hardcoded in the bunker parameters, but\n * that is not correct as that may be the bunker pubkey and the actual signer\n * pubkey may be different.)\n */\n async getPublicKey(): Promise<string> {\n if (!this.cachedPubKey) {\n this.cachedPubKey = await this.sendRequest('get_public_key', [])\n }\n return this.cachedPubKey\n }\n\n /**\n * Signs an event using the remote private key.\n * @param event - The event to sign.\n * @returns A Promise that resolves to the signed event.\n */\n async signEvent(event: EventTemplate): Promise<VerifiedEvent> {\n let resp = await this.sendRequest('sign_event', [JSON.stringify(event)])\n let signed: NostrEvent = JSON.parse(resp)\n if (verifyEvent(signed)) {\n return signed\n } else {\n throw new Error(`event returned from bunker is improperly signed: ${JSON.stringify(signed)}`)\n }\n }\n\n async nip04Encrypt(thirdPartyPubkey: string, plaintext: string): Promise<string> {\n return await this.sendRequest('nip04_encrypt', [thirdPartyPubkey, plaintext])\n }\n\n async nip04Decrypt(thirdPartyPubkey: string, ciphertext: string): Promise<string> {\n return await this.sendRequest('nip04_decrypt', [thirdPartyPubkey, ciphertext])\n }\n\n async nip44Encrypt(thirdPartyPubkey: string, plaintext: string): Promise<string> {\n return await this.sendRequest('nip44_encrypt', [thirdPartyPubkey, plaintext])\n }\n\n async nip44Decrypt(thirdPartyPubkey: string, ciphertext: string): Promise<string> {\n return await this.sendRequest('nip44_decrypt', [thirdPartyPubkey, ciphertext])\n }\n}\n\n/**\n * Creates an account with the specified username, domain, and optional email.\n * @param bunkerPubkey - The public key of the bunker to use for the create_account call.\n * @param username - The username for the account.\n * @param domain - The domain for the account.\n * @param email - The optional email for the account.\n * @param localSecretKey - Optionally pass a local secret key that will be used to communicate with the bunker,\n this will default to generating a random key.\n * @throws Error if the email is present but invalid.\n * @returns A Promise that resolves to the auth_url that the client should follow to create an account.\n */\nexport async function createAccount(\n bunker: BunkerProfile,\n params: BunkerSignerParams,\n username: string,\n domain: string,\n email?: string,\n localSecretKey: Uint8Array = generateSecretKey(),\n): Promise<BunkerSigner> {\n if (email && !EMAIL_REGEX.test(email)) throw new Error('invalid email')\n\n let rpc = BunkerSigner.fromBunker(localSecretKey, bunker.bunkerPointer, params)\n\n let pubkey = await rpc.sendRequest('create_account', [username, domain, email || ''])\n\n // once we get the newly created pubkey back, we hijack this signer instance\n // and turn it into the main instance for this newly created pubkey\n rpc.bp.pubkey = pubkey\n await rpc.connect()\n\n return rpc\n}\n\n/**\n * Fetches info on available providers that announce themselves using NIP-89 events.\n * @returns A promise that resolves to an array of available bunker objects.\n */\nexport async function fetchBunkerProviders(pool: AbstractSimplePool, relays: string[]): Promise<BunkerProfile[]> {\n const events = await pool.querySync(relays, {\n kinds: [Handlerinformation],\n '#k': [NostrConnect.toString()],\n })\n\n events.sort((a, b) => b.created_at - a.created_at)\n\n // validate bunkers by checking their NIP-05 and pubkey\n // map to a more useful object\n const validatedBunkers = await Promise.all(\n events.map(async (event, i) => {\n try {\n const content = JSON.parse(event.content)\n\n // skip duplicates\n try {\n if (events.findIndex(ev => JSON.parse(ev.content).nip05 === content.nip05) !== i) return undefined\n } catch (err) {\n /***/\n }\n\n const bp = await queryBunkerProfile(content.nip05)\n if (bp && bp.pubkey === event.pubkey && bp.relays.length) {\n return {\n bunkerPointer: bp,\n nip05: content.nip05,\n domain: content.nip05.split('@')[1],\n name: content.name || content.display_name,\n picture: content.picture,\n about: content.about,\n website: content.website,\n local: false,\n }\n }\n } catch (err) {\n return undefined\n }\n }),\n )\n\n return validatedBunkers.filter(b => b !== undefined) as BunkerProfile[]\n}\n\nexport type BunkerProfile = {\n bunkerPointer: BunkerPointer\n domain: string\n nip05: string\n name: string\n picture: string\n about: string\n website: string\n local: boolean\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { chacha20 } from '@noble/ciphers/chacha'\nimport { equalBytes } from '@noble/ciphers/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf'\nimport { hmac } from '@noble/hashes/hmac'\nimport { sha256 } from '@noble/hashes/sha256'\nimport { concatBytes, randomBytes } from '@noble/hashes/utils'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, 'nip44-v2')\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import { ProfilePointer } from './nip19.ts'\n\nexport type Nip05 = `${string}@${string}`\n\n/**\n * NIP-05 regex. The localpart is optional, and should be assumed to be `_` otherwise.\n *\n * - 0: full match\n * - 1: name (optional)\n * - 2: domain\n */\nexport const NIP05_REGEX = /^(?:([\\w.+-]+)@)?([\\w_-]+(\\.[\\w_-]+)+)$/\nexport const isNip05 = (value?: string | null): value is Nip05 => NIP05_REGEX.test(value || '')\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _fetch: any\n\ntry {\n _fetch = fetch\n} catch (_) {\n null\n}\n\nexport function useFetchImplementation(fetchImplementation: unknown) {\n _fetch = fetchImplementation\n}\n\nexport async function searchDomain(domain: string, query = ''): Promise<{ [name: string]: string }> {\n try {\n const url = `https://${domain}/.well-known/nostr.json?name=${query}`\n const res = await _fetch(url, { redirect: 'manual' })\n if (res.status !== 200) {\n throw Error('Wrong response code')\n }\n const json = await res.json()\n return json.names\n } catch (_) {\n return {}\n }\n}\n\nexport async function queryProfile(fullname: string): Promise<ProfilePointer | null> {\n const match = fullname.match(NIP05_REGEX)\n if (!match) return null\n\n const [, name = '_', domain] = match\n\n try {\n const url = `https://${domain}/.well-known/nostr.json?name=${name}`\n const res = await _fetch(url, { redirect: 'manual' })\n if (res.status !== 200) {\n throw Error('Wrong response code')\n }\n const json = await res.json()\n\n const pubkey = json.names[name]\n return pubkey ? { pubkey, relays: json.relays?.[pubkey] } : null\n } catch (_e) {\n return null\n }\n}\n\nexport async function isValid(pubkey: string, nip05: Nip05): Promise<boolean> {\n const res = await queryProfile(nip05)\n return res ? res.pubkey === pubkey : false\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n", "/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractSimplePool, type AbstractPoolConstructorOptions } from './abstract-pool.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class SimplePool extends AbstractSimplePool {\n constructor(options?: Pick<AbstractPoolConstructorOptions, 'enablePing' | 'enableReconnect'>) {\n super({ verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n}\n\nexport * from './abstract-pool.ts'\n"],
- "mappings": "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",
- "names": ["import_utils", "i", "target", "import_utils", "import_secp256k1", "import_sha256", "hkdf_extract", "hkdf_expand", "i", "i", "reason", "_fetch", "resolve", "i"]
+ "sourcesContent": ["import { EventTemplate, NostrEvent, VerifiedEvent } from './core.ts'\nimport { generateSecretKey, finalizeEvent, getPublicKey, verifyEvent } from './pure.ts'\nimport { AbstractSimplePool, SubCloser } from './abstract-pool.ts'\nimport { getConversationKey, decrypt, encrypt } from './nip44.ts'\nimport { NIP05_REGEX } from './nip05.ts'\nimport { SimplePool } from './pool.ts'\nimport { Handlerinformation, NostrConnect } from './kinds.ts'\nimport { Signer } from './signer.ts'\n\nvar _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any) {\n _fetch = fetchImplementation\n}\n\nexport const BUNKER_REGEX = /^bunker:\\/\\/([0-9a-f]{64})\\??([?\\/\\w:.=&%-]*)$/\nconst EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\nexport type BunkerPointer = {\n relays: string[]\n pubkey: string\n secret: null | string\n}\n\nexport function toBunkerURL(bunkerPointer: BunkerPointer): string {\n let bunkerURL = new URL(`bunker://${bunkerPointer.pubkey}`)\n bunkerPointer.relays.forEach(relay => {\n bunkerURL.searchParams.append('relay', relay)\n })\n if (bunkerPointer.secret) {\n bunkerURL.searchParams.set('secret', bunkerPointer.secret)\n }\n return bunkerURL.toString()\n}\n\n/** This takes either a bunker:// URL or a [email protected] NIP-05 identifier\n and returns a BunkerPointer -- or null in case of error */\nexport async function parseBunkerInput(input: string): Promise<BunkerPointer | null> {\n let match = input.match(BUNKER_REGEX)\n if (match) {\n try {\n const pubkey = match[1]\n const qs = new URLSearchParams(match[2])\n return {\n pubkey,\n relays: qs.getAll('relay'),\n secret: qs.get('secret'),\n }\n } catch (_err) {\n /* just move to the next case */\n }\n }\n\n return queryBunkerProfile(input)\n}\n\nexport async function queryBunkerProfile(nip05: string): Promise<BunkerPointer | null> {\n const match = nip05.match(NIP05_REGEX)\n if (!match) return null\n\n const [_, name = '_', domain] = match\n\n try {\n const url = `https://${domain}/.well-known/nostr.json?name=${name}`\n const res = await (await _fetch(url, { redirect: 'error' })).json()\n\n let pubkey = res.names[name]\n let relays = res.nip46[pubkey] || []\n\n return { pubkey, relays, secret: null }\n } catch (_err) {\n return null\n }\n}\n\nexport type NostrConnectParams = {\n clientPubkey: string\n relays: string[]\n secret: string\n perms?: string[]\n name?: string\n url?: string\n image?: string\n}\n\nexport function createNostrConnectURI(params: NostrConnectParams): string {\n const queryParams = new URLSearchParams()\n\n params.relays.forEach(relay => {\n queryParams.append('relay', relay)\n })\n\n queryParams.append('secret', params.secret)\n\n if (params.perms && params.perms.length > 0) {\n queryParams.append('perms', params.perms.join(','))\n }\n if (params.name) {\n queryParams.append('name', params.name)\n }\n if (params.url) {\n queryParams.append('url', params.url)\n }\n if (params.image) {\n queryParams.append('image', params.image)\n }\n\n return `nostrconnect://${params.clientPubkey}?${queryParams.toString()}`\n}\n\nexport type BunkerSignerParams = {\n pool?: AbstractSimplePool\n onauth?: (url: string) => void\n}\n\nexport class BunkerSigner implements Signer {\n private params: BunkerSignerParams\n private pool: AbstractSimplePool\n private subCloser: SubCloser | undefined\n private isOpen: boolean\n private serial: number\n private idPrefix: string\n private listeners: {\n [id: string]: {\n resolve: (_: string) => void\n reject: (_: string) => void\n }\n }\n private waitingForAuth: { [id: string]: boolean }\n private secretKey: Uint8Array\n // If the client initiates the connection, the two variables below can be filled in later.\n private conversationKey!: Uint8Array\n public bp!: BunkerPointer\n\n private cachedPubKey: string | undefined\n\n /**\n * Creates a new instance of the Nip46 class.\n * @param relays - An array of relay addresses.\n * @param remotePubkey - An optional remote public key. This is the key you want to sign as.\n * @param secretKey - An optional key pair.\n */\n private constructor(clientSecretKey: Uint8Array, params: BunkerSignerParams) {\n this.params = params\n this.pool = params.pool || new SimplePool()\n this.secretKey = clientSecretKey\n this.isOpen = false\n this.idPrefix = Math.random().toString(36).substring(7)\n this.serial = 0\n this.listeners = {}\n this.waitingForAuth = {}\n }\n\n /**\n * [Factory Method 1] Creates a Signer using bunker information (bunker:// URL or NIP-05).\n * This method is used when the public key of the bunker is known in advance.\n */\n public static fromBunker(\n clientSecretKey: Uint8Array,\n bp: BunkerPointer,\n params: BunkerSignerParams = {},\n ): BunkerSigner {\n if (bp.relays.length === 0) {\n throw new Error('no relays specified for this bunker')\n }\n\n const signer = new BunkerSigner(clientSecretKey, params)\n\n signer.conversationKey = getConversationKey(clientSecretKey, bp.pubkey)\n signer.bp = bp\n\n signer.setupSubscription()\n return signer\n }\n\n /**\n * [Factory Method 2] Creates a Signer using a nostrconnect:// URI generated by the client.\n * In this method, the bunker initiates the connection by scanning the URI.\n */\n public static async fromURI(\n clientSecretKey: Uint8Array,\n connectionURI: string,\n bunkerParams: BunkerSignerParams = {},\n maxWaitOrAbort: number | AbortSignal = 300_000,\n ): Promise<BunkerSigner> {\n const signer = new BunkerSigner(clientSecretKey, bunkerParams)\n const uri = new URL(connectionURI)\n const clientPubkey = getPublicKey(clientSecretKey)\n\n return new Promise((resolve, reject) => {\n let success = false\n const sub = signer.pool.subscribe(\n uri.searchParams.getAll('relay'),\n {\n kinds: [NostrConnect],\n '#p': [clientPubkey],\n limit: 0,\n },\n {\n onevent: async (event: NostrEvent) => {\n try {\n const tempConvKey = getConversationKey(clientSecretKey, event.pubkey)\n const decryptedContent = decrypt(event.content, tempConvKey)\n\n const response = JSON.parse(decryptedContent)\n\n if (response.result === uri.searchParams.get('secret')) {\n sub.close()\n\n signer.bp = {\n pubkey: event.pubkey,\n relays: uri.searchParams.getAll('relay'),\n secret: uri.searchParams.get('secret'),\n }\n signer.conversationKey = getConversationKey(clientSecretKey, event.pubkey)\n signer.setupSubscription()\n\n success = true\n await Promise.race([new Promise(resolve => setTimeout(resolve, 1000)), signer.switchRelays()])\n resolve(signer)\n }\n } catch (e) {\n console.warn('failed to process potential connection event', e)\n }\n },\n onclose: () => {\n if (!success) reject(new Error('subscription closed before connection was established.'))\n },\n maxWait: typeof maxWaitOrAbort === 'number' ? maxWaitOrAbort : undefined,\n abort: typeof maxWaitOrAbort !== 'number' ? maxWaitOrAbort : undefined,\n },\n )\n })\n }\n\n private setupSubscription() {\n const listeners = this.listeners\n const waitingForAuth = this.waitingForAuth\n const convKey = this.conversationKey\n\n this.subCloser = this.pool.subscribe(\n this.bp.relays,\n {\n kinds: [NostrConnect],\n authors: [this.bp.pubkey],\n '#p': [getPublicKey(this.secretKey)],\n limit: 0,\n },\n {\n onevent: async (event: NostrEvent) => {\n const o = JSON.parse(decrypt(event.content, convKey))\n const { id, result, error } = o\n\n if (result === 'auth_url' && waitingForAuth[id]) {\n delete waitingForAuth[id]\n\n if (this.params.onauth) {\n this.params.onauth(error)\n } else {\n console.warn(\n `nostr-tools/nip46: remote signer ${this.bp.pubkey} tried to send an \"auth_url\"='${error}' but there was no onauth() callback configured.`,\n )\n }\n return\n }\n\n let handler = listeners[id]\n if (handler) {\n if (error) handler.reject(error)\n else if (result) handler.resolve(result)\n delete listeners[id]\n }\n },\n onclose: () => {\n this.subCloser = undefined\n },\n },\n )\n this.isOpen = true\n }\n\n async switchRelays(): Promise<boolean> {\n try {\n const switchResp = await this.sendRequest('switch_relays', [])\n let relays = JSON.parse(switchResp) as string[] | null\n if (!relays) return false\n if (JSON.stringify(relays.sort()) === JSON.stringify(this.bp.relays)) return false\n\n this.bp.relays = relays\n let previousCloser = this.subCloser!\n setTimeout(() => {\n previousCloser.close()\n }, 5000)\n\n this.subCloser = undefined\n this.setupSubscription()\n return true\n } catch {\n return false\n }\n }\n\n // closes the subscription -- this object can't be used anymore after this\n async close() {\n this.isOpen = false\n this.subCloser!.close()\n }\n\n async sendRequest(method: string, params: string[]): Promise<string> {\n return new Promise(async (resolve, reject) => {\n try {\n if (!this.isOpen) throw new Error('this signer is not open anymore, create a new one')\n if (!this.subCloser) this.setupSubscription()\n\n this.serial++\n const id = `${this.idPrefix}-${this.serial}`\n\n const encryptedContent = encrypt(JSON.stringify({ id, method, params }), this.conversationKey)\n\n // the request event\n const verifiedEvent: VerifiedEvent = finalizeEvent(\n {\n kind: NostrConnect,\n tags: [['p', this.bp.pubkey]],\n content: encryptedContent,\n created_at: Math.floor(Date.now() / 1000),\n },\n this.secretKey,\n )\n\n // setup callback listener\n this.listeners[id] = { resolve, reject }\n this.waitingForAuth[id] = true\n\n // publish the event\n await Promise.any(this.pool.publish(this.bp.relays, verifiedEvent))\n } catch (err) {\n reject(err)\n }\n })\n }\n\n /**\n * Calls the \"connect\" method on the bunker.\n * The promise will be rejected if the response is not \"pong\".\n */\n async ping(): Promise<void> {\n let resp = await this.sendRequest('ping', [])\n if (resp !== 'pong') throw new Error(`result is not pong: ${resp}`)\n }\n\n /**\n * Calls the \"connect\" method on the bunker.\n */\n async connect(): Promise<void> {\n await this.sendRequest('connect', [this.bp.pubkey, this.bp.secret || ''])\n }\n\n /**\n * Calls the \"get_public_key\" method on the bunker.\n * (before we would return the public key hardcoded in the bunker parameters, but\n * that is not correct as that may be the bunker pubkey and the actual signer\n * pubkey may be different.)\n */\n async getPublicKey(): Promise<string> {\n if (!this.cachedPubKey) {\n this.cachedPubKey = await this.sendRequest('get_public_key', [])\n }\n return this.cachedPubKey\n }\n\n /**\n * Signs an event using the remote private key.\n * @param event - The event to sign.\n * @returns A Promise that resolves to the signed event.\n */\n async signEvent(event: EventTemplate): Promise<VerifiedEvent> {\n let resp = await this.sendRequest('sign_event', [JSON.stringify(event)])\n let signed: NostrEvent = JSON.parse(resp)\n if (verifyEvent(signed)) {\n return signed\n } else {\n throw new Error(`event returned from bunker is improperly signed: ${JSON.stringify(signed)}`)\n }\n }\n\n async nip04Encrypt(thirdPartyPubkey: string, plaintext: string): Promise<string> {\n return await this.sendRequest('nip04_encrypt', [thirdPartyPubkey, plaintext])\n }\n\n async nip04Decrypt(thirdPartyPubkey: string, ciphertext: string): Promise<string> {\n return await this.sendRequest('nip04_decrypt', [thirdPartyPubkey, ciphertext])\n }\n\n async nip44Encrypt(thirdPartyPubkey: string, plaintext: string): Promise<string> {\n return await this.sendRequest('nip44_encrypt', [thirdPartyPubkey, plaintext])\n }\n\n async nip44Decrypt(thirdPartyPubkey: string, ciphertext: string): Promise<string> {\n return await this.sendRequest('nip44_decrypt', [thirdPartyPubkey, ciphertext])\n }\n}\n\n/**\n * Creates an account with the specified username, domain, and optional email.\n * @param bunkerPubkey - The public key of the bunker to use for the create_account call.\n * @param username - The username for the account.\n * @param domain - The domain for the account.\n * @param email - The optional email for the account.\n * @param localSecretKey - Optionally pass a local secret key that will be used to communicate with the bunker,\n this will default to generating a random key.\n * @throws Error if the email is present but invalid.\n * @returns A Promise that resolves to the auth_url that the client should follow to create an account.\n */\nexport async function createAccount(\n bunker: BunkerProfile,\n params: BunkerSignerParams,\n username: string,\n domain: string,\n email?: string,\n localSecretKey: Uint8Array = generateSecretKey(),\n): Promise<BunkerSigner> {\n if (email && !EMAIL_REGEX.test(email)) throw new Error('invalid email')\n\n let rpc = BunkerSigner.fromBunker(localSecretKey, bunker.bunkerPointer, params)\n\n let pubkey = await rpc.sendRequest('create_account', [username, domain, email || ''])\n\n // once we get the newly created pubkey back, we hijack this signer instance\n // and turn it into the main instance for this newly created pubkey\n rpc.bp.pubkey = pubkey\n await rpc.connect()\n\n return rpc\n}\n\n/**\n * Fetches info on available providers that announce themselves using NIP-89 events.\n * @returns A promise that resolves to an array of available bunker objects.\n */\nexport async function fetchBunkerProviders(pool: AbstractSimplePool, relays: string[]): Promise<BunkerProfile[]> {\n const events = await pool.querySync(relays, {\n kinds: [Handlerinformation],\n '#k': [NostrConnect.toString()],\n })\n\n events.sort((a, b) => b.created_at - a.created_at)\n\n // validate bunkers by checking their NIP-05 and pubkey\n // map to a more useful object\n const validatedBunkers = await Promise.all(\n events.map(async (event, i) => {\n try {\n const content = JSON.parse(event.content)\n\n // skip duplicates\n try {\n if (events.findIndex(ev => JSON.parse(ev.content).nip05 === content.nip05) !== i) return undefined\n } catch (err) {\n /***/\n }\n\n const bp = await queryBunkerProfile(content.nip05)\n if (bp && bp.pubkey === event.pubkey && bp.relays.length) {\n return {\n bunkerPointer: bp,\n nip05: content.nip05,\n domain: content.nip05.split('@')[1],\n name: content.name || content.display_name,\n picture: content.picture,\n about: content.about,\n website: content.website,\n local: false,\n }\n }\n } catch (err) {\n return undefined\n }\n }),\n )\n\n return validatedBunkers.filter(b => b !== undefined) as BunkerProfile[]\n}\n\nexport type BunkerProfile = {\n bunkerPointer: BunkerPointer\n domain: string\n nip05: string\n name: string\n picture: string\n about: string\n website: string\n local: boolean\n}\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { chacha20 } from '@noble/ciphers/chacha.js'\nimport { equalBytes } from '@noble/ciphers/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf.js'\nimport { hmac } from '@noble/hashes/hmac.js'\nimport { sha256 } from '@noble/hashes/sha2.js'\nimport { concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes('02' + pubkeyB)).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, utf8Encoder.encode('nip44-v2'))\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import { ProfilePointer } from './nip19.ts'\n\nexport type Nip05 = `${string}@${string}`\n\n/**\n * NIP-05 regex. The localpart is optional, and should be assumed to be `_` otherwise.\n *\n * - 0: full match\n * - 1: name (optional)\n * - 2: domain\n */\nexport const NIP05_REGEX = /^(?:([\\w.+-]+)@)?([\\w_-]+(\\.[\\w_-]+)+)$/\nexport const isNip05 = (value?: string | null): value is Nip05 => NIP05_REGEX.test(value || '')\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _fetch: any\n\ntry {\n _fetch = fetch\n} catch (_) {\n null\n}\n\nexport function useFetchImplementation(fetchImplementation: unknown) {\n _fetch = fetchImplementation\n}\n\nexport async function searchDomain(domain: string, query = ''): Promise<{ [name: string]: string }> {\n try {\n const url = `https://${domain}/.well-known/nostr.json?name=${query}`\n const res = await _fetch(url, { redirect: 'manual' })\n if (res.status !== 200) {\n throw Error('Wrong response code')\n }\n const json = await res.json()\n return json.names\n } catch (_) {\n return {}\n }\n}\n\nexport async function queryProfile(fullname: string): Promise<ProfilePointer | null> {\n const match = fullname.match(NIP05_REGEX)\n if (!match) return null\n\n const [, name = '_', domain] = match\n\n try {\n const url = `https://${domain}/.well-known/nostr.json?name=${name}`\n const res = await _fetch(url, { redirect: 'manual' })\n if (res.status !== 200) {\n throw Error('Wrong response code')\n }\n const json = await res.json()\n\n const pubkey = json.names[name]\n return pubkey ? { pubkey, relays: json.relays?.[pubkey] } : null\n } catch (_e) {\n return null\n }\n}\n\nexport async function isValid(pubkey: string, nip05: Nip05): Promise<boolean> {\n const res = await queryProfile(nip05)\n return res ? res.pubkey === pubkey : false\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n", "/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractSimplePool, type AbstractPoolConstructorOptions } from './abstract-pool.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class SimplePool extends AbstractSimplePool {\n constructor(options?: Pick<AbstractPoolConstructorOptions, 'enablePing' | 'enableReconnect'>) {\n super({ verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n}\n\nexport * from './abstract-pool.ts'\n"],
+ "mappings": "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",
+ "names": ["import_utils", "i", "target", "import_utils", "import_secp256k1", "import_sha2", "hkdf_extract", "hkdf_expand", "i", "i", "reason", "_fetch", "resolve", "i"]
} Index: package/lib/esm/nip46.js.map
===================================================================
--- package/lib/esm/nip46.js.map
+++ package/lib/esm/nip46.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../pure.ts", "../../core.ts", "../../utils.ts", "../../nip44.ts", "../../nip05.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts", "../../helpers.ts", "../../abstract-relay.ts", "../../abstract-pool.ts", "../../pool.ts", "../../nip46.ts"],
- "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { chacha20 } from '@noble/ciphers/chacha'\nimport { equalBytes } from '@noble/ciphers/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf'\nimport { hmac } from '@noble/hashes/hmac'\nimport { sha256 } from '@noble/hashes/sha256'\nimport { concatBytes, randomBytes } from '@noble/hashes/utils'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, 'nip44-v2')\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import { ProfilePointer } from './nip19.ts'\n\nexport type Nip05 = `${string}@${string}`\n\n/**\n * NIP-05 regex. The localpart is optional, and should be assumed to be `_` otherwise.\n *\n * - 0: full match\n * - 1: name (optional)\n * - 2: domain\n */\nexport const NIP05_REGEX = /^(?:([\\w.+-]+)@)?([\\w_-]+(\\.[\\w_-]+)+)$/\nexport const isNip05 = (value?: string | null): value is Nip05 => NIP05_REGEX.test(value || '')\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _fetch: any\n\ntry {\n _fetch = fetch\n} catch (_) {\n null\n}\n\nexport function useFetchImplementation(fetchImplementation: unknown) {\n _fetch = fetchImplementation\n}\n\nexport async function searchDomain(domain: string, query = ''): Promise<{ [name: string]: string }> {\n try {\n const url = `https://${domain}/.well-known/nostr.json?name=${query}`\n const res = await _fetch(url, { redirect: 'manual' })\n if (res.status !== 200) {\n throw Error('Wrong response code')\n }\n const json = await res.json()\n return json.names\n } catch (_) {\n return {}\n }\n}\n\nexport async function queryProfile(fullname: string): Promise<ProfilePointer | null> {\n const match = fullname.match(NIP05_REGEX)\n if (!match) return null\n\n const [, name = '_', domain] = match\n\n try {\n const url = `https://${domain}/.well-known/nostr.json?name=${name}`\n const res = await _fetch(url, { redirect: 'manual' })\n if (res.status !== 200) {\n throw Error('Wrong response code')\n }\n const json = await res.json()\n\n const pubkey = json.names[name]\n return pubkey ? { pubkey, relays: json.relays?.[pubkey] } : null\n } catch (_e) {\n return null\n }\n}\n\nexport async function isValid(pubkey: string, nip05: Nip05): Promise<boolean> {\n const res = await queryProfile(nip05)\n return res ? res.pubkey === pubkey : false\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n", "/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractSimplePool, type AbstractPoolConstructorOptions } from './abstract-pool.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class SimplePool extends AbstractSimplePool {\n constructor(options?: Pick<AbstractPoolConstructorOptions, 'enablePing' | 'enableReconnect'>) {\n super({ verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n}\n\nexport * from './abstract-pool.ts'\n", "import { EventTemplate, NostrEvent, VerifiedEvent } from './core.ts'\nimport { generateSecretKey, finalizeEvent, getPublicKey, verifyEvent } from './pure.ts'\nimport { AbstractSimplePool, SubCloser } from './abstract-pool.ts'\nimport { getConversationKey, decrypt, encrypt } from './nip44.ts'\nimport { NIP05_REGEX } from './nip05.ts'\nimport { SimplePool } from './pool.ts'\nimport { Handlerinformation, NostrConnect } from './kinds.ts'\nimport { Signer } from './signer.ts'\n\nvar _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any) {\n _fetch = fetchImplementation\n}\n\nexport const BUNKER_REGEX = /^bunker:\\/\\/([0-9a-f]{64})\\??([?\\/\\w:.=&%-]*)$/\nconst EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\nexport type BunkerPointer = {\n relays: string[]\n pubkey: string\n secret: null | string\n}\n\nexport function toBunkerURL(bunkerPointer: BunkerPointer): string {\n let bunkerURL = new URL(`bunker://${bunkerPointer.pubkey}`)\n bunkerPointer.relays.forEach(relay => {\n bunkerURL.searchParams.append('relay', relay)\n })\n if (bunkerPointer.secret) {\n bunkerURL.searchParams.set('secret', bunkerPointer.secret)\n }\n return bunkerURL.toString()\n}\n\n/** This takes either a bunker:// URL or a [email protected] NIP-05 identifier\n and returns a BunkerPointer -- or null in case of error */\nexport async function parseBunkerInput(input: string): Promise<BunkerPointer | null> {\n let match = input.match(BUNKER_REGEX)\n if (match) {\n try {\n const pubkey = match[1]\n const qs = new URLSearchParams(match[2])\n return {\n pubkey,\n relays: qs.getAll('relay'),\n secret: qs.get('secret'),\n }\n } catch (_err) {\n /* just move to the next case */\n }\n }\n\n return queryBunkerProfile(input)\n}\n\nexport async function queryBunkerProfile(nip05: string): Promise<BunkerPointer | null> {\n const match = nip05.match(NIP05_REGEX)\n if (!match) return null\n\n const [_, name = '_', domain] = match\n\n try {\n const url = `https://${domain}/.well-known/nostr.json?name=${name}`\n const res = await (await _fetch(url, { redirect: 'error' })).json()\n\n let pubkey = res.names[name]\n let relays = res.nip46[pubkey] || []\n\n return { pubkey, relays, secret: null }\n } catch (_err) {\n return null\n }\n}\n\nexport type NostrConnectParams = {\n clientPubkey: string\n relays: string[]\n secret: string\n perms?: string[]\n name?: string\n url?: string\n image?: string\n}\n\nexport function createNostrConnectURI(params: NostrConnectParams): string {\n const queryParams = new URLSearchParams()\n\n params.relays.forEach(relay => {\n queryParams.append('relay', relay)\n })\n\n queryParams.append('secret', params.secret)\n\n if (params.perms && params.perms.length > 0) {\n queryParams.append('perms', params.perms.join(','))\n }\n if (params.name) {\n queryParams.append('name', params.name)\n }\n if (params.url) {\n queryParams.append('url', params.url)\n }\n if (params.image) {\n queryParams.append('image', params.image)\n }\n\n return `nostrconnect://${params.clientPubkey}?${queryParams.toString()}`\n}\n\nexport type BunkerSignerParams = {\n pool?: AbstractSimplePool\n onauth?: (url: string) => void\n}\n\nexport class BunkerSigner implements Signer {\n private params: BunkerSignerParams\n private pool: AbstractSimplePool\n private subCloser: SubCloser | undefined\n private isOpen: boolean\n private serial: number\n private idPrefix: string\n private listeners: {\n [id: string]: {\n resolve: (_: string) => void\n reject: (_: string) => void\n }\n }\n private waitingForAuth: { [id: string]: boolean }\n private secretKey: Uint8Array\n // If the client initiates the connection, the two variables below can be filled in later.\n private conversationKey!: Uint8Array\n public bp!: BunkerPointer\n\n private cachedPubKey: string | undefined\n\n /**\n * Creates a new instance of the Nip46 class.\n * @param relays - An array of relay addresses.\n * @param remotePubkey - An optional remote public key. This is the key you want to sign as.\n * @param secretKey - An optional key pair.\n */\n private constructor(clientSecretKey: Uint8Array, params: BunkerSignerParams) {\n this.params = params\n this.pool = params.pool || new SimplePool()\n this.secretKey = clientSecretKey\n this.isOpen = false\n this.idPrefix = Math.random().toString(36).substring(7)\n this.serial = 0\n this.listeners = {}\n this.waitingForAuth = {}\n }\n\n /**\n * [Factory Method 1] Creates a Signer using bunker information (bunker:// URL or NIP-05).\n * This method is used when the public key of the bunker is known in advance.\n */\n public static fromBunker(\n clientSecretKey: Uint8Array,\n bp: BunkerPointer,\n params: BunkerSignerParams = {},\n ): BunkerSigner {\n if (bp.relays.length === 0) {\n throw new Error('no relays specified for this bunker')\n }\n\n const signer = new BunkerSigner(clientSecretKey, params)\n\n signer.conversationKey = getConversationKey(clientSecretKey, bp.pubkey)\n signer.bp = bp\n\n signer.setupSubscription()\n return signer\n }\n\n /**\n * [Factory Method 2] Creates a Signer using a nostrconnect:// URI generated by the client.\n * In this method, the bunker initiates the connection by scanning the URI.\n */\n public static async fromURI(\n clientSecretKey: Uint8Array,\n connectionURI: string,\n bunkerParams: BunkerSignerParams = {},\n maxWaitOrAbort: number | AbortSignal = 300_000,\n ): Promise<BunkerSigner> {\n const signer = new BunkerSigner(clientSecretKey, bunkerParams)\n const uri = new URL(connectionURI)\n const clientPubkey = getPublicKey(clientSecretKey)\n\n return new Promise((resolve, reject) => {\n let success = false\n const sub = signer.pool.subscribe(\n uri.searchParams.getAll('relay'),\n {\n kinds: [NostrConnect],\n '#p': [clientPubkey],\n limit: 0,\n },\n {\n onevent: async (event: NostrEvent) => {\n try {\n const tempConvKey = getConversationKey(clientSecretKey, event.pubkey)\n const decryptedContent = decrypt(event.content, tempConvKey)\n\n const response = JSON.parse(decryptedContent)\n\n if (response.result === uri.searchParams.get('secret')) {\n sub.close()\n\n signer.bp = {\n pubkey: event.pubkey,\n relays: uri.searchParams.getAll('relay'),\n secret: uri.searchParams.get('secret'),\n }\n signer.conversationKey = getConversationKey(clientSecretKey, event.pubkey)\n signer.setupSubscription()\n\n success = true\n await Promise.race([new Promise(resolve => setTimeout(resolve, 1000)), signer.switchRelays()])\n resolve(signer)\n }\n } catch (e) {\n console.warn('failed to process potential connection event', e)\n }\n },\n onclose: () => {\n if (!success) reject(new Error('subscription closed before connection was established.'))\n },\n maxWait: typeof maxWaitOrAbort === 'number' ? maxWaitOrAbort : undefined,\n abort: typeof maxWaitOrAbort !== 'number' ? maxWaitOrAbort : undefined,\n },\n )\n })\n }\n\n private setupSubscription() {\n const listeners = this.listeners\n const waitingForAuth = this.waitingForAuth\n const convKey = this.conversationKey\n\n this.subCloser = this.pool.subscribe(\n this.bp.relays,\n {\n kinds: [NostrConnect],\n authors: [this.bp.pubkey],\n '#p': [getPublicKey(this.secretKey)],\n limit: 0,\n },\n {\n onevent: async (event: NostrEvent) => {\n const o = JSON.parse(decrypt(event.content, convKey))\n const { id, result, error } = o\n\n if (result === 'auth_url' && waitingForAuth[id]) {\n delete waitingForAuth[id]\n\n if (this.params.onauth) {\n this.params.onauth(error)\n } else {\n console.warn(\n `nostr-tools/nip46: remote signer ${this.bp.pubkey} tried to send an \"auth_url\"='${error}' but there was no onauth() callback configured.`,\n )\n }\n return\n }\n\n let handler = listeners[id]\n if (handler) {\n if (error) handler.reject(error)\n else if (result) handler.resolve(result)\n delete listeners[id]\n }\n },\n onclose: () => {\n this.subCloser = undefined\n },\n },\n )\n this.isOpen = true\n }\n\n async switchRelays(): Promise<boolean> {\n try {\n const switchResp = await this.sendRequest('switch_relays', [])\n let relays = JSON.parse(switchResp) as string[] | null\n if (!relays) return false\n if (JSON.stringify(relays.sort()) === JSON.stringify(this.bp.relays)) return false\n\n this.bp.relays = relays\n let previousCloser = this.subCloser!\n setTimeout(() => {\n previousCloser.close()\n }, 5000)\n\n this.subCloser = undefined\n this.setupSubscription()\n return true\n } catch {\n return false\n }\n }\n\n // closes the subscription -- this object can't be used anymore after this\n async close() {\n this.isOpen = false\n this.subCloser!.close()\n }\n\n async sendRequest(method: string, params: string[]): Promise<string> {\n return new Promise(async (resolve, reject) => {\n try {\n if (!this.isOpen) throw new Error('this signer is not open anymore, create a new one')\n if (!this.subCloser) this.setupSubscription()\n\n this.serial++\n const id = `${this.idPrefix}-${this.serial}`\n\n const encryptedContent = encrypt(JSON.stringify({ id, method, params }), this.conversationKey)\n\n // the request event\n const verifiedEvent: VerifiedEvent = finalizeEvent(\n {\n kind: NostrConnect,\n tags: [['p', this.bp.pubkey]],\n content: encryptedContent,\n created_at: Math.floor(Date.now() / 1000),\n },\n this.secretKey,\n )\n\n // setup callback listener\n this.listeners[id] = { resolve, reject }\n this.waitingForAuth[id] = true\n\n // publish the event\n await Promise.any(this.pool.publish(this.bp.relays, verifiedEvent))\n } catch (err) {\n reject(err)\n }\n })\n }\n\n /**\n * Calls the \"connect\" method on the bunker.\n * The promise will be rejected if the response is not \"pong\".\n */\n async ping(): Promise<void> {\n let resp = await this.sendRequest('ping', [])\n if (resp !== 'pong') throw new Error(`result is not pong: ${resp}`)\n }\n\n /**\n * Calls the \"connect\" method on the bunker.\n */\n async connect(): Promise<void> {\n await this.sendRequest('connect', [this.bp.pubkey, this.bp.secret || ''])\n }\n\n /**\n * Calls the \"get_public_key\" method on the bunker.\n * (before we would return the public key hardcoded in the bunker parameters, but\n * that is not correct as that may be the bunker pubkey and the actual signer\n * pubkey may be different.)\n */\n async getPublicKey(): Promise<string> {\n if (!this.cachedPubKey) {\n this.cachedPubKey = await this.sendRequest('get_public_key', [])\n }\n return this.cachedPubKey\n }\n\n /**\n * Signs an event using the remote private key.\n * @param event - The event to sign.\n * @returns A Promise that resolves to the signed event.\n */\n async signEvent(event: EventTemplate): Promise<VerifiedEvent> {\n let resp = await this.sendRequest('sign_event', [JSON.stringify(event)])\n let signed: NostrEvent = JSON.parse(resp)\n if (verifyEvent(signed)) {\n return signed\n } else {\n throw new Error(`event returned from bunker is improperly signed: ${JSON.stringify(signed)}`)\n }\n }\n\n async nip04Encrypt(thirdPartyPubkey: string, plaintext: string): Promise<string> {\n return await this.sendRequest('nip04_encrypt', [thirdPartyPubkey, plaintext])\n }\n\n async nip04Decrypt(thirdPartyPubkey: string, ciphertext: string): Promise<string> {\n return await this.sendRequest('nip04_decrypt', [thirdPartyPubkey, ciphertext])\n }\n\n async nip44Encrypt(thirdPartyPubkey: string, plaintext: string): Promise<string> {\n return await this.sendRequest('nip44_encrypt', [thirdPartyPubkey, plaintext])\n }\n\n async nip44Decrypt(thirdPartyPubkey: string, ciphertext: string): Promise<string> {\n return await this.sendRequest('nip44_decrypt', [thirdPartyPubkey, ciphertext])\n }\n}\n\n/**\n * Creates an account with the specified username, domain, and optional email.\n * @param bunkerPubkey - The public key of the bunker to use for the create_account call.\n * @param username - The username for the account.\n * @param domain - The domain for the account.\n * @param email - The optional email for the account.\n * @param localSecretKey - Optionally pass a local secret key that will be used to communicate with the bunker,\n this will default to generating a random key.\n * @throws Error if the email is present but invalid.\n * @returns A Promise that resolves to the auth_url that the client should follow to create an account.\n */\nexport async function createAccount(\n bunker: BunkerProfile,\n params: BunkerSignerParams,\n username: string,\n domain: string,\n email?: string,\n localSecretKey: Uint8Array = generateSecretKey(),\n): Promise<BunkerSigner> {\n if (email && !EMAIL_REGEX.test(email)) throw new Error('invalid email')\n\n let rpc = BunkerSigner.fromBunker(localSecretKey, bunker.bunkerPointer, params)\n\n let pubkey = await rpc.sendRequest('create_account', [username, domain, email || ''])\n\n // once we get the newly created pubkey back, we hijack this signer instance\n // and turn it into the main instance for this newly created pubkey\n rpc.bp.pubkey = pubkey\n await rpc.connect()\n\n return rpc\n}\n\n/**\n * Fetches info on available providers that announce themselves using NIP-89 events.\n * @returns A promise that resolves to an array of available bunker objects.\n */\nexport async function fetchBunkerProviders(pool: AbstractSimplePool, relays: string[]): Promise<BunkerProfile[]> {\n const events = await pool.querySync(relays, {\n kinds: [Handlerinformation],\n '#k': [NostrConnect.toString()],\n })\n\n events.sort((a, b) => b.created_at - a.created_at)\n\n // validate bunkers by checking their NIP-05 and pubkey\n // map to a more useful object\n const validatedBunkers = await Promise.all(\n events.map(async (event, i) => {\n try {\n const content = JSON.parse(event.content)\n\n // skip duplicates\n try {\n if (events.findIndex(ev => JSON.parse(ev.content).nip05 === content.nip05) !== i) return undefined\n } catch (err) {\n /***/\n }\n\n const bp = await queryBunkerProfile(content.nip05)\n if (bp && bp.pubkey === event.pubkey && bp.relays.length) {\n return {\n bunkerPointer: bp,\n nip05: content.nip05,\n domain: content.nip05.split('@')[1],\n name: content.name || content.display_name,\n picture: content.picture,\n about: content.about,\n website: content.website,\n local: false,\n }\n }\n } catch (err) {\n return undefined\n }\n }),\n )\n\n return validatedBunkers.filter(b => b !== undefined) as BunkerProfile[]\n}\n\nexport type BunkerProfile = {\n bunkerPointer: BunkerPointer\n domain: string\n nip05: string\n name: string\n picture: string\n about: string\n website: string\n local: boolean\n}\n"],
- "mappings": "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",
- "names": ["bytesToHex", "i", "target", "bytesToHex", "sha256", "sha256", "i", "i", "reason", "_fetch", "resolve", "i"]
+ "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { chacha20 } from '@noble/ciphers/chacha.js'\nimport { equalBytes } from '@noble/ciphers/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf.js'\nimport { hmac } from '@noble/hashes/hmac.js'\nimport { sha256 } from '@noble/hashes/sha2.js'\nimport { concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes('02' + pubkeyB)).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, utf8Encoder.encode('nip44-v2'))\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import { ProfilePointer } from './nip19.ts'\n\nexport type Nip05 = `${string}@${string}`\n\n/**\n * NIP-05 regex. The localpart is optional, and should be assumed to be `_` otherwise.\n *\n * - 0: full match\n * - 1: name (optional)\n * - 2: domain\n */\nexport const NIP05_REGEX = /^(?:([\\w.+-]+)@)?([\\w_-]+(\\.[\\w_-]+)+)$/\nexport const isNip05 = (value?: string | null): value is Nip05 => NIP05_REGEX.test(value || '')\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nlet _fetch: any\n\ntry {\n _fetch = fetch\n} catch (_) {\n null\n}\n\nexport function useFetchImplementation(fetchImplementation: unknown) {\n _fetch = fetchImplementation\n}\n\nexport async function searchDomain(domain: string, query = ''): Promise<{ [name: string]: string }> {\n try {\n const url = `https://${domain}/.well-known/nostr.json?name=${query}`\n const res = await _fetch(url, { redirect: 'manual' })\n if (res.status !== 200) {\n throw Error('Wrong response code')\n }\n const json = await res.json()\n return json.names\n } catch (_) {\n return {}\n }\n}\n\nexport async function queryProfile(fullname: string): Promise<ProfilePointer | null> {\n const match = fullname.match(NIP05_REGEX)\n if (!match) return null\n\n const [, name = '_', domain] = match\n\n try {\n const url = `https://${domain}/.well-known/nostr.json?name=${name}`\n const res = await _fetch(url, { redirect: 'manual' })\n if (res.status !== 200) {\n throw Error('Wrong response code')\n }\n const json = await res.json()\n\n const pubkey = json.names[name]\n return pubkey ? { pubkey, relays: json.relays?.[pubkey] } : null\n } catch (_e) {\n return null\n }\n}\n\nexport async function isValid(pubkey: string, nip05: Nip05): Promise<boolean> {\n const res = await queryProfile(nip05)\n return res ? res.pubkey === pubkey : false\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n", "/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractSimplePool, type AbstractPoolConstructorOptions } from './abstract-pool.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class SimplePool extends AbstractSimplePool {\n constructor(options?: Pick<AbstractPoolConstructorOptions, 'enablePing' | 'enableReconnect'>) {\n super({ verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n}\n\nexport * from './abstract-pool.ts'\n", "import { EventTemplate, NostrEvent, VerifiedEvent } from './core.ts'\nimport { generateSecretKey, finalizeEvent, getPublicKey, verifyEvent } from './pure.ts'\nimport { AbstractSimplePool, SubCloser } from './abstract-pool.ts'\nimport { getConversationKey, decrypt, encrypt } from './nip44.ts'\nimport { NIP05_REGEX } from './nip05.ts'\nimport { SimplePool } from './pool.ts'\nimport { Handlerinformation, NostrConnect } from './kinds.ts'\nimport { Signer } from './signer.ts'\n\nvar _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any) {\n _fetch = fetchImplementation\n}\n\nexport const BUNKER_REGEX = /^bunker:\\/\\/([0-9a-f]{64})\\??([?\\/\\w:.=&%-]*)$/\nconst EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\nexport type BunkerPointer = {\n relays: string[]\n pubkey: string\n secret: null | string\n}\n\nexport function toBunkerURL(bunkerPointer: BunkerPointer): string {\n let bunkerURL = new URL(`bunker://${bunkerPointer.pubkey}`)\n bunkerPointer.relays.forEach(relay => {\n bunkerURL.searchParams.append('relay', relay)\n })\n if (bunkerPointer.secret) {\n bunkerURL.searchParams.set('secret', bunkerPointer.secret)\n }\n return bunkerURL.toString()\n}\n\n/** This takes either a bunker:// URL or a [email protected] NIP-05 identifier\n and returns a BunkerPointer -- or null in case of error */\nexport async function parseBunkerInput(input: string): Promise<BunkerPointer | null> {\n let match = input.match(BUNKER_REGEX)\n if (match) {\n try {\n const pubkey = match[1]\n const qs = new URLSearchParams(match[2])\n return {\n pubkey,\n relays: qs.getAll('relay'),\n secret: qs.get('secret'),\n }\n } catch (_err) {\n /* just move to the next case */\n }\n }\n\n return queryBunkerProfile(input)\n}\n\nexport async function queryBunkerProfile(nip05: string): Promise<BunkerPointer | null> {\n const match = nip05.match(NIP05_REGEX)\n if (!match) return null\n\n const [_, name = '_', domain] = match\n\n try {\n const url = `https://${domain}/.well-known/nostr.json?name=${name}`\n const res = await (await _fetch(url, { redirect: 'error' })).json()\n\n let pubkey = res.names[name]\n let relays = res.nip46[pubkey] || []\n\n return { pubkey, relays, secret: null }\n } catch (_err) {\n return null\n }\n}\n\nexport type NostrConnectParams = {\n clientPubkey: string\n relays: string[]\n secret: string\n perms?: string[]\n name?: string\n url?: string\n image?: string\n}\n\nexport function createNostrConnectURI(params: NostrConnectParams): string {\n const queryParams = new URLSearchParams()\n\n params.relays.forEach(relay => {\n queryParams.append('relay', relay)\n })\n\n queryParams.append('secret', params.secret)\n\n if (params.perms && params.perms.length > 0) {\n queryParams.append('perms', params.perms.join(','))\n }\n if (params.name) {\n queryParams.append('name', params.name)\n }\n if (params.url) {\n queryParams.append('url', params.url)\n }\n if (params.image) {\n queryParams.append('image', params.image)\n }\n\n return `nostrconnect://${params.clientPubkey}?${queryParams.toString()}`\n}\n\nexport type BunkerSignerParams = {\n pool?: AbstractSimplePool\n onauth?: (url: string) => void\n}\n\nexport class BunkerSigner implements Signer {\n private params: BunkerSignerParams\n private pool: AbstractSimplePool\n private subCloser: SubCloser | undefined\n private isOpen: boolean\n private serial: number\n private idPrefix: string\n private listeners: {\n [id: string]: {\n resolve: (_: string) => void\n reject: (_: string) => void\n }\n }\n private waitingForAuth: { [id: string]: boolean }\n private secretKey: Uint8Array\n // If the client initiates the connection, the two variables below can be filled in later.\n private conversationKey!: Uint8Array\n public bp!: BunkerPointer\n\n private cachedPubKey: string | undefined\n\n /**\n * Creates a new instance of the Nip46 class.\n * @param relays - An array of relay addresses.\n * @param remotePubkey - An optional remote public key. This is the key you want to sign as.\n * @param secretKey - An optional key pair.\n */\n private constructor(clientSecretKey: Uint8Array, params: BunkerSignerParams) {\n this.params = params\n this.pool = params.pool || new SimplePool()\n this.secretKey = clientSecretKey\n this.isOpen = false\n this.idPrefix = Math.random().toString(36).substring(7)\n this.serial = 0\n this.listeners = {}\n this.waitingForAuth = {}\n }\n\n /**\n * [Factory Method 1] Creates a Signer using bunker information (bunker:// URL or NIP-05).\n * This method is used when the public key of the bunker is known in advance.\n */\n public static fromBunker(\n clientSecretKey: Uint8Array,\n bp: BunkerPointer,\n params: BunkerSignerParams = {},\n ): BunkerSigner {\n if (bp.relays.length === 0) {\n throw new Error('no relays specified for this bunker')\n }\n\n const signer = new BunkerSigner(clientSecretKey, params)\n\n signer.conversationKey = getConversationKey(clientSecretKey, bp.pubkey)\n signer.bp = bp\n\n signer.setupSubscription()\n return signer\n }\n\n /**\n * [Factory Method 2] Creates a Signer using a nostrconnect:// URI generated by the client.\n * In this method, the bunker initiates the connection by scanning the URI.\n */\n public static async fromURI(\n clientSecretKey: Uint8Array,\n connectionURI: string,\n bunkerParams: BunkerSignerParams = {},\n maxWaitOrAbort: number | AbortSignal = 300_000,\n ): Promise<BunkerSigner> {\n const signer = new BunkerSigner(clientSecretKey, bunkerParams)\n const uri = new URL(connectionURI)\n const clientPubkey = getPublicKey(clientSecretKey)\n\n return new Promise((resolve, reject) => {\n let success = false\n const sub = signer.pool.subscribe(\n uri.searchParams.getAll('relay'),\n {\n kinds: [NostrConnect],\n '#p': [clientPubkey],\n limit: 0,\n },\n {\n onevent: async (event: NostrEvent) => {\n try {\n const tempConvKey = getConversationKey(clientSecretKey, event.pubkey)\n const decryptedContent = decrypt(event.content, tempConvKey)\n\n const response = JSON.parse(decryptedContent)\n\n if (response.result === uri.searchParams.get('secret')) {\n sub.close()\n\n signer.bp = {\n pubkey: event.pubkey,\n relays: uri.searchParams.getAll('relay'),\n secret: uri.searchParams.get('secret'),\n }\n signer.conversationKey = getConversationKey(clientSecretKey, event.pubkey)\n signer.setupSubscription()\n\n success = true\n await Promise.race([new Promise(resolve => setTimeout(resolve, 1000)), signer.switchRelays()])\n resolve(signer)\n }\n } catch (e) {\n console.warn('failed to process potential connection event', e)\n }\n },\n onclose: () => {\n if (!success) reject(new Error('subscription closed before connection was established.'))\n },\n maxWait: typeof maxWaitOrAbort === 'number' ? maxWaitOrAbort : undefined,\n abort: typeof maxWaitOrAbort !== 'number' ? maxWaitOrAbort : undefined,\n },\n )\n })\n }\n\n private setupSubscription() {\n const listeners = this.listeners\n const waitingForAuth = this.waitingForAuth\n const convKey = this.conversationKey\n\n this.subCloser = this.pool.subscribe(\n this.bp.relays,\n {\n kinds: [NostrConnect],\n authors: [this.bp.pubkey],\n '#p': [getPublicKey(this.secretKey)],\n limit: 0,\n },\n {\n onevent: async (event: NostrEvent) => {\n const o = JSON.parse(decrypt(event.content, convKey))\n const { id, result, error } = o\n\n if (result === 'auth_url' && waitingForAuth[id]) {\n delete waitingForAuth[id]\n\n if (this.params.onauth) {\n this.params.onauth(error)\n } else {\n console.warn(\n `nostr-tools/nip46: remote signer ${this.bp.pubkey} tried to send an \"auth_url\"='${error}' but there was no onauth() callback configured.`,\n )\n }\n return\n }\n\n let handler = listeners[id]\n if (handler) {\n if (error) handler.reject(error)\n else if (result) handler.resolve(result)\n delete listeners[id]\n }\n },\n onclose: () => {\n this.subCloser = undefined\n },\n },\n )\n this.isOpen = true\n }\n\n async switchRelays(): Promise<boolean> {\n try {\n const switchResp = await this.sendRequest('switch_relays', [])\n let relays = JSON.parse(switchResp) as string[] | null\n if (!relays) return false\n if (JSON.stringify(relays.sort()) === JSON.stringify(this.bp.relays)) return false\n\n this.bp.relays = relays\n let previousCloser = this.subCloser!\n setTimeout(() => {\n previousCloser.close()\n }, 5000)\n\n this.subCloser = undefined\n this.setupSubscription()\n return true\n } catch {\n return false\n }\n }\n\n // closes the subscription -- this object can't be used anymore after this\n async close() {\n this.isOpen = false\n this.subCloser!.close()\n }\n\n async sendRequest(method: string, params: string[]): Promise<string> {\n return new Promise(async (resolve, reject) => {\n try {\n if (!this.isOpen) throw new Error('this signer is not open anymore, create a new one')\n if (!this.subCloser) this.setupSubscription()\n\n this.serial++\n const id = `${this.idPrefix}-${this.serial}`\n\n const encryptedContent = encrypt(JSON.stringify({ id, method, params }), this.conversationKey)\n\n // the request event\n const verifiedEvent: VerifiedEvent = finalizeEvent(\n {\n kind: NostrConnect,\n tags: [['p', this.bp.pubkey]],\n content: encryptedContent,\n created_at: Math.floor(Date.now() / 1000),\n },\n this.secretKey,\n )\n\n // setup callback listener\n this.listeners[id] = { resolve, reject }\n this.waitingForAuth[id] = true\n\n // publish the event\n await Promise.any(this.pool.publish(this.bp.relays, verifiedEvent))\n } catch (err) {\n reject(err)\n }\n })\n }\n\n /**\n * Calls the \"connect\" method on the bunker.\n * The promise will be rejected if the response is not \"pong\".\n */\n async ping(): Promise<void> {\n let resp = await this.sendRequest('ping', [])\n if (resp !== 'pong') throw new Error(`result is not pong: ${resp}`)\n }\n\n /**\n * Calls the \"connect\" method on the bunker.\n */\n async connect(): Promise<void> {\n await this.sendRequest('connect', [this.bp.pubkey, this.bp.secret || ''])\n }\n\n /**\n * Calls the \"get_public_key\" method on the bunker.\n * (before we would return the public key hardcoded in the bunker parameters, but\n * that is not correct as that may be the bunker pubkey and the actual signer\n * pubkey may be different.)\n */\n async getPublicKey(): Promise<string> {\n if (!this.cachedPubKey) {\n this.cachedPubKey = await this.sendRequest('get_public_key', [])\n }\n return this.cachedPubKey\n }\n\n /**\n * Signs an event using the remote private key.\n * @param event - The event to sign.\n * @returns A Promise that resolves to the signed event.\n */\n async signEvent(event: EventTemplate): Promise<VerifiedEvent> {\n let resp = await this.sendRequest('sign_event', [JSON.stringify(event)])\n let signed: NostrEvent = JSON.parse(resp)\n if (verifyEvent(signed)) {\n return signed\n } else {\n throw new Error(`event returned from bunker is improperly signed: ${JSON.stringify(signed)}`)\n }\n }\n\n async nip04Encrypt(thirdPartyPubkey: string, plaintext: string): Promise<string> {\n return await this.sendRequest('nip04_encrypt', [thirdPartyPubkey, plaintext])\n }\n\n async nip04Decrypt(thirdPartyPubkey: string, ciphertext: string): Promise<string> {\n return await this.sendRequest('nip04_decrypt', [thirdPartyPubkey, ciphertext])\n }\n\n async nip44Encrypt(thirdPartyPubkey: string, plaintext: string): Promise<string> {\n return await this.sendRequest('nip44_encrypt', [thirdPartyPubkey, plaintext])\n }\n\n async nip44Decrypt(thirdPartyPubkey: string, ciphertext: string): Promise<string> {\n return await this.sendRequest('nip44_decrypt', [thirdPartyPubkey, ciphertext])\n }\n}\n\n/**\n * Creates an account with the specified username, domain, and optional email.\n * @param bunkerPubkey - The public key of the bunker to use for the create_account call.\n * @param username - The username for the account.\n * @param domain - The domain for the account.\n * @param email - The optional email for the account.\n * @param localSecretKey - Optionally pass a local secret key that will be used to communicate with the bunker,\n this will default to generating a random key.\n * @throws Error if the email is present but invalid.\n * @returns A Promise that resolves to the auth_url that the client should follow to create an account.\n */\nexport async function createAccount(\n bunker: BunkerProfile,\n params: BunkerSignerParams,\n username: string,\n domain: string,\n email?: string,\n localSecretKey: Uint8Array = generateSecretKey(),\n): Promise<BunkerSigner> {\n if (email && !EMAIL_REGEX.test(email)) throw new Error('invalid email')\n\n let rpc = BunkerSigner.fromBunker(localSecretKey, bunker.bunkerPointer, params)\n\n let pubkey = await rpc.sendRequest('create_account', [username, domain, email || ''])\n\n // once we get the newly created pubkey back, we hijack this signer instance\n // and turn it into the main instance for this newly created pubkey\n rpc.bp.pubkey = pubkey\n await rpc.connect()\n\n return rpc\n}\n\n/**\n * Fetches info on available providers that announce themselves using NIP-89 events.\n * @returns A promise that resolves to an array of available bunker objects.\n */\nexport async function fetchBunkerProviders(pool: AbstractSimplePool, relays: string[]): Promise<BunkerProfile[]> {\n const events = await pool.querySync(relays, {\n kinds: [Handlerinformation],\n '#k': [NostrConnect.toString()],\n })\n\n events.sort((a, b) => b.created_at - a.created_at)\n\n // validate bunkers by checking their NIP-05 and pubkey\n // map to a more useful object\n const validatedBunkers = await Promise.all(\n events.map(async (event, i) => {\n try {\n const content = JSON.parse(event.content)\n\n // skip duplicates\n try {\n if (events.findIndex(ev => JSON.parse(ev.content).nip05 === content.nip05) !== i) return undefined\n } catch (err) {\n /***/\n }\n\n const bp = await queryBunkerProfile(content.nip05)\n if (bp && bp.pubkey === event.pubkey && bp.relays.length) {\n return {\n bunkerPointer: bp,\n nip05: content.nip05,\n domain: content.nip05.split('@')[1],\n name: content.name || content.display_name,\n picture: content.picture,\n about: content.about,\n website: content.website,\n local: false,\n }\n }\n } catch (err) {\n return undefined\n }\n }),\n )\n\n return validatedBunkers.filter(b => b !== undefined) as BunkerProfile[]\n}\n\nexport type BunkerProfile = {\n bunkerPointer: BunkerPointer\n domain: string\n nip05: string\n name: string\n picture: string\n about: string\n website: string\n local: boolean\n}\n"],
+ "mappings": "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",
+ "names": ["bytesToHex", "hexToBytes", "i", "target", "bytesToHex", "hexToBytes", "sha256", "hexToBytes", "hexToBytes", "sha256", "i", "i", "reason", "_fetch", "resolve", "i"]
} Index: package/lib/cjs/nip47.js.map
===================================================================
--- package/lib/cjs/nip47.js.map
+++ package/lib/cjs/nip47.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip47.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../nip04.ts"],
- "sourcesContent": ["import { type VerifiedEvent, finalizeEvent } from './pure.ts'\nimport { NWCWalletRequest } from './kinds.ts'\nimport { encrypt } from './nip04.ts'\n\ninterface NWCConnection {\n pubkey: string\n relay: string\n secret: string\n}\n\nexport function parseConnectionString(connectionString: string): NWCConnection {\n const { host, pathname, searchParams } = new URL(connectionString)\n const pubkey = pathname || host\n const relay = searchParams.get('relay')\n const secret = searchParams.get('secret')\n\n if (!pubkey || !relay || !secret) {\n throw new Error('invalid connection string')\n }\n\n return { pubkey, relay, secret }\n}\n\nexport async function makeNwcRequestEvent(\n pubkey: string,\n secretKey: Uint8Array,\n invoice: string,\n): Promise<VerifiedEvent> {\n const content = {\n method: 'pay_invoice',\n params: {\n invoice,\n },\n }\n const encryptedContent = encrypt(secretKey, pubkey, JSON.stringify(content))\n const eventTemplate = {\n kind: NWCWalletRequest,\n created_at: Math.round(Date.now() / 1000),\n content: encryptedContent,\n tags: [['p', pubkey]],\n }\n\n return finalizeEvent(eventTemplate, secretKey)\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { bytesToHex, randomBytes } from '@noble/hashes/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { cbc } from '@noble/ciphers/aes'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport function encrypt(secretKey: string | Uint8Array, pubkey: string, text: string): string {\n const privkey: string = secretKey instanceof Uint8Array ? bytesToHex(secretKey) : secretKey\n const key = secp256k1.getSharedSecret(privkey, '02' + pubkey)\n const normalizedKey = getNormalizedX(key)\n\n let iv = Uint8Array.from(randomBytes(16))\n let plaintext = utf8Encoder.encode(text)\n\n let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext)\n\n let ctb64 = base64.encode(new Uint8Array(ciphertext))\n let ivb64 = base64.encode(new Uint8Array(iv.buffer))\n\n return `${ctb64}?iv=${ivb64}`\n}\n\nexport function decrypt(secretKey: string | Uint8Array, pubkey: string, data: string): string {\n const privkey: string = secretKey instanceof Uint8Array ? bytesToHex(secretKey) : secretKey\n let [ctb64, ivb64] = data.split('?iv=')\n let key = secp256k1.getSharedSecret(privkey, '02' + pubkey)\n let normalizedKey = getNormalizedX(key)\n\n let iv = base64.decode(ivb64)\n let ciphertext = base64.decode(ctb64)\n\n let plaintext = cbc(normalizedKey, iv).decrypt(ciphertext)\n\n return utf8Decoder.decode(plaintext)\n}\n\nfunction getNormalizedX(key: Uint8Array): Uint8Array {\n return key.slice(1, 33)\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { type VerifiedEvent, finalizeEvent } from './pure.ts'\nimport { NWCWalletRequest } from './kinds.ts'\nimport { encrypt } from './nip04.ts'\n\ninterface NWCConnection {\n pubkey: string\n relay: string\n secret: string\n}\n\nexport function parseConnectionString(connectionString: string): NWCConnection {\n const { host, pathname, searchParams } = new URL(connectionString)\n const pubkey = pathname || host\n const relay = searchParams.get('relay')\n const secret = searchParams.get('secret')\n\n if (!pubkey || !relay || !secret) {\n throw new Error('invalid connection string')\n }\n\n return { pubkey, relay, secret }\n}\n\nexport async function makeNwcRequestEvent(\n pubkey: string,\n secretKey: Uint8Array,\n invoice: string,\n): Promise<VerifiedEvent> {\n const content = {\n method: 'pay_invoice',\n params: {\n invoice,\n },\n }\n const encryptedContent = encrypt(secretKey, pubkey, JSON.stringify(content))\n const eventTemplate = {\n kind: NWCWalletRequest,\n created_at: Math.round(Date.now() / 1000),\n content: encryptedContent,\n tags: [['p', pubkey]],\n }\n\n return finalizeEvent(eventTemplate, secretKey)\n}\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { cbc } from '@noble/ciphers/aes.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport function encrypt(secretKey: string | Uint8Array, pubkey: string, text: string): string {\n const privkey: Uint8Array = secretKey instanceof Uint8Array ? secretKey : hexToBytes(secretKey)\n const key = secp256k1.getSharedSecret(privkey, hexToBytes('02' + pubkey))\n const normalizedKey = getNormalizedX(key)\n\n let iv = Uint8Array.from(randomBytes(16))\n let plaintext = utf8Encoder.encode(text)\n\n let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext)\n\n let ctb64 = base64.encode(new Uint8Array(ciphertext))\n let ivb64 = base64.encode(new Uint8Array(iv.buffer))\n\n return `${ctb64}?iv=${ivb64}`\n}\n\nexport function decrypt(secretKey: string | Uint8Array, pubkey: string, data: string): string {\n const privkey: Uint8Array = secretKey instanceof Uint8Array ? secretKey : hexToBytes(secretKey)\n let [ctb64, ivb64] = data.split('?iv=')\n let key = secp256k1.getSharedSecret(privkey, hexToBytes('02' + pubkey))\n let normalizedKey = getNormalizedX(key)\n\n let iv = base64.decode(ivb64)\n let ciphertext = base64.decode(ctb64)\n\n let plaintext = cbc(normalizedKey, iv).decrypt(ciphertext)\n\n return utf8Decoder.decode(plaintext)\n}\n\nfunction getNormalizedX(key: Uint8Array): Uint8Array {\n return key.slice(1, 33)\n}\n"],
+ "mappings": "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",
"names": ["import_utils", "i", "import_utils", "import_secp256k1"]
} Index: package/lib/esm/nip47.js.map
===================================================================
--- package/lib/esm/nip47.js.map
+++ package/lib/esm/nip47.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../nip04.ts", "../../nip47.ts"],
- "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { bytesToHex, randomBytes } from '@noble/hashes/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { cbc } from '@noble/ciphers/aes'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport function encrypt(secretKey: string | Uint8Array, pubkey: string, text: string): string {\n const privkey: string = secretKey instanceof Uint8Array ? bytesToHex(secretKey) : secretKey\n const key = secp256k1.getSharedSecret(privkey, '02' + pubkey)\n const normalizedKey = getNormalizedX(key)\n\n let iv = Uint8Array.from(randomBytes(16))\n let plaintext = utf8Encoder.encode(text)\n\n let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext)\n\n let ctb64 = base64.encode(new Uint8Array(ciphertext))\n let ivb64 = base64.encode(new Uint8Array(iv.buffer))\n\n return `${ctb64}?iv=${ivb64}`\n}\n\nexport function decrypt(secretKey: string | Uint8Array, pubkey: string, data: string): string {\n const privkey: string = secretKey instanceof Uint8Array ? bytesToHex(secretKey) : secretKey\n let [ctb64, ivb64] = data.split('?iv=')\n let key = secp256k1.getSharedSecret(privkey, '02' + pubkey)\n let normalizedKey = getNormalizedX(key)\n\n let iv = base64.decode(ivb64)\n let ciphertext = base64.decode(ctb64)\n\n let plaintext = cbc(normalizedKey, iv).decrypt(ciphertext)\n\n return utf8Decoder.decode(plaintext)\n}\n\nfunction getNormalizedX(key: Uint8Array): Uint8Array {\n return key.slice(1, 33)\n}\n", "import { type VerifiedEvent, finalizeEvent } from './pure.ts'\nimport { NWCWalletRequest } from './kinds.ts'\nimport { encrypt } from './nip04.ts'\n\ninterface NWCConnection {\n pubkey: string\n relay: string\n secret: string\n}\n\nexport function parseConnectionString(connectionString: string): NWCConnection {\n const { host, pathname, searchParams } = new URL(connectionString)\n const pubkey = pathname || host\n const relay = searchParams.get('relay')\n const secret = searchParams.get('secret')\n\n if (!pubkey || !relay || !secret) {\n throw new Error('invalid connection string')\n }\n\n return { pubkey, relay, secret }\n}\n\nexport async function makeNwcRequestEvent(\n pubkey: string,\n secretKey: Uint8Array,\n invoice: string,\n): Promise<VerifiedEvent> {\n const content = {\n method: 'pay_invoice',\n params: {\n invoice,\n },\n }\n const encryptedContent = encrypt(secretKey, pubkey, JSON.stringify(content))\n const eventTemplate = {\n kind: NWCWalletRequest,\n created_at: Math.round(Date.now() / 1000),\n content: encryptedContent,\n tags: [['p', pubkey]],\n }\n\n return finalizeEvent(eventTemplate, secretKey)\n}\n"],
- "mappings": ";AAAA,SAAS,eAAe;AACxB,SAAS,cAAAA,mBAAkB;;;ACOpB,IAAM,iBAAiB,OAAO,UAAU;AAsB/C,IAAM,WAAW,CAAC,QAAiD,eAAe;AAE3E,SAAS,cAAiB,OAAsC;AACrE,MAAI,CAAC,SAAS,KAAK;AAAG,WAAO;AAC7B,MAAI,OAAO,MAAM,SAAS;AAAU,WAAO;AAC3C,MAAI,OAAO,MAAM,YAAY;AAAU,WAAO;AAC9C,MAAI,OAAO,MAAM,eAAe;AAAU,WAAO;AACjD,MAAI,OAAO,MAAM,WAAW;AAAU,WAAO;AAC7C,MAAI,CAAC,MAAM,OAAO,MAAM,gBAAgB;AAAG,WAAO;AAElD,MAAI,CAAC,MAAM,QAAQ,MAAM,IAAI;AAAG,WAAO;AACvC,WAASC,KAAI,GAAGA,KAAI,MAAM,KAAK,QAAQA,MAAK;AAC1C,QAAI,MAAM,MAAM,KAAKA;AACrB,QAAI,CAAC,MAAM,QAAQ,GAAG;AAAG,aAAO;AAChC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAI,OAAO,IAAI,OAAO;AAAU,eAAO;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AACT;;;AD/CA,SAAS,cAAc;;;AEEvB,SAAS,YAAY,kBAAkB;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;AFIxD,IAAM,KAAN,MAA0B;AAAA,EACxB,oBAAgC;AAC9B,WAAO,QAAQ,MAAM,iBAAiB;AAAA,EACxC;AAAA,EACA,aAAa,WAA+B;AAC1C,WAAOC,YAAW,QAAQ,aAAa,SAAS,CAAC;AAAA,EACnD;AAAA,EACA,cAAc,GAAkB,WAAsC;AACpE,UAAM,QAAQ;AACd,UAAM,SAASA,YAAW,QAAQ,aAAa,SAAS,CAAC;AACzD,UAAM,KAAK,aAAa,KAAK;AAC7B,UAAM,MAAMA,YAAW,QAAQ,KAAK,aAAa,KAAK,GAAG,SAAS,CAAC;AACnE,UAAM,kBAAkB;AACxB,WAAO;AAAA,EACT;AAAA,EACA,YAAY,OAAsC;AAChD,QAAI,OAAO,MAAM,oBAAoB;AAAW,aAAO,MAAM;AAE7D,UAAM,OAAO,aAAa,KAAK;AAC/B,QAAI,SAAS,MAAM,IAAI;AACrB,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,QAAQ,QAAQ,OAAO,MAAM,KAAK,MAAM,MAAM,MAAM;AAC1D,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT,SAAS,KAAP;AACA,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,eAAe,KAA4B;AACzD,MAAI,CAAC,cAAc,GAAG;AAAG,UAAM,IAAI,MAAM,wDAAwD;AACjG,SAAO,KAAK,UAAU,CAAC,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,CAAC;AACxF;AAEO,SAAS,aAAa,OAA8B;AACzD,MAAI,YAAY,OAAO,YAAY,OAAO,eAAe,KAAK,CAAC,CAAC;AAChE,SAAOA,YAAW,SAAS;AAC7B;AAEA,IAAM,IAAQ,IAAI,GAAG;AAEd,IAAM,oBAAoB,EAAE;AAC5B,IAAM,eAAe,EAAE;AACvB,IAAM,gBAAgB,EAAE;AACxB,IAAM,cAAc,EAAE;;;AGwGtB,IAAM,mBAAmB;;;ACjKhC,SAAS,cAAAC,aAAY,mBAAmB;AACxC,SAAS,iBAAiB;AAC1B,SAAS,WAAW;AACpB,SAAS,cAAc;AAIhB,SAAS,QAAQ,WAAgC,QAAgB,MAAsB;AAC5F,QAAM,UAAkB,qBAAqB,aAAaC,YAAW,SAAS,IAAI;AAClF,QAAM,MAAM,UAAU,gBAAgB,SAAS,OAAO,MAAM;AAC5D,QAAM,gBAAgB,eAAe,GAAG;AAExC,MAAI,KAAK,WAAW,KAAK,YAAY,EAAE,CAAC;AACxC,MAAI,YAAY,YAAY,OAAO,IAAI;AAEvC,MAAI,aAAa,IAAI,eAAe,EAAE,EAAE,QAAQ,SAAS;AAEzD,MAAI,QAAQ,OAAO,OAAO,IAAI,WAAW,UAAU,CAAC;AACpD,MAAI,QAAQ,OAAO,OAAO,IAAI,WAAW,GAAG,MAAM,CAAC;AAEnD,SAAO,GAAG,YAAY;AACxB;AAgBA,SAAS,eAAe,KAA6B;AACnD,SAAO,IAAI,MAAM,GAAG,EAAE;AACxB;;;AC7BO,SAAS,sBAAsB,kBAAyC;AAC7E,QAAM,EAAE,MAAM,UAAU,aAAa,IAAI,IAAI,IAAI,gBAAgB;AACjE,QAAM,SAAS,YAAY;AAC3B,QAAM,QAAQ,aAAa,IAAI,OAAO;AACtC,QAAM,SAAS,aAAa,IAAI,QAAQ;AAExC,MAAI,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ;AAChC,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC7C;AAEA,SAAO,EAAE,QAAQ,OAAO,OAAO;AACjC;AAEA,eAAsB,oBACpB,QACA,WACA,SACwB;AACxB,QAAM,UAAU;AAAA,IACd,QAAQ;AAAA,IACR,QAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AACA,QAAM,mBAAmB,QAAQ,WAAW,QAAQ,KAAK,UAAU,OAAO,CAAC;AAC3E,QAAM,gBAAgB;AAAA,IACpB,MAAM;AAAA,IACN,YAAY,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAAA,IACxC,SAAS;AAAA,IACT,MAAM,CAAC,CAAC,KAAK,MAAM,CAAC;AAAA,EACtB;AAEA,SAAO,cAAc,eAAe,SAAS;AAC/C;",
- "names": ["bytesToHex", "i", "bytesToHex", "bytesToHex", "bytesToHex"]
+ "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { cbc } from '@noble/ciphers/aes.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport function encrypt(secretKey: string | Uint8Array, pubkey: string, text: string): string {\n const privkey: Uint8Array = secretKey instanceof Uint8Array ? secretKey : hexToBytes(secretKey)\n const key = secp256k1.getSharedSecret(privkey, hexToBytes('02' + pubkey))\n const normalizedKey = getNormalizedX(key)\n\n let iv = Uint8Array.from(randomBytes(16))\n let plaintext = utf8Encoder.encode(text)\n\n let ciphertext = cbc(normalizedKey, iv).encrypt(plaintext)\n\n let ctb64 = base64.encode(new Uint8Array(ciphertext))\n let ivb64 = base64.encode(new Uint8Array(iv.buffer))\n\n return `${ctb64}?iv=${ivb64}`\n}\n\nexport function decrypt(secretKey: string | Uint8Array, pubkey: string, data: string): string {\n const privkey: Uint8Array = secretKey instanceof Uint8Array ? secretKey : hexToBytes(secretKey)\n let [ctb64, ivb64] = data.split('?iv=')\n let key = secp256k1.getSharedSecret(privkey, hexToBytes('02' + pubkey))\n let normalizedKey = getNormalizedX(key)\n\n let iv = base64.decode(ivb64)\n let ciphertext = base64.decode(ctb64)\n\n let plaintext = cbc(normalizedKey, iv).decrypt(ciphertext)\n\n return utf8Decoder.decode(plaintext)\n}\n\nfunction getNormalizedX(key: Uint8Array): Uint8Array {\n return key.slice(1, 33)\n}\n", "import { type VerifiedEvent, finalizeEvent } from './pure.ts'\nimport { NWCWalletRequest } from './kinds.ts'\nimport { encrypt } from './nip04.ts'\n\ninterface NWCConnection {\n pubkey: string\n relay: string\n secret: string\n}\n\nexport function parseConnectionString(connectionString: string): NWCConnection {\n const { host, pathname, searchParams } = new URL(connectionString)\n const pubkey = pathname || host\n const relay = searchParams.get('relay')\n const secret = searchParams.get('secret')\n\n if (!pubkey || !relay || !secret) {\n throw new Error('invalid connection string')\n }\n\n return { pubkey, relay, secret }\n}\n\nexport async function makeNwcRequestEvent(\n pubkey: string,\n secretKey: Uint8Array,\n invoice: string,\n): Promise<VerifiedEvent> {\n const content = {\n method: 'pay_invoice',\n params: {\n invoice,\n },\n }\n const encryptedContent = encrypt(secretKey, pubkey, JSON.stringify(content))\n const eventTemplate = {\n kind: NWCWalletRequest,\n created_at: Math.round(Date.now() / 1000),\n content: encryptedContent,\n tags: [['p', pubkey]],\n }\n\n return finalizeEvent(eventTemplate, secretKey)\n}\n"],
+ "mappings": "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",
+ "names": ["bytesToHex", "hexToBytes", "i", "bytesToHex", "hexToBytes", "hexToBytes", "hexToBytes"]
} Index: package/lib/cjs/nip49.js.map
===================================================================
--- package/lib/cjs/nip49.js.map
+++ package/lib/cjs/nip49.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip49.ts", "../../nip19.ts"],
- "sourcesContent": ["import { scrypt } from '@noble/hashes/scrypt'\nimport { xchacha20poly1305 } from '@noble/ciphers/chacha'\nimport { concatBytes, randomBytes } from '@noble/hashes/utils'\nimport { Bech32MaxSize, Ncryptsec, encodeBytes } from './nip19.ts'\nimport { bech32 } from '@scure/base'\n\nexport function encrypt(\n sec: Uint8Array,\n password: string,\n logn: number = 16,\n ksb: 0x00 | 0x01 | 0x02 = 0x02,\n): Ncryptsec {\n let salt = randomBytes(16)\n let n = 2 ** logn\n let key = scrypt(password.normalize('NFKC'), salt, { N: n, r: 8, p: 1, dkLen: 32 })\n let nonce = randomBytes(24)\n let aad = Uint8Array.from([ksb])\n let xc2p1 = xchacha20poly1305(key, nonce, aad)\n let ciphertext = xc2p1.encrypt(sec)\n let b = concatBytes(Uint8Array.from([0x02]), Uint8Array.from([logn]), salt, nonce, aad, ciphertext)\n return encodeBytes('ncryptsec', b)\n}\n\nexport function decrypt(ncryptsec: string, password: string): Uint8Array {\n let { prefix, words } = bech32.decode(ncryptsec, Bech32MaxSize)\n if (prefix !== 'ncryptsec') {\n throw new Error(`invalid prefix ${prefix}, expected 'ncryptsec'`)\n }\n let b = new Uint8Array(bech32.fromWords(words))\n\n let version = b[0]\n if (version !== 0x02) {\n throw new Error(`invalid version ${version}, expected 0x02`)\n }\n\n let logn = b[1]\n let n = 2 ** logn\n\n let salt = b.slice(2, 2 + 16)\n let nonce = b.slice(2 + 16, 2 + 16 + 24)\n let ksb = b[2 + 16 + 24]\n let aad = Uint8Array.from([ksb])\n let ciphertext = b.slice(2 + 16 + 24 + 1)\n\n let key = scrypt(password.normalize('NFKC'), salt, { N: n, r: 8, p: 1, dkLen: 32 })\n let xc2p1 = xchacha20poly1305(key, nonce, aad)\n let sec = xc2p1.decrypt(ciphertext)\n\n return sec\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n"],
- "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAuB;AACvB,oBAAkC;AAClC,IAAAA,gBAAyC;;;ACFzC,mBAAoD;AACpD,kBAAuB;AAsBhB,IAAM,gBAAgB;AAwL7B,SAAS,aAAoC,QAAgB,MAAyC;AACpG,MAAI,QAAQ,mBAAO,QAAQ,IAAI;AAC/B,SAAO,mBAAO,OAAO,QAAQ,OAAO,aAAa;AACnD;AAEO,SAAS,YAAmC,QAAgB,OAA0C;AAC3G,SAAO,aAAa,QAAQ,KAAK;AACnC;;;ADlNA,IAAAC,eAAuB;AAEhB,SAAS,QACd,KACA,UACA,OAAe,IACf,MAA0B,GACf;AACX,MAAI,WAAO,2BAAY,EAAE;AACzB,MAAI,IAAI,KAAK;AACb,MAAI,UAAM,sBAAO,SAAS,UAAU,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,CAAC;AAClF,MAAI,YAAQ,2BAAY,EAAE;AAC1B,MAAI,MAAM,WAAW,KAAK,CAAC,GAAG,CAAC;AAC/B,MAAI,YAAQ,iCAAkB,KAAK,OAAO,GAAG;AAC7C,MAAI,aAAa,MAAM,QAAQ,GAAG;AAClC,MAAI,QAAI,2BAAY,WAAW,KAAK,CAAC,CAAI,CAAC,GAAG,WAAW,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,OAAO,KAAK,UAAU;AAClG,SAAO,YAAY,aAAa,CAAC;AACnC;AAEO,SAAS,QAAQ,WAAmB,UAA8B;AACvE,MAAI,EAAE,QAAQ,MAAM,IAAI,oBAAO,OAAO,WAAW,aAAa;AAC9D,MAAI,WAAW,aAAa;AAC1B,UAAM,IAAI,MAAM,kBAAkB,8BAA8B;AAAA,EAClE;AACA,MAAI,IAAI,IAAI,WAAW,oBAAO,UAAU,KAAK,CAAC;AAE9C,MAAI,UAAU,EAAE;AAChB,MAAI,YAAY,GAAM;AACpB,UAAM,IAAI,MAAM,mBAAmB,wBAAwB;AAAA,EAC7D;AAEA,MAAI,OAAO,EAAE;AACb,MAAI,IAAI,KAAK;AAEb,MAAI,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE;AAC5B,MAAI,QAAQ,EAAE,MAAM,IAAI,IAAI,IAAI,KAAK,EAAE;AACvC,MAAI,MAAM,EAAE,IAAI,KAAK;AACrB,MAAI,MAAM,WAAW,KAAK,CAAC,GAAG,CAAC;AAC/B,MAAI,aAAa,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC;AAExC,MAAI,UAAM,sBAAO,SAAS,UAAU,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,CAAC;AAClF,MAAI,YAAQ,iCAAkB,KAAK,OAAO,GAAG;AAC7C,MAAI,MAAM,MAAM,QAAQ,UAAU;AAElC,SAAO;AACT;",
- "names": ["import_utils", "import_base"]
+ "sourcesContent": ["import { bech32 } from '@scure/base'\nimport { scrypt } from '@noble/hashes/scrypt.js'\nimport { xchacha20poly1305 } from '@noble/ciphers/chacha.js'\nimport { concatBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { Bech32MaxSize, Ncryptsec, encodeBytes } from './nip19.ts'\n\nexport function encrypt(\n sec: Uint8Array,\n password: string,\n logn: number = 16,\n ksb: 0x00 | 0x01 | 0x02 = 0x02,\n): Ncryptsec {\n let salt = randomBytes(16)\n let n = 2 ** logn\n let key = scrypt(password.normalize('NFKC'), salt, { N: n, r: 8, p: 1, dkLen: 32 })\n let nonce = randomBytes(24)\n let aad = Uint8Array.from([ksb])\n let xc2p1 = xchacha20poly1305(key, nonce, aad)\n let ciphertext = xc2p1.encrypt(sec)\n let b = concatBytes(Uint8Array.from([0x02]), Uint8Array.from([logn]), salt, nonce, aad, ciphertext)\n return encodeBytes('ncryptsec', b)\n}\n\nexport function decrypt(ncryptsec: string, password: string): Uint8Array {\n let { prefix, words } = bech32.decode(ncryptsec as `${string}1${string}`, Bech32MaxSize)\n if (prefix !== 'ncryptsec') {\n throw new Error(`invalid prefix ${prefix}, expected 'ncryptsec'`)\n }\n let b = new Uint8Array(bech32.fromWords(words))\n\n let version = b[0]\n if (version !== 0x02) {\n throw new Error(`invalid version ${version}, expected 0x02`)\n }\n\n let logn = b[1]\n let n = 2 ** logn\n\n let salt = b.slice(2, 2 + 16)\n let nonce = b.slice(2 + 16, 2 + 16 + 24)\n let ksb = b[2 + 16 + 24]\n let aad = Uint8Array.from([ksb])\n let ciphertext = b.slice(2 + 16 + 24 + 1)\n\n let key = scrypt(password.normalize('NFKC'), salt, { N: n, r: 8, p: 1, dkLen: 32 })\n let xc2p1 = xchacha20poly1305(key, nonce, aad)\n let sec = xc2p1.decrypt(ciphertext)\n\n return sec\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n"],
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,eAAuB;AACvB,oBAAuB;AACvB,oBAAkC;AAClC,IAAAC,gBAAyC;;;ACHzC,mBAAoD;AACpD,kBAAuB;AAsBhB,IAAM,gBAAgB;AAwL7B,SAAS,aAAoC,QAAgB,MAAyC;AACpG,MAAI,QAAQ,mBAAO,QAAQ,IAAI;AAC/B,SAAO,mBAAO,OAAO,QAAQ,OAAO,aAAa;AACnD;AAEO,SAAS,YAAmC,QAAgB,OAA0C;AAC3G,SAAO,aAAa,QAAQ,KAAK;AACnC;;;ADhNO,SAAS,QACd,KACA,UACA,OAAe,IACf,MAA0B,GACf;AACX,MAAI,WAAO,2BAAY,EAAE;AACzB,MAAI,IAAI,KAAK;AACb,MAAI,UAAM,sBAAO,SAAS,UAAU,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,CAAC;AAClF,MAAI,YAAQ,2BAAY,EAAE;AAC1B,MAAI,MAAM,WAAW,KAAK,CAAC,GAAG,CAAC;AAC/B,MAAI,YAAQ,iCAAkB,KAAK,OAAO,GAAG;AAC7C,MAAI,aAAa,MAAM,QAAQ,GAAG;AAClC,MAAI,QAAI,2BAAY,WAAW,KAAK,CAAC,CAAI,CAAC,GAAG,WAAW,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,OAAO,KAAK,UAAU;AAClG,SAAO,YAAY,aAAa,CAAC;AACnC;AAEO,SAAS,QAAQ,WAAmB,UAA8B;AACvE,MAAI,EAAE,QAAQ,MAAM,IAAI,oBAAO,OAAO,WAAoC,aAAa;AACvF,MAAI,WAAW,aAAa;AAC1B,UAAM,IAAI,MAAM,kBAAkB,8BAA8B;AAAA,EAClE;AACA,MAAI,IAAI,IAAI,WAAW,oBAAO,UAAU,KAAK,CAAC;AAE9C,MAAI,UAAU,EAAE;AAChB,MAAI,YAAY,GAAM;AACpB,UAAM,IAAI,MAAM,mBAAmB,wBAAwB;AAAA,EAC7D;AAEA,MAAI,OAAO,EAAE;AACb,MAAI,IAAI,KAAK;AAEb,MAAI,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE;AAC5B,MAAI,QAAQ,EAAE,MAAM,IAAI,IAAI,IAAI,KAAK,EAAE;AACvC,MAAI,MAAM,EAAE,IAAI,KAAK;AACrB,MAAI,MAAM,WAAW,KAAK,CAAC,GAAG,CAAC;AAC/B,MAAI,aAAa,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC;AAExC,MAAI,UAAM,sBAAO,SAAS,UAAU,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,CAAC;AAClF,MAAI,YAAQ,iCAAkB,KAAK,OAAO,GAAG;AAC7C,MAAI,MAAM,MAAM,QAAQ,UAAU;AAElC,SAAO;AACT;",
+ "names": ["import_base", "import_utils"]
} Index: package/lib/esm/nip49.js.map
===================================================================
--- package/lib/esm/nip49.js.map
+++ package/lib/esm/nip49.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip49.ts", "../../nip19.ts"],
- "sourcesContent": ["import { scrypt } from '@noble/hashes/scrypt'\nimport { xchacha20poly1305 } from '@noble/ciphers/chacha'\nimport { concatBytes, randomBytes } from '@noble/hashes/utils'\nimport { Bech32MaxSize, Ncryptsec, encodeBytes } from './nip19.ts'\nimport { bech32 } from '@scure/base'\n\nexport function encrypt(\n sec: Uint8Array,\n password: string,\n logn: number = 16,\n ksb: 0x00 | 0x01 | 0x02 = 0x02,\n): Ncryptsec {\n let salt = randomBytes(16)\n let n = 2 ** logn\n let key = scrypt(password.normalize('NFKC'), salt, { N: n, r: 8, p: 1, dkLen: 32 })\n let nonce = randomBytes(24)\n let aad = Uint8Array.from([ksb])\n let xc2p1 = xchacha20poly1305(key, nonce, aad)\n let ciphertext = xc2p1.encrypt(sec)\n let b = concatBytes(Uint8Array.from([0x02]), Uint8Array.from([logn]), salt, nonce, aad, ciphertext)\n return encodeBytes('ncryptsec', b)\n}\n\nexport function decrypt(ncryptsec: string, password: string): Uint8Array {\n let { prefix, words } = bech32.decode(ncryptsec, Bech32MaxSize)\n if (prefix !== 'ncryptsec') {\n throw new Error(`invalid prefix ${prefix}, expected 'ncryptsec'`)\n }\n let b = new Uint8Array(bech32.fromWords(words))\n\n let version = b[0]\n if (version !== 0x02) {\n throw new Error(`invalid version ${version}, expected 0x02`)\n }\n\n let logn = b[1]\n let n = 2 ** logn\n\n let salt = b.slice(2, 2 + 16)\n let nonce = b.slice(2 + 16, 2 + 16 + 24)\n let ksb = b[2 + 16 + 24]\n let aad = Uint8Array.from([ksb])\n let ciphertext = b.slice(2 + 16 + 24 + 1)\n\n let key = scrypt(password.normalize('NFKC'), salt, { N: n, r: 8, p: 1, dkLen: 32 })\n let xc2p1 = xchacha20poly1305(key, nonce, aad)\n let sec = xc2p1.decrypt(ciphertext)\n\n return sec\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n"],
- "mappings": ";AAAA,SAAS,cAAc;AACvB,SAAS,yBAAyB;AAClC,SAAS,eAAAA,cAAa,mBAAmB;;;ACFzC,SAAS,YAAY,aAAa,kBAAkB;AACpD,SAAS,cAAc;AAsBhB,IAAM,gBAAgB;AAwL7B,SAAS,aAAoC,QAAgB,MAAyC;AACpG,MAAI,QAAQ,OAAO,QAAQ,IAAI;AAC/B,SAAO,OAAO,OAAO,QAAQ,OAAO,aAAa;AACnD;AAEO,SAAS,YAAmC,QAAgB,OAA0C;AAC3G,SAAO,aAAa,QAAQ,KAAK;AACnC;;;ADlNA,SAAS,UAAAC,eAAc;AAEhB,SAAS,QACd,KACA,UACA,OAAe,IACf,MAA0B,GACf;AACX,MAAI,OAAO,YAAY,EAAE;AACzB,MAAI,IAAI,KAAK;AACb,MAAI,MAAM,OAAO,SAAS,UAAU,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,CAAC;AAClF,MAAI,QAAQ,YAAY,EAAE;AAC1B,MAAI,MAAM,WAAW,KAAK,CAAC,GAAG,CAAC;AAC/B,MAAI,QAAQ,kBAAkB,KAAK,OAAO,GAAG;AAC7C,MAAI,aAAa,MAAM,QAAQ,GAAG;AAClC,MAAI,IAAIC,aAAY,WAAW,KAAK,CAAC,CAAI,CAAC,GAAG,WAAW,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,OAAO,KAAK,UAAU;AAClG,SAAO,YAAY,aAAa,CAAC;AACnC;AAEO,SAAS,QAAQ,WAAmB,UAA8B;AACvE,MAAI,EAAE,QAAQ,MAAM,IAAID,QAAO,OAAO,WAAW,aAAa;AAC9D,MAAI,WAAW,aAAa;AAC1B,UAAM,IAAI,MAAM,kBAAkB,8BAA8B;AAAA,EAClE;AACA,MAAI,IAAI,IAAI,WAAWA,QAAO,UAAU,KAAK,CAAC;AAE9C,MAAI,UAAU,EAAE;AAChB,MAAI,YAAY,GAAM;AACpB,UAAM,IAAI,MAAM,mBAAmB,wBAAwB;AAAA,EAC7D;AAEA,MAAI,OAAO,EAAE;AACb,MAAI,IAAI,KAAK;AAEb,MAAI,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE;AAC5B,MAAI,QAAQ,EAAE,MAAM,IAAI,IAAI,IAAI,KAAK,EAAE;AACvC,MAAI,MAAM,EAAE,IAAI,KAAK;AACrB,MAAI,MAAM,WAAW,KAAK,CAAC,GAAG,CAAC;AAC/B,MAAI,aAAa,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC;AAExC,MAAI,MAAM,OAAO,SAAS,UAAU,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,CAAC;AAClF,MAAI,QAAQ,kBAAkB,KAAK,OAAO,GAAG;AAC7C,MAAI,MAAM,MAAM,QAAQ,UAAU;AAElC,SAAO;AACT;",
- "names": ["concatBytes", "bech32", "concatBytes"]
+ "sourcesContent": ["import { bech32 } from '@scure/base'\nimport { scrypt } from '@noble/hashes/scrypt.js'\nimport { xchacha20poly1305 } from '@noble/ciphers/chacha.js'\nimport { concatBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { Bech32MaxSize, Ncryptsec, encodeBytes } from './nip19.ts'\n\nexport function encrypt(\n sec: Uint8Array,\n password: string,\n logn: number = 16,\n ksb: 0x00 | 0x01 | 0x02 = 0x02,\n): Ncryptsec {\n let salt = randomBytes(16)\n let n = 2 ** logn\n let key = scrypt(password.normalize('NFKC'), salt, { N: n, r: 8, p: 1, dkLen: 32 })\n let nonce = randomBytes(24)\n let aad = Uint8Array.from([ksb])\n let xc2p1 = xchacha20poly1305(key, nonce, aad)\n let ciphertext = xc2p1.encrypt(sec)\n let b = concatBytes(Uint8Array.from([0x02]), Uint8Array.from([logn]), salt, nonce, aad, ciphertext)\n return encodeBytes('ncryptsec', b)\n}\n\nexport function decrypt(ncryptsec: string, password: string): Uint8Array {\n let { prefix, words } = bech32.decode(ncryptsec as `${string}1${string}`, Bech32MaxSize)\n if (prefix !== 'ncryptsec') {\n throw new Error(`invalid prefix ${prefix}, expected 'ncryptsec'`)\n }\n let b = new Uint8Array(bech32.fromWords(words))\n\n let version = b[0]\n if (version !== 0x02) {\n throw new Error(`invalid version ${version}, expected 0x02`)\n }\n\n let logn = b[1]\n let n = 2 ** logn\n\n let salt = b.slice(2, 2 + 16)\n let nonce = b.slice(2 + 16, 2 + 16 + 24)\n let ksb = b[2 + 16 + 24]\n let aad = Uint8Array.from([ksb])\n let ciphertext = b.slice(2 + 16 + 24 + 1)\n\n let key = scrypt(password.normalize('NFKC'), salt, { N: n, r: 8, p: 1, dkLen: 32 })\n let xc2p1 = xchacha20poly1305(key, nonce, aad)\n let sec = xc2p1.decrypt(ciphertext)\n\n return sec\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n"],
+ "mappings": ";AAAA,SAAS,UAAAA,eAAc;AACvB,SAAS,cAAc;AACvB,SAAS,yBAAyB;AAClC,SAAS,eAAAC,cAAa,mBAAmB;;;ACHzC,SAAS,YAAY,aAAa,kBAAkB;AACpD,SAAS,cAAc;AAsBhB,IAAM,gBAAgB;AAwL7B,SAAS,aAAoC,QAAgB,MAAyC;AACpG,MAAI,QAAQ,OAAO,QAAQ,IAAI;AAC/B,SAAO,OAAO,OAAO,QAAQ,OAAO,aAAa;AACnD;AAEO,SAAS,YAAmC,QAAgB,OAA0C;AAC3G,SAAO,aAAa,QAAQ,KAAK;AACnC;;;ADhNO,SAAS,QACd,KACA,UACA,OAAe,IACf,MAA0B,GACf;AACX,MAAI,OAAO,YAAY,EAAE;AACzB,MAAI,IAAI,KAAK;AACb,MAAI,MAAM,OAAO,SAAS,UAAU,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,CAAC;AAClF,MAAI,QAAQ,YAAY,EAAE;AAC1B,MAAI,MAAM,WAAW,KAAK,CAAC,GAAG,CAAC;AAC/B,MAAI,QAAQ,kBAAkB,KAAK,OAAO,GAAG;AAC7C,MAAI,aAAa,MAAM,QAAQ,GAAG;AAClC,MAAI,IAAIC,aAAY,WAAW,KAAK,CAAC,CAAI,CAAC,GAAG,WAAW,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,OAAO,KAAK,UAAU;AAClG,SAAO,YAAY,aAAa,CAAC;AACnC;AAEO,SAAS,QAAQ,WAAmB,UAA8B;AACvE,MAAI,EAAE,QAAQ,MAAM,IAAIC,QAAO,OAAO,WAAoC,aAAa;AACvF,MAAI,WAAW,aAAa;AAC1B,UAAM,IAAI,MAAM,kBAAkB,8BAA8B;AAAA,EAClE;AACA,MAAI,IAAI,IAAI,WAAWA,QAAO,UAAU,KAAK,CAAC;AAE9C,MAAI,UAAU,EAAE;AAChB,MAAI,YAAY,GAAM;AACpB,UAAM,IAAI,MAAM,mBAAmB,wBAAwB;AAAA,EAC7D;AAEA,MAAI,OAAO,EAAE;AACb,MAAI,IAAI,KAAK;AAEb,MAAI,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE;AAC5B,MAAI,QAAQ,EAAE,MAAM,IAAI,IAAI,IAAI,KAAK,EAAE;AACvC,MAAI,MAAM,EAAE,IAAI,KAAK;AACrB,MAAI,MAAM,WAAW,KAAK,CAAC,GAAG,CAAC;AAC/B,MAAI,aAAa,EAAE,MAAM,IAAI,KAAK,KAAK,CAAC;AAExC,MAAI,MAAM,OAAO,SAAS,UAAU,MAAM,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,GAAG,CAAC;AAClF,MAAI,QAAQ,kBAAkB,KAAK,OAAO,GAAG;AAC7C,MAAI,MAAM,MAAM,QAAQ,UAAU;AAElC,SAAO;AACT;",
+ "names": ["bech32", "concatBytes", "concatBytes", "bech32"]
} Index: package/lib/cjs/nip57.js.map
===================================================================
--- package/lib/cjs/nip57.js.map
+++ package/lib/cjs/nip57.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip57.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts"],
- "sourcesContent": ["import { bech32 } from '@scure/base'\n\nimport { NostrEvent, validateEvent, verifyEvent, type Event, type EventTemplate } from './pure.ts'\nimport { utf8Decoder } from './utils.ts'\nimport { isReplaceableKind, isAddressableKind } from './kinds.ts'\n\nvar _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any) {\n _fetch = fetchImplementation\n}\n\nexport async function getZapEndpoint(metadata: Event): Promise<null | string> {\n try {\n let lnurl: string = ''\n let { lud06, lud16 } = JSON.parse(metadata.content)\n if (lud16) {\n let [name, domain] = lud16.split('@')\n lnurl = new URL(`/.well-known/lnurlp/${name}`, `https://${domain}`).toString()\n } else if (lud06) {\n let { words } = bech32.decode(lud06, 1000)\n let data = bech32.fromWords(words)\n lnurl = utf8Decoder.decode(data)\n } else {\n return null\n }\n\n let res = await _fetch(lnurl)\n let body = await res.json()\n\n if (body.allowsNostr && body.nostrPubkey) {\n return body.callback\n }\n } catch (err) {\n /*-*/\n }\n\n return null\n}\n\ntype ProfileZap = {\n pubkey: string\n amount: number\n comment?: string\n relays: string[]\n}\n\ntype EventZap = {\n event: NostrEvent\n amount: number\n comment?: string\n relays: string[]\n}\n\nexport function makeZapRequest(params: ProfileZap | EventZap): EventTemplate {\n let zr: EventTemplate = {\n kind: 9734,\n created_at: Math.round(Date.now() / 1000),\n content: params.comment || '',\n tags: [\n ['p', 'pubkey' in params ? params.pubkey : params.event.pubkey],\n ['amount', params.amount.toString()],\n ['relays', ...params.relays],\n ],\n }\n\n if ('event' in params) {\n zr.tags.push(['e', params.event.id])\n if (isReplaceableKind(params.event.kind)) {\n const a = ['a', `${params.event.kind}:${params.event.pubkey}:`]\n zr.tags.push(a)\n } else if (isAddressableKind(params.event.kind)) {\n let d = params.event.tags.find(([t, v]) => t === 'd' && v)\n if (!d) throw new Error('d tag not found or is empty')\n const a = ['a', `${params.event.kind}:${params.event.pubkey}:${d[1]}`]\n zr.tags.push(a)\n }\n zr.tags.push(['k', params.event.kind.toString()])\n }\n\n return zr\n}\n\nexport function validateZapRequest(zapRequestString: string): string | null {\n let zapRequest: Event\n\n try {\n zapRequest = JSON.parse(zapRequestString)\n } catch (err) {\n return 'Invalid zap request JSON.'\n }\n\n if (!validateEvent(zapRequest)) return 'Zap request is not a valid Nostr event.'\n\n if (!verifyEvent(zapRequest)) return 'Invalid signature on zap request.'\n\n let p = zapRequest.tags.find(([t, v]) => t === 'p' && v)\n if (!p) return \"Zap request doesn't have a 'p' tag.\"\n if (!p[1].match(/^[a-f0-9]{64}$/)) return \"Zap request 'p' tag is not valid hex.\"\n\n let e = zapRequest.tags.find(([t, v]) => t === 'e' && v)\n if (e && !e[1].match(/^[a-f0-9]{64}$/)) return \"Zap request 'e' tag is not valid hex.\"\n\n let relays = zapRequest.tags.find(([t, v]) => t === 'relays' && v)\n if (!relays) return \"Zap request doesn't have a 'relays' tag.\"\n\n return null\n}\n\nexport function makeZapReceipt({\n zapRequest,\n preimage,\n bolt11,\n paidAt,\n}: {\n zapRequest: string\n preimage?: string\n bolt11: string\n paidAt: Date\n}): EventTemplate {\n let zr: Event = JSON.parse(zapRequest)\n let tagsFromZapRequest = zr.tags.filter(([t]) => t === 'e' || t === 'p' || t === 'a')\n\n let zap: EventTemplate = {\n kind: 9735,\n created_at: Math.round(paidAt.getTime() / 1000),\n content: '',\n tags: [...tagsFromZapRequest, ['P', zr.pubkey], ['bolt11', bolt11], ['description', zapRequest]],\n }\n\n if (preimage) {\n zap.tags.push(['preimage', preimage])\n }\n\n return zap\n}\n\nexport function getSatoshisAmountFromBolt11(bolt11: string): number {\n if (bolt11.length < 50) {\n return 0\n }\n bolt11 = bolt11.substring(0, 50)\n const idx = bolt11.lastIndexOf('1')\n if (idx === -1) {\n return 0\n }\n const hrp = bolt11.substring(0, idx)\n if (!hrp.startsWith('lnbc')) {\n return 0\n }\n const amount = hrp.substring(4) // equivalent to strings.CutPrefix\n\n if (amount.length < 1) {\n return 0\n }\n\n // if last character is a digit, then the amount can just be interpreted as BTC\n const char = amount[amount.length - 1]\n const digit = char.charCodeAt(0) - '0'.charCodeAt(0)\n const isDigit = digit >= 0 && digit <= 9\n\n let cutPoint = amount.length - 1\n if (isDigit) {\n cutPoint++\n }\n\n if (cutPoint < 1) {\n return 0\n }\n\n const num = parseInt(amount.substring(0, cutPoint))\n\n switch (char) {\n case 'm':\n return num * 100000\n case 'u':\n return num * 100\n case 'n':\n return num / 10\n case 'p':\n return num / 10000\n default:\n return num * 100000000\n }\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
- "mappings": "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",
+ "sourcesContent": ["import { bech32 } from '@scure/base'\n\nimport { NostrEvent, validateEvent, verifyEvent, type Event, type EventTemplate } from './pure.ts'\nimport { utf8Decoder } from './utils.ts'\nimport { isReplaceableKind, isAddressableKind } from './kinds.ts'\n\nvar _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any) {\n _fetch = fetchImplementation\n}\n\nexport async function getZapEndpoint(metadata: Event): Promise<null | string> {\n try {\n let lnurl: string = ''\n let { lud06, lud16 } = JSON.parse(metadata.content)\n if (lud16) {\n let [name, domain] = lud16.split('@')\n lnurl = new URL(`/.well-known/lnurlp/${name}`, `https://${domain}`).toString()\n } else if (lud06) {\n let { words } = bech32.decode(lud06, 1000)\n let data = bech32.fromWords(words)\n lnurl = utf8Decoder.decode(data)\n } else {\n return null\n }\n\n let res = await _fetch(lnurl)\n let body = await res.json()\n\n if (body.allowsNostr && body.nostrPubkey) {\n return body.callback\n }\n } catch (err) {\n /*-*/\n }\n\n return null\n}\n\ntype ProfileZap = {\n pubkey: string\n amount: number\n comment?: string\n relays: string[]\n}\n\ntype EventZap = {\n event: NostrEvent\n amount: number\n comment?: string\n relays: string[]\n}\n\nexport function makeZapRequest(params: ProfileZap | EventZap): EventTemplate {\n let zr: EventTemplate = {\n kind: 9734,\n created_at: Math.round(Date.now() / 1000),\n content: params.comment || '',\n tags: [\n ['p', 'pubkey' in params ? params.pubkey : params.event.pubkey],\n ['amount', params.amount.toString()],\n ['relays', ...params.relays],\n ],\n }\n\n if ('event' in params) {\n zr.tags.push(['e', params.event.id])\n if (isReplaceableKind(params.event.kind)) {\n const a = ['a', `${params.event.kind}:${params.event.pubkey}:`]\n zr.tags.push(a)\n } else if (isAddressableKind(params.event.kind)) {\n let d = params.event.tags.find(([t, v]) => t === 'd' && v)\n if (!d) throw new Error('d tag not found or is empty')\n const a = ['a', `${params.event.kind}:${params.event.pubkey}:${d[1]}`]\n zr.tags.push(a)\n }\n zr.tags.push(['k', params.event.kind.toString()])\n }\n\n return zr\n}\n\nexport function validateZapRequest(zapRequestString: string): string | null {\n let zapRequest: Event\n\n try {\n zapRequest = JSON.parse(zapRequestString)\n } catch (err) {\n return 'Invalid zap request JSON.'\n }\n\n if (!validateEvent(zapRequest)) return 'Zap request is not a valid Nostr event.'\n\n if (!verifyEvent(zapRequest)) return 'Invalid signature on zap request.'\n\n let p = zapRequest.tags.find(([t, v]) => t === 'p' && v)\n if (!p) return \"Zap request doesn't have a 'p' tag.\"\n if (!p[1].match(/^[a-f0-9]{64}$/)) return \"Zap request 'p' tag is not valid hex.\"\n\n let e = zapRequest.tags.find(([t, v]) => t === 'e' && v)\n if (e && !e[1].match(/^[a-f0-9]{64}$/)) return \"Zap request 'e' tag is not valid hex.\"\n\n let relays = zapRequest.tags.find(([t, v]) => t === 'relays' && v)\n if (!relays) return \"Zap request doesn't have a 'relays' tag.\"\n\n return null\n}\n\nexport function makeZapReceipt({\n zapRequest,\n preimage,\n bolt11,\n paidAt,\n}: {\n zapRequest: string\n preimage?: string\n bolt11: string\n paidAt: Date\n}): EventTemplate {\n let zr: Event = JSON.parse(zapRequest)\n let tagsFromZapRequest = zr.tags.filter(([t]) => t === 'e' || t === 'p' || t === 'a')\n\n let zap: EventTemplate = {\n kind: 9735,\n created_at: Math.round(paidAt.getTime() / 1000),\n content: '',\n tags: [...tagsFromZapRequest, ['P', zr.pubkey], ['bolt11', bolt11], ['description', zapRequest]],\n }\n\n if (preimage) {\n zap.tags.push(['preimage', preimage])\n }\n\n return zap\n}\n\nexport function getSatoshisAmountFromBolt11(bolt11: string): number {\n if (bolt11.length < 50) {\n return 0\n }\n bolt11 = bolt11.substring(0, 50)\n const idx = bolt11.lastIndexOf('1')\n if (idx === -1) {\n return 0\n }\n const hrp = bolt11.substring(0, idx)\n if (!hrp.startsWith('lnbc')) {\n return 0\n }\n const amount = hrp.substring(4) // equivalent to strings.CutPrefix\n\n if (amount.length < 1) {\n return 0\n }\n\n // if last character is a digit, then the amount can just be interpreted as BTC\n const char = amount[amount.length - 1]\n const digit = char.charCodeAt(0) - '0'.charCodeAt(0)\n const isDigit = digit >= 0 && digit <= 9\n\n let cutPoint = amount.length - 1\n if (isDigit) {\n cutPoint++\n }\n\n if (cutPoint < 1) {\n return 0\n }\n\n const num = parseInt(amount.substring(0, cutPoint))\n\n switch (char) {\n case 'm':\n return num * 100000\n case 'u':\n return num * 100\n case 'n':\n return num / 10\n case 'p':\n return num / 10000\n default:\n return num * 100000000\n }\n}\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
+ "mappings": "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",
"names": ["import_utils", "i"]
} Index: package/lib/esm/nip57.js.map
===================================================================
--- package/lib/esm/nip57.js.map
+++ package/lib/esm/nip57.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip57.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts"],
- "sourcesContent": ["import { bech32 } from '@scure/base'\n\nimport { NostrEvent, validateEvent, verifyEvent, type Event, type EventTemplate } from './pure.ts'\nimport { utf8Decoder } from './utils.ts'\nimport { isReplaceableKind, isAddressableKind } from './kinds.ts'\n\nvar _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any) {\n _fetch = fetchImplementation\n}\n\nexport async function getZapEndpoint(metadata: Event): Promise<null | string> {\n try {\n let lnurl: string = ''\n let { lud06, lud16 } = JSON.parse(metadata.content)\n if (lud16) {\n let [name, domain] = lud16.split('@')\n lnurl = new URL(`/.well-known/lnurlp/${name}`, `https://${domain}`).toString()\n } else if (lud06) {\n let { words } = bech32.decode(lud06, 1000)\n let data = bech32.fromWords(words)\n lnurl = utf8Decoder.decode(data)\n } else {\n return null\n }\n\n let res = await _fetch(lnurl)\n let body = await res.json()\n\n if (body.allowsNostr && body.nostrPubkey) {\n return body.callback\n }\n } catch (err) {\n /*-*/\n }\n\n return null\n}\n\ntype ProfileZap = {\n pubkey: string\n amount: number\n comment?: string\n relays: string[]\n}\n\ntype EventZap = {\n event: NostrEvent\n amount: number\n comment?: string\n relays: string[]\n}\n\nexport function makeZapRequest(params: ProfileZap | EventZap): EventTemplate {\n let zr: EventTemplate = {\n kind: 9734,\n created_at: Math.round(Date.now() / 1000),\n content: params.comment || '',\n tags: [\n ['p', 'pubkey' in params ? params.pubkey : params.event.pubkey],\n ['amount', params.amount.toString()],\n ['relays', ...params.relays],\n ],\n }\n\n if ('event' in params) {\n zr.tags.push(['e', params.event.id])\n if (isReplaceableKind(params.event.kind)) {\n const a = ['a', `${params.event.kind}:${params.event.pubkey}:`]\n zr.tags.push(a)\n } else if (isAddressableKind(params.event.kind)) {\n let d = params.event.tags.find(([t, v]) => t === 'd' && v)\n if (!d) throw new Error('d tag not found or is empty')\n const a = ['a', `${params.event.kind}:${params.event.pubkey}:${d[1]}`]\n zr.tags.push(a)\n }\n zr.tags.push(['k', params.event.kind.toString()])\n }\n\n return zr\n}\n\nexport function validateZapRequest(zapRequestString: string): string | null {\n let zapRequest: Event\n\n try {\n zapRequest = JSON.parse(zapRequestString)\n } catch (err) {\n return 'Invalid zap request JSON.'\n }\n\n if (!validateEvent(zapRequest)) return 'Zap request is not a valid Nostr event.'\n\n if (!verifyEvent(zapRequest)) return 'Invalid signature on zap request.'\n\n let p = zapRequest.tags.find(([t, v]) => t === 'p' && v)\n if (!p) return \"Zap request doesn't have a 'p' tag.\"\n if (!p[1].match(/^[a-f0-9]{64}$/)) return \"Zap request 'p' tag is not valid hex.\"\n\n let e = zapRequest.tags.find(([t, v]) => t === 'e' && v)\n if (e && !e[1].match(/^[a-f0-9]{64}$/)) return \"Zap request 'e' tag is not valid hex.\"\n\n let relays = zapRequest.tags.find(([t, v]) => t === 'relays' && v)\n if (!relays) return \"Zap request doesn't have a 'relays' tag.\"\n\n return null\n}\n\nexport function makeZapReceipt({\n zapRequest,\n preimage,\n bolt11,\n paidAt,\n}: {\n zapRequest: string\n preimage?: string\n bolt11: string\n paidAt: Date\n}): EventTemplate {\n let zr: Event = JSON.parse(zapRequest)\n let tagsFromZapRequest = zr.tags.filter(([t]) => t === 'e' || t === 'p' || t === 'a')\n\n let zap: EventTemplate = {\n kind: 9735,\n created_at: Math.round(paidAt.getTime() / 1000),\n content: '',\n tags: [...tagsFromZapRequest, ['P', zr.pubkey], ['bolt11', bolt11], ['description', zapRequest]],\n }\n\n if (preimage) {\n zap.tags.push(['preimage', preimage])\n }\n\n return zap\n}\n\nexport function getSatoshisAmountFromBolt11(bolt11: string): number {\n if (bolt11.length < 50) {\n return 0\n }\n bolt11 = bolt11.substring(0, 50)\n const idx = bolt11.lastIndexOf('1')\n if (idx === -1) {\n return 0\n }\n const hrp = bolt11.substring(0, idx)\n if (!hrp.startsWith('lnbc')) {\n return 0\n }\n const amount = hrp.substring(4) // equivalent to strings.CutPrefix\n\n if (amount.length < 1) {\n return 0\n }\n\n // if last character is a digit, then the amount can just be interpreted as BTC\n const char = amount[amount.length - 1]\n const digit = char.charCodeAt(0) - '0'.charCodeAt(0)\n const isDigit = digit >= 0 && digit <= 9\n\n let cutPoint = amount.length - 1\n if (isDigit) {\n cutPoint++\n }\n\n if (cutPoint < 1) {\n return 0\n }\n\n const num = parseInt(amount.substring(0, cutPoint))\n\n switch (char) {\n case 'm':\n return num * 100000\n case 'u':\n return num * 100\n case 'n':\n return num / 10\n case 'p':\n return num / 10000\n default:\n return num * 100000000\n }\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
- "mappings": ";AAAA,SAAS,cAAc;;;ACAvB,SAAS,eAAe;AACxB,SAAS,cAAAA,mBAAkB;;;ACOpB,IAAM,iBAAiB,OAAO,UAAU;AAsB/C,IAAM,WAAW,CAAC,QAAiD,eAAe;AAE3E,SAAS,cAAiB,OAAsC;AACrE,MAAI,CAAC,SAAS,KAAK;AAAG,WAAO;AAC7B,MAAI,OAAO,MAAM,SAAS;AAAU,WAAO;AAC3C,MAAI,OAAO,MAAM,YAAY;AAAU,WAAO;AAC9C,MAAI,OAAO,MAAM,eAAe;AAAU,WAAO;AACjD,MAAI,OAAO,MAAM,WAAW;AAAU,WAAO;AAC7C,MAAI,CAAC,MAAM,OAAO,MAAM,gBAAgB;AAAG,WAAO;AAElD,MAAI,CAAC,MAAM,QAAQ,MAAM,IAAI;AAAG,WAAO;AACvC,WAASC,KAAI,GAAGA,KAAI,MAAM,KAAK,QAAQA,MAAK;AAC1C,QAAI,MAAM,MAAM,KAAKA;AACrB,QAAI,CAAC,MAAM,QAAQ,GAAG;AAAG,aAAO;AAChC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAI,OAAO,IAAI,OAAO;AAAU,eAAO;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AACT;;;AD/CA,SAAS,cAAc;;;AEEvB,SAAS,YAAY,kBAAkB;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;AFIxD,IAAM,KAAN,MAA0B;AAAA,EACxB,oBAAgC;AAC9B,WAAO,QAAQ,MAAM,iBAAiB;AAAA,EACxC;AAAA,EACA,aAAa,WAA+B;AAC1C,WAAOC,YAAW,QAAQ,aAAa,SAAS,CAAC;AAAA,EACnD;AAAA,EACA,cAAc,GAAkB,WAAsC;AACpE,UAAM,QAAQ;AACd,UAAM,SAASA,YAAW,QAAQ,aAAa,SAAS,CAAC;AACzD,UAAM,KAAK,aAAa,KAAK;AAC7B,UAAM,MAAMA,YAAW,QAAQ,KAAK,aAAa,KAAK,GAAG,SAAS,CAAC;AACnE,UAAM,kBAAkB;AACxB,WAAO;AAAA,EACT;AAAA,EACA,YAAY,OAAsC;AAChD,QAAI,OAAO,MAAM,oBAAoB;AAAW,aAAO,MAAM;AAE7D,UAAM,OAAO,aAAa,KAAK;AAC/B,QAAI,SAAS,MAAM,IAAI;AACrB,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,QAAQ,QAAQ,OAAO,MAAM,KAAK,MAAM,MAAM,MAAM;AAC1D,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT,SAAS,KAAP;AACA,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,eAAe,KAA4B;AACzD,MAAI,CAAC,cAAc,GAAG;AAAG,UAAM,IAAI,MAAM,wDAAwD;AACjG,SAAO,KAAK,UAAU,CAAC,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,CAAC;AACxF;AAEO,SAAS,aAAa,OAA8B;AACzD,MAAI,YAAY,OAAO,YAAY,OAAO,eAAe,KAAK,CAAC,CAAC;AAChE,SAAOA,YAAW,SAAS;AAC7B;AAEA,IAAM,IAAQ,IAAI,GAAG;AAEd,IAAM,oBAAoB,EAAE;AAC5B,IAAM,eAAe,EAAE;AACvB,IAAM,gBAAgB,EAAE;AACxB,IAAM,cAAc,EAAE;;;AGjDtB,SAAS,kBAAkB,MAAuB;AACvD,SAAO,SAAS,KAAK,SAAS,KAAM,OAAS,QAAQ,OAAO;AAC9D;AAQO,SAAS,kBAAkB,MAAuB;AACvD,SAAO,OAAS,QAAQ,OAAO;AACjC;;;AJdA,IAAI;AAEJ,IAAI;AACF,WAAS;AACX,QAAE;AAAO;AAEF,SAAS,uBAAuB,qBAA0B;AAC/D,WAAS;AACX;AAEA,eAAsB,eAAe,UAAyC;AAC5E,MAAI;AACF,QAAI,QAAgB;AACpB,QAAI,EAAE,OAAO,MAAM,IAAI,KAAK,MAAM,SAAS,OAAO;AAClD,QAAI,OAAO;AACT,UAAI,CAAC,MAAM,MAAM,IAAI,MAAM,MAAM,GAAG;AACpC,cAAQ,IAAI,IAAI,uBAAuB,QAAQ,WAAW,QAAQ,EAAE,SAAS;AAAA,IAC/E,WAAW,OAAO;AAChB,UAAI,EAAE,MAAM,IAAI,OAAO,OAAO,OAAO,GAAI;AACzC,UAAI,OAAO,OAAO,UAAU,KAAK;AACjC,cAAQ,YAAY,OAAO,IAAI;AAAA,IACjC,OAAO;AACL,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,MAAM,OAAO,KAAK;AAC5B,QAAI,OAAO,MAAM,IAAI,KAAK;AAE1B,QAAI,KAAK,eAAe,KAAK,aAAa;AACxC,aAAO,KAAK;AAAA,IACd;AAAA,EACF,SAAS,KAAP;AAAA,EAEF;AAEA,SAAO;AACT;AAgBO,SAAS,eAAe,QAA8C;AAC3E,MAAI,KAAoB;AAAA,IACtB,MAAM;AAAA,IACN,YAAY,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAAA,IACxC,SAAS,OAAO,WAAW;AAAA,IAC3B,MAAM;AAAA,MACJ,CAAC,KAAK,YAAY,SAAS,OAAO,SAAS,OAAO,MAAM,MAAM;AAAA,MAC9D,CAAC,UAAU,OAAO,OAAO,SAAS,CAAC;AAAA,MACnC,CAAC,UAAU,GAAG,OAAO,MAAM;AAAA,IAC7B;AAAA,EACF;AAEA,MAAI,WAAW,QAAQ;AACrB,OAAG,KAAK,KAAK,CAAC,KAAK,OAAO,MAAM,EAAE,CAAC;AACnC,QAAI,kBAAkB,OAAO,MAAM,IAAI,GAAG;AACxC,YAAM,IAAI,CAAC,KAAK,GAAG,OAAO,MAAM,QAAQ,OAAO,MAAM,SAAS;AAC9D,SAAG,KAAK,KAAK,CAAC;AAAA,IAChB,WAAW,kBAAkB,OAAO,MAAM,IAAI,GAAG;AAC/C,UAAI,IAAI,OAAO,MAAM,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,MAAM,OAAO,CAAC;AACzD,UAAI,CAAC;AAAG,cAAM,IAAI,MAAM,6BAA6B;AACrD,YAAM,IAAI,CAAC,KAAK,GAAG,OAAO,MAAM,QAAQ,OAAO,MAAM,UAAU,EAAE,IAAI;AACrE,SAAG,KAAK,KAAK,CAAC;AAAA,IAChB;AACA,OAAG,KAAK,KAAK,CAAC,KAAK,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC;AAAA,EAClD;AAEA,SAAO;AACT;AAEO,SAAS,mBAAmB,kBAAyC;AAC1E,MAAI;AAEJ,MAAI;AACF,iBAAa,KAAK,MAAM,gBAAgB;AAAA,EAC1C,SAAS,KAAP;AACA,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,cAAc,UAAU;AAAG,WAAO;AAEvC,MAAI,CAAC,YAAY,UAAU;AAAG,WAAO;AAErC,MAAI,IAAI,WAAW,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,MAAM,OAAO,CAAC;AACvD,MAAI,CAAC;AAAG,WAAO;AACf,MAAI,CAAC,EAAE,GAAG,MAAM,gBAAgB;AAAG,WAAO;AAE1C,MAAI,IAAI,WAAW,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,MAAM,OAAO,CAAC;AACvD,MAAI,KAAK,CAAC,EAAE,GAAG,MAAM,gBAAgB;AAAG,WAAO;AAE/C,MAAI,SAAS,WAAW,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,MAAM,YAAY,CAAC;AACjE,MAAI,CAAC;AAAQ,WAAO;AAEpB,SAAO;AACT;AAEO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKkB;AAChB,MAAI,KAAY,KAAK,MAAM,UAAU;AACrC,MAAI,qBAAqB,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,OAAO,MAAM,OAAO,MAAM,GAAG;AAEpF,MAAI,MAAqB;AAAA,IACvB,MAAM;AAAA,IACN,YAAY,KAAK,MAAM,OAAO,QAAQ,IAAI,GAAI;AAAA,IAC9C,SAAS;AAAA,IACT,MAAM,CAAC,GAAG,oBAAoB,CAAC,KAAK,GAAG,MAAM,GAAG,CAAC,UAAU,MAAM,GAAG,CAAC,eAAe,UAAU,CAAC;AAAA,EACjG;AAEA,MAAI,UAAU;AACZ,QAAI,KAAK,KAAK,CAAC,YAAY,QAAQ,CAAC;AAAA,EACtC;AAEA,SAAO;AACT;AAEO,SAAS,4BAA4B,QAAwB;AAClE,MAAI,OAAO,SAAS,IAAI;AACtB,WAAO;AAAA,EACT;AACA,WAAS,OAAO,UAAU,GAAG,EAAE;AAC/B,QAAM,MAAM,OAAO,YAAY,GAAG;AAClC,MAAI,QAAQ,IAAI;AACd,WAAO;AAAA,EACT;AACA,QAAM,MAAM,OAAO,UAAU,GAAG,GAAG;AACnC,MAAI,CAAC,IAAI,WAAW,MAAM,GAAG;AAC3B,WAAO;AAAA,EACT;AACA,QAAM,SAAS,IAAI,UAAU,CAAC;AAE9B,MAAI,OAAO,SAAS,GAAG;AACrB,WAAO;AAAA,EACT;AAGA,QAAM,OAAO,OAAO,OAAO,SAAS;AACpC,QAAM,QAAQ,KAAK,WAAW,CAAC,IAAI,IAAI,WAAW,CAAC;AACnD,QAAM,UAAU,SAAS,KAAK,SAAS;AAEvC,MAAI,WAAW,OAAO,SAAS;AAC/B,MAAI,SAAS;AACX;AAAA,EACF;AAEA,MAAI,WAAW,GAAG;AAChB,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,SAAS,OAAO,UAAU,GAAG,QAAQ,CAAC;AAElD,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,MAAM;AAAA,IACf,KAAK;AACH,aAAO,MAAM;AAAA,IACf,KAAK;AACH,aAAO,MAAM;AAAA,IACf,KAAK;AACH,aAAO,MAAM;AAAA,IACf;AACE,aAAO,MAAM;AAAA,EACjB;AACF;",
- "names": ["bytesToHex", "i", "bytesToHex"]
+ "sourcesContent": ["import { bech32 } from '@scure/base'\n\nimport { NostrEvent, validateEvent, verifyEvent, type Event, type EventTemplate } from './pure.ts'\nimport { utf8Decoder } from './utils.ts'\nimport { isReplaceableKind, isAddressableKind } from './kinds.ts'\n\nvar _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any) {\n _fetch = fetchImplementation\n}\n\nexport async function getZapEndpoint(metadata: Event): Promise<null | string> {\n try {\n let lnurl: string = ''\n let { lud06, lud16 } = JSON.parse(metadata.content)\n if (lud16) {\n let [name, domain] = lud16.split('@')\n lnurl = new URL(`/.well-known/lnurlp/${name}`, `https://${domain}`).toString()\n } else if (lud06) {\n let { words } = bech32.decode(lud06, 1000)\n let data = bech32.fromWords(words)\n lnurl = utf8Decoder.decode(data)\n } else {\n return null\n }\n\n let res = await _fetch(lnurl)\n let body = await res.json()\n\n if (body.allowsNostr && body.nostrPubkey) {\n return body.callback\n }\n } catch (err) {\n /*-*/\n }\n\n return null\n}\n\ntype ProfileZap = {\n pubkey: string\n amount: number\n comment?: string\n relays: string[]\n}\n\ntype EventZap = {\n event: NostrEvent\n amount: number\n comment?: string\n relays: string[]\n}\n\nexport function makeZapRequest(params: ProfileZap | EventZap): EventTemplate {\n let zr: EventTemplate = {\n kind: 9734,\n created_at: Math.round(Date.now() / 1000),\n content: params.comment || '',\n tags: [\n ['p', 'pubkey' in params ? params.pubkey : params.event.pubkey],\n ['amount', params.amount.toString()],\n ['relays', ...params.relays],\n ],\n }\n\n if ('event' in params) {\n zr.tags.push(['e', params.event.id])\n if (isReplaceableKind(params.event.kind)) {\n const a = ['a', `${params.event.kind}:${params.event.pubkey}:`]\n zr.tags.push(a)\n } else if (isAddressableKind(params.event.kind)) {\n let d = params.event.tags.find(([t, v]) => t === 'd' && v)\n if (!d) throw new Error('d tag not found or is empty')\n const a = ['a', `${params.event.kind}:${params.event.pubkey}:${d[1]}`]\n zr.tags.push(a)\n }\n zr.tags.push(['k', params.event.kind.toString()])\n }\n\n return zr\n}\n\nexport function validateZapRequest(zapRequestString: string): string | null {\n let zapRequest: Event\n\n try {\n zapRequest = JSON.parse(zapRequestString)\n } catch (err) {\n return 'Invalid zap request JSON.'\n }\n\n if (!validateEvent(zapRequest)) return 'Zap request is not a valid Nostr event.'\n\n if (!verifyEvent(zapRequest)) return 'Invalid signature on zap request.'\n\n let p = zapRequest.tags.find(([t, v]) => t === 'p' && v)\n if (!p) return \"Zap request doesn't have a 'p' tag.\"\n if (!p[1].match(/^[a-f0-9]{64}$/)) return \"Zap request 'p' tag is not valid hex.\"\n\n let e = zapRequest.tags.find(([t, v]) => t === 'e' && v)\n if (e && !e[1].match(/^[a-f0-9]{64}$/)) return \"Zap request 'e' tag is not valid hex.\"\n\n let relays = zapRequest.tags.find(([t, v]) => t === 'relays' && v)\n if (!relays) return \"Zap request doesn't have a 'relays' tag.\"\n\n return null\n}\n\nexport function makeZapReceipt({\n zapRequest,\n preimage,\n bolt11,\n paidAt,\n}: {\n zapRequest: string\n preimage?: string\n bolt11: string\n paidAt: Date\n}): EventTemplate {\n let zr: Event = JSON.parse(zapRequest)\n let tagsFromZapRequest = zr.tags.filter(([t]) => t === 'e' || t === 'p' || t === 'a')\n\n let zap: EventTemplate = {\n kind: 9735,\n created_at: Math.round(paidAt.getTime() / 1000),\n content: '',\n tags: [...tagsFromZapRequest, ['P', zr.pubkey], ['bolt11', bolt11], ['description', zapRequest]],\n }\n\n if (preimage) {\n zap.tags.push(['preimage', preimage])\n }\n\n return zap\n}\n\nexport function getSatoshisAmountFromBolt11(bolt11: string): number {\n if (bolt11.length < 50) {\n return 0\n }\n bolt11 = bolt11.substring(0, 50)\n const idx = bolt11.lastIndexOf('1')\n if (idx === -1) {\n return 0\n }\n const hrp = bolt11.substring(0, idx)\n if (!hrp.startsWith('lnbc')) {\n return 0\n }\n const amount = hrp.substring(4) // equivalent to strings.CutPrefix\n\n if (amount.length < 1) {\n return 0\n }\n\n // if last character is a digit, then the amount can just be interpreted as BTC\n const char = amount[amount.length - 1]\n const digit = char.charCodeAt(0) - '0'.charCodeAt(0)\n const isDigit = digit >= 0 && digit <= 9\n\n let cutPoint = amount.length - 1\n if (isDigit) {\n cutPoint++\n }\n\n if (cutPoint < 1) {\n return 0\n }\n\n const num = parseInt(amount.substring(0, cutPoint))\n\n switch (char) {\n case 'm':\n return num * 100000\n case 'u':\n return num * 100\n case 'n':\n return num / 10\n case 'p':\n return num / 10000\n default:\n return num * 100000000\n }\n}\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
+ "mappings": "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",
+ "names": ["bytesToHex", "hexToBytes", "i", "bytesToHex", "hexToBytes"]
} Index: package/lib/cjs/nip59.js.map
===================================================================
--- package/lib/cjs/nip59.js.map
+++ package/lib/cjs/nip59.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip59.ts", "../../nip44.ts", "../../utils.ts", "../../pure.ts", "../../core.ts", "../../kinds.ts"],
- "sourcesContent": ["import { EventTemplate, UnsignedEvent, NostrEvent } from './core.ts'\nimport { getConversationKey, decrypt, encrypt } from './nip44.ts'\nimport { getEventHash, generateSecretKey, finalizeEvent, getPublicKey } from './pure.ts'\nimport { Seal, GiftWrap } from './kinds.ts'\n\ntype Rumor = UnsignedEvent & { id: string }\n\nconst TWO_DAYS = 2 * 24 * 60 * 60\n\nconst now = () => Math.round(Date.now() / 1000)\nconst randomNow = () => Math.round(now() - Math.random() * TWO_DAYS)\n\nconst nip44ConversationKey = (privateKey: Uint8Array, publicKey: string) => getConversationKey(privateKey, publicKey)\n\nconst nip44Encrypt = (data: EventTemplate, privateKey: Uint8Array, publicKey: string) =>\n encrypt(JSON.stringify(data), nip44ConversationKey(privateKey, publicKey))\n\nconst nip44Decrypt = (data: NostrEvent, privateKey: Uint8Array) =>\n JSON.parse(decrypt(data.content, nip44ConversationKey(privateKey, data.pubkey)))\n\nexport function createRumor(event: Partial<UnsignedEvent>, privateKey: Uint8Array): Rumor {\n const rumor = {\n created_at: now(),\n content: '',\n tags: [],\n ...event,\n pubkey: getPublicKey(privateKey),\n } as any\n\n rumor.id = getEventHash(rumor)\n\n return rumor as Rumor\n}\n\nexport function createSeal(rumor: Rumor, privateKey: Uint8Array, recipientPublicKey: string): NostrEvent {\n return finalizeEvent(\n {\n kind: Seal,\n content: nip44Encrypt(rumor, privateKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [],\n },\n privateKey,\n )\n}\n\nexport function createWrap(seal: NostrEvent, recipientPublicKey: string): NostrEvent {\n const randomKey = generateSecretKey()\n\n return finalizeEvent(\n {\n kind: GiftWrap,\n content: nip44Encrypt(seal, randomKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [['p', recipientPublicKey]],\n },\n randomKey,\n ) as NostrEvent\n}\n\nexport function wrapEvent(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientPublicKey: string,\n): NostrEvent {\n const rumor = createRumor(event, senderPrivateKey)\n\n const seal = createSeal(rumor, senderPrivateKey, recipientPublicKey)\n return createWrap(seal, recipientPublicKey)\n}\n\nexport function wrapManyEvents(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientsPublicKeys: string[],\n): NostrEvent[] {\n if (!recipientsPublicKeys || recipientsPublicKeys.length === 0) {\n throw new Error('At least one recipient is required.')\n }\n\n const senderPublicKey = getPublicKey(senderPrivateKey)\n\n const wrappeds = [wrapEvent(event, senderPrivateKey, senderPublicKey)]\n\n recipientsPublicKeys.forEach(recipientPublicKey => {\n wrappeds.push(wrapEvent(event, senderPrivateKey, recipientPublicKey))\n })\n\n return wrappeds\n}\n\nexport function unwrapEvent(wrap: NostrEvent, recipientPrivateKey: Uint8Array): Rumor {\n const unwrappedSeal = nip44Decrypt(wrap, recipientPrivateKey)\n return nip44Decrypt(unwrappedSeal, recipientPrivateKey)\n}\n\nexport function unwrapManyEvents(wrappedEvents: NostrEvent[], recipientPrivateKey: Uint8Array): Rumor[] {\n let unwrappedEvents: Rumor[] = []\n\n wrappedEvents.forEach(e => {\n unwrappedEvents.push(unwrapEvent(e, recipientPrivateKey))\n })\n\n unwrappedEvents.sort((a, b) => a.created_at - b.created_at)\n\n return unwrappedEvents\n}\n", "import { chacha20 } from '@noble/ciphers/chacha'\nimport { equalBytes } from '@noble/ciphers/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf'\nimport { hmac } from '@noble/hashes/hmac'\nimport { sha256 } from '@noble/hashes/sha256'\nimport { concatBytes, randomBytes } from '@noble/hashes/utils'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, 'nip44-v2')\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
- "mappings": "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",
- "names": ["import_utils", "hkdf_extract", "hkdf_expand", "import_secp256k1", "import_utils", "i", "import_sha256"]
+ "sourcesContent": ["import { EventTemplate, UnsignedEvent, NostrEvent } from './core.ts'\nimport { getConversationKey, decrypt, encrypt } from './nip44.ts'\nimport { getEventHash, generateSecretKey, finalizeEvent, getPublicKey } from './pure.ts'\nimport { Seal, GiftWrap } from './kinds.ts'\n\ntype Rumor = UnsignedEvent & { id: string }\n\nconst TWO_DAYS = 2 * 24 * 60 * 60\n\nconst now = () => Math.round(Date.now() / 1000)\nconst randomNow = () => Math.round(now() - Math.random() * TWO_DAYS)\n\nconst nip44ConversationKey = (privateKey: Uint8Array, publicKey: string) => getConversationKey(privateKey, publicKey)\n\nconst nip44Encrypt = (data: EventTemplate, privateKey: Uint8Array, publicKey: string) =>\n encrypt(JSON.stringify(data), nip44ConversationKey(privateKey, publicKey))\n\nconst nip44Decrypt = (data: NostrEvent, privateKey: Uint8Array) =>\n JSON.parse(decrypt(data.content, nip44ConversationKey(privateKey, data.pubkey)))\n\nexport function createRumor(event: Partial<UnsignedEvent>, privateKey: Uint8Array): Rumor {\n const rumor = {\n created_at: now(),\n content: '',\n tags: [],\n ...event,\n pubkey: getPublicKey(privateKey),\n } as any\n\n rumor.id = getEventHash(rumor)\n\n return rumor as Rumor\n}\n\nexport function createSeal(rumor: Rumor, privateKey: Uint8Array, recipientPublicKey: string): NostrEvent {\n return finalizeEvent(\n {\n kind: Seal,\n content: nip44Encrypt(rumor, privateKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [],\n },\n privateKey,\n )\n}\n\nexport function createWrap(seal: NostrEvent, recipientPublicKey: string): NostrEvent {\n const randomKey = generateSecretKey()\n\n return finalizeEvent(\n {\n kind: GiftWrap,\n content: nip44Encrypt(seal, randomKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [['p', recipientPublicKey]],\n },\n randomKey,\n ) as NostrEvent\n}\n\nexport function wrapEvent(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientPublicKey: string,\n): NostrEvent {\n const rumor = createRumor(event, senderPrivateKey)\n\n const seal = createSeal(rumor, senderPrivateKey, recipientPublicKey)\n return createWrap(seal, recipientPublicKey)\n}\n\nexport function wrapManyEvents(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientsPublicKeys: string[],\n): NostrEvent[] {\n if (!recipientsPublicKeys || recipientsPublicKeys.length === 0) {\n throw new Error('At least one recipient is required.')\n }\n\n const senderPublicKey = getPublicKey(senderPrivateKey)\n\n const wrappeds = [wrapEvent(event, senderPrivateKey, senderPublicKey)]\n\n recipientsPublicKeys.forEach(recipientPublicKey => {\n wrappeds.push(wrapEvent(event, senderPrivateKey, recipientPublicKey))\n })\n\n return wrappeds\n}\n\nexport function unwrapEvent(wrap: NostrEvent, recipientPrivateKey: Uint8Array): Rumor {\n const unwrappedSeal = nip44Decrypt(wrap, recipientPrivateKey)\n return nip44Decrypt(unwrappedSeal, recipientPrivateKey)\n}\n\nexport function unwrapManyEvents(wrappedEvents: NostrEvent[], recipientPrivateKey: Uint8Array): Rumor[] {\n let unwrappedEvents: Rumor[] = []\n\n wrappedEvents.forEach(e => {\n unwrappedEvents.push(unwrapEvent(e, recipientPrivateKey))\n })\n\n unwrappedEvents.sort((a, b) => a.created_at - b.created_at)\n\n return unwrappedEvents\n}\n", "import { chacha20 } from '@noble/ciphers/chacha.js'\nimport { equalBytes } from '@noble/ciphers/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf.js'\nimport { hmac } from '@noble/hashes/hmac.js'\nimport { sha256 } from '@noble/hashes/sha2.js'\nimport { concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes('02' + pubkeyB)).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, utf8Encoder.encode('nip44-v2'))\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
+ "mappings": "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",
+ "names": ["import_utils", "hkdf_extract", "hkdf_expand", "import_secp256k1", "import_utils", "i", "import_sha2"]
} Index: package/lib/esm/nip59.js.map
===================================================================
--- package/lib/esm/nip59.js.map
+++ package/lib/esm/nip59.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip44.ts", "../../utils.ts", "../../pure.ts", "../../core.ts", "../../kinds.ts", "../../nip59.ts"],
- "sourcesContent": ["import { chacha20 } from '@noble/ciphers/chacha'\nimport { equalBytes } from '@noble/ciphers/utils'\nimport { secp256k1 } from '@noble/curves/secp256k1'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf'\nimport { hmac } from '@noble/hashes/hmac'\nimport { sha256 } from '@noble/hashes/sha256'\nimport { concatBytes, randomBytes } from '@noble/hashes/utils'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, '02' + pubkeyB).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, 'nip44-v2')\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { EventTemplate, UnsignedEvent, NostrEvent } from './core.ts'\nimport { getConversationKey, decrypt, encrypt } from './nip44.ts'\nimport { getEventHash, generateSecretKey, finalizeEvent, getPublicKey } from './pure.ts'\nimport { Seal, GiftWrap } from './kinds.ts'\n\ntype Rumor = UnsignedEvent & { id: string }\n\nconst TWO_DAYS = 2 * 24 * 60 * 60\n\nconst now = () => Math.round(Date.now() / 1000)\nconst randomNow = () => Math.round(now() - Math.random() * TWO_DAYS)\n\nconst nip44ConversationKey = (privateKey: Uint8Array, publicKey: string) => getConversationKey(privateKey, publicKey)\n\nconst nip44Encrypt = (data: EventTemplate, privateKey: Uint8Array, publicKey: string) =>\n encrypt(JSON.stringify(data), nip44ConversationKey(privateKey, publicKey))\n\nconst nip44Decrypt = (data: NostrEvent, privateKey: Uint8Array) =>\n JSON.parse(decrypt(data.content, nip44ConversationKey(privateKey, data.pubkey)))\n\nexport function createRumor(event: Partial<UnsignedEvent>, privateKey: Uint8Array): Rumor {\n const rumor = {\n created_at: now(),\n content: '',\n tags: [],\n ...event,\n pubkey: getPublicKey(privateKey),\n } as any\n\n rumor.id = getEventHash(rumor)\n\n return rumor as Rumor\n}\n\nexport function createSeal(rumor: Rumor, privateKey: Uint8Array, recipientPublicKey: string): NostrEvent {\n return finalizeEvent(\n {\n kind: Seal,\n content: nip44Encrypt(rumor, privateKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [],\n },\n privateKey,\n )\n}\n\nexport function createWrap(seal: NostrEvent, recipientPublicKey: string): NostrEvent {\n const randomKey = generateSecretKey()\n\n return finalizeEvent(\n {\n kind: GiftWrap,\n content: nip44Encrypt(seal, randomKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [['p', recipientPublicKey]],\n },\n randomKey,\n ) as NostrEvent\n}\n\nexport function wrapEvent(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientPublicKey: string,\n): NostrEvent {\n const rumor = createRumor(event, senderPrivateKey)\n\n const seal = createSeal(rumor, senderPrivateKey, recipientPublicKey)\n return createWrap(seal, recipientPublicKey)\n}\n\nexport function wrapManyEvents(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientsPublicKeys: string[],\n): NostrEvent[] {\n if (!recipientsPublicKeys || recipientsPublicKeys.length === 0) {\n throw new Error('At least one recipient is required.')\n }\n\n const senderPublicKey = getPublicKey(senderPrivateKey)\n\n const wrappeds = [wrapEvent(event, senderPrivateKey, senderPublicKey)]\n\n recipientsPublicKeys.forEach(recipientPublicKey => {\n wrappeds.push(wrapEvent(event, senderPrivateKey, recipientPublicKey))\n })\n\n return wrappeds\n}\n\nexport function unwrapEvent(wrap: NostrEvent, recipientPrivateKey: Uint8Array): Rumor {\n const unwrappedSeal = nip44Decrypt(wrap, recipientPrivateKey)\n return nip44Decrypt(unwrappedSeal, recipientPrivateKey)\n}\n\nexport function unwrapManyEvents(wrappedEvents: NostrEvent[], recipientPrivateKey: Uint8Array): Rumor[] {\n let unwrappedEvents: Rumor[] = []\n\n wrappedEvents.forEach(e => {\n unwrappedEvents.push(unwrapEvent(e, recipientPrivateKey))\n })\n\n unwrappedEvents.sort((a, b) => a.created_at - b.created_at)\n\n return unwrappedEvents\n}\n"],
- "mappings": "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",
- "names": ["bytesToHex", "i", "sha256", "bytesToHex", "sha256"]
+ "sourcesContent": ["import { chacha20 } from '@noble/ciphers/chacha.js'\nimport { equalBytes } from '@noble/ciphers/utils.js'\nimport { secp256k1 } from '@noble/curves/secp256k1.js'\nimport { extract as hkdf_extract, expand as hkdf_expand } from '@noble/hashes/hkdf.js'\nimport { hmac } from '@noble/hashes/hmac.js'\nimport { sha256 } from '@noble/hashes/sha2.js'\nimport { concatBytes, hexToBytes, randomBytes } from '@noble/hashes/utils.js'\nimport { base64 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst minPlaintextSize = 0x0001 // 1b msg => padded to 32b\nconst maxPlaintextSize = 0xffff // 65535 (64kb-1) => padded to 64kb\n\nexport function getConversationKey(privkeyA: Uint8Array, pubkeyB: string): Uint8Array {\n const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes('02' + pubkeyB)).subarray(1, 33)\n return hkdf_extract(sha256, sharedX, utf8Encoder.encode('nip44-v2'))\n}\n\nfunction getMessageKeys(\n conversationKey: Uint8Array,\n nonce: Uint8Array,\n): { chacha_key: Uint8Array; chacha_nonce: Uint8Array; hmac_key: Uint8Array } {\n const keys = hkdf_expand(sha256, conversationKey, nonce, 76)\n return {\n chacha_key: keys.subarray(0, 32),\n chacha_nonce: keys.subarray(32, 44),\n hmac_key: keys.subarray(44, 76),\n }\n}\n\nfunction calcPaddedLen(len: number): number {\n if (!Number.isSafeInteger(len) || len < 1) throw new Error('expected positive integer')\n if (len <= 32) return 32\n const nextPower = 1 << (Math.floor(Math.log2(len - 1)) + 1)\n const chunk = nextPower <= 256 ? 32 : nextPower / 8\n return chunk * (Math.floor((len - 1) / chunk) + 1)\n}\n\nfunction writeU16BE(num: number): Uint8Array {\n if (!Number.isSafeInteger(num) || num < minPlaintextSize || num > maxPlaintextSize)\n throw new Error('invalid plaintext size: must be between 1 and 65535 bytes')\n const arr = new Uint8Array(2)\n new DataView(arr.buffer).setUint16(0, num, false)\n return arr\n}\n\nfunction pad(plaintext: string): Uint8Array {\n const unpadded = utf8Encoder.encode(plaintext)\n const unpaddedLen = unpadded.length\n const prefix = writeU16BE(unpaddedLen)\n const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen)\n return concatBytes(prefix, unpadded, suffix)\n}\n\nfunction unpad(padded: Uint8Array): string {\n const unpaddedLen = new DataView(padded.buffer).getUint16(0)\n const unpadded = padded.subarray(2, 2 + unpaddedLen)\n if (\n unpaddedLen < minPlaintextSize ||\n unpaddedLen > maxPlaintextSize ||\n unpadded.length !== unpaddedLen ||\n padded.length !== 2 + calcPaddedLen(unpaddedLen)\n )\n throw new Error('invalid padding')\n return utf8Decoder.decode(unpadded)\n}\n\nfunction hmacAad(key: Uint8Array, message: Uint8Array, aad: Uint8Array): Uint8Array {\n if (aad.length !== 32) throw new Error('AAD associated data must be 32 bytes')\n const combined = concatBytes(aad, message)\n return hmac(sha256, key, combined)\n}\n\n// metadata: always 65b (version: 1b, nonce: 32b, max: 32b)\n// plaintext: 1b to 0xffff\n// padded plaintext: 32b to 0xffff\n// ciphertext: 32b+2 to 0xffff+2\n// raw payload: 99 (65+32+2) to 65603 (65+0xffff+2)\n// compressed payload (base64): 132b to 87472b\nfunction decodePayload(payload: string): { nonce: Uint8Array; ciphertext: Uint8Array; mac: Uint8Array } {\n if (typeof payload !== 'string') throw new Error('payload must be a valid string')\n const plen = payload.length\n if (plen < 132 || plen > 87472) throw new Error('invalid payload length: ' + plen)\n if (payload[0] === '#') throw new Error('unknown encryption version')\n let data: Uint8Array\n try {\n data = base64.decode(payload)\n } catch (error) {\n throw new Error('invalid base64: ' + (error as any).message)\n }\n const dlen = data.length\n if (dlen < 99 || dlen > 65603) throw new Error('invalid data length: ' + dlen)\n const vers = data[0]\n if (vers !== 2) throw new Error('unknown encryption version ' + vers)\n return {\n nonce: data.subarray(1, 33),\n ciphertext: data.subarray(33, -32),\n mac: data.subarray(-32),\n }\n}\n\nexport function encrypt(plaintext: string, conversationKey: Uint8Array, nonce: Uint8Array = randomBytes(32)): string {\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const padded = pad(plaintext)\n const ciphertext = chacha20(chacha_key, chacha_nonce, padded)\n const mac = hmacAad(hmac_key, ciphertext, nonce)\n return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac))\n}\n\nexport function decrypt(payload: string, conversationKey: Uint8Array): string {\n const { nonce, ciphertext, mac } = decodePayload(payload)\n const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce)\n const calculatedMac = hmacAad(hmac_key, ciphertext, nonce)\n if (!equalBytes(calculatedMac, mac)) throw new Error('invalid MAC')\n const padded = chacha20(chacha_key, chacha_nonce, ciphertext)\n return unpad(padded)\n}\n\nexport const v2 = {\n utils: {\n getConversationKey,\n calcPaddedLen,\n },\n encrypt,\n decrypt,\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { EventTemplate, UnsignedEvent, NostrEvent } from './core.ts'\nimport { getConversationKey, decrypt, encrypt } from './nip44.ts'\nimport { getEventHash, generateSecretKey, finalizeEvent, getPublicKey } from './pure.ts'\nimport { Seal, GiftWrap } from './kinds.ts'\n\ntype Rumor = UnsignedEvent & { id: string }\n\nconst TWO_DAYS = 2 * 24 * 60 * 60\n\nconst now = () => Math.round(Date.now() / 1000)\nconst randomNow = () => Math.round(now() - Math.random() * TWO_DAYS)\n\nconst nip44ConversationKey = (privateKey: Uint8Array, publicKey: string) => getConversationKey(privateKey, publicKey)\n\nconst nip44Encrypt = (data: EventTemplate, privateKey: Uint8Array, publicKey: string) =>\n encrypt(JSON.stringify(data), nip44ConversationKey(privateKey, publicKey))\n\nconst nip44Decrypt = (data: NostrEvent, privateKey: Uint8Array) =>\n JSON.parse(decrypt(data.content, nip44ConversationKey(privateKey, data.pubkey)))\n\nexport function createRumor(event: Partial<UnsignedEvent>, privateKey: Uint8Array): Rumor {\n const rumor = {\n created_at: now(),\n content: '',\n tags: [],\n ...event,\n pubkey: getPublicKey(privateKey),\n } as any\n\n rumor.id = getEventHash(rumor)\n\n return rumor as Rumor\n}\n\nexport function createSeal(rumor: Rumor, privateKey: Uint8Array, recipientPublicKey: string): NostrEvent {\n return finalizeEvent(\n {\n kind: Seal,\n content: nip44Encrypt(rumor, privateKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [],\n },\n privateKey,\n )\n}\n\nexport function createWrap(seal: NostrEvent, recipientPublicKey: string): NostrEvent {\n const randomKey = generateSecretKey()\n\n return finalizeEvent(\n {\n kind: GiftWrap,\n content: nip44Encrypt(seal, randomKey, recipientPublicKey),\n created_at: randomNow(),\n tags: [['p', recipientPublicKey]],\n },\n randomKey,\n ) as NostrEvent\n}\n\nexport function wrapEvent(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientPublicKey: string,\n): NostrEvent {\n const rumor = createRumor(event, senderPrivateKey)\n\n const seal = createSeal(rumor, senderPrivateKey, recipientPublicKey)\n return createWrap(seal, recipientPublicKey)\n}\n\nexport function wrapManyEvents(\n event: Partial<UnsignedEvent>,\n senderPrivateKey: Uint8Array,\n recipientsPublicKeys: string[],\n): NostrEvent[] {\n if (!recipientsPublicKeys || recipientsPublicKeys.length === 0) {\n throw new Error('At least one recipient is required.')\n }\n\n const senderPublicKey = getPublicKey(senderPrivateKey)\n\n const wrappeds = [wrapEvent(event, senderPrivateKey, senderPublicKey)]\n\n recipientsPublicKeys.forEach(recipientPublicKey => {\n wrappeds.push(wrapEvent(event, senderPrivateKey, recipientPublicKey))\n })\n\n return wrappeds\n}\n\nexport function unwrapEvent(wrap: NostrEvent, recipientPrivateKey: Uint8Array): Rumor {\n const unwrappedSeal = nip44Decrypt(wrap, recipientPrivateKey)\n return nip44Decrypt(unwrappedSeal, recipientPrivateKey)\n}\n\nexport function unwrapManyEvents(wrappedEvents: NostrEvent[], recipientPrivateKey: Uint8Array): Rumor[] {\n let unwrappedEvents: Rumor[] = []\n\n wrappedEvents.forEach(e => {\n unwrappedEvents.push(unwrapEvent(e, recipientPrivateKey))\n })\n\n unwrappedEvents.sort((a, b) => a.created_at - b.created_at)\n\n return unwrappedEvents\n}\n"],
+ "mappings": "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",
+ "names": ["hexToBytes", "hexToBytes", "bytesToHex", "hexToBytes", "i", "sha256", "bytesToHex", "hexToBytes", "sha256"]
} Index: package/lib/cjs/nip77.js.map
===================================================================
--- package/lib/cjs/nip77.js.map
+++ package/lib/cjs/nip77.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip77.ts"],
- "sourcesContent": ["import { bytesToHex, hexToBytes } from '@noble/ciphers/utils'\nimport { Filter } from './filter.ts'\nimport { AbstractRelay, Subscription } from './relay.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\n// Negentropy implementation by Doug Hoyte\nconst PROTOCOL_VERSION = 0x61 // Version 1\nconst ID_SIZE = 32\nconst FINGERPRINT_SIZE = 16\n\nconst Mode = {\n Skip: 0,\n Fingerprint: 1,\n IdList: 2,\n}\n\nclass WrappedBuffer {\n _raw: Uint8Array\n length: number\n\n constructor(buffer?: Uint8Array | number) {\n if (typeof buffer === 'number') {\n this._raw = new Uint8Array(buffer)\n this.length = 0\n } else if (buffer instanceof Uint8Array) {\n this._raw = new Uint8Array(buffer)\n this.length = buffer.length\n } else {\n this._raw = new Uint8Array(512)\n this.length = 0\n }\n }\n\n unwrap(): Uint8Array {\n return this._raw.subarray(0, this.length)\n }\n\n get capacity(): number {\n return this._raw.byteLength\n }\n\n extend(buf: Uint8Array | WrappedBuffer): void {\n if (buf instanceof WrappedBuffer) buf = buf.unwrap()\n if (typeof buf.length !== 'number') throw Error('bad length')\n const targetSize = buf.length + this.length\n if (this.capacity < targetSize) {\n const oldRaw = this._raw\n const newCapacity = Math.max(this.capacity * 2, targetSize)\n this._raw = new Uint8Array(newCapacity)\n this._raw.set(oldRaw)\n }\n\n this._raw.set(buf, this.length)\n this.length += buf.length\n }\n\n shift(): number {\n const first = this._raw[0]\n this._raw = this._raw.subarray(1)\n this.length--\n return first\n }\n\n shiftN(n: number = 1): Uint8Array {\n const firstSubarray = this._raw.subarray(0, n)\n this._raw = this._raw.subarray(n)\n this.length -= n\n return firstSubarray\n }\n}\n\nfunction decodeVarInt(buf: WrappedBuffer): number {\n let res = 0\n\n while (1) {\n if (buf.length === 0) throw Error('parse ends prematurely')\n let byte = buf.shift()\n res = (res << 7) | (byte & 127)\n if ((byte & 128) === 0) break\n }\n\n return res\n}\n\nfunction encodeVarInt(n: number): WrappedBuffer {\n if (n === 0) return new WrappedBuffer(new Uint8Array([0]))\n\n let o: number[] = []\n\n while (n !== 0) {\n o.push(n & 127)\n n >>>= 7\n }\n\n o.reverse()\n\n for (let i = 0; i < o.length - 1; i++) o[i] |= 128\n\n return new WrappedBuffer(new Uint8Array(o))\n}\n\nfunction getByte(buf: WrappedBuffer): number {\n return getBytes(buf, 1)[0]\n}\n\nfunction getBytes(buf: WrappedBuffer, n: number): Uint8Array {\n if (buf.length < n) throw Error('parse ends prematurely')\n return buf.shiftN(n)\n}\n\nclass Accumulator {\n buf!: Uint8Array\n\n constructor() {\n this.setToZero()\n }\n\n setToZero(): void {\n this.buf = new Uint8Array(ID_SIZE)\n }\n\n add(otherBuf: Uint8Array): void {\n let currCarry = 0,\n nextCarry = 0\n let p = new DataView(this.buf.buffer)\n let po = new DataView(otherBuf.buffer)\n\n for (let i = 0; i < 8; i++) {\n let offset = i * 4\n let orig = p.getUint32(offset, true)\n let otherV = po.getUint32(offset, true)\n\n let next = orig\n\n next += currCarry\n next += otherV\n if (next > 0xffffffff) nextCarry = 1\n\n p.setUint32(offset, next & 0xffffffff, true)\n currCarry = nextCarry\n nextCarry = 0\n }\n }\n\n negate(): void {\n let p = new DataView(this.buf.buffer)\n\n for (let i = 0; i < 8; i++) {\n let offset = i * 4\n p.setUint32(offset, ~p.getUint32(offset, true))\n }\n\n let one = new Uint8Array(ID_SIZE)\n one[0] = 1\n this.add(one)\n }\n\n getFingerprint(n: number): Uint8Array {\n let input = new WrappedBuffer()\n input.extend(this.buf)\n input.extend(encodeVarInt(n))\n\n let hash = sha256(input.unwrap())\n return hash.subarray(0, FINGERPRINT_SIZE)\n }\n}\n\nexport class NegentropyStorageVector {\n items: { timestamp: number; id: Uint8Array }[]\n sealed: boolean\n\n constructor() {\n this.items = []\n this.sealed = false\n }\n\n insert(timestamp: number, id: string): void {\n if (this.sealed) throw Error('already sealed')\n const idb = hexToBytes(id)\n if (idb.byteLength !== ID_SIZE) throw Error('bad id size for added item')\n this.items.push({ timestamp, id: idb })\n }\n\n seal(): void {\n if (this.sealed) throw Error('already sealed')\n this.sealed = true\n\n this.items.sort(itemCompare)\n\n for (let i = 1; i < this.items.length; i++) {\n if (itemCompare(this.items[i - 1], this.items[i]) === 0) throw Error('duplicate item inserted')\n }\n }\n\n unseal(): void {\n this.sealed = false\n }\n\n size(): number {\n this._checkSealed()\n return this.items.length\n }\n\n getItem(i: number): { timestamp: number; id: Uint8Array } {\n this._checkSealed()\n if (i >= this.items.length) throw Error('out of range')\n return this.items[i]\n }\n\n iterate(begin: number, end: number, cb: (item: { timestamp: number; id: Uint8Array }, i: number) => boolean): void {\n this._checkSealed()\n this._checkBounds(begin, end)\n\n for (let i = begin; i < end; ++i) {\n if (!cb(this.items[i], i)) break\n }\n }\n\n findLowerBound(begin: number, end: number, bound: { timestamp: number; id: Uint8Array }): number {\n this._checkSealed()\n this._checkBounds(begin, end)\n\n return this._binarySearch(this.items, begin, end, a => itemCompare(a, bound) < 0)\n }\n\n fingerprint(begin: number, end: number): Uint8Array {\n let out = new Accumulator()\n out.setToZero()\n\n this.iterate(begin, end, item => {\n out.add(item.id)\n return true\n })\n\n return out.getFingerprint(end - begin)\n }\n\n _checkSealed(): void {\n if (!this.sealed) throw Error('not sealed')\n }\n\n _checkBounds(begin: number, end: number): void {\n if (begin > end || end > this.items.length) throw Error('bad range')\n }\n\n _binarySearch(\n arr: { timestamp: number; id: Uint8Array }[],\n first: number,\n last: number,\n cmp: (a: { timestamp: number; id: Uint8Array }) => boolean,\n ): number {\n let count = last - first\n\n while (count > 0) {\n let it = first\n let step = Math.floor(count / 2)\n it += step\n\n if (cmp(arr[it])) {\n first = ++it\n count -= step + 1\n } else {\n count = step\n }\n }\n\n return first\n }\n}\n\nexport class Negentropy {\n storage: NegentropyStorageVector\n frameSizeLimit: number\n lastTimestampIn: number\n lastTimestampOut: number\n\n constructor(storage: NegentropyStorageVector, frameSizeLimit: number = 60_000) {\n if (frameSizeLimit < 4096) throw Error('frameSizeLimit too small')\n\n this.storage = storage\n this.frameSizeLimit = frameSizeLimit\n\n this.lastTimestampIn = 0\n this.lastTimestampOut = 0\n }\n\n _bound(timestamp: number, id?: Uint8Array): { timestamp: number; id: Uint8Array } {\n return { timestamp, id: id || new Uint8Array(0) }\n }\n\n initiate(): string {\n let output = new WrappedBuffer()\n output.extend(new Uint8Array([PROTOCOL_VERSION]))\n this.splitRange(0, this.storage.size(), this._bound(Number.MAX_VALUE), output)\n return bytesToHex(output.unwrap())\n }\n\n reconcile(queryMsg: string, onhave?: (id: string) => void, onneed?: (id: string) => void): string | null {\n const query = new WrappedBuffer(hexToBytes(queryMsg))\n\n this.lastTimestampIn = this.lastTimestampOut = 0 // reset for each message\n\n let fullOutput = new WrappedBuffer()\n fullOutput.extend(new Uint8Array([PROTOCOL_VERSION]))\n\n let protocolVersion = getByte(query)\n if (protocolVersion < 0x60 || protocolVersion > 0x6f) throw Error('invalid negentropy protocol version byte')\n if (protocolVersion !== PROTOCOL_VERSION) {\n throw Error('unsupported negentropy protocol version requested: ' + (protocolVersion - 0x60))\n }\n\n let storageSize = this.storage.size()\n let prevBound = this._bound(0)\n let prevIndex = 0\n let skip = false\n\n while (query.length !== 0) {\n let o = new WrappedBuffer()\n\n let doSkip = () => {\n if (skip) {\n skip = false\n o.extend(this.encodeBound(prevBound))\n o.extend(encodeVarInt(Mode.Skip))\n }\n }\n\n let currBound = this.decodeBound(query)\n let mode = decodeVarInt(query)\n\n let lower = prevIndex\n let upper = this.storage.findLowerBound(prevIndex, storageSize, currBound)\n\n if (mode === Mode.Skip) {\n skip = true\n } else if (mode === Mode.Fingerprint) {\n let theirFingerprint = getBytes(query, FINGERPRINT_SIZE)\n let ourFingerprint = this.storage.fingerprint(lower, upper)\n\n if (compareUint8Array(theirFingerprint, ourFingerprint) !== 0) {\n doSkip()\n this.splitRange(lower, upper, currBound, o)\n } else {\n skip = true\n }\n } else if (mode === Mode.IdList) {\n let numIds = decodeVarInt(query)\n\n let theirElems: { [key: string]: Uint8Array } = {} // stringified Uint8Array -> original Uint8Array (or hex)\n for (let i = 0; i < numIds; i++) {\n let e = getBytes(query, ID_SIZE)\n theirElems[bytesToHex(e)] = e\n }\n\n skip = true\n this.storage.iterate(lower, upper, item => {\n let k = item.id\n const id = bytesToHex(k)\n\n if (!theirElems[id]) {\n // ID exists on our side, but not their side\n onhave?.(id)\n } else {\n // ID exists on both sides\n delete theirElems[bytesToHex(k)]\n }\n\n return true\n })\n\n if (onneed) {\n for (let v of Object.values(theirElems)) {\n // ID exists on their side, but not our side\n onneed(bytesToHex(v))\n }\n }\n } else {\n throw Error('unexpected mode')\n }\n\n if (this.exceededFrameSizeLimit(fullOutput.length + o.length)) {\n // frameSizeLimit exceeded: stop range processing and return a fingerprint for the remaining range\n let remainingFingerprint = this.storage.fingerprint(upper, storageSize)\n\n fullOutput.extend(this.encodeBound(this._bound(Number.MAX_VALUE)))\n fullOutput.extend(encodeVarInt(Mode.Fingerprint))\n fullOutput.extend(remainingFingerprint)\n break\n } else {\n fullOutput.extend(o)\n }\n\n prevIndex = upper\n prevBound = currBound\n }\n\n return fullOutput.length === 1 ? null : bytesToHex(fullOutput.unwrap())\n }\n\n splitRange(lower: number, upper: number, upperBound: { timestamp: number; id: Uint8Array }, o: WrappedBuffer) {\n let numElems = upper - lower\n let buckets = 16\n\n if (numElems < buckets * 2) {\n o.extend(this.encodeBound(upperBound))\n o.extend(encodeVarInt(Mode.IdList))\n\n o.extend(encodeVarInt(numElems))\n this.storage.iterate(lower, upper, item => {\n o.extend(item.id)\n return true\n })\n } else {\n let itemsPerBucket = Math.floor(numElems / buckets)\n let bucketsWithExtra = numElems % buckets\n let curr = lower\n\n for (let i = 0; i < buckets; i++) {\n let bucketSize = itemsPerBucket + (i < bucketsWithExtra ? 1 : 0)\n let ourFingerprint = this.storage.fingerprint(curr, curr + bucketSize)\n curr += bucketSize\n\n let nextBound: { timestamp: number; id: Uint8Array }\n\n if (curr === upper) {\n nextBound = upperBound\n } else {\n let prevItem: { timestamp: number; id: Uint8Array } | undefined\n let currItem: { timestamp: number; id: Uint8Array } | undefined\n\n this.storage.iterate(curr - 1, curr + 1, (item, index) => {\n if (index === curr - 1) prevItem = item\n else currItem = item\n return true\n })\n\n nextBound = this.getMinimalBound(prevItem!, currItem!)\n }\n\n o.extend(this.encodeBound(nextBound))\n o.extend(encodeVarInt(Mode.Fingerprint))\n o.extend(ourFingerprint)\n }\n }\n }\n\n exceededFrameSizeLimit(n: number): boolean {\n return n > this.frameSizeLimit - 200\n }\n\n // Decoding\n decodeTimestampIn(encoded: WrappedBuffer): number {\n let timestamp = decodeVarInt(encoded)\n timestamp = timestamp === 0 ? Number.MAX_VALUE : timestamp - 1\n if (this.lastTimestampIn === Number.MAX_VALUE || timestamp === Number.MAX_VALUE) {\n this.lastTimestampIn = Number.MAX_VALUE\n return Number.MAX_VALUE\n }\n timestamp += this.lastTimestampIn\n this.lastTimestampIn = timestamp\n return timestamp\n }\n\n decodeBound(encoded: WrappedBuffer): { timestamp: number; id: Uint8Array } {\n let timestamp = this.decodeTimestampIn(encoded)\n let len = decodeVarInt(encoded)\n if (len > ID_SIZE) throw Error('bound key too long')\n let id = getBytes(encoded, len)\n return { timestamp, id }\n }\n\n // Encoding\n encodeTimestampOut(timestamp: number): WrappedBuffer {\n if (timestamp === Number.MAX_VALUE) {\n this.lastTimestampOut = Number.MAX_VALUE\n return encodeVarInt(0)\n }\n\n let temp = timestamp\n timestamp -= this.lastTimestampOut\n this.lastTimestampOut = temp\n return encodeVarInt(timestamp + 1)\n }\n\n encodeBound(key: { timestamp: number; id: Uint8Array }): WrappedBuffer {\n let output = new WrappedBuffer()\n\n output.extend(this.encodeTimestampOut(key.timestamp))\n output.extend(encodeVarInt(key.id.length))\n output.extend(key.id)\n\n return output\n }\n\n getMinimalBound(\n prev: { timestamp: number; id: Uint8Array },\n curr: { timestamp: number; id: Uint8Array },\n ): { timestamp: number; id: Uint8Array } {\n if (curr.timestamp !== prev.timestamp) {\n return this._bound(curr.timestamp)\n } else {\n let sharedPrefixBytes = 0\n let currKey = curr.id\n let prevKey = prev.id\n\n for (let i = 0; i < ID_SIZE; i++) {\n if (currKey[i] !== prevKey[i]) break\n sharedPrefixBytes++\n }\n\n return this._bound(curr.timestamp, curr.id.subarray(0, sharedPrefixBytes + 1))\n }\n }\n}\n\nfunction compareUint8Array(a: Uint8Array, b: Uint8Array): number {\n for (let i = 0; i < a.byteLength; i++) {\n if (a[i] < b[i]) return -1\n if (a[i] > b[i]) return 1\n }\n\n if (a.byteLength > b.byteLength) return 1\n if (a.byteLength < b.byteLength) return -1\n\n return 0\n}\n\nfunction itemCompare(a: { timestamp: number; id: Uint8Array }, b: { timestamp: number; id: Uint8Array }): number {\n if (a.timestamp === b.timestamp) {\n return compareUint8Array(a.id, b.id)\n }\n\n return a.timestamp - b.timestamp\n}\n\nexport class NegentropySync {\n relay: AbstractRelay\n storage: NegentropyStorageVector\n private neg: Negentropy\n private filter: Filter\n private subscription: Subscription\n private onhave?: (id: string) => void\n private onneed?: (id: string) => void\n\n constructor(\n relay: AbstractRelay,\n storage: NegentropyStorageVector,\n filter: Filter,\n params: {\n label?: string\n onhave?: (id: string) => void\n onneed?: (id: string) => void\n onclose?: (errReason?: string) => void\n } = {},\n ) {\n this.relay = relay\n this.storage = storage\n this.neg = new Negentropy(storage)\n this.onhave = params.onhave\n this.onneed = params.onneed\n this.filter = filter\n\n // we prepare a subscription with an empty filter, but it will not be used\n this.subscription = this.relay.prepareSubscription([{}], { label: params.label || 'negentropy' })\n this.subscription.oncustom = (data: string[]) => {\n switch (data[0]) {\n case 'NEG-MSG': {\n if (data.length < 3) {\n console.warn(`got invalid NEG-MSG from ${this.relay.url}: ${data}`)\n }\n try {\n const response = this.neg.reconcile(data[2], this.onhave, this.onneed)\n if (response) {\n this.relay.send(`[\"NEG-MSG\", \"${this.subscription.id}\", \"${response}\"]`)\n } else {\n this.close()\n params.onclose?.()\n }\n } catch (error) {\n console.error('negentropy reconcile error:', error)\n params?.onclose?.(`reconcile error: ${error}`)\n }\n break\n }\n case 'NEG-CLOSE': {\n const reason = data[2]\n console.warn('negentropy error:', reason)\n params.onclose?.(reason)\n break\n }\n case 'NEG-ERR': {\n params.onclose?.()\n }\n }\n }\n }\n\n async start(): Promise<void> {\n const initMsg = this.neg.initiate()\n this.relay.send(`[\"NEG-OPEN\",\"${this.subscription.id}\",${JSON.stringify(this.filter)},\"${initMsg}\"]`)\n }\n\n close(): void {\n this.relay.send(`[\"NEG-CLOSE\",\"${this.subscription.id}\"]`)\n this.subscription.close()\n }\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Filter } from './filter.ts'\nimport { AbstractRelay, Subscription } from './relay.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\n// Negentropy implementation by Doug Hoyte\nconst PROTOCOL_VERSION = 0x61 // Version 1\nconst ID_SIZE = 32\nconst FINGERPRINT_SIZE = 16\n\nconst Mode = {\n Skip: 0,\n Fingerprint: 1,\n IdList: 2,\n}\n\nclass WrappedBuffer {\n _raw: Uint8Array\n length: number\n\n constructor(buffer?: Uint8Array | number) {\n if (typeof buffer === 'number') {\n this._raw = new Uint8Array(buffer)\n this.length = 0\n } else if (buffer instanceof Uint8Array) {\n this._raw = new Uint8Array(buffer)\n this.length = buffer.length\n } else {\n this._raw = new Uint8Array(512)\n this.length = 0\n }\n }\n\n unwrap(): Uint8Array {\n return this._raw.subarray(0, this.length)\n }\n\n get capacity(): number {\n return this._raw.byteLength\n }\n\n extend(buf: Uint8Array | WrappedBuffer): void {\n if (buf instanceof WrappedBuffer) buf = buf.unwrap()\n if (typeof buf.length !== 'number') throw Error('bad length')\n const targetSize = buf.length + this.length\n if (this.capacity < targetSize) {\n const oldRaw = this._raw\n const newCapacity = Math.max(this.capacity * 2, targetSize)\n this._raw = new Uint8Array(newCapacity)\n this._raw.set(oldRaw)\n }\n\n this._raw.set(buf, this.length)\n this.length += buf.length\n }\n\n shift(): number {\n const first = this._raw[0]\n this._raw = this._raw.subarray(1)\n this.length--\n return first\n }\n\n shiftN(n: number = 1): Uint8Array {\n const firstSubarray = this._raw.subarray(0, n)\n this._raw = this._raw.subarray(n)\n this.length -= n\n return firstSubarray\n }\n}\n\nfunction decodeVarInt(buf: WrappedBuffer): number {\n let res = 0\n\n while (1) {\n if (buf.length === 0) throw Error('parse ends prematurely')\n let byte = buf.shift()\n res = (res << 7) | (byte & 127)\n if ((byte & 128) === 0) break\n }\n\n return res\n}\n\nfunction encodeVarInt(n: number): WrappedBuffer {\n if (n === 0) return new WrappedBuffer(new Uint8Array([0]))\n\n let o: number[] = []\n\n while (n !== 0) {\n o.push(n & 127)\n n >>>= 7\n }\n\n o.reverse()\n\n for (let i = 0; i < o.length - 1; i++) o[i] |= 128\n\n return new WrappedBuffer(new Uint8Array(o))\n}\n\nfunction getByte(buf: WrappedBuffer): number {\n return getBytes(buf, 1)[0]\n}\n\nfunction getBytes(buf: WrappedBuffer, n: number): Uint8Array {\n if (buf.length < n) throw Error('parse ends prematurely')\n return buf.shiftN(n)\n}\n\nclass Accumulator {\n buf!: Uint8Array\n\n constructor() {\n this.setToZero()\n }\n\n setToZero(): void {\n this.buf = new Uint8Array(ID_SIZE)\n }\n\n add(otherBuf: Uint8Array): void {\n let currCarry = 0,\n nextCarry = 0\n let p = new DataView(this.buf.buffer)\n let po = new DataView(otherBuf.buffer)\n\n for (let i = 0; i < 8; i++) {\n let offset = i * 4\n let orig = p.getUint32(offset, true)\n let otherV = po.getUint32(offset, true)\n\n let next = orig\n\n next += currCarry\n next += otherV\n if (next > 0xffffffff) nextCarry = 1\n\n p.setUint32(offset, next & 0xffffffff, true)\n currCarry = nextCarry\n nextCarry = 0\n }\n }\n\n negate(): void {\n let p = new DataView(this.buf.buffer)\n\n for (let i = 0; i < 8; i++) {\n let offset = i * 4\n p.setUint32(offset, ~p.getUint32(offset, true))\n }\n\n let one = new Uint8Array(ID_SIZE)\n one[0] = 1\n this.add(one)\n }\n\n getFingerprint(n: number): Uint8Array {\n let input = new WrappedBuffer()\n input.extend(this.buf)\n input.extend(encodeVarInt(n))\n\n let hash = sha256(input.unwrap())\n return hash.subarray(0, FINGERPRINT_SIZE)\n }\n}\n\nexport class NegentropyStorageVector {\n items: { timestamp: number; id: Uint8Array }[]\n sealed: boolean\n\n constructor() {\n this.items = []\n this.sealed = false\n }\n\n insert(timestamp: number, id: string): void {\n if (this.sealed) throw Error('already sealed')\n const idb = hexToBytes(id)\n if (idb.byteLength !== ID_SIZE) throw Error('bad id size for added item')\n this.items.push({ timestamp, id: idb })\n }\n\n seal(): void {\n if (this.sealed) throw Error('already sealed')\n this.sealed = true\n\n this.items.sort(itemCompare)\n\n for (let i = 1; i < this.items.length; i++) {\n if (itemCompare(this.items[i - 1], this.items[i]) === 0) throw Error('duplicate item inserted')\n }\n }\n\n unseal(): void {\n this.sealed = false\n }\n\n size(): number {\n this._checkSealed()\n return this.items.length\n }\n\n getItem(i: number): { timestamp: number; id: Uint8Array } {\n this._checkSealed()\n if (i >= this.items.length) throw Error('out of range')\n return this.items[i]\n }\n\n iterate(begin: number, end: number, cb: (item: { timestamp: number; id: Uint8Array }, i: number) => boolean): void {\n this._checkSealed()\n this._checkBounds(begin, end)\n\n for (let i = begin; i < end; ++i) {\n if (!cb(this.items[i], i)) break\n }\n }\n\n findLowerBound(begin: number, end: number, bound: { timestamp: number; id: Uint8Array }): number {\n this._checkSealed()\n this._checkBounds(begin, end)\n\n return this._binarySearch(this.items, begin, end, a => itemCompare(a, bound) < 0)\n }\n\n fingerprint(begin: number, end: number): Uint8Array {\n let out = new Accumulator()\n out.setToZero()\n\n this.iterate(begin, end, item => {\n out.add(item.id)\n return true\n })\n\n return out.getFingerprint(end - begin)\n }\n\n _checkSealed(): void {\n if (!this.sealed) throw Error('not sealed')\n }\n\n _checkBounds(begin: number, end: number): void {\n if (begin > end || end > this.items.length) throw Error('bad range')\n }\n\n _binarySearch(\n arr: { timestamp: number; id: Uint8Array }[],\n first: number,\n last: number,\n cmp: (a: { timestamp: number; id: Uint8Array }) => boolean,\n ): number {\n let count = last - first\n\n while (count > 0) {\n let it = first\n let step = Math.floor(count / 2)\n it += step\n\n if (cmp(arr[it])) {\n first = ++it\n count -= step + 1\n } else {\n count = step\n }\n }\n\n return first\n }\n}\n\nexport class Negentropy {\n storage: NegentropyStorageVector\n frameSizeLimit: number\n lastTimestampIn: number\n lastTimestampOut: number\n\n constructor(storage: NegentropyStorageVector, frameSizeLimit: number = 60_000) {\n if (frameSizeLimit < 4096) throw Error('frameSizeLimit too small')\n\n this.storage = storage\n this.frameSizeLimit = frameSizeLimit\n\n this.lastTimestampIn = 0\n this.lastTimestampOut = 0\n }\n\n _bound(timestamp: number, id?: Uint8Array): { timestamp: number; id: Uint8Array } {\n return { timestamp, id: id || new Uint8Array(0) }\n }\n\n initiate(): string {\n let output = new WrappedBuffer()\n output.extend(new Uint8Array([PROTOCOL_VERSION]))\n this.splitRange(0, this.storage.size(), this._bound(Number.MAX_VALUE), output)\n return bytesToHex(output.unwrap())\n }\n\n reconcile(queryMsg: string, onhave?: (id: string) => void, onneed?: (id: string) => void): string | null {\n const query = new WrappedBuffer(hexToBytes(queryMsg))\n\n this.lastTimestampIn = this.lastTimestampOut = 0 // reset for each message\n\n let fullOutput = new WrappedBuffer()\n fullOutput.extend(new Uint8Array([PROTOCOL_VERSION]))\n\n let protocolVersion = getByte(query)\n if (protocolVersion < 0x60 || protocolVersion > 0x6f) throw Error('invalid negentropy protocol version byte')\n if (protocolVersion !== PROTOCOL_VERSION) {\n throw Error('unsupported negentropy protocol version requested: ' + (protocolVersion - 0x60))\n }\n\n let storageSize = this.storage.size()\n let prevBound = this._bound(0)\n let prevIndex = 0\n let skip = false\n\n while (query.length !== 0) {\n let o = new WrappedBuffer()\n\n let doSkip = () => {\n if (skip) {\n skip = false\n o.extend(this.encodeBound(prevBound))\n o.extend(encodeVarInt(Mode.Skip))\n }\n }\n\n let currBound = this.decodeBound(query)\n let mode = decodeVarInt(query)\n\n let lower = prevIndex\n let upper = this.storage.findLowerBound(prevIndex, storageSize, currBound)\n\n if (mode === Mode.Skip) {\n skip = true\n } else if (mode === Mode.Fingerprint) {\n let theirFingerprint = getBytes(query, FINGERPRINT_SIZE)\n let ourFingerprint = this.storage.fingerprint(lower, upper)\n\n if (compareUint8Array(theirFingerprint, ourFingerprint) !== 0) {\n doSkip()\n this.splitRange(lower, upper, currBound, o)\n } else {\n skip = true\n }\n } else if (mode === Mode.IdList) {\n let numIds = decodeVarInt(query)\n\n let theirElems: { [key: string]: Uint8Array } = {} // stringified Uint8Array -> original Uint8Array (or hex)\n for (let i = 0; i < numIds; i++) {\n let e = getBytes(query, ID_SIZE)\n theirElems[bytesToHex(e)] = e\n }\n\n skip = true\n this.storage.iterate(lower, upper, item => {\n let k = item.id\n const id = bytesToHex(k)\n\n if (!theirElems[id]) {\n // ID exists on our side, but not their side\n onhave?.(id)\n } else {\n // ID exists on both sides\n delete theirElems[bytesToHex(k)]\n }\n\n return true\n })\n\n if (onneed) {\n for (let v of Object.values(theirElems)) {\n // ID exists on their side, but not our side\n onneed(bytesToHex(v))\n }\n }\n } else {\n throw Error('unexpected mode')\n }\n\n if (this.exceededFrameSizeLimit(fullOutput.length + o.length)) {\n // frameSizeLimit exceeded: stop range processing and return a fingerprint for the remaining range\n let remainingFingerprint = this.storage.fingerprint(upper, storageSize)\n\n fullOutput.extend(this.encodeBound(this._bound(Number.MAX_VALUE)))\n fullOutput.extend(encodeVarInt(Mode.Fingerprint))\n fullOutput.extend(remainingFingerprint)\n break\n } else {\n fullOutput.extend(o)\n }\n\n prevIndex = upper\n prevBound = currBound\n }\n\n return fullOutput.length === 1 ? null : bytesToHex(fullOutput.unwrap())\n }\n\n splitRange(lower: number, upper: number, upperBound: { timestamp: number; id: Uint8Array }, o: WrappedBuffer) {\n let numElems = upper - lower\n let buckets = 16\n\n if (numElems < buckets * 2) {\n o.extend(this.encodeBound(upperBound))\n o.extend(encodeVarInt(Mode.IdList))\n\n o.extend(encodeVarInt(numElems))\n this.storage.iterate(lower, upper, item => {\n o.extend(item.id)\n return true\n })\n } else {\n let itemsPerBucket = Math.floor(numElems / buckets)\n let bucketsWithExtra = numElems % buckets\n let curr = lower\n\n for (let i = 0; i < buckets; i++) {\n let bucketSize = itemsPerBucket + (i < bucketsWithExtra ? 1 : 0)\n let ourFingerprint = this.storage.fingerprint(curr, curr + bucketSize)\n curr += bucketSize\n\n let nextBound: { timestamp: number; id: Uint8Array }\n\n if (curr === upper) {\n nextBound = upperBound\n } else {\n let prevItem: { timestamp: number; id: Uint8Array } | undefined\n let currItem: { timestamp: number; id: Uint8Array } | undefined\n\n this.storage.iterate(curr - 1, curr + 1, (item, index) => {\n if (index === curr - 1) prevItem = item\n else currItem = item\n return true\n })\n\n nextBound = this.getMinimalBound(prevItem!, currItem!)\n }\n\n o.extend(this.encodeBound(nextBound))\n o.extend(encodeVarInt(Mode.Fingerprint))\n o.extend(ourFingerprint)\n }\n }\n }\n\n exceededFrameSizeLimit(n: number): boolean {\n return n > this.frameSizeLimit - 200\n }\n\n // Decoding\n decodeTimestampIn(encoded: WrappedBuffer): number {\n let timestamp = decodeVarInt(encoded)\n timestamp = timestamp === 0 ? Number.MAX_VALUE : timestamp - 1\n if (this.lastTimestampIn === Number.MAX_VALUE || timestamp === Number.MAX_VALUE) {\n this.lastTimestampIn = Number.MAX_VALUE\n return Number.MAX_VALUE\n }\n timestamp += this.lastTimestampIn\n this.lastTimestampIn = timestamp\n return timestamp\n }\n\n decodeBound(encoded: WrappedBuffer): { timestamp: number; id: Uint8Array } {\n let timestamp = this.decodeTimestampIn(encoded)\n let len = decodeVarInt(encoded)\n if (len > ID_SIZE) throw Error('bound key too long')\n let id = getBytes(encoded, len)\n return { timestamp, id }\n }\n\n // Encoding\n encodeTimestampOut(timestamp: number): WrappedBuffer {\n if (timestamp === Number.MAX_VALUE) {\n this.lastTimestampOut = Number.MAX_VALUE\n return encodeVarInt(0)\n }\n\n let temp = timestamp\n timestamp -= this.lastTimestampOut\n this.lastTimestampOut = temp\n return encodeVarInt(timestamp + 1)\n }\n\n encodeBound(key: { timestamp: number; id: Uint8Array }): WrappedBuffer {\n let output = new WrappedBuffer()\n\n output.extend(this.encodeTimestampOut(key.timestamp))\n output.extend(encodeVarInt(key.id.length))\n output.extend(key.id)\n\n return output\n }\n\n getMinimalBound(\n prev: { timestamp: number; id: Uint8Array },\n curr: { timestamp: number; id: Uint8Array },\n ): { timestamp: number; id: Uint8Array } {\n if (curr.timestamp !== prev.timestamp) {\n return this._bound(curr.timestamp)\n } else {\n let sharedPrefixBytes = 0\n let currKey = curr.id\n let prevKey = prev.id\n\n for (let i = 0; i < ID_SIZE; i++) {\n if (currKey[i] !== prevKey[i]) break\n sharedPrefixBytes++\n }\n\n return this._bound(curr.timestamp, curr.id.subarray(0, sharedPrefixBytes + 1))\n }\n }\n}\n\nfunction compareUint8Array(a: Uint8Array, b: Uint8Array): number {\n for (let i = 0; i < a.byteLength; i++) {\n if (a[i] < b[i]) return -1\n if (a[i] > b[i]) return 1\n }\n\n if (a.byteLength > b.byteLength) return 1\n if (a.byteLength < b.byteLength) return -1\n\n return 0\n}\n\nfunction itemCompare(a: { timestamp: number; id: Uint8Array }, b: { timestamp: number; id: Uint8Array }): number {\n if (a.timestamp === b.timestamp) {\n return compareUint8Array(a.id, b.id)\n }\n\n return a.timestamp - b.timestamp\n}\n\nexport class NegentropySync {\n relay: AbstractRelay\n storage: NegentropyStorageVector\n private neg: Negentropy\n private filter: Filter\n private subscription: Subscription\n private onhave?: (id: string) => void\n private onneed?: (id: string) => void\n\n constructor(\n relay: AbstractRelay,\n storage: NegentropyStorageVector,\n filter: Filter,\n params: {\n label?: string\n onhave?: (id: string) => void\n onneed?: (id: string) => void\n onclose?: (errReason?: string) => void\n } = {},\n ) {\n this.relay = relay\n this.storage = storage\n this.neg = new Negentropy(storage)\n this.onhave = params.onhave\n this.onneed = params.onneed\n this.filter = filter\n\n // we prepare a subscription with an empty filter, but it will not be used\n this.subscription = this.relay.prepareSubscription([{}], { label: params.label || 'negentropy' })\n this.subscription.oncustom = (data: string[]) => {\n switch (data[0]) {\n case 'NEG-MSG': {\n if (data.length < 3) {\n console.warn(`got invalid NEG-MSG from ${this.relay.url}: ${data}`)\n }\n try {\n const response = this.neg.reconcile(data[2], this.onhave, this.onneed)\n if (response) {\n this.relay.send(`[\"NEG-MSG\", \"${this.subscription.id}\", \"${response}\"]`)\n } else {\n this.close()\n params.onclose?.()\n }\n } catch (error) {\n console.error('negentropy reconcile error:', error)\n params?.onclose?.(`reconcile error: ${error}`)\n }\n break\n }\n case 'NEG-CLOSE': {\n const reason = data[2]\n console.warn('negentropy error:', reason)\n params.onclose?.(reason)\n break\n }\n case 'NEG-ERR': {\n params.onclose?.()\n }\n }\n }\n }\n\n async start(): Promise<void> {\n const initMsg = this.neg.initiate()\n this.relay.send(`[\"NEG-OPEN\",\"${this.subscription.id}\",${JSON.stringify(this.filter)},\"${initMsg}\"]`)\n }\n\n close(): void {\n this.relay.send(`[\"NEG-CLOSE\",\"${this.subscription.id}\"]`)\n this.subscription.close()\n }\n}\n"],
+ "mappings": "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",
"names": []
} Index: package/lib/esm/nip77.js.map
===================================================================
--- package/lib/esm/nip77.js.map
+++ package/lib/esm/nip77.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip77.ts"],
- "sourcesContent": ["import { bytesToHex, hexToBytes } from '@noble/ciphers/utils'\nimport { Filter } from './filter.ts'\nimport { AbstractRelay, Subscription } from './relay.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\n// Negentropy implementation by Doug Hoyte\nconst PROTOCOL_VERSION = 0x61 // Version 1\nconst ID_SIZE = 32\nconst FINGERPRINT_SIZE = 16\n\nconst Mode = {\n Skip: 0,\n Fingerprint: 1,\n IdList: 2,\n}\n\nclass WrappedBuffer {\n _raw: Uint8Array\n length: number\n\n constructor(buffer?: Uint8Array | number) {\n if (typeof buffer === 'number') {\n this._raw = new Uint8Array(buffer)\n this.length = 0\n } else if (buffer instanceof Uint8Array) {\n this._raw = new Uint8Array(buffer)\n this.length = buffer.length\n } else {\n this._raw = new Uint8Array(512)\n this.length = 0\n }\n }\n\n unwrap(): Uint8Array {\n return this._raw.subarray(0, this.length)\n }\n\n get capacity(): number {\n return this._raw.byteLength\n }\n\n extend(buf: Uint8Array | WrappedBuffer): void {\n if (buf instanceof WrappedBuffer) buf = buf.unwrap()\n if (typeof buf.length !== 'number') throw Error('bad length')\n const targetSize = buf.length + this.length\n if (this.capacity < targetSize) {\n const oldRaw = this._raw\n const newCapacity = Math.max(this.capacity * 2, targetSize)\n this._raw = new Uint8Array(newCapacity)\n this._raw.set(oldRaw)\n }\n\n this._raw.set(buf, this.length)\n this.length += buf.length\n }\n\n shift(): number {\n const first = this._raw[0]\n this._raw = this._raw.subarray(1)\n this.length--\n return first\n }\n\n shiftN(n: number = 1): Uint8Array {\n const firstSubarray = this._raw.subarray(0, n)\n this._raw = this._raw.subarray(n)\n this.length -= n\n return firstSubarray\n }\n}\n\nfunction decodeVarInt(buf: WrappedBuffer): number {\n let res = 0\n\n while (1) {\n if (buf.length === 0) throw Error('parse ends prematurely')\n let byte = buf.shift()\n res = (res << 7) | (byte & 127)\n if ((byte & 128) === 0) break\n }\n\n return res\n}\n\nfunction encodeVarInt(n: number): WrappedBuffer {\n if (n === 0) return new WrappedBuffer(new Uint8Array([0]))\n\n let o: number[] = []\n\n while (n !== 0) {\n o.push(n & 127)\n n >>>= 7\n }\n\n o.reverse()\n\n for (let i = 0; i < o.length - 1; i++) o[i] |= 128\n\n return new WrappedBuffer(new Uint8Array(o))\n}\n\nfunction getByte(buf: WrappedBuffer): number {\n return getBytes(buf, 1)[0]\n}\n\nfunction getBytes(buf: WrappedBuffer, n: number): Uint8Array {\n if (buf.length < n) throw Error('parse ends prematurely')\n return buf.shiftN(n)\n}\n\nclass Accumulator {\n buf!: Uint8Array\n\n constructor() {\n this.setToZero()\n }\n\n setToZero(): void {\n this.buf = new Uint8Array(ID_SIZE)\n }\n\n add(otherBuf: Uint8Array): void {\n let currCarry = 0,\n nextCarry = 0\n let p = new DataView(this.buf.buffer)\n let po = new DataView(otherBuf.buffer)\n\n for (let i = 0; i < 8; i++) {\n let offset = i * 4\n let orig = p.getUint32(offset, true)\n let otherV = po.getUint32(offset, true)\n\n let next = orig\n\n next += currCarry\n next += otherV\n if (next > 0xffffffff) nextCarry = 1\n\n p.setUint32(offset, next & 0xffffffff, true)\n currCarry = nextCarry\n nextCarry = 0\n }\n }\n\n negate(): void {\n let p = new DataView(this.buf.buffer)\n\n for (let i = 0; i < 8; i++) {\n let offset = i * 4\n p.setUint32(offset, ~p.getUint32(offset, true))\n }\n\n let one = new Uint8Array(ID_SIZE)\n one[0] = 1\n this.add(one)\n }\n\n getFingerprint(n: number): Uint8Array {\n let input = new WrappedBuffer()\n input.extend(this.buf)\n input.extend(encodeVarInt(n))\n\n let hash = sha256(input.unwrap())\n return hash.subarray(0, FINGERPRINT_SIZE)\n }\n}\n\nexport class NegentropyStorageVector {\n items: { timestamp: number; id: Uint8Array }[]\n sealed: boolean\n\n constructor() {\n this.items = []\n this.sealed = false\n }\n\n insert(timestamp: number, id: string): void {\n if (this.sealed) throw Error('already sealed')\n const idb = hexToBytes(id)\n if (idb.byteLength !== ID_SIZE) throw Error('bad id size for added item')\n this.items.push({ timestamp, id: idb })\n }\n\n seal(): void {\n if (this.sealed) throw Error('already sealed')\n this.sealed = true\n\n this.items.sort(itemCompare)\n\n for (let i = 1; i < this.items.length; i++) {\n if (itemCompare(this.items[i - 1], this.items[i]) === 0) throw Error('duplicate item inserted')\n }\n }\n\n unseal(): void {\n this.sealed = false\n }\n\n size(): number {\n this._checkSealed()\n return this.items.length\n }\n\n getItem(i: number): { timestamp: number; id: Uint8Array } {\n this._checkSealed()\n if (i >= this.items.length) throw Error('out of range')\n return this.items[i]\n }\n\n iterate(begin: number, end: number, cb: (item: { timestamp: number; id: Uint8Array }, i: number) => boolean): void {\n this._checkSealed()\n this._checkBounds(begin, end)\n\n for (let i = begin; i < end; ++i) {\n if (!cb(this.items[i], i)) break\n }\n }\n\n findLowerBound(begin: number, end: number, bound: { timestamp: number; id: Uint8Array }): number {\n this._checkSealed()\n this._checkBounds(begin, end)\n\n return this._binarySearch(this.items, begin, end, a => itemCompare(a, bound) < 0)\n }\n\n fingerprint(begin: number, end: number): Uint8Array {\n let out = new Accumulator()\n out.setToZero()\n\n this.iterate(begin, end, item => {\n out.add(item.id)\n return true\n })\n\n return out.getFingerprint(end - begin)\n }\n\n _checkSealed(): void {\n if (!this.sealed) throw Error('not sealed')\n }\n\n _checkBounds(begin: number, end: number): void {\n if (begin > end || end > this.items.length) throw Error('bad range')\n }\n\n _binarySearch(\n arr: { timestamp: number; id: Uint8Array }[],\n first: number,\n last: number,\n cmp: (a: { timestamp: number; id: Uint8Array }) => boolean,\n ): number {\n let count = last - first\n\n while (count > 0) {\n let it = first\n let step = Math.floor(count / 2)\n it += step\n\n if (cmp(arr[it])) {\n first = ++it\n count -= step + 1\n } else {\n count = step\n }\n }\n\n return first\n }\n}\n\nexport class Negentropy {\n storage: NegentropyStorageVector\n frameSizeLimit: number\n lastTimestampIn: number\n lastTimestampOut: number\n\n constructor(storage: NegentropyStorageVector, frameSizeLimit: number = 60_000) {\n if (frameSizeLimit < 4096) throw Error('frameSizeLimit too small')\n\n this.storage = storage\n this.frameSizeLimit = frameSizeLimit\n\n this.lastTimestampIn = 0\n this.lastTimestampOut = 0\n }\n\n _bound(timestamp: number, id?: Uint8Array): { timestamp: number; id: Uint8Array } {\n return { timestamp, id: id || new Uint8Array(0) }\n }\n\n initiate(): string {\n let output = new WrappedBuffer()\n output.extend(new Uint8Array([PROTOCOL_VERSION]))\n this.splitRange(0, this.storage.size(), this._bound(Number.MAX_VALUE), output)\n return bytesToHex(output.unwrap())\n }\n\n reconcile(queryMsg: string, onhave?: (id: string) => void, onneed?: (id: string) => void): string | null {\n const query = new WrappedBuffer(hexToBytes(queryMsg))\n\n this.lastTimestampIn = this.lastTimestampOut = 0 // reset for each message\n\n let fullOutput = new WrappedBuffer()\n fullOutput.extend(new Uint8Array([PROTOCOL_VERSION]))\n\n let protocolVersion = getByte(query)\n if (protocolVersion < 0x60 || protocolVersion > 0x6f) throw Error('invalid negentropy protocol version byte')\n if (protocolVersion !== PROTOCOL_VERSION) {\n throw Error('unsupported negentropy protocol version requested: ' + (protocolVersion - 0x60))\n }\n\n let storageSize = this.storage.size()\n let prevBound = this._bound(0)\n let prevIndex = 0\n let skip = false\n\n while (query.length !== 0) {\n let o = new WrappedBuffer()\n\n let doSkip = () => {\n if (skip) {\n skip = false\n o.extend(this.encodeBound(prevBound))\n o.extend(encodeVarInt(Mode.Skip))\n }\n }\n\n let currBound = this.decodeBound(query)\n let mode = decodeVarInt(query)\n\n let lower = prevIndex\n let upper = this.storage.findLowerBound(prevIndex, storageSize, currBound)\n\n if (mode === Mode.Skip) {\n skip = true\n } else if (mode === Mode.Fingerprint) {\n let theirFingerprint = getBytes(query, FINGERPRINT_SIZE)\n let ourFingerprint = this.storage.fingerprint(lower, upper)\n\n if (compareUint8Array(theirFingerprint, ourFingerprint) !== 0) {\n doSkip()\n this.splitRange(lower, upper, currBound, o)\n } else {\n skip = true\n }\n } else if (mode === Mode.IdList) {\n let numIds = decodeVarInt(query)\n\n let theirElems: { [key: string]: Uint8Array } = {} // stringified Uint8Array -> original Uint8Array (or hex)\n for (let i = 0; i < numIds; i++) {\n let e = getBytes(query, ID_SIZE)\n theirElems[bytesToHex(e)] = e\n }\n\n skip = true\n this.storage.iterate(lower, upper, item => {\n let k = item.id\n const id = bytesToHex(k)\n\n if (!theirElems[id]) {\n // ID exists on our side, but not their side\n onhave?.(id)\n } else {\n // ID exists on both sides\n delete theirElems[bytesToHex(k)]\n }\n\n return true\n })\n\n if (onneed) {\n for (let v of Object.values(theirElems)) {\n // ID exists on their side, but not our side\n onneed(bytesToHex(v))\n }\n }\n } else {\n throw Error('unexpected mode')\n }\n\n if (this.exceededFrameSizeLimit(fullOutput.length + o.length)) {\n // frameSizeLimit exceeded: stop range processing and return a fingerprint for the remaining range\n let remainingFingerprint = this.storage.fingerprint(upper, storageSize)\n\n fullOutput.extend(this.encodeBound(this._bound(Number.MAX_VALUE)))\n fullOutput.extend(encodeVarInt(Mode.Fingerprint))\n fullOutput.extend(remainingFingerprint)\n break\n } else {\n fullOutput.extend(o)\n }\n\n prevIndex = upper\n prevBound = currBound\n }\n\n return fullOutput.length === 1 ? null : bytesToHex(fullOutput.unwrap())\n }\n\n splitRange(lower: number, upper: number, upperBound: { timestamp: number; id: Uint8Array }, o: WrappedBuffer) {\n let numElems = upper - lower\n let buckets = 16\n\n if (numElems < buckets * 2) {\n o.extend(this.encodeBound(upperBound))\n o.extend(encodeVarInt(Mode.IdList))\n\n o.extend(encodeVarInt(numElems))\n this.storage.iterate(lower, upper, item => {\n o.extend(item.id)\n return true\n })\n } else {\n let itemsPerBucket = Math.floor(numElems / buckets)\n let bucketsWithExtra = numElems % buckets\n let curr = lower\n\n for (let i = 0; i < buckets; i++) {\n let bucketSize = itemsPerBucket + (i < bucketsWithExtra ? 1 : 0)\n let ourFingerprint = this.storage.fingerprint(curr, curr + bucketSize)\n curr += bucketSize\n\n let nextBound: { timestamp: number; id: Uint8Array }\n\n if (curr === upper) {\n nextBound = upperBound\n } else {\n let prevItem: { timestamp: number; id: Uint8Array } | undefined\n let currItem: { timestamp: number; id: Uint8Array } | undefined\n\n this.storage.iterate(curr - 1, curr + 1, (item, index) => {\n if (index === curr - 1) prevItem = item\n else currItem = item\n return true\n })\n\n nextBound = this.getMinimalBound(prevItem!, currItem!)\n }\n\n o.extend(this.encodeBound(nextBound))\n o.extend(encodeVarInt(Mode.Fingerprint))\n o.extend(ourFingerprint)\n }\n }\n }\n\n exceededFrameSizeLimit(n: number): boolean {\n return n > this.frameSizeLimit - 200\n }\n\n // Decoding\n decodeTimestampIn(encoded: WrappedBuffer): number {\n let timestamp = decodeVarInt(encoded)\n timestamp = timestamp === 0 ? Number.MAX_VALUE : timestamp - 1\n if (this.lastTimestampIn === Number.MAX_VALUE || timestamp === Number.MAX_VALUE) {\n this.lastTimestampIn = Number.MAX_VALUE\n return Number.MAX_VALUE\n }\n timestamp += this.lastTimestampIn\n this.lastTimestampIn = timestamp\n return timestamp\n }\n\n decodeBound(encoded: WrappedBuffer): { timestamp: number; id: Uint8Array } {\n let timestamp = this.decodeTimestampIn(encoded)\n let len = decodeVarInt(encoded)\n if (len > ID_SIZE) throw Error('bound key too long')\n let id = getBytes(encoded, len)\n return { timestamp, id }\n }\n\n // Encoding\n encodeTimestampOut(timestamp: number): WrappedBuffer {\n if (timestamp === Number.MAX_VALUE) {\n this.lastTimestampOut = Number.MAX_VALUE\n return encodeVarInt(0)\n }\n\n let temp = timestamp\n timestamp -= this.lastTimestampOut\n this.lastTimestampOut = temp\n return encodeVarInt(timestamp + 1)\n }\n\n encodeBound(key: { timestamp: number; id: Uint8Array }): WrappedBuffer {\n let output = new WrappedBuffer()\n\n output.extend(this.encodeTimestampOut(key.timestamp))\n output.extend(encodeVarInt(key.id.length))\n output.extend(key.id)\n\n return output\n }\n\n getMinimalBound(\n prev: { timestamp: number; id: Uint8Array },\n curr: { timestamp: number; id: Uint8Array },\n ): { timestamp: number; id: Uint8Array } {\n if (curr.timestamp !== prev.timestamp) {\n return this._bound(curr.timestamp)\n } else {\n let sharedPrefixBytes = 0\n let currKey = curr.id\n let prevKey = prev.id\n\n for (let i = 0; i < ID_SIZE; i++) {\n if (currKey[i] !== prevKey[i]) break\n sharedPrefixBytes++\n }\n\n return this._bound(curr.timestamp, curr.id.subarray(0, sharedPrefixBytes + 1))\n }\n }\n}\n\nfunction compareUint8Array(a: Uint8Array, b: Uint8Array): number {\n for (let i = 0; i < a.byteLength; i++) {\n if (a[i] < b[i]) return -1\n if (a[i] > b[i]) return 1\n }\n\n if (a.byteLength > b.byteLength) return 1\n if (a.byteLength < b.byteLength) return -1\n\n return 0\n}\n\nfunction itemCompare(a: { timestamp: number; id: Uint8Array }, b: { timestamp: number; id: Uint8Array }): number {\n if (a.timestamp === b.timestamp) {\n return compareUint8Array(a.id, b.id)\n }\n\n return a.timestamp - b.timestamp\n}\n\nexport class NegentropySync {\n relay: AbstractRelay\n storage: NegentropyStorageVector\n private neg: Negentropy\n private filter: Filter\n private subscription: Subscription\n private onhave?: (id: string) => void\n private onneed?: (id: string) => void\n\n constructor(\n relay: AbstractRelay,\n storage: NegentropyStorageVector,\n filter: Filter,\n params: {\n label?: string\n onhave?: (id: string) => void\n onneed?: (id: string) => void\n onclose?: (errReason?: string) => void\n } = {},\n ) {\n this.relay = relay\n this.storage = storage\n this.neg = new Negentropy(storage)\n this.onhave = params.onhave\n this.onneed = params.onneed\n this.filter = filter\n\n // we prepare a subscription with an empty filter, but it will not be used\n this.subscription = this.relay.prepareSubscription([{}], { label: params.label || 'negentropy' })\n this.subscription.oncustom = (data: string[]) => {\n switch (data[0]) {\n case 'NEG-MSG': {\n if (data.length < 3) {\n console.warn(`got invalid NEG-MSG from ${this.relay.url}: ${data}`)\n }\n try {\n const response = this.neg.reconcile(data[2], this.onhave, this.onneed)\n if (response) {\n this.relay.send(`[\"NEG-MSG\", \"${this.subscription.id}\", \"${response}\"]`)\n } else {\n this.close()\n params.onclose?.()\n }\n } catch (error) {\n console.error('negentropy reconcile error:', error)\n params?.onclose?.(`reconcile error: ${error}`)\n }\n break\n }\n case 'NEG-CLOSE': {\n const reason = data[2]\n console.warn('negentropy error:', reason)\n params.onclose?.(reason)\n break\n }\n case 'NEG-ERR': {\n params.onclose?.()\n }\n }\n }\n }\n\n async start(): Promise<void> {\n const initMsg = this.neg.initiate()\n this.relay.send(`[\"NEG-OPEN\",\"${this.subscription.id}\",${JSON.stringify(this.filter)},\"${initMsg}\"]`)\n }\n\n close(): void {\n this.relay.send(`[\"NEG-CLOSE\",\"${this.subscription.id}\"]`)\n this.subscription.close()\n }\n}\n"],
+ "sourcesContent": ["import { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Filter } from './filter.ts'\nimport { AbstractRelay, Subscription } from './relay.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\n// Negentropy implementation by Doug Hoyte\nconst PROTOCOL_VERSION = 0x61 // Version 1\nconst ID_SIZE = 32\nconst FINGERPRINT_SIZE = 16\n\nconst Mode = {\n Skip: 0,\n Fingerprint: 1,\n IdList: 2,\n}\n\nclass WrappedBuffer {\n _raw: Uint8Array\n length: number\n\n constructor(buffer?: Uint8Array | number) {\n if (typeof buffer === 'number') {\n this._raw = new Uint8Array(buffer)\n this.length = 0\n } else if (buffer instanceof Uint8Array) {\n this._raw = new Uint8Array(buffer)\n this.length = buffer.length\n } else {\n this._raw = new Uint8Array(512)\n this.length = 0\n }\n }\n\n unwrap(): Uint8Array {\n return this._raw.subarray(0, this.length)\n }\n\n get capacity(): number {\n return this._raw.byteLength\n }\n\n extend(buf: Uint8Array | WrappedBuffer): void {\n if (buf instanceof WrappedBuffer) buf = buf.unwrap()\n if (typeof buf.length !== 'number') throw Error('bad length')\n const targetSize = buf.length + this.length\n if (this.capacity < targetSize) {\n const oldRaw = this._raw\n const newCapacity = Math.max(this.capacity * 2, targetSize)\n this._raw = new Uint8Array(newCapacity)\n this._raw.set(oldRaw)\n }\n\n this._raw.set(buf, this.length)\n this.length += buf.length\n }\n\n shift(): number {\n const first = this._raw[0]\n this._raw = this._raw.subarray(1)\n this.length--\n return first\n }\n\n shiftN(n: number = 1): Uint8Array {\n const firstSubarray = this._raw.subarray(0, n)\n this._raw = this._raw.subarray(n)\n this.length -= n\n return firstSubarray\n }\n}\n\nfunction decodeVarInt(buf: WrappedBuffer): number {\n let res = 0\n\n while (1) {\n if (buf.length === 0) throw Error('parse ends prematurely')\n let byte = buf.shift()\n res = (res << 7) | (byte & 127)\n if ((byte & 128) === 0) break\n }\n\n return res\n}\n\nfunction encodeVarInt(n: number): WrappedBuffer {\n if (n === 0) return new WrappedBuffer(new Uint8Array([0]))\n\n let o: number[] = []\n\n while (n !== 0) {\n o.push(n & 127)\n n >>>= 7\n }\n\n o.reverse()\n\n for (let i = 0; i < o.length - 1; i++) o[i] |= 128\n\n return new WrappedBuffer(new Uint8Array(o))\n}\n\nfunction getByte(buf: WrappedBuffer): number {\n return getBytes(buf, 1)[0]\n}\n\nfunction getBytes(buf: WrappedBuffer, n: number): Uint8Array {\n if (buf.length < n) throw Error('parse ends prematurely')\n return buf.shiftN(n)\n}\n\nclass Accumulator {\n buf!: Uint8Array\n\n constructor() {\n this.setToZero()\n }\n\n setToZero(): void {\n this.buf = new Uint8Array(ID_SIZE)\n }\n\n add(otherBuf: Uint8Array): void {\n let currCarry = 0,\n nextCarry = 0\n let p = new DataView(this.buf.buffer)\n let po = new DataView(otherBuf.buffer)\n\n for (let i = 0; i < 8; i++) {\n let offset = i * 4\n let orig = p.getUint32(offset, true)\n let otherV = po.getUint32(offset, true)\n\n let next = orig\n\n next += currCarry\n next += otherV\n if (next > 0xffffffff) nextCarry = 1\n\n p.setUint32(offset, next & 0xffffffff, true)\n currCarry = nextCarry\n nextCarry = 0\n }\n }\n\n negate(): void {\n let p = new DataView(this.buf.buffer)\n\n for (let i = 0; i < 8; i++) {\n let offset = i * 4\n p.setUint32(offset, ~p.getUint32(offset, true))\n }\n\n let one = new Uint8Array(ID_SIZE)\n one[0] = 1\n this.add(one)\n }\n\n getFingerprint(n: number): Uint8Array {\n let input = new WrappedBuffer()\n input.extend(this.buf)\n input.extend(encodeVarInt(n))\n\n let hash = sha256(input.unwrap())\n return hash.subarray(0, FINGERPRINT_SIZE)\n }\n}\n\nexport class NegentropyStorageVector {\n items: { timestamp: number; id: Uint8Array }[]\n sealed: boolean\n\n constructor() {\n this.items = []\n this.sealed = false\n }\n\n insert(timestamp: number, id: string): void {\n if (this.sealed) throw Error('already sealed')\n const idb = hexToBytes(id)\n if (idb.byteLength !== ID_SIZE) throw Error('bad id size for added item')\n this.items.push({ timestamp, id: idb })\n }\n\n seal(): void {\n if (this.sealed) throw Error('already sealed')\n this.sealed = true\n\n this.items.sort(itemCompare)\n\n for (let i = 1; i < this.items.length; i++) {\n if (itemCompare(this.items[i - 1], this.items[i]) === 0) throw Error('duplicate item inserted')\n }\n }\n\n unseal(): void {\n this.sealed = false\n }\n\n size(): number {\n this._checkSealed()\n return this.items.length\n }\n\n getItem(i: number): { timestamp: number; id: Uint8Array } {\n this._checkSealed()\n if (i >= this.items.length) throw Error('out of range')\n return this.items[i]\n }\n\n iterate(begin: number, end: number, cb: (item: { timestamp: number; id: Uint8Array }, i: number) => boolean): void {\n this._checkSealed()\n this._checkBounds(begin, end)\n\n for (let i = begin; i < end; ++i) {\n if (!cb(this.items[i], i)) break\n }\n }\n\n findLowerBound(begin: number, end: number, bound: { timestamp: number; id: Uint8Array }): number {\n this._checkSealed()\n this._checkBounds(begin, end)\n\n return this._binarySearch(this.items, begin, end, a => itemCompare(a, bound) < 0)\n }\n\n fingerprint(begin: number, end: number): Uint8Array {\n let out = new Accumulator()\n out.setToZero()\n\n this.iterate(begin, end, item => {\n out.add(item.id)\n return true\n })\n\n return out.getFingerprint(end - begin)\n }\n\n _checkSealed(): void {\n if (!this.sealed) throw Error('not sealed')\n }\n\n _checkBounds(begin: number, end: number): void {\n if (begin > end || end > this.items.length) throw Error('bad range')\n }\n\n _binarySearch(\n arr: { timestamp: number; id: Uint8Array }[],\n first: number,\n last: number,\n cmp: (a: { timestamp: number; id: Uint8Array }) => boolean,\n ): number {\n let count = last - first\n\n while (count > 0) {\n let it = first\n let step = Math.floor(count / 2)\n it += step\n\n if (cmp(arr[it])) {\n first = ++it\n count -= step + 1\n } else {\n count = step\n }\n }\n\n return first\n }\n}\n\nexport class Negentropy {\n storage: NegentropyStorageVector\n frameSizeLimit: number\n lastTimestampIn: number\n lastTimestampOut: number\n\n constructor(storage: NegentropyStorageVector, frameSizeLimit: number = 60_000) {\n if (frameSizeLimit < 4096) throw Error('frameSizeLimit too small')\n\n this.storage = storage\n this.frameSizeLimit = frameSizeLimit\n\n this.lastTimestampIn = 0\n this.lastTimestampOut = 0\n }\n\n _bound(timestamp: number, id?: Uint8Array): { timestamp: number; id: Uint8Array } {\n return { timestamp, id: id || new Uint8Array(0) }\n }\n\n initiate(): string {\n let output = new WrappedBuffer()\n output.extend(new Uint8Array([PROTOCOL_VERSION]))\n this.splitRange(0, this.storage.size(), this._bound(Number.MAX_VALUE), output)\n return bytesToHex(output.unwrap())\n }\n\n reconcile(queryMsg: string, onhave?: (id: string) => void, onneed?: (id: string) => void): string | null {\n const query = new WrappedBuffer(hexToBytes(queryMsg))\n\n this.lastTimestampIn = this.lastTimestampOut = 0 // reset for each message\n\n let fullOutput = new WrappedBuffer()\n fullOutput.extend(new Uint8Array([PROTOCOL_VERSION]))\n\n let protocolVersion = getByte(query)\n if (protocolVersion < 0x60 || protocolVersion > 0x6f) throw Error('invalid negentropy protocol version byte')\n if (protocolVersion !== PROTOCOL_VERSION) {\n throw Error('unsupported negentropy protocol version requested: ' + (protocolVersion - 0x60))\n }\n\n let storageSize = this.storage.size()\n let prevBound = this._bound(0)\n let prevIndex = 0\n let skip = false\n\n while (query.length !== 0) {\n let o = new WrappedBuffer()\n\n let doSkip = () => {\n if (skip) {\n skip = false\n o.extend(this.encodeBound(prevBound))\n o.extend(encodeVarInt(Mode.Skip))\n }\n }\n\n let currBound = this.decodeBound(query)\n let mode = decodeVarInt(query)\n\n let lower = prevIndex\n let upper = this.storage.findLowerBound(prevIndex, storageSize, currBound)\n\n if (mode === Mode.Skip) {\n skip = true\n } else if (mode === Mode.Fingerprint) {\n let theirFingerprint = getBytes(query, FINGERPRINT_SIZE)\n let ourFingerprint = this.storage.fingerprint(lower, upper)\n\n if (compareUint8Array(theirFingerprint, ourFingerprint) !== 0) {\n doSkip()\n this.splitRange(lower, upper, currBound, o)\n } else {\n skip = true\n }\n } else if (mode === Mode.IdList) {\n let numIds = decodeVarInt(query)\n\n let theirElems: { [key: string]: Uint8Array } = {} // stringified Uint8Array -> original Uint8Array (or hex)\n for (let i = 0; i < numIds; i++) {\n let e = getBytes(query, ID_SIZE)\n theirElems[bytesToHex(e)] = e\n }\n\n skip = true\n this.storage.iterate(lower, upper, item => {\n let k = item.id\n const id = bytesToHex(k)\n\n if (!theirElems[id]) {\n // ID exists on our side, but not their side\n onhave?.(id)\n } else {\n // ID exists on both sides\n delete theirElems[bytesToHex(k)]\n }\n\n return true\n })\n\n if (onneed) {\n for (let v of Object.values(theirElems)) {\n // ID exists on their side, but not our side\n onneed(bytesToHex(v))\n }\n }\n } else {\n throw Error('unexpected mode')\n }\n\n if (this.exceededFrameSizeLimit(fullOutput.length + o.length)) {\n // frameSizeLimit exceeded: stop range processing and return a fingerprint for the remaining range\n let remainingFingerprint = this.storage.fingerprint(upper, storageSize)\n\n fullOutput.extend(this.encodeBound(this._bound(Number.MAX_VALUE)))\n fullOutput.extend(encodeVarInt(Mode.Fingerprint))\n fullOutput.extend(remainingFingerprint)\n break\n } else {\n fullOutput.extend(o)\n }\n\n prevIndex = upper\n prevBound = currBound\n }\n\n return fullOutput.length === 1 ? null : bytesToHex(fullOutput.unwrap())\n }\n\n splitRange(lower: number, upper: number, upperBound: { timestamp: number; id: Uint8Array }, o: WrappedBuffer) {\n let numElems = upper - lower\n let buckets = 16\n\n if (numElems < buckets * 2) {\n o.extend(this.encodeBound(upperBound))\n o.extend(encodeVarInt(Mode.IdList))\n\n o.extend(encodeVarInt(numElems))\n this.storage.iterate(lower, upper, item => {\n o.extend(item.id)\n return true\n })\n } else {\n let itemsPerBucket = Math.floor(numElems / buckets)\n let bucketsWithExtra = numElems % buckets\n let curr = lower\n\n for (let i = 0; i < buckets; i++) {\n let bucketSize = itemsPerBucket + (i < bucketsWithExtra ? 1 : 0)\n let ourFingerprint = this.storage.fingerprint(curr, curr + bucketSize)\n curr += bucketSize\n\n let nextBound: { timestamp: number; id: Uint8Array }\n\n if (curr === upper) {\n nextBound = upperBound\n } else {\n let prevItem: { timestamp: number; id: Uint8Array } | undefined\n let currItem: { timestamp: number; id: Uint8Array } | undefined\n\n this.storage.iterate(curr - 1, curr + 1, (item, index) => {\n if (index === curr - 1) prevItem = item\n else currItem = item\n return true\n })\n\n nextBound = this.getMinimalBound(prevItem!, currItem!)\n }\n\n o.extend(this.encodeBound(nextBound))\n o.extend(encodeVarInt(Mode.Fingerprint))\n o.extend(ourFingerprint)\n }\n }\n }\n\n exceededFrameSizeLimit(n: number): boolean {\n return n > this.frameSizeLimit - 200\n }\n\n // Decoding\n decodeTimestampIn(encoded: WrappedBuffer): number {\n let timestamp = decodeVarInt(encoded)\n timestamp = timestamp === 0 ? Number.MAX_VALUE : timestamp - 1\n if (this.lastTimestampIn === Number.MAX_VALUE || timestamp === Number.MAX_VALUE) {\n this.lastTimestampIn = Number.MAX_VALUE\n return Number.MAX_VALUE\n }\n timestamp += this.lastTimestampIn\n this.lastTimestampIn = timestamp\n return timestamp\n }\n\n decodeBound(encoded: WrappedBuffer): { timestamp: number; id: Uint8Array } {\n let timestamp = this.decodeTimestampIn(encoded)\n let len = decodeVarInt(encoded)\n if (len > ID_SIZE) throw Error('bound key too long')\n let id = getBytes(encoded, len)\n return { timestamp, id }\n }\n\n // Encoding\n encodeTimestampOut(timestamp: number): WrappedBuffer {\n if (timestamp === Number.MAX_VALUE) {\n this.lastTimestampOut = Number.MAX_VALUE\n return encodeVarInt(0)\n }\n\n let temp = timestamp\n timestamp -= this.lastTimestampOut\n this.lastTimestampOut = temp\n return encodeVarInt(timestamp + 1)\n }\n\n encodeBound(key: { timestamp: number; id: Uint8Array }): WrappedBuffer {\n let output = new WrappedBuffer()\n\n output.extend(this.encodeTimestampOut(key.timestamp))\n output.extend(encodeVarInt(key.id.length))\n output.extend(key.id)\n\n return output\n }\n\n getMinimalBound(\n prev: { timestamp: number; id: Uint8Array },\n curr: { timestamp: number; id: Uint8Array },\n ): { timestamp: number; id: Uint8Array } {\n if (curr.timestamp !== prev.timestamp) {\n return this._bound(curr.timestamp)\n } else {\n let sharedPrefixBytes = 0\n let currKey = curr.id\n let prevKey = prev.id\n\n for (let i = 0; i < ID_SIZE; i++) {\n if (currKey[i] !== prevKey[i]) break\n sharedPrefixBytes++\n }\n\n return this._bound(curr.timestamp, curr.id.subarray(0, sharedPrefixBytes + 1))\n }\n }\n}\n\nfunction compareUint8Array(a: Uint8Array, b: Uint8Array): number {\n for (let i = 0; i < a.byteLength; i++) {\n if (a[i] < b[i]) return -1\n if (a[i] > b[i]) return 1\n }\n\n if (a.byteLength > b.byteLength) return 1\n if (a.byteLength < b.byteLength) return -1\n\n return 0\n}\n\nfunction itemCompare(a: { timestamp: number; id: Uint8Array }, b: { timestamp: number; id: Uint8Array }): number {\n if (a.timestamp === b.timestamp) {\n return compareUint8Array(a.id, b.id)\n }\n\n return a.timestamp - b.timestamp\n}\n\nexport class NegentropySync {\n relay: AbstractRelay\n storage: NegentropyStorageVector\n private neg: Negentropy\n private filter: Filter\n private subscription: Subscription\n private onhave?: (id: string) => void\n private onneed?: (id: string) => void\n\n constructor(\n relay: AbstractRelay,\n storage: NegentropyStorageVector,\n filter: Filter,\n params: {\n label?: string\n onhave?: (id: string) => void\n onneed?: (id: string) => void\n onclose?: (errReason?: string) => void\n } = {},\n ) {\n this.relay = relay\n this.storage = storage\n this.neg = new Negentropy(storage)\n this.onhave = params.onhave\n this.onneed = params.onneed\n this.filter = filter\n\n // we prepare a subscription with an empty filter, but it will not be used\n this.subscription = this.relay.prepareSubscription([{}], { label: params.label || 'negentropy' })\n this.subscription.oncustom = (data: string[]) => {\n switch (data[0]) {\n case 'NEG-MSG': {\n if (data.length < 3) {\n console.warn(`got invalid NEG-MSG from ${this.relay.url}: ${data}`)\n }\n try {\n const response = this.neg.reconcile(data[2], this.onhave, this.onneed)\n if (response) {\n this.relay.send(`[\"NEG-MSG\", \"${this.subscription.id}\", \"${response}\"]`)\n } else {\n this.close()\n params.onclose?.()\n }\n } catch (error) {\n console.error('negentropy reconcile error:', error)\n params?.onclose?.(`reconcile error: ${error}`)\n }\n break\n }\n case 'NEG-CLOSE': {\n const reason = data[2]\n console.warn('negentropy error:', reason)\n params.onclose?.(reason)\n break\n }\n case 'NEG-ERR': {\n params.onclose?.()\n }\n }\n }\n }\n\n async start(): Promise<void> {\n const initMsg = this.neg.initiate()\n this.relay.send(`[\"NEG-OPEN\",\"${this.subscription.id}\",${JSON.stringify(this.filter)},\"${initMsg}\"]`)\n }\n\n close(): void {\n this.relay.send(`[\"NEG-CLOSE\",\"${this.subscription.id}\"]`)\n this.subscription.close()\n }\n}\n"],
"mappings": "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",
"names": []
} Index: package/lib/cjs/nip98.js.map
===================================================================
--- package/lib/cjs/nip98.js.map
+++ package/lib/cjs/nip98.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip98.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts"],
- "sourcesContent": ["import { sha256 } from '@noble/hashes/sha256'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { base64 } from '@scure/base'\n\nimport { HTTPAuth } from './kinds.ts'\nimport { Event, EventTemplate, verifyEvent } from './pure.ts'\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst _authorizationScheme = 'Nostr '\n\n/**\n * Generate token for NIP-98 flow.\n *\n * @example\n * const sign = window.nostr.signEvent\n * await nip98.getToken('https://example.com/login', 'post', (e) => sign(e), true)\n */\nexport async function getToken(\n loginUrl: string,\n httpMethod: string,\n sign: (e: EventTemplate) => Promise<Event> | Event,\n includeAuthorizationScheme: boolean = false,\n payload?: Record<string, any>,\n): Promise<string> {\n const event: EventTemplate = {\n kind: HTTPAuth,\n tags: [\n ['u', loginUrl],\n ['method', httpMethod],\n ],\n created_at: Math.round(new Date().getTime() / 1000),\n content: '',\n }\n\n if (payload) {\n event.tags.push(['payload', hashPayload(payload)])\n }\n\n const signedEvent = await sign(event)\n const authorizationScheme = includeAuthorizationScheme ? _authorizationScheme : ''\n\n return authorizationScheme + base64.encode(utf8Encoder.encode(JSON.stringify(signedEvent)))\n}\n\n/**\n * Validate token for NIP-98 flow.\n *\n * @example\n * await nip98.validateToken('Nostr base64token', 'https://example.com/login', 'post')\n */\nexport async function validateToken(token: string, url: string, method: string): Promise<boolean> {\n const event = await unpackEventFromToken(token).catch(error => {\n throw error\n })\n\n const valid = await validateEvent(event, url, method).catch(error => {\n throw error\n })\n\n return valid\n}\n\n/**\n * Unpacks an event from a token.\n *\n * @param token - The token to unpack.\n * @returns A promise that resolves to the unpacked event.\n * @throws {Error} If the token is missing, invalid, or cannot be parsed.\n */\nexport async function unpackEventFromToken(token: string): Promise<Event> {\n if (!token) {\n throw new Error('Missing token')\n }\n\n token = token.replace(_authorizationScheme, '')\n\n const eventB64 = utf8Decoder.decode(base64.decode(token))\n if (!eventB64 || eventB64.length === 0 || !eventB64.startsWith('{')) {\n throw new Error('Invalid token')\n }\n\n const event = JSON.parse(eventB64) as Event\n\n return event\n}\n\n/**\n * Validates the timestamp of an event.\n * @param event - The event object to validate.\n * @returns A boolean indicating whether the event timestamp is within the last 60 seconds.\n */\nexport function validateEventTimestamp(event: Event): boolean {\n if (!event.created_at) {\n return false\n }\n\n return Math.round(new Date().getTime() / 1000) - event.created_at < 60\n}\n\n/**\n * Validates the kind of an event.\n * @param event The event to validate.\n * @returns A boolean indicating whether the event kind is valid.\n */\nexport function validateEventKind(event: Event): boolean {\n return event.kind === HTTPAuth\n}\n\n/**\n * Validates if the given URL matches the URL tag of the event.\n * @param event - The event object.\n * @param url - The URL to validate.\n * @returns A boolean indicating whether the URL is valid or not.\n */\nexport function validateEventUrlTag(event: Event, url: string): boolean {\n const urlTag = event.tags.find(t => t[0] === 'u')\n\n if (!urlTag) {\n return false\n }\n\n return urlTag.length > 0 && urlTag[1] === url\n}\n\n/**\n * Validates if the given event has a method tag that matches the specified method.\n * @param event - The event to validate.\n * @param method - The method to match against the method tag.\n * @returns A boolean indicating whether the event has a matching method tag.\n */\nexport function validateEventMethodTag(event: Event, method: string): boolean {\n const methodTag = event.tags.find(t => t[0] === 'method')\n\n if (!methodTag) {\n return false\n }\n\n return methodTag.length > 0 && methodTag[1].toLowerCase() === method.toLowerCase()\n}\n\n/**\n * Calculates the hash of a payload.\n * @param payload - The payload to be hashed.\n * @returns The hash value as a string.\n */\nexport function hashPayload(payload: any): string {\n const hash = sha256(utf8Encoder.encode(JSON.stringify(payload)))\n return bytesToHex(hash)\n}\n\n/**\n * Validates the event payload tag against the provided payload.\n * @param event The event object.\n * @param payload The payload to validate.\n * @returns A boolean indicating whether the payload tag is valid.\n */\nexport function validateEventPayloadTag(event: Event, payload: any): boolean {\n const payloadTag = event.tags.find(t => t[0] === 'payload')\n\n if (!payloadTag) {\n return false\n }\n\n const payloadHash = hashPayload(payload)\n return payloadTag.length > 0 && payloadTag[1] === payloadHash\n}\n\n/**\n * Validates a Nostr event for the NIP-98 flow.\n *\n * @param event - The Nostr event to validate.\n * @param url - The URL associated with the event.\n * @param method - The HTTP method associated with the event.\n * @param body - The request body associated with the event (optional).\n * @returns A promise that resolves to a boolean indicating whether the event is valid.\n * @throws An error if the event is invalid.\n */\nexport async function validateEvent(event: Event, url: string, method: string, body?: any): Promise<boolean> {\n if (!verifyEvent(event)) {\n throw new Error('Invalid nostr event, signature invalid')\n }\n\n if (!validateEventKind(event)) {\n throw new Error('Invalid nostr event, kind invalid')\n }\n\n if (!validateEventTimestamp(event)) {\n throw new Error('Invalid nostr event, created_at timestamp invalid')\n }\n\n if (!validateEventUrlTag(event, url)) {\n throw new Error('Invalid nostr event, url tag invalid')\n }\n\n if (!validateEventMethodTag(event, method)) {\n throw new Error('Invalid nostr event, method tag invalid')\n }\n\n if (Boolean(body) && typeof body === 'object' && Object.keys(body).length > 0) {\n if (!validateEventPayloadTag(event, body)) {\n throw new Error('Invalid nostr event, payload tag does not match request body hash')\n }\n }\n\n return true\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
- "mappings": "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",
- "names": ["validateEvent", "import_sha256", "import_utils", "import_utils", "i", "validateEvent"]
+ "sourcesContent": ["import { sha256 } from '@noble/hashes/sha2.js'\nimport { bytesToHex } from '@noble/hashes/utils.js'\nimport { base64 } from '@scure/base'\n\nimport { HTTPAuth } from './kinds.ts'\nimport { Event, EventTemplate, verifyEvent } from './pure.ts'\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst _authorizationScheme = 'Nostr '\n\n/**\n * Generate token for NIP-98 flow.\n *\n * @example\n * const sign = window.nostr.signEvent\n * await nip98.getToken('https://example.com/login', 'post', (e) => sign(e), true)\n */\nexport async function getToken(\n loginUrl: string,\n httpMethod: string,\n sign: (e: EventTemplate) => Promise<Event> | Event,\n includeAuthorizationScheme: boolean = false,\n payload?: Record<string, any>,\n): Promise<string> {\n const event: EventTemplate = {\n kind: HTTPAuth,\n tags: [\n ['u', loginUrl],\n ['method', httpMethod],\n ],\n created_at: Math.round(new Date().getTime() / 1000),\n content: '',\n }\n\n if (payload) {\n event.tags.push(['payload', hashPayload(payload)])\n }\n\n const signedEvent = await sign(event)\n const authorizationScheme = includeAuthorizationScheme ? _authorizationScheme : ''\n\n return authorizationScheme + base64.encode(utf8Encoder.encode(JSON.stringify(signedEvent)))\n}\n\n/**\n * Validate token for NIP-98 flow.\n *\n * @example\n * await nip98.validateToken('Nostr base64token', 'https://example.com/login', 'post')\n */\nexport async function validateToken(token: string, url: string, method: string): Promise<boolean> {\n const event = await unpackEventFromToken(token).catch(error => {\n throw error\n })\n\n const valid = await validateEvent(event, url, method).catch(error => {\n throw error\n })\n\n return valid\n}\n\n/**\n * Unpacks an event from a token.\n *\n * @param token - The token to unpack.\n * @returns A promise that resolves to the unpacked event.\n * @throws {Error} If the token is missing, invalid, or cannot be parsed.\n */\nexport async function unpackEventFromToken(token: string): Promise<Event> {\n if (!token) {\n throw new Error('Missing token')\n }\n\n token = token.replace(_authorizationScheme, '')\n\n const eventB64 = utf8Decoder.decode(base64.decode(token))\n if (!eventB64 || eventB64.length === 0 || !eventB64.startsWith('{')) {\n throw new Error('Invalid token')\n }\n\n const event = JSON.parse(eventB64) as Event\n\n return event\n}\n\n/**\n * Validates the timestamp of an event.\n * @param event - The event object to validate.\n * @returns A boolean indicating whether the event timestamp is within the last 60 seconds.\n */\nexport function validateEventTimestamp(event: Event): boolean {\n if (!event.created_at) {\n return false\n }\n\n return Math.round(new Date().getTime() / 1000) - event.created_at < 60\n}\n\n/**\n * Validates the kind of an event.\n * @param event The event to validate.\n * @returns A boolean indicating whether the event kind is valid.\n */\nexport function validateEventKind(event: Event): boolean {\n return event.kind === HTTPAuth\n}\n\n/**\n * Validates if the given URL matches the URL tag of the event.\n * @param event - The event object.\n * @param url - The URL to validate.\n * @returns A boolean indicating whether the URL is valid or not.\n */\nexport function validateEventUrlTag(event: Event, url: string): boolean {\n const urlTag = event.tags.find(t => t[0] === 'u')\n\n if (!urlTag) {\n return false\n }\n\n return urlTag.length > 0 && urlTag[1] === url\n}\n\n/**\n * Validates if the given event has a method tag that matches the specified method.\n * @param event - The event to validate.\n * @param method - The method to match against the method tag.\n * @returns A boolean indicating whether the event has a matching method tag.\n */\nexport function validateEventMethodTag(event: Event, method: string): boolean {\n const methodTag = event.tags.find(t => t[0] === 'method')\n\n if (!methodTag) {\n return false\n }\n\n return methodTag.length > 0 && methodTag[1].toLowerCase() === method.toLowerCase()\n}\n\n/**\n * Calculates the hash of a payload.\n * @param payload - The payload to be hashed.\n * @returns The hash value as a string.\n */\nexport function hashPayload(payload: any): string {\n const hash = sha256(utf8Encoder.encode(JSON.stringify(payload)))\n return bytesToHex(hash)\n}\n\n/**\n * Validates the event payload tag against the provided payload.\n * @param event The event object.\n * @param payload The payload to validate.\n * @returns A boolean indicating whether the payload tag is valid.\n */\nexport function validateEventPayloadTag(event: Event, payload: any): boolean {\n const payloadTag = event.tags.find(t => t[0] === 'payload')\n\n if (!payloadTag) {\n return false\n }\n\n const payloadHash = hashPayload(payload)\n return payloadTag.length > 0 && payloadTag[1] === payloadHash\n}\n\n/**\n * Validates a Nostr event for the NIP-98 flow.\n *\n * @param event - The Nostr event to validate.\n * @param url - The URL associated with the event.\n * @param method - The HTTP method associated with the event.\n * @param body - The request body associated with the event (optional).\n * @returns A promise that resolves to a boolean indicating whether the event is valid.\n * @throws An error if the event is invalid.\n */\nexport async function validateEvent(event: Event, url: string, method: string, body?: any): Promise<boolean> {\n if (!verifyEvent(event)) {\n throw new Error('Invalid nostr event, signature invalid')\n }\n\n if (!validateEventKind(event)) {\n throw new Error('Invalid nostr event, kind invalid')\n }\n\n if (!validateEventTimestamp(event)) {\n throw new Error('Invalid nostr event, created_at timestamp invalid')\n }\n\n if (!validateEventUrlTag(event, url)) {\n throw new Error('Invalid nostr event, url tag invalid')\n }\n\n if (!validateEventMethodTag(event, method)) {\n throw new Error('Invalid nostr event, method tag invalid')\n }\n\n if (Boolean(body) && typeof body === 'object' && Object.keys(body).length > 0) {\n if (!validateEventPayloadTag(event, body)) {\n throw new Error('Invalid nostr event, payload tag does not match request body hash')\n }\n }\n\n return true\n}\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
+ "mappings": "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",
+ "names": ["validateEvent", "import_sha2", "import_utils", "import_utils", "i", "validateEvent"]
} Index: package/lib/esm/nip98.js.map
===================================================================
--- package/lib/esm/nip98.js.map
+++ package/lib/esm/nip98.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip98.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts"],
- "sourcesContent": ["import { sha256 } from '@noble/hashes/sha256'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { base64 } from '@scure/base'\n\nimport { HTTPAuth } from './kinds.ts'\nimport { Event, EventTemplate, verifyEvent } from './pure.ts'\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst _authorizationScheme = 'Nostr '\n\n/**\n * Generate token for NIP-98 flow.\n *\n * @example\n * const sign = window.nostr.signEvent\n * await nip98.getToken('https://example.com/login', 'post', (e) => sign(e), true)\n */\nexport async function getToken(\n loginUrl: string,\n httpMethod: string,\n sign: (e: EventTemplate) => Promise<Event> | Event,\n includeAuthorizationScheme: boolean = false,\n payload?: Record<string, any>,\n): Promise<string> {\n const event: EventTemplate = {\n kind: HTTPAuth,\n tags: [\n ['u', loginUrl],\n ['method', httpMethod],\n ],\n created_at: Math.round(new Date().getTime() / 1000),\n content: '',\n }\n\n if (payload) {\n event.tags.push(['payload', hashPayload(payload)])\n }\n\n const signedEvent = await sign(event)\n const authorizationScheme = includeAuthorizationScheme ? _authorizationScheme : ''\n\n return authorizationScheme + base64.encode(utf8Encoder.encode(JSON.stringify(signedEvent)))\n}\n\n/**\n * Validate token for NIP-98 flow.\n *\n * @example\n * await nip98.validateToken('Nostr base64token', 'https://example.com/login', 'post')\n */\nexport async function validateToken(token: string, url: string, method: string): Promise<boolean> {\n const event = await unpackEventFromToken(token).catch(error => {\n throw error\n })\n\n const valid = await validateEvent(event, url, method).catch(error => {\n throw error\n })\n\n return valid\n}\n\n/**\n * Unpacks an event from a token.\n *\n * @param token - The token to unpack.\n * @returns A promise that resolves to the unpacked event.\n * @throws {Error} If the token is missing, invalid, or cannot be parsed.\n */\nexport async function unpackEventFromToken(token: string): Promise<Event> {\n if (!token) {\n throw new Error('Missing token')\n }\n\n token = token.replace(_authorizationScheme, '')\n\n const eventB64 = utf8Decoder.decode(base64.decode(token))\n if (!eventB64 || eventB64.length === 0 || !eventB64.startsWith('{')) {\n throw new Error('Invalid token')\n }\n\n const event = JSON.parse(eventB64) as Event\n\n return event\n}\n\n/**\n * Validates the timestamp of an event.\n * @param event - The event object to validate.\n * @returns A boolean indicating whether the event timestamp is within the last 60 seconds.\n */\nexport function validateEventTimestamp(event: Event): boolean {\n if (!event.created_at) {\n return false\n }\n\n return Math.round(new Date().getTime() / 1000) - event.created_at < 60\n}\n\n/**\n * Validates the kind of an event.\n * @param event The event to validate.\n * @returns A boolean indicating whether the event kind is valid.\n */\nexport function validateEventKind(event: Event): boolean {\n return event.kind === HTTPAuth\n}\n\n/**\n * Validates if the given URL matches the URL tag of the event.\n * @param event - The event object.\n * @param url - The URL to validate.\n * @returns A boolean indicating whether the URL is valid or not.\n */\nexport function validateEventUrlTag(event: Event, url: string): boolean {\n const urlTag = event.tags.find(t => t[0] === 'u')\n\n if (!urlTag) {\n return false\n }\n\n return urlTag.length > 0 && urlTag[1] === url\n}\n\n/**\n * Validates if the given event has a method tag that matches the specified method.\n * @param event - The event to validate.\n * @param method - The method to match against the method tag.\n * @returns A boolean indicating whether the event has a matching method tag.\n */\nexport function validateEventMethodTag(event: Event, method: string): boolean {\n const methodTag = event.tags.find(t => t[0] === 'method')\n\n if (!methodTag) {\n return false\n }\n\n return methodTag.length > 0 && methodTag[1].toLowerCase() === method.toLowerCase()\n}\n\n/**\n * Calculates the hash of a payload.\n * @param payload - The payload to be hashed.\n * @returns The hash value as a string.\n */\nexport function hashPayload(payload: any): string {\n const hash = sha256(utf8Encoder.encode(JSON.stringify(payload)))\n return bytesToHex(hash)\n}\n\n/**\n * Validates the event payload tag against the provided payload.\n * @param event The event object.\n * @param payload The payload to validate.\n * @returns A boolean indicating whether the payload tag is valid.\n */\nexport function validateEventPayloadTag(event: Event, payload: any): boolean {\n const payloadTag = event.tags.find(t => t[0] === 'payload')\n\n if (!payloadTag) {\n return false\n }\n\n const payloadHash = hashPayload(payload)\n return payloadTag.length > 0 && payloadTag[1] === payloadHash\n}\n\n/**\n * Validates a Nostr event for the NIP-98 flow.\n *\n * @param event - The Nostr event to validate.\n * @param url - The URL associated with the event.\n * @param method - The HTTP method associated with the event.\n * @param body - The request body associated with the event (optional).\n * @returns A promise that resolves to a boolean indicating whether the event is valid.\n * @throws An error if the event is invalid.\n */\nexport async function validateEvent(event: Event, url: string, method: string, body?: any): Promise<boolean> {\n if (!verifyEvent(event)) {\n throw new Error('Invalid nostr event, signature invalid')\n }\n\n if (!validateEventKind(event)) {\n throw new Error('Invalid nostr event, kind invalid')\n }\n\n if (!validateEventTimestamp(event)) {\n throw new Error('Invalid nostr event, created_at timestamp invalid')\n }\n\n if (!validateEventUrlTag(event, url)) {\n throw new Error('Invalid nostr event, url tag invalid')\n }\n\n if (!validateEventMethodTag(event, method)) {\n throw new Error('Invalid nostr event, method tag invalid')\n }\n\n if (Boolean(body) && typeof body === 'object' && Object.keys(body).length > 0) {\n if (!validateEventPayloadTag(event, body)) {\n throw new Error('Invalid nostr event, payload tag does not match request body hash')\n }\n }\n\n return true\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
- "mappings": "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",
- "names": ["sha256", "bytesToHex", "bytesToHex", "i", "bytesToHex", "validateEvent", "sha256", "bytesToHex"]
+ "sourcesContent": ["import { sha256 } from '@noble/hashes/sha2.js'\nimport { bytesToHex } from '@noble/hashes/utils.js'\nimport { base64 } from '@scure/base'\n\nimport { HTTPAuth } from './kinds.ts'\nimport { Event, EventTemplate, verifyEvent } from './pure.ts'\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nconst _authorizationScheme = 'Nostr '\n\n/**\n * Generate token for NIP-98 flow.\n *\n * @example\n * const sign = window.nostr.signEvent\n * await nip98.getToken('https://example.com/login', 'post', (e) => sign(e), true)\n */\nexport async function getToken(\n loginUrl: string,\n httpMethod: string,\n sign: (e: EventTemplate) => Promise<Event> | Event,\n includeAuthorizationScheme: boolean = false,\n payload?: Record<string, any>,\n): Promise<string> {\n const event: EventTemplate = {\n kind: HTTPAuth,\n tags: [\n ['u', loginUrl],\n ['method', httpMethod],\n ],\n created_at: Math.round(new Date().getTime() / 1000),\n content: '',\n }\n\n if (payload) {\n event.tags.push(['payload', hashPayload(payload)])\n }\n\n const signedEvent = await sign(event)\n const authorizationScheme = includeAuthorizationScheme ? _authorizationScheme : ''\n\n return authorizationScheme + base64.encode(utf8Encoder.encode(JSON.stringify(signedEvent)))\n}\n\n/**\n * Validate token for NIP-98 flow.\n *\n * @example\n * await nip98.validateToken('Nostr base64token', 'https://example.com/login', 'post')\n */\nexport async function validateToken(token: string, url: string, method: string): Promise<boolean> {\n const event = await unpackEventFromToken(token).catch(error => {\n throw error\n })\n\n const valid = await validateEvent(event, url, method).catch(error => {\n throw error\n })\n\n return valid\n}\n\n/**\n * Unpacks an event from a token.\n *\n * @param token - The token to unpack.\n * @returns A promise that resolves to the unpacked event.\n * @throws {Error} If the token is missing, invalid, or cannot be parsed.\n */\nexport async function unpackEventFromToken(token: string): Promise<Event> {\n if (!token) {\n throw new Error('Missing token')\n }\n\n token = token.replace(_authorizationScheme, '')\n\n const eventB64 = utf8Decoder.decode(base64.decode(token))\n if (!eventB64 || eventB64.length === 0 || !eventB64.startsWith('{')) {\n throw new Error('Invalid token')\n }\n\n const event = JSON.parse(eventB64) as Event\n\n return event\n}\n\n/**\n * Validates the timestamp of an event.\n * @param event - The event object to validate.\n * @returns A boolean indicating whether the event timestamp is within the last 60 seconds.\n */\nexport function validateEventTimestamp(event: Event): boolean {\n if (!event.created_at) {\n return false\n }\n\n return Math.round(new Date().getTime() / 1000) - event.created_at < 60\n}\n\n/**\n * Validates the kind of an event.\n * @param event The event to validate.\n * @returns A boolean indicating whether the event kind is valid.\n */\nexport function validateEventKind(event: Event): boolean {\n return event.kind === HTTPAuth\n}\n\n/**\n * Validates if the given URL matches the URL tag of the event.\n * @param event - The event object.\n * @param url - The URL to validate.\n * @returns A boolean indicating whether the URL is valid or not.\n */\nexport function validateEventUrlTag(event: Event, url: string): boolean {\n const urlTag = event.tags.find(t => t[0] === 'u')\n\n if (!urlTag) {\n return false\n }\n\n return urlTag.length > 0 && urlTag[1] === url\n}\n\n/**\n * Validates if the given event has a method tag that matches the specified method.\n * @param event - The event to validate.\n * @param method - The method to match against the method tag.\n * @returns A boolean indicating whether the event has a matching method tag.\n */\nexport function validateEventMethodTag(event: Event, method: string): boolean {\n const methodTag = event.tags.find(t => t[0] === 'method')\n\n if (!methodTag) {\n return false\n }\n\n return methodTag.length > 0 && methodTag[1].toLowerCase() === method.toLowerCase()\n}\n\n/**\n * Calculates the hash of a payload.\n * @param payload - The payload to be hashed.\n * @returns The hash value as a string.\n */\nexport function hashPayload(payload: any): string {\n const hash = sha256(utf8Encoder.encode(JSON.stringify(payload)))\n return bytesToHex(hash)\n}\n\n/**\n * Validates the event payload tag against the provided payload.\n * @param event The event object.\n * @param payload The payload to validate.\n * @returns A boolean indicating whether the payload tag is valid.\n */\nexport function validateEventPayloadTag(event: Event, payload: any): boolean {\n const payloadTag = event.tags.find(t => t[0] === 'payload')\n\n if (!payloadTag) {\n return false\n }\n\n const payloadHash = hashPayload(payload)\n return payloadTag.length > 0 && payloadTag[1] === payloadHash\n}\n\n/**\n * Validates a Nostr event for the NIP-98 flow.\n *\n * @param event - The Nostr event to validate.\n * @param url - The URL associated with the event.\n * @param method - The HTTP method associated with the event.\n * @param body - The request body associated with the event (optional).\n * @returns A promise that resolves to a boolean indicating whether the event is valid.\n * @throws An error if the event is invalid.\n */\nexport async function validateEvent(event: Event, url: string, method: string, body?: any): Promise<boolean> {\n if (!verifyEvent(event)) {\n throw new Error('Invalid nostr event, signature invalid')\n }\n\n if (!validateEventKind(event)) {\n throw new Error('Invalid nostr event, kind invalid')\n }\n\n if (!validateEventTimestamp(event)) {\n throw new Error('Invalid nostr event, created_at timestamp invalid')\n }\n\n if (!validateEventUrlTag(event, url)) {\n throw new Error('Invalid nostr event, url tag invalid')\n }\n\n if (!validateEventMethodTag(event, method)) {\n throw new Error('Invalid nostr event, method tag invalid')\n }\n\n if (Boolean(body) && typeof body === 'object' && Object.keys(body).length > 0) {\n if (!validateEventPayloadTag(event, body)) {\n throw new Error('Invalid nostr event, payload tag does not match request body hash')\n }\n }\n\n return true\n}\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n"],
+ "mappings": ";AAAA,SAAS,UAAAA,eAAc;AACvB,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,cAAc;;;ACFvB,SAAS,eAAe;AACxB,SAAS,cAAAC,aAAY,cAAAC,mBAAkB;;;ACOhC,IAAM,iBAAiB,OAAO,UAAU;AAsB/C,IAAM,WAAW,CAAC,QAAiD,eAAe;AAE3E,SAAS,cAAiB,OAAsC;AACrE,MAAI,CAAC,SAAS,KAAK;AAAG,WAAO;AAC7B,MAAI,OAAO,MAAM,SAAS;AAAU,WAAO;AAC3C,MAAI,OAAO,MAAM,YAAY;AAAU,WAAO;AAC9C,MAAI,OAAO,MAAM,eAAe;AAAU,WAAO;AACjD,MAAI,OAAO,MAAM,WAAW;AAAU,WAAO;AAC7C,MAAI,CAAC,MAAM,OAAO,MAAM,gBAAgB;AAAG,WAAO;AAElD,MAAI,CAAC,MAAM,QAAQ,MAAM,IAAI;AAAG,WAAO;AACvC,WAASC,KAAI,GAAGA,KAAI,MAAM,KAAK,QAAQA,MAAK;AAC1C,QAAI,MAAM,MAAM,KAAKA;AACrB,QAAI,CAAC,MAAM,QAAQ,GAAG;AAAG,aAAO;AAChC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAI,OAAO,IAAI,OAAO;AAAU,eAAO;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AACT;;;AD/CA,SAAS,cAAc;;;AEEvB,SAAS,YAAY,kBAAkB;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;AFIxD,IAAM,KAAN,MAA0B;AAAA,EACxB,oBAAgC;AAC9B,WAAO,QAAQ,MAAM,gBAAgB;AAAA,EACvC;AAAA,EACA,aAAa,WAA+B;AAC1C,WAAOC,YAAW,QAAQ,aAAa,SAAS,CAAC;AAAA,EACnD;AAAA,EACA,cAAc,GAAkB,WAAsC;AACpE,UAAM,QAAQ;AACd,UAAM,SAASA,YAAW,QAAQ,aAAa,SAAS,CAAC;AACzD,UAAM,KAAK,aAAa,KAAK;AAC7B,UAAM,MAAMA,YAAW,QAAQ,KAAKC,YAAW,aAAa,KAAK,CAAC,GAAG,SAAS,CAAC;AAC/E,UAAM,kBAAkB;AACxB,WAAO;AAAA,EACT;AAAA,EACA,YAAY,OAAsC;AAChD,QAAI,OAAO,MAAM,oBAAoB;AAAW,aAAO,MAAM;AAE7D,UAAM,OAAO,aAAa,KAAK;AAC/B,QAAI,SAAS,MAAM,IAAI;AACrB,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,QAAQ,QAAQ,OAAOA,YAAW,MAAM,GAAG,GAAGA,YAAW,IAAI,GAAGA,YAAW,MAAM,MAAM,CAAC;AAC9F,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT,SAAS,KAAP;AACA,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,eAAe,KAA4B;AACzD,MAAI,CAAC,cAAc,GAAG;AAAG,UAAM,IAAI,MAAM,wDAAwD;AACjG,SAAO,KAAK,UAAU,CAAC,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,CAAC;AACxF;AAEO,SAAS,aAAa,OAA8B;AACzD,MAAI,YAAY,OAAO,YAAY,OAAO,eAAe,KAAK,CAAC,CAAC;AAChE,SAAOD,YAAW,SAAS;AAC7B;AAEA,IAAM,IAAQ,IAAI,GAAG;AAEd,IAAM,oBAAoB,EAAE;AAC5B,IAAM,eAAe,EAAE;AACvB,IAAM,gBAAgB,EAAE;AACxB,IAAM,cAAc,EAAE;;;AG8GtB,IAAM,WAAW;;;AJ/JxB,IAAM,uBAAuB;AAS7B,eAAsB,SACpB,UACA,YACA,MACA,6BAAsC,OACtC,SACiB;AACjB,QAAM,QAAuB;AAAA,IAC3B,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,CAAC,KAAK,QAAQ;AAAA,MACd,CAAC,UAAU,UAAU;AAAA,IACvB;AAAA,IACA,YAAY,KAAK,MAAM,IAAI,KAAK,EAAE,QAAQ,IAAI,GAAI;AAAA,IAClD,SAAS;AAAA,EACX;AAEA,MAAI,SAAS;AACX,UAAM,KAAK,KAAK,CAAC,WAAW,YAAY,OAAO,CAAC,CAAC;AAAA,EACnD;AAEA,QAAM,cAAc,MAAM,KAAK,KAAK;AACpC,QAAM,sBAAsB,6BAA6B,uBAAuB;AAEhF,SAAO,sBAAsB,OAAO,OAAO,YAAY,OAAO,KAAK,UAAU,WAAW,CAAC,CAAC;AAC5F;AAQA,eAAsB,cAAc,OAAe,KAAa,QAAkC;AAChG,QAAM,QAAQ,MAAM,qBAAqB,KAAK,EAAE,MAAM,WAAS;AAC7D,UAAM;AAAA,EACR,CAAC;AAED,QAAM,QAAQ,MAAME,eAAc,OAAO,KAAK,MAAM,EAAE,MAAM,WAAS;AACnE,UAAM;AAAA,EACR,CAAC;AAED,SAAO;AACT;AASA,eAAsB,qBAAqB,OAA+B;AACxE,MAAI,CAAC,OAAO;AACV,UAAM,IAAI,MAAM,eAAe;AAAA,EACjC;AAEA,UAAQ,MAAM,QAAQ,sBAAsB,EAAE;AAE9C,QAAM,WAAW,YAAY,OAAO,OAAO,OAAO,KAAK,CAAC;AACxD,MAAI,CAAC,YAAY,SAAS,WAAW,KAAK,CAAC,SAAS,WAAW,GAAG,GAAG;AACnE,UAAM,IAAI,MAAM,eAAe;AAAA,EACjC;AAEA,QAAM,QAAQ,KAAK,MAAM,QAAQ;AAEjC,SAAO;AACT;AAOO,SAAS,uBAAuB,OAAuB;AAC5D,MAAI,CAAC,MAAM,YAAY;AACrB,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,MAAM,IAAI,KAAK,EAAE,QAAQ,IAAI,GAAI,IAAI,MAAM,aAAa;AACtE;AAOO,SAAS,kBAAkB,OAAuB;AACvD,SAAO,MAAM,SAAS;AACxB;AAQO,SAAS,oBAAoB,OAAc,KAAsB;AACtE,QAAM,SAAS,MAAM,KAAK,KAAK,OAAK,EAAE,OAAO,GAAG;AAEhD,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAEA,SAAO,OAAO,SAAS,KAAK,OAAO,OAAO;AAC5C;AAQO,SAAS,uBAAuB,OAAc,QAAyB;AAC5E,QAAM,YAAY,MAAM,KAAK,KAAK,OAAK,EAAE,OAAO,QAAQ;AAExD,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,SAAO,UAAU,SAAS,KAAK,UAAU,GAAG,YAAY,MAAM,OAAO,YAAY;AACnF;AAOO,SAAS,YAAY,SAAsB;AAChD,QAAM,OAAOC,QAAO,YAAY,OAAO,KAAK,UAAU,OAAO,CAAC,CAAC;AAC/D,SAAOC,YAAW,IAAI;AACxB;AAQO,SAAS,wBAAwB,OAAc,SAAuB;AAC3E,QAAM,aAAa,MAAM,KAAK,KAAK,OAAK,EAAE,OAAO,SAAS;AAE1D,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,YAAY,OAAO;AACvC,SAAO,WAAW,SAAS,KAAK,WAAW,OAAO;AACpD;AAYA,eAAsBF,eAAc,OAAc,KAAa,QAAgB,MAA8B;AAC3G,MAAI,CAAC,YAAY,KAAK,GAAG;AACvB,UAAM,IAAI,MAAM,wCAAwC;AAAA,EAC1D;AAEA,MAAI,CAAC,kBAAkB,KAAK,GAAG;AAC7B,UAAM,IAAI,MAAM,mCAAmC;AAAA,EACrD;AAEA,MAAI,CAAC,uBAAuB,KAAK,GAAG;AAClC,UAAM,IAAI,MAAM,mDAAmD;AAAA,EACrE;AAEA,MAAI,CAAC,oBAAoB,OAAO,GAAG,GAAG;AACpC,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AAEA,MAAI,CAAC,uBAAuB,OAAO,MAAM,GAAG;AAC1C,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC3D;AAEA,MAAI,QAAQ,IAAI,KAAK,OAAO,SAAS,YAAY,OAAO,KAAK,IAAI,EAAE,SAAS,GAAG;AAC7E,QAAI,CAAC,wBAAwB,OAAO,IAAI,GAAG;AACzC,YAAM,IAAI,MAAM,mEAAmE;AAAA,IACrF;AAAA,EACF;AAEA,SAAO;AACT;",
+ "names": ["sha256", "bytesToHex", "bytesToHex", "hexToBytes", "i", "bytesToHex", "hexToBytes", "validateEvent", "sha256", "bytesToHex"]
} Index: package/lib/cjs/nipb7.js.map
===================================================================
--- package/lib/cjs/nipb7.js.map
+++ package/lib/cjs/nipb7.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nipb7.ts", "../../utils.ts"],
- "sourcesContent": ["import { sha256 } from '@noble/hashes/sha256'\nimport { EventTemplate } from './core.ts'\nimport { Signer } from './signer.ts'\nimport { bytesToHex } from './utils.ts'\n\nexport type BlobDescriptor = {\n url: string\n sha256: string\n size: number\n type: string\n uploaded: number\n}\n\nexport class BlossomClient {\n private mediaserver: string\n private signer: Signer\n\n constructor(mediaserver: string, signer: Signer) {\n if (!mediaserver.startsWith('http')) {\n mediaserver = 'https://' + mediaserver\n }\n this.mediaserver = mediaserver.replace(/\\/$/, '') + '/'\n this.signer = signer\n }\n\n private async httpCall(\n method: string,\n url: string,\n contentType?: string,\n addAuthorization?: () => Promise<string>,\n body?: File | Blob,\n result?: any,\n ): Promise<any> {\n const headers: { [_: string]: string } = {}\n\n if (contentType) {\n headers['Content-Type'] = contentType\n }\n\n if (addAuthorization) {\n const auth = await addAuthorization()\n if (auth) {\n headers['Authorization'] = auth\n }\n }\n\n const response = await fetch(this.mediaserver + url, {\n method,\n headers,\n body,\n })\n\n if (response.status >= 300) {\n const reason = response.headers.get('X-Reason') || response.statusText\n throw new Error(`${url} returned an error (${response.status}): ${reason}`)\n }\n\n if (result !== null && response.headers.get('content-type')?.includes('application/json')) {\n return await response.json()\n }\n\n return response\n }\n\n private async authorizationHeader(modify?: (event: EventTemplate) => void): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n const event: EventTemplate = {\n created_at: now,\n kind: 24242,\n content: 'blossom stuff',\n tags: [['expiration', String(now + 60)]],\n }\n\n if (modify) {\n modify(event)\n }\n\n try {\n const signedEvent = await this.signer.signEvent(event)\n const eventJson = JSON.stringify(signedEvent)\n return 'Nostr ' + btoa(eventJson)\n } catch (error) {\n return ''\n }\n }\n\n private isValid32ByteHex(hash: string): boolean {\n return /^[a-f0-9]{64}$/i.test(hash)\n }\n\n async check(hash: string): Promise<void> {\n if (!this.isValid32ByteHex(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n try {\n await this.httpCall('HEAD', hash)\n } catch (error) {\n throw new Error(`failed to check for ${hash}: ${error}`)\n }\n }\n\n async uploadBlob(file: File | Blob, contentType?: string): Promise<BlobDescriptor> {\n const hash = bytesToHex(sha256(new Uint8Array(await file.arrayBuffer())))\n const actualContentType = contentType || file.type || 'application/octet-stream'\n\n const bd = await this.httpCall(\n 'PUT',\n 'upload',\n actualContentType,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'upload'])\n evt.tags.push(['x', hash])\n }),\n file,\n {},\n )\n\n return bd\n }\n\n async uploadFile(file: File): Promise<BlobDescriptor> {\n return this.uploadBlob(file, file.type)\n }\n\n async download(hash: string): Promise<ArrayBuffer> {\n if (!this.isValid32ByteHex(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n const authHeader = await this.authorizationHeader(evt => {\n evt.tags.push(['t', 'get'])\n evt.tags.push(['x', hash])\n })\n\n const response = await fetch(this.mediaserver + hash, {\n method: 'GET',\n headers: {\n Authorization: authHeader,\n },\n })\n\n if (response.status >= 300) {\n throw new Error(`${hash} is not present in ${this.mediaserver}: ${response.status}`)\n }\n\n return await response.arrayBuffer()\n }\n\n async downloadAsBlob(hash: string): Promise<Blob> {\n const arrayBuffer = await this.download(hash)\n return new Blob([arrayBuffer])\n }\n\n async list(): Promise<BlobDescriptor[]> {\n const pubkey = await this.signer.getPublicKey()\n\n if (!this.isValid32ByteHex(pubkey)) {\n throw new Error(`pubkey ${pubkey} is not valid`)\n }\n\n try {\n const bds = await this.httpCall(\n 'GET',\n `list/${pubkey}`,\n undefined,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'list'])\n }),\n undefined,\n [],\n )\n return bds\n } catch (error) {\n throw new Error(`failed to list blobs: ${error}`)\n }\n }\n\n async delete(hash: string): Promise<void> {\n if (!this.isValid32ByteHex(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n try {\n await this.httpCall(\n 'DELETE',\n hash,\n undefined,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'delete'])\n evt.tags.push(['x', hash])\n }),\n undefined,\n null,\n )\n } catch (error) {\n throw new Error(`failed to delete ${hash}: ${error}`)\n }\n }\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { sha256 } from '@noble/hashes/sha2.js'\nimport { EventTemplate } from './core.ts'\nimport { Signer } from './signer.ts'\nimport { bytesToHex } from './utils.ts'\n\nexport type BlobDescriptor = {\n url: string\n sha256: string\n size: number\n type: string\n uploaded: number\n}\n\nexport class BlossomClient {\n private mediaserver: string\n private signer: Signer\n\n constructor(mediaserver: string, signer: Signer) {\n if (!mediaserver.startsWith('http')) {\n mediaserver = 'https://' + mediaserver\n }\n this.mediaserver = mediaserver.replace(/\\/$/, '') + '/'\n this.signer = signer\n }\n\n private async httpCall(\n method: string,\n url: string,\n contentType?: string,\n addAuthorization?: () => Promise<string>,\n body?: File | Blob,\n result?: any,\n ): Promise<any> {\n const headers: { [_: string]: string } = {}\n\n if (contentType) {\n headers['Content-Type'] = contentType\n }\n\n if (addAuthorization) {\n const auth = await addAuthorization()\n if (auth) {\n headers['Authorization'] = auth\n }\n }\n\n const response = await fetch(this.mediaserver + url, {\n method,\n headers,\n body,\n })\n\n if (response.status >= 300) {\n const reason = response.headers.get('X-Reason') || response.statusText\n throw new Error(`${url} returned an error (${response.status}): ${reason}`)\n }\n\n if (result !== null && response.headers.get('content-type')?.includes('application/json')) {\n return await response.json()\n }\n\n return response\n }\n\n private async authorizationHeader(modify?: (event: EventTemplate) => void): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n const event: EventTemplate = {\n created_at: now,\n kind: 24242,\n content: 'blossom stuff',\n tags: [['expiration', String(now + 60)]],\n }\n\n if (modify) {\n modify(event)\n }\n\n try {\n const signedEvent = await this.signer.signEvent(event)\n const eventJson = JSON.stringify(signedEvent)\n return 'Nostr ' + btoa(eventJson)\n } catch (error) {\n return ''\n }\n }\n\n private isValid32ByteHex(hash: string): boolean {\n return /^[a-f0-9]{64}$/i.test(hash)\n }\n\n async check(hash: string): Promise<void> {\n if (!this.isValid32ByteHex(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n try {\n await this.httpCall('HEAD', hash)\n } catch (error) {\n throw new Error(`failed to check for ${hash}: ${error}`)\n }\n }\n\n async uploadBlob(file: File | Blob, contentType?: string): Promise<BlobDescriptor> {\n const hash = bytesToHex(sha256(new Uint8Array(await file.arrayBuffer())))\n const actualContentType = contentType || file.type || 'application/octet-stream'\n\n const bd = await this.httpCall(\n 'PUT',\n 'upload',\n actualContentType,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'upload'])\n evt.tags.push(['x', hash])\n }),\n file,\n {},\n )\n\n return bd\n }\n\n async uploadFile(file: File): Promise<BlobDescriptor> {\n return this.uploadBlob(file, file.type)\n }\n\n async download(hash: string): Promise<ArrayBuffer> {\n if (!this.isValid32ByteHex(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n const authHeader = await this.authorizationHeader(evt => {\n evt.tags.push(['t', 'get'])\n evt.tags.push(['x', hash])\n })\n\n const response = await fetch(this.mediaserver + hash, {\n method: 'GET',\n headers: {\n Authorization: authHeader,\n },\n })\n\n if (response.status >= 300) {\n throw new Error(`${hash} is not present in ${this.mediaserver}: ${response.status}`)\n }\n\n return await response.arrayBuffer()\n }\n\n async downloadAsBlob(hash: string): Promise<Blob> {\n const arrayBuffer = await this.download(hash)\n return new Blob([arrayBuffer])\n }\n\n async list(): Promise<BlobDescriptor[]> {\n const pubkey = await this.signer.getPublicKey()\n\n if (!this.isValid32ByteHex(pubkey)) {\n throw new Error(`pubkey ${pubkey} is not valid`)\n }\n\n try {\n const bds = await this.httpCall(\n 'GET',\n `list/${pubkey}`,\n undefined,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'list'])\n }),\n undefined,\n [],\n )\n return bds\n } catch (error) {\n throw new Error(`failed to list blobs: ${error}`)\n }\n }\n\n async delete(hash: string): Promise<void> {\n if (!this.isValid32ByteHex(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n try {\n await this.httpCall(\n 'DELETE',\n hash,\n undefined,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'delete'])\n evt.tags.push(['x', hash])\n }),\n undefined,\n null,\n )\n } catch (error) {\n throw new Error(`failed to delete ${hash}: ${error}`)\n }\n }\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAuB;;;ACKvB,mBAAuC;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;ADUjD,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EACA;AAAA,EAER,YAAY,aAAqB,QAAgB;AAC/C,QAAI,CAAC,YAAY,WAAW,MAAM,GAAG;AACnC,oBAAc,aAAa;AAAA,IAC7B;AACA,SAAK,cAAc,YAAY,QAAQ,OAAO,EAAE,IAAI;AACpD,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,MAAc,SACZ,QACA,KACA,aACA,kBACA,MACA,QACc;AACd,UAAM,UAAmC,CAAC;AAE1C,QAAI,aAAa;AACf,cAAQ,kBAAkB;AAAA,IAC5B;AAEA,QAAI,kBAAkB;AACpB,YAAM,OAAO,MAAM,iBAAiB;AACpC,UAAI,MAAM;AACR,gBAAQ,mBAAmB;AAAA,MAC7B;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK,cAAc,KAAK;AAAA,MACnD;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,SAAS,UAAU,KAAK;AAC1B,YAAM,SAAS,SAAS,QAAQ,IAAI,UAAU,KAAK,SAAS;AAC5D,YAAM,IAAI,MAAM,GAAG,0BAA0B,SAAS,YAAY,QAAQ;AAAA,IAC5E;AAEA,QAAI,WAAW,QAAQ,SAAS,QAAQ,IAAI,cAAc,GAAG,SAAS,kBAAkB,GAAG;AACzF,aAAO,MAAM,SAAS,KAAK;AAAA,IAC7B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,oBAAoB,QAA0D;AAC1F,UAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AACxC,UAAM,QAAuB;AAAA,MAC3B,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM,CAAC,CAAC,cAAc,OAAO,MAAM,EAAE,CAAC,CAAC;AAAA,IACzC;AAEA,QAAI,QAAQ;AACV,aAAO,KAAK;AAAA,IACd;AAEA,QAAI;AACF,YAAM,cAAc,MAAM,KAAK,OAAO,UAAU,KAAK;AACrD,YAAM,YAAY,KAAK,UAAU,WAAW;AAC5C,aAAO,WAAW,KAAK,SAAS;AAAA,IAClC,SAAS,OAAP;AACA,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,iBAAiB,MAAuB;AAC9C,WAAO,kBAAkB,KAAK,IAAI;AAAA,EACpC;AAAA,EAEA,MAAM,MAAM,MAA6B;AACvC,QAAI,CAAC,KAAK,iBAAiB,IAAI,GAAG;AAChC,YAAM,IAAI,MAAM,GAAG,wCAAwC;AAAA,IAC7D;AAEA,QAAI;AACF,YAAM,KAAK,SAAS,QAAQ,IAAI;AAAA,IAClC,SAAS,OAAP;AACA,YAAM,IAAI,MAAM,uBAAuB,SAAS,OAAO;AAAA,IACzD;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,MAAmB,aAA+C;AACjF,UAAM,WAAO,6BAAW,oBAAO,IAAI,WAAW,MAAM,KAAK,YAAY,CAAC,CAAC,CAAC;AACxE,UAAM,oBAAoB,eAAe,KAAK,QAAQ;AAEtD,UAAM,KAAK,MAAM,KAAK;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA,MACE,KAAK,oBAAoB,SAAO;AAC9B,YAAI,KAAK,KAAK,CAAC,KAAK,QAAQ,CAAC;AAC7B,YAAI,KAAK,KAAK,CAAC,KAAK,IAAI,CAAC;AAAA,MAC3B,CAAC;AAAA,MACH;AAAA,MACA,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,MAAqC;AACpD,WAAO,KAAK,WAAW,MAAM,KAAK,IAAI;AAAA,EACxC;AAAA,EAEA,MAAM,SAAS,MAAoC;AACjD,QAAI,CAAC,KAAK,iBAAiB,IAAI,GAAG;AAChC,YAAM,IAAI,MAAM,GAAG,wCAAwC;AAAA,IAC7D;AAEA,UAAM,aAAa,MAAM,KAAK,oBAAoB,SAAO;AACvD,UAAI,KAAK,KAAK,CAAC,KAAK,KAAK,CAAC;AAC1B,UAAI,KAAK,KAAK,CAAC,KAAK,IAAI,CAAC;AAAA,IAC3B,CAAC;AAED,UAAM,WAAW,MAAM,MAAM,KAAK,cAAc,MAAM;AAAA,MACpD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe;AAAA,MACjB;AAAA,IACF,CAAC;AAED,QAAI,SAAS,UAAU,KAAK;AAC1B,YAAM,IAAI,MAAM,GAAG,0BAA0B,KAAK,gBAAgB,SAAS,QAAQ;AAAA,IACrF;AAEA,WAAO,MAAM,SAAS,YAAY;AAAA,EACpC;AAAA,EAEA,MAAM,eAAe,MAA6B;AAChD,UAAM,cAAc,MAAM,KAAK,SAAS,IAAI;AAC5C,WAAO,IAAI,KAAK,CAAC,WAAW,CAAC;AAAA,EAC/B;AAAA,EAEA,MAAM,OAAkC;AACtC,UAAM,SAAS,MAAM,KAAK,OAAO,aAAa;AAE9C,QAAI,CAAC,KAAK,iBAAiB,MAAM,GAAG;AAClC,YAAM,IAAI,MAAM,UAAU,qBAAqB;AAAA,IACjD;AAEA,QAAI;AACF,YAAM,MAAM,MAAM,KAAK;AAAA,QACrB;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,QACA,MACE,KAAK,oBAAoB,SAAO;AAC9B,cAAI,KAAK,KAAK,CAAC,KAAK,MAAM,CAAC;AAAA,QAC7B,CAAC;AAAA,QACH;AAAA,QACA,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT,SAAS,OAAP;AACA,YAAM,IAAI,MAAM,yBAAyB,OAAO;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,MAAM,OAAO,MAA6B;AACxC,QAAI,CAAC,KAAK,iBAAiB,IAAI,GAAG;AAChC,YAAM,IAAI,MAAM,GAAG,wCAAwC;AAAA,IAC7D;AAEA,QAAI;AACF,YAAM,KAAK;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,QACA,MACE,KAAK,oBAAoB,SAAO;AAC9B,cAAI,KAAK,KAAK,CAAC,KAAK,QAAQ,CAAC;AAC7B,cAAI,KAAK,KAAK,CAAC,KAAK,IAAI,CAAC;AAAA,QAC3B,CAAC;AAAA,QACH;AAAA,QACA;AAAA,MACF;AAAA,IACF,SAAS,OAAP;AACA,YAAM,IAAI,MAAM,oBAAoB,SAAS,OAAO;AAAA,IACtD;AAAA,EACF;AACF;",
"names": []
} Index: package/lib/esm/nipb7.js.map
===================================================================
--- package/lib/esm/nipb7.js.map
+++ package/lib/esm/nipb7.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nipb7.ts", "../../utils.ts"],
- "sourcesContent": ["import { sha256 } from '@noble/hashes/sha256'\nimport { EventTemplate } from './core.ts'\nimport { Signer } from './signer.ts'\nimport { bytesToHex } from './utils.ts'\n\nexport type BlobDescriptor = {\n url: string\n sha256: string\n size: number\n type: string\n uploaded: number\n}\n\nexport class BlossomClient {\n private mediaserver: string\n private signer: Signer\n\n constructor(mediaserver: string, signer: Signer) {\n if (!mediaserver.startsWith('http')) {\n mediaserver = 'https://' + mediaserver\n }\n this.mediaserver = mediaserver.replace(/\\/$/, '') + '/'\n this.signer = signer\n }\n\n private async httpCall(\n method: string,\n url: string,\n contentType?: string,\n addAuthorization?: () => Promise<string>,\n body?: File | Blob,\n result?: any,\n ): Promise<any> {\n const headers: { [_: string]: string } = {}\n\n if (contentType) {\n headers['Content-Type'] = contentType\n }\n\n if (addAuthorization) {\n const auth = await addAuthorization()\n if (auth) {\n headers['Authorization'] = auth\n }\n }\n\n const response = await fetch(this.mediaserver + url, {\n method,\n headers,\n body,\n })\n\n if (response.status >= 300) {\n const reason = response.headers.get('X-Reason') || response.statusText\n throw new Error(`${url} returned an error (${response.status}): ${reason}`)\n }\n\n if (result !== null && response.headers.get('content-type')?.includes('application/json')) {\n return await response.json()\n }\n\n return response\n }\n\n private async authorizationHeader(modify?: (event: EventTemplate) => void): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n const event: EventTemplate = {\n created_at: now,\n kind: 24242,\n content: 'blossom stuff',\n tags: [['expiration', String(now + 60)]],\n }\n\n if (modify) {\n modify(event)\n }\n\n try {\n const signedEvent = await this.signer.signEvent(event)\n const eventJson = JSON.stringify(signedEvent)\n return 'Nostr ' + btoa(eventJson)\n } catch (error) {\n return ''\n }\n }\n\n private isValid32ByteHex(hash: string): boolean {\n return /^[a-f0-9]{64}$/i.test(hash)\n }\n\n async check(hash: string): Promise<void> {\n if (!this.isValid32ByteHex(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n try {\n await this.httpCall('HEAD', hash)\n } catch (error) {\n throw new Error(`failed to check for ${hash}: ${error}`)\n }\n }\n\n async uploadBlob(file: File | Blob, contentType?: string): Promise<BlobDescriptor> {\n const hash = bytesToHex(sha256(new Uint8Array(await file.arrayBuffer())))\n const actualContentType = contentType || file.type || 'application/octet-stream'\n\n const bd = await this.httpCall(\n 'PUT',\n 'upload',\n actualContentType,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'upload'])\n evt.tags.push(['x', hash])\n }),\n file,\n {},\n )\n\n return bd\n }\n\n async uploadFile(file: File): Promise<BlobDescriptor> {\n return this.uploadBlob(file, file.type)\n }\n\n async download(hash: string): Promise<ArrayBuffer> {\n if (!this.isValid32ByteHex(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n const authHeader = await this.authorizationHeader(evt => {\n evt.tags.push(['t', 'get'])\n evt.tags.push(['x', hash])\n })\n\n const response = await fetch(this.mediaserver + hash, {\n method: 'GET',\n headers: {\n Authorization: authHeader,\n },\n })\n\n if (response.status >= 300) {\n throw new Error(`${hash} is not present in ${this.mediaserver}: ${response.status}`)\n }\n\n return await response.arrayBuffer()\n }\n\n async downloadAsBlob(hash: string): Promise<Blob> {\n const arrayBuffer = await this.download(hash)\n return new Blob([arrayBuffer])\n }\n\n async list(): Promise<BlobDescriptor[]> {\n const pubkey = await this.signer.getPublicKey()\n\n if (!this.isValid32ByteHex(pubkey)) {\n throw new Error(`pubkey ${pubkey} is not valid`)\n }\n\n try {\n const bds = await this.httpCall(\n 'GET',\n `list/${pubkey}`,\n undefined,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'list'])\n }),\n undefined,\n [],\n )\n return bds\n } catch (error) {\n throw new Error(`failed to list blobs: ${error}`)\n }\n }\n\n async delete(hash: string): Promise<void> {\n if (!this.isValid32ByteHex(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n try {\n await this.httpCall(\n 'DELETE',\n hash,\n undefined,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'delete'])\n evt.tags.push(['x', hash])\n }),\n undefined,\n null,\n )\n } catch (error) {\n throw new Error(`failed to delete ${hash}: ${error}`)\n }\n }\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "sourcesContent": ["import { sha256 } from '@noble/hashes/sha2.js'\nimport { EventTemplate } from './core.ts'\nimport { Signer } from './signer.ts'\nimport { bytesToHex } from './utils.ts'\n\nexport type BlobDescriptor = {\n url: string\n sha256: string\n size: number\n type: string\n uploaded: number\n}\n\nexport class BlossomClient {\n private mediaserver: string\n private signer: Signer\n\n constructor(mediaserver: string, signer: Signer) {\n if (!mediaserver.startsWith('http')) {\n mediaserver = 'https://' + mediaserver\n }\n this.mediaserver = mediaserver.replace(/\\/$/, '') + '/'\n this.signer = signer\n }\n\n private async httpCall(\n method: string,\n url: string,\n contentType?: string,\n addAuthorization?: () => Promise<string>,\n body?: File | Blob,\n result?: any,\n ): Promise<any> {\n const headers: { [_: string]: string } = {}\n\n if (contentType) {\n headers['Content-Type'] = contentType\n }\n\n if (addAuthorization) {\n const auth = await addAuthorization()\n if (auth) {\n headers['Authorization'] = auth\n }\n }\n\n const response = await fetch(this.mediaserver + url, {\n method,\n headers,\n body,\n })\n\n if (response.status >= 300) {\n const reason = response.headers.get('X-Reason') || response.statusText\n throw new Error(`${url} returned an error (${response.status}): ${reason}`)\n }\n\n if (result !== null && response.headers.get('content-type')?.includes('application/json')) {\n return await response.json()\n }\n\n return response\n }\n\n private async authorizationHeader(modify?: (event: EventTemplate) => void): Promise<string> {\n const now = Math.floor(Date.now() / 1000)\n const event: EventTemplate = {\n created_at: now,\n kind: 24242,\n content: 'blossom stuff',\n tags: [['expiration', String(now + 60)]],\n }\n\n if (modify) {\n modify(event)\n }\n\n try {\n const signedEvent = await this.signer.signEvent(event)\n const eventJson = JSON.stringify(signedEvent)\n return 'Nostr ' + btoa(eventJson)\n } catch (error) {\n return ''\n }\n }\n\n private isValid32ByteHex(hash: string): boolean {\n return /^[a-f0-9]{64}$/i.test(hash)\n }\n\n async check(hash: string): Promise<void> {\n if (!this.isValid32ByteHex(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n try {\n await this.httpCall('HEAD', hash)\n } catch (error) {\n throw new Error(`failed to check for ${hash}: ${error}`)\n }\n }\n\n async uploadBlob(file: File | Blob, contentType?: string): Promise<BlobDescriptor> {\n const hash = bytesToHex(sha256(new Uint8Array(await file.arrayBuffer())))\n const actualContentType = contentType || file.type || 'application/octet-stream'\n\n const bd = await this.httpCall(\n 'PUT',\n 'upload',\n actualContentType,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'upload'])\n evt.tags.push(['x', hash])\n }),\n file,\n {},\n )\n\n return bd\n }\n\n async uploadFile(file: File): Promise<BlobDescriptor> {\n return this.uploadBlob(file, file.type)\n }\n\n async download(hash: string): Promise<ArrayBuffer> {\n if (!this.isValid32ByteHex(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n const authHeader = await this.authorizationHeader(evt => {\n evt.tags.push(['t', 'get'])\n evt.tags.push(['x', hash])\n })\n\n const response = await fetch(this.mediaserver + hash, {\n method: 'GET',\n headers: {\n Authorization: authHeader,\n },\n })\n\n if (response.status >= 300) {\n throw new Error(`${hash} is not present in ${this.mediaserver}: ${response.status}`)\n }\n\n return await response.arrayBuffer()\n }\n\n async downloadAsBlob(hash: string): Promise<Blob> {\n const arrayBuffer = await this.download(hash)\n return new Blob([arrayBuffer])\n }\n\n async list(): Promise<BlobDescriptor[]> {\n const pubkey = await this.signer.getPublicKey()\n\n if (!this.isValid32ByteHex(pubkey)) {\n throw new Error(`pubkey ${pubkey} is not valid`)\n }\n\n try {\n const bds = await this.httpCall(\n 'GET',\n `list/${pubkey}`,\n undefined,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'list'])\n }),\n undefined,\n [],\n )\n return bds\n } catch (error) {\n throw new Error(`failed to list blobs: ${error}`)\n }\n }\n\n async delete(hash: string): Promise<void> {\n if (!this.isValid32ByteHex(hash)) {\n throw new Error(`${hash} is not a valid 32-byte hex string`)\n }\n\n try {\n await this.httpCall(\n 'DELETE',\n hash,\n undefined,\n () =>\n this.authorizationHeader(evt => {\n evt.tags.push(['t', 'delete'])\n evt.tags.push(['x', hash])\n }),\n undefined,\n null,\n )\n } catch (error) {\n throw new Error(`failed to delete ${hash}: ${error}`)\n }\n }\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
"mappings": "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",
"names": []
} File too large for inline diff
Index: package/lib/cjs/pool.js.map
===================================================================
--- package/lib/cjs/pool.js.map
+++ package/lib/cjs/pool.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../pool.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts", "../../helpers.ts", "../../abstract-relay.ts", "../../abstract-pool.ts"],
- "sourcesContent": ["/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractSimplePool, type AbstractPoolConstructorOptions } from './abstract-pool.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class SimplePool extends AbstractSimplePool {\n constructor(options?: Pick<AbstractPoolConstructorOptions, 'enablePing' | 'enableReconnect'>) {\n super({ verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n}\n\nexport * from './abstract-pool.ts'\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractSimplePool, type AbstractPoolConstructorOptions } from './abstract-pool.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class SimplePool extends AbstractSimplePool {\n constructor(options?: Pick<AbstractPoolConstructorOptions, 'enablePing' | 'enableReconnect'>) {\n super({ verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n}\n\nexport * from './abstract-pool.ts'\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n"],
+ "mappings": "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",
"names": ["import_utils", "i", "target", "i", "i", "reason"]
} Index: package/lib/esm/pool.js.map
===================================================================
--- package/lib/esm/pool.js.map
+++ package/lib/esm/pool.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts", "../../helpers.ts", "../../abstract-relay.ts", "../../abstract-pool.ts", "../../pool.ts"],
- "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n", "/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractSimplePool, type AbstractPoolConstructorOptions } from './abstract-pool.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class SimplePool extends AbstractSimplePool {\n constructor(options?: Pick<AbstractPoolConstructorOptions, 'enablePing' | 'enableReconnect'>) {\n super({ verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n}\n\nexport * from './abstract-pool.ts'\n"],
- "mappings": "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",
- "names": ["bytesToHex", "i", "target", "bytesToHex", "i", "i", "reason"]
+ "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "/* global WebSocket */\n\nimport {\n AbstractRelay as AbstractRelay,\n SubscriptionParams,\n Subscription,\n type AbstractRelayConstructorOptions,\n} from './abstract-relay.ts'\nimport { normalizeURL } from './utils.ts'\n\nimport type { Event, EventTemplate, Nostr, VerifiedEvent } from './core.ts'\nimport { type Filter } from './filter.ts'\nimport { alwaysTrue } from './helpers.ts'\n\nexport type SubCloser = { close: (reason?: string) => void }\n\nexport type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {\n // automaticallyAuth takes a relay URL and should return null\n // in case that relay shouldn't be authenticated against\n // or a function to sign the AUTH event template otherwise (that function may still throw in case of failure)\n automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n}\n\nexport type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {\n maxWait?: number\n abort?: AbortSignal\n onclose?: (reasons: string[]) => void\n onauth?: (event: EventTemplate) => Promise<VerifiedEvent>\n id?: string\n label?: string\n}\n\nexport class AbstractSimplePool {\n protected relays: Map<string, AbstractRelay> = new Map()\n public seenOn: Map<string, Set<AbstractRelay>> = new Map()\n public trackRelays: boolean = false\n\n public verifyEvent: Nostr['verifyEvent']\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n public automaticallyAuth?: (relayURL: string) => null | ((event: EventTemplate) => Promise<VerifiedEvent>)\n public trustedRelayURLs: Set<string> = new Set()\n\n private _WebSocket?: typeof WebSocket\n\n constructor(opts: AbstractPoolConstructorOptions) {\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n this.automaticallyAuth = opts.automaticallyAuth\n }\n\n async ensureRelay(\n url: string,\n params?: {\n connectionTimeout?: number\n abort?: AbortSignal\n },\n ): Promise<AbstractRelay> {\n url = normalizeURL(url)\n\n let relay = this.relays.get(url)\n if (!relay) {\n relay = new AbstractRelay(url, {\n verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,\n websocketImplementation: this._WebSocket,\n enablePing: this.enablePing,\n enableReconnect: this.enableReconnect,\n })\n relay.onclose = () => {\n if (relay && !relay.enableReconnect) {\n this.relays.delete(url)\n }\n }\n this.relays.set(url, relay)\n }\n\n if (this.automaticallyAuth) {\n const authSignerFn = this.automaticallyAuth(url)\n if (authSignerFn) {\n relay.onauth = authSignerFn\n }\n }\n\n await relay.connect({\n timeout: params?.connectionTimeout,\n abort: params?.abort,\n })\n\n return relay\n }\n\n close(relays: string[]) {\n relays.map(normalizeURL).forEach(url => {\n this.relays.get(url)?.close()\n this.relays.delete(url)\n })\n }\n\n subscribe(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (!request.find(r => r.url === url)) {\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMany(relays: string[], filter: Filter, params: SubscribeManyParams): SubCloser {\n const request: { url: string; filter: Filter }[] = []\n const uniqUrls: string[] = []\n for (let i = 0; i < relays.length; i++) {\n const url = normalizeURL(relays[i])\n if (uniqUrls.indexOf(url) === -1) {\n uniqUrls.push(url)\n request.push({ url, filter: filter })\n }\n }\n\n return this.subscribeMap(request, params)\n }\n\n subscribeMap(requests: { url: string; filter: Filter }[], params: SubscribeManyParams): SubCloser {\n const grouped = new Map<string, Filter[]>()\n for (const req of requests) {\n const { url, filter } = req\n if (!grouped.has(url)) grouped.set(url, [])\n grouped.get(url)!.push(filter)\n }\n const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }))\n\n if (this.trackRelays) {\n params.receivedEvent = (relay: AbstractRelay, id: string) => {\n let set = this.seenOn.get(id)\n if (!set) {\n set = new Set()\n this.seenOn.set(id, set)\n }\n set.add(relay)\n }\n }\n\n const _knownIds = new Set<string>()\n const subs: Subscription[] = []\n\n // batch all EOSEs into a single\n const eosesReceived: boolean[] = []\n let handleEose = (i: number) => {\n if (eosesReceived[i]) return // do not act twice for the same relay\n eosesReceived[i] = true\n if (eosesReceived.filter(a => a).length === groupedRequests.length) {\n params.oneose?.()\n handleEose = () => {}\n }\n }\n // batch all closes into a single\n const closesReceived: string[] = []\n let handleClose = (i: number, reason: string) => {\n if (closesReceived[i]) return // do not act twice for the same relay\n handleEose(i)\n closesReceived[i] = reason\n if (closesReceived.filter(a => a).length === groupedRequests.length) {\n params.onclose?.(closesReceived)\n handleClose = () => {}\n }\n }\n\n const localAlreadyHaveEventHandler = (id: string) => {\n if (params.alreadyHaveEvent?.(id)) {\n return true\n }\n const have = _knownIds.has(id)\n _knownIds.add(id)\n return have\n }\n\n // open a subscription in all given relays\n const allOpened = Promise.all(\n groupedRequests.map(async ({ url, filters }, i) => {\n let relay: AbstractRelay\n try {\n relay = await this.ensureRelay(url, {\n connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,\n abort: params.abort,\n })\n } catch (err) {\n handleClose(i, (err as any)?.message || String(err))\n return\n }\n\n let subscription = relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n if (reason.startsWith('auth-required: ') && params.onauth) {\n relay\n .auth(params.onauth)\n .then(() => {\n relay.subscribe(filters, {\n ...params,\n oneose: () => handleEose(i),\n onclose: reason => {\n handleClose(i, reason) // the second time we won't try to auth anymore\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n })\n .catch(err => {\n handleClose(i, `auth was required and attempted, but failed with: ${err}`)\n })\n } else {\n handleClose(i, reason)\n }\n },\n alreadyHaveEvent: localAlreadyHaveEventHandler,\n eoseTimeout: params.maxWait,\n abort: params.abort,\n })\n\n subs.push(subscription)\n }),\n )\n\n return {\n async close(reason?: string) {\n await allOpened\n subs.forEach(sub => {\n sub.close(reason)\n })\n },\n }\n }\n\n subscribeEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribe(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n subscribeManyEose(\n relays: string[],\n filter: Filter,\n params: Pick<SubscribeManyParams, 'label' | 'id' | 'onevent' | 'onclose' | 'maxWait' | 'onauth'>,\n ): SubCloser {\n const subcloser = this.subscribeMany(relays, filter, {\n ...params,\n oneose() {\n subcloser.close('closed automatically on eose')\n },\n })\n return subcloser\n }\n\n async querySync(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event[]> {\n return new Promise(async resolve => {\n const events: Event[] = []\n this.subscribeEose(relays, filter, {\n ...params,\n onevent(event: Event) {\n events.push(event)\n },\n onclose(_: string[]) {\n resolve(events)\n },\n })\n })\n }\n\n async get(\n relays: string[],\n filter: Filter,\n params?: Pick<SubscribeManyParams, 'label' | 'id' | 'maxWait'>,\n ): Promise<Event | null> {\n filter.limit = 1\n const events = await this.querySync(relays, filter, params)\n events.sort((a, b) => b.created_at - a.created_at)\n return events[0] || null\n }\n\n publish(\n relays: string[],\n event: Event,\n options?: { onauth?: (evt: EventTemplate) => Promise<VerifiedEvent> },\n ): Promise<string>[] {\n return relays.map(normalizeURL).map(async (url, i, arr) => {\n if (arr.indexOf(url) !== i) {\n // duplicate\n return Promise.reject('duplicate url')\n }\n\n let r = await this.ensureRelay(url)\n return r\n .publish(event)\n .catch(async err => {\n if (err instanceof Error && err.message.startsWith('auth-required: ') && options?.onauth) {\n await r.auth(options.onauth)\n return r.publish(event) // retry\n }\n throw err\n })\n .then(reason => {\n if (this.trackRelays) {\n let set = this.seenOn.get(event.id)\n if (!set) {\n set = new Set()\n this.seenOn.set(event.id, set)\n }\n set.add(r)\n }\n return reason\n })\n })\n }\n\n listConnectionStatus(): Map<string, boolean> {\n const map = new Map<string, boolean>()\n this.relays.forEach((relay, url) => map.set(url, relay.connected))\n\n return map\n }\n\n destroy(): void {\n this.relays.forEach(conn => conn.close())\n this.relays = new Map()\n }\n}\n", "/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractSimplePool, type AbstractPoolConstructorOptions } from './abstract-pool.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class SimplePool extends AbstractSimplePool {\n constructor(options?: Pick<AbstractPoolConstructorOptions, 'enablePing' | 'enableReconnect'>) {\n super({ verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n}\n\nexport * from './abstract-pool.ts'\n"],
+ "mappings": "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",
+ "names": ["bytesToHex", "hexToBytes", "i", "target", "bytesToHex", "hexToBytes", "i", "i", "reason"]
} Index: package/lib/cjs/pure.js.map
===================================================================
--- package/lib/cjs/pure.js.map
+++ package/lib/cjs/pure.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../pure.ts", "../../core.ts", "../../utils.ts"],
- "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": "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",
"names": ["import_utils", "i"]
} Index: package/lib/esm/pure.js.map
===================================================================
--- package/lib/esm/pure.js.map
+++ package/lib/esm/pure.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../pure.ts", "../../core.ts", "../../utils.ts"],
- "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": ";AAAA,SAAS,eAAe;AACxB,SAAS,cAAAA,mBAAkB;;;ACOpB,IAAM,iBAAiB,OAAO,UAAU;AAsB/C,IAAM,WAAW,CAAC,QAAiD,eAAe;AAE3E,SAAS,cAAiB,OAAsC;AACrE,MAAI,CAAC,SAAS,KAAK;AAAG,WAAO;AAC7B,MAAI,OAAO,MAAM,SAAS;AAAU,WAAO;AAC3C,MAAI,OAAO,MAAM,YAAY;AAAU,WAAO;AAC9C,MAAI,OAAO,MAAM,eAAe;AAAU,WAAO;AACjD,MAAI,OAAO,MAAM,WAAW;AAAU,WAAO;AAC7C,MAAI,CAAC,MAAM,OAAO,MAAM,gBAAgB;AAAG,WAAO;AAElD,MAAI,CAAC,MAAM,QAAQ,MAAM,IAAI;AAAG,WAAO;AACvC,WAASC,KAAI,GAAGA,KAAI,MAAM,KAAK,QAAQA,MAAK;AAC1C,QAAI,MAAM,MAAM,KAAKA;AACrB,QAAI,CAAC,MAAM,QAAQ,GAAG;AAAG,aAAO;AAChC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAI,OAAO,IAAI,OAAO;AAAU,eAAO;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AACT;AAOO,SAAS,WAAW,QAA0B;AACnD,SAAO,OAAO,KAAK,CAAC,GAAe,MAA0B;AAC3D,QAAI,EAAE,eAAe,EAAE,YAAY;AACjC,aAAO,EAAE,aAAa,EAAE;AAAA,IAC1B;AACA,WAAO,EAAE,GAAG,cAAc,EAAE,EAAE;AAAA,EAChC,CAAC;AACH;;;AD7DA,SAAS,cAAc;;;AEEvB,SAAS,YAAY,kBAAkB;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;AFIxD,IAAM,KAAN,MAA0B;AAAA,EACxB,oBAAgC;AAC9B,WAAO,QAAQ,MAAM,iBAAiB;AAAA,EACxC;AAAA,EACA,aAAa,WAA+B;AAC1C,WAAOC,YAAW,QAAQ,aAAa,SAAS,CAAC;AAAA,EACnD;AAAA,EACA,cAAc,GAAkB,WAAsC;AACpE,UAAM,QAAQ;AACd,UAAM,SAASA,YAAW,QAAQ,aAAa,SAAS,CAAC;AACzD,UAAM,KAAK,aAAa,KAAK;AAC7B,UAAM,MAAMA,YAAW,QAAQ,KAAK,aAAa,KAAK,GAAG,SAAS,CAAC;AACnE,UAAM,kBAAkB;AACxB,WAAO;AAAA,EACT;AAAA,EACA,YAAY,OAAsC;AAChD,QAAI,OAAO,MAAM,oBAAoB;AAAW,aAAO,MAAM;AAE7D,UAAM,OAAO,aAAa,KAAK;AAC/B,QAAI,SAAS,MAAM,IAAI;AACrB,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,QAAQ,QAAQ,OAAO,MAAM,KAAK,MAAM,MAAM,MAAM;AAC1D,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT,SAAS,KAAP;AACA,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,eAAe,KAA4B;AACzD,MAAI,CAAC,cAAc,GAAG;AAAG,UAAM,IAAI,MAAM,wDAAwD;AACjG,SAAO,KAAK,UAAU,CAAC,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,CAAC;AACxF;AAEO,SAAS,aAAa,OAA8B;AACzD,MAAI,YAAY,OAAO,YAAY,OAAO,eAAe,KAAK,CAAC,CAAC;AAChE,SAAOA,YAAW,SAAS;AAC7B;AAEA,IAAM,IAAQ,IAAI,GAAG;AAEd,IAAM,oBAAoB,EAAE;AAC5B,IAAM,eAAe,EAAE;AACvB,IAAM,gBAAgB,EAAE;AACxB,IAAM,cAAc,EAAE;",
- "names": ["bytesToHex", "i", "bytesToHex"]
+ "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": "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",
+ "names": ["bytesToHex", "hexToBytes", "i", "bytesToHex", "hexToBytes"]
} Index: package/lib/cjs/references.js.map
===================================================================
--- package/lib/cjs/references.js.map
+++ package/lib/cjs/references.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../references.ts", "../../nip19.ts", "../../utils.ts"],
- "sourcesContent": ["import { decode, type AddressPointer, type ProfilePointer, type EventPointer } from './nip19.ts'\n\nimport type { Event } from './core.ts'\n\ntype Reference = {\n text: string\n profile?: ProfilePointer\n event?: EventPointer\n address?: AddressPointer\n}\n\nconst mentionRegex = /\\bnostr:((note|npub|naddr|nevent|nprofile)1\\w+)\\b|#\\[(\\d+)\\]/g\n\nexport function parseReferences(evt: Event): Reference[] {\n let references: Reference[] = []\n for (let ref of evt.content.matchAll(mentionRegex)) {\n if (ref[2]) {\n // it's a NIP-27 mention\n try {\n let { type, data } = decode(ref[1])\n switch (type) {\n case 'npub': {\n references.push({\n text: ref[0],\n profile: { pubkey: data as string, relays: [] },\n })\n break\n }\n case 'nprofile': {\n references.push({\n text: ref[0],\n profile: data as ProfilePointer,\n })\n break\n }\n case 'note': {\n references.push({\n text: ref[0],\n event: { id: data as string, relays: [] },\n })\n break\n }\n case 'nevent': {\n references.push({\n text: ref[0],\n event: data as EventPointer,\n })\n break\n }\n case 'naddr': {\n references.push({\n text: ref[0],\n address: data as AddressPointer,\n })\n break\n }\n }\n } catch (err) {\n /***/\n }\n } else if (ref[3]) {\n // it's a NIP-10 mention\n let idx = parseInt(ref[3], 10)\n let tag = evt.tags[idx]\n if (!tag) continue\n\n switch (tag[0]) {\n case 'p': {\n references.push({\n text: ref[0],\n profile: { pubkey: tag[1], relays: tag[2] ? [tag[2]] : [] },\n })\n break\n }\n case 'e': {\n references.push({\n text: ref[0],\n event: { id: tag[1], relays: tag[2] ? [tag[2]] : [] },\n })\n break\n }\n case 'a': {\n try {\n let [kind, pubkey, identifier] = tag[1].split(':')\n references.push({\n text: ref[0],\n address: {\n identifier,\n pubkey,\n kind: parseInt(kind, 10),\n relays: tag[2] ? [tag[2]] : [],\n },\n })\n } catch (err) {\n /***/\n }\n break\n }\n }\n }\n }\n\n return references\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { decode, type AddressPointer, type ProfilePointer, type EventPointer } from './nip19.ts'\n\nimport type { Event } from './core.ts'\n\ntype Reference = {\n text: string\n profile?: ProfilePointer\n event?: EventPointer\n address?: AddressPointer\n}\n\nconst mentionRegex = /\\bnostr:((note|npub|naddr|nevent|nprofile)1\\w+)\\b|#\\[(\\d+)\\]/g\n\nexport function parseReferences(evt: Event): Reference[] {\n let references: Reference[] = []\n for (let ref of evt.content.matchAll(mentionRegex)) {\n if (ref[2]) {\n // it's a NIP-27 mention\n try {\n let { type, data } = decode(ref[1])\n switch (type) {\n case 'npub': {\n references.push({\n text: ref[0],\n profile: { pubkey: data as string, relays: [] },\n })\n break\n }\n case 'nprofile': {\n references.push({\n text: ref[0],\n profile: data as ProfilePointer,\n })\n break\n }\n case 'note': {\n references.push({\n text: ref[0],\n event: { id: data as string, relays: [] },\n })\n break\n }\n case 'nevent': {\n references.push({\n text: ref[0],\n event: data as EventPointer,\n })\n break\n }\n case 'naddr': {\n references.push({\n text: ref[0],\n address: data as AddressPointer,\n })\n break\n }\n }\n } catch (err) {\n /***/\n }\n } else if (ref[3]) {\n // it's a NIP-10 mention\n let idx = parseInt(ref[3], 10)\n let tag = evt.tags[idx]\n if (!tag) continue\n\n switch (tag[0]) {\n case 'p': {\n references.push({\n text: ref[0],\n profile: { pubkey: tag[1], relays: tag[2] ? [tag[2]] : [] },\n })\n break\n }\n case 'e': {\n references.push({\n text: ref[0],\n event: { id: tag[1], relays: tag[2] ? [tag[2]] : [] },\n })\n break\n }\n case 'a': {\n try {\n let [kind, pubkey, identifier] = tag[1].split(':')\n references.push({\n text: ref[0],\n address: {\n identifier,\n pubkey,\n kind: parseInt(kind, 10),\n relays: tag[2] ? [tag[2]] : [],\n },\n })\n } catch (err) {\n /***/\n }\n break\n }\n }\n }\n }\n\n return references\n}\n", "import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": "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",
"names": ["import_utils"]
} Index: package/lib/esm/references.js.map
===================================================================
--- package/lib/esm/references.js.map
+++ package/lib/esm/references.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../nip19.ts", "../../utils.ts", "../../references.ts"],
- "sourcesContent": ["import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { decode, type AddressPointer, type ProfilePointer, type EventPointer } from './nip19.ts'\n\nimport type { Event } from './core.ts'\n\ntype Reference = {\n text: string\n profile?: ProfilePointer\n event?: EventPointer\n address?: AddressPointer\n}\n\nconst mentionRegex = /\\bnostr:((note|npub|naddr|nevent|nprofile)1\\w+)\\b|#\\[(\\d+)\\]/g\n\nexport function parseReferences(evt: Event): Reference[] {\n let references: Reference[] = []\n for (let ref of evt.content.matchAll(mentionRegex)) {\n if (ref[2]) {\n // it's a NIP-27 mention\n try {\n let { type, data } = decode(ref[1])\n switch (type) {\n case 'npub': {\n references.push({\n text: ref[0],\n profile: { pubkey: data as string, relays: [] },\n })\n break\n }\n case 'nprofile': {\n references.push({\n text: ref[0],\n profile: data as ProfilePointer,\n })\n break\n }\n case 'note': {\n references.push({\n text: ref[0],\n event: { id: data as string, relays: [] },\n })\n break\n }\n case 'nevent': {\n references.push({\n text: ref[0],\n event: data as EventPointer,\n })\n break\n }\n case 'naddr': {\n references.push({\n text: ref[0],\n address: data as AddressPointer,\n })\n break\n }\n }\n } catch (err) {\n /***/\n }\n } else if (ref[3]) {\n // it's a NIP-10 mention\n let idx = parseInt(ref[3], 10)\n let tag = evt.tags[idx]\n if (!tag) continue\n\n switch (tag[0]) {\n case 'p': {\n references.push({\n text: ref[0],\n profile: { pubkey: tag[1], relays: tag[2] ? [tag[2]] : [] },\n })\n break\n }\n case 'e': {\n references.push({\n text: ref[0],\n event: { id: tag[1], relays: tag[2] ? [tag[2]] : [] },\n })\n break\n }\n case 'a': {\n try {\n let [kind, pubkey, identifier] = tag[1].split(':')\n references.push({\n text: ref[0],\n address: {\n identifier,\n pubkey,\n kind: parseInt(kind, 10),\n relays: tag[2] ? [tag[2]] : [],\n },\n })\n } catch (err) {\n /***/\n }\n break\n }\n }\n }\n }\n\n return references\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { bytesToHex, concatBytes, hexToBytes } from '@noble/hashes/utils.js'\nimport { bech32 } from '@scure/base'\n\nimport { utf8Decoder, utf8Encoder } from './utils.ts'\n\nexport type NProfile = `nprofile1${string}`\nexport type NEvent = `nevent1${string}`\nexport type NAddr = `naddr1${string}`\nexport type NSec = `nsec1${string}`\nexport type NPub = `npub1${string}`\nexport type Note = `note1${string}`\nexport type Ncryptsec = `ncryptsec1${string}`\n\nexport const NostrTypeGuard = {\n isNProfile: (value?: string | null): value is NProfile => /^nprofile1[a-z\\d]+$/.test(value || ''),\n isNEvent: (value?: string | null): value is NEvent => /^nevent1[a-z\\d]+$/.test(value || ''),\n isNAddr: (value?: string | null): value is NAddr => /^naddr1[a-z\\d]+$/.test(value || ''),\n isNSec: (value?: string | null): value is NSec => /^nsec1[a-z\\d]{58}$/.test(value || ''),\n isNPub: (value?: string | null): value is NPub => /^npub1[a-z\\d]{58}$/.test(value || ''),\n isNote: (value?: string | null): value is Note => /^note1[a-z\\d]+$/.test(value || ''),\n isNcryptsec: (value?: string | null): value is Ncryptsec => /^ncryptsec1[a-z\\d]+$/.test(value || ''),\n}\n\nexport const Bech32MaxSize = 5000\n\n/**\n * Bech32 regex.\n * @see https://github.com/bitcoin/bips/blob/master/bip-0173.mediawiki#bech32\n */\nexport const BECH32_REGEX = /[\\x21-\\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/\n\nfunction integerToUint8Array(number: number) {\n // Create a Uint8Array with enough space to hold a 32-bit integer (4 bytes).\n const uint8Array = new Uint8Array(4)\n\n // Use bitwise operations to extract the bytes.\n uint8Array[0] = (number >> 24) & 0xff // Most significant byte (MSB)\n uint8Array[1] = (number >> 16) & 0xff\n uint8Array[2] = (number >> 8) & 0xff\n uint8Array[3] = number & 0xff // Least significant byte (LSB)\n\n return uint8Array\n}\n\nexport type ProfilePointer = {\n pubkey: string // hex\n relays?: string[]\n}\n\nexport type EventPointer = {\n id: string // hex\n relays?: string[]\n author?: string\n kind?: number\n}\n\nexport type AddressPointer = {\n identifier: string\n pubkey: string\n kind: number\n relays?: string[]\n}\n\nexport function decodeNostrURI(nip19code: string): ReturnType<typeof decode> | { type: 'invalid'; data: null } {\n try {\n if (nip19code.startsWith('nostr:')) nip19code = nip19code.substring(6)\n return decode(nip19code)\n } catch (_err) {\n return { type: 'invalid', data: null }\n }\n}\n\nexport type DecodedNevent = {\n type: 'nevent'\n data: EventPointer\n}\n\nexport type DecodedNprofile = {\n type: 'nprofile'\n data: ProfilePointer\n}\n\nexport type DecodedNaddr = {\n type: 'naddr'\n data: AddressPointer\n}\n\nexport type DecodedNsec = {\n type: 'nsec'\n data: Uint8Array\n}\n\nexport type DecodedNpub = {\n type: 'npub'\n data: string\n}\n\nexport type DecodedNote = {\n type: 'note'\n data: string\n}\n\nexport type DecodedResult = DecodedNevent | DecodedNprofile | DecodedNaddr | DecodedNpub | DecodedNsec | DecodedNote\n\nexport function decode(nip19: NEvent): DecodedNevent\nexport function decode(nip19: NProfile): DecodedNprofile\nexport function decode(nip19: NAddr): DecodedNaddr\nexport function decode(nip19: NSec): DecodedNsec\nexport function decode(nip19: NPub): DecodedNpub\nexport function decode(nip19: Note): DecodedNote\nexport function decode(code: string): DecodedResult\nexport function decode(code: string): DecodedResult {\n let { prefix, words } = bech32.decode(code as `${string}1${string}`, Bech32MaxSize)\n let data = new Uint8Array(bech32.fromWords(words))\n\n switch (prefix) {\n case 'nprofile': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nprofile')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n\n return {\n type: 'nprofile',\n data: {\n pubkey: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n case 'nevent': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for nevent')\n if (tlv[0][0].length !== 32) throw new Error('TLV 0 should be 32 bytes')\n if (tlv[2] && tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (tlv[3] && tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'nevent',\n data: {\n id: bytesToHex(tlv[0][0]),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : undefined,\n kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : undefined,\n },\n }\n }\n\n case 'naddr': {\n let tlv = parseTLV(data)\n if (!tlv[0]?.[0]) throw new Error('missing TLV 0 for naddr')\n if (!tlv[2]?.[0]) throw new Error('missing TLV 2 for naddr')\n if (tlv[2][0].length !== 32) throw new Error('TLV 2 should be 32 bytes')\n if (!tlv[3]?.[0]) throw new Error('missing TLV 3 for naddr')\n if (tlv[3][0].length !== 4) throw new Error('TLV 3 should be 4 bytes')\n\n return {\n type: 'naddr',\n data: {\n identifier: utf8Decoder.decode(tlv[0][0]),\n pubkey: bytesToHex(tlv[2][0]),\n kind: parseInt(bytesToHex(tlv[3][0]), 16),\n relays: tlv[1] ? tlv[1].map(d => utf8Decoder.decode(d)) : [],\n },\n }\n }\n\n case 'nsec':\n return { type: prefix, data }\n\n case 'npub':\n case 'note':\n return { type: prefix, data: bytesToHex(data) }\n\n default:\n throw new Error(`unknown prefix ${prefix}`)\n }\n}\n\ntype TLV = { [t: number]: Uint8Array[] }\n\nfunction parseTLV(data: Uint8Array): TLV {\n let result: TLV = {}\n let rest = data\n while (rest.length > 0) {\n let t = rest[0]\n let l = rest[1]\n let v = rest.slice(2, 2 + l)\n rest = rest.slice(2 + l)\n if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)\n result[t] = result[t] || []\n result[t].push(v)\n }\n return result\n}\n\nexport function nsecEncode(key: Uint8Array): NSec {\n return encodeBytes('nsec', key)\n}\n\nexport function npubEncode(hex: string): NPub {\n return encodeBytes('npub', hexToBytes(hex))\n}\n\nexport function noteEncode(hex: string): Note {\n return encodeBytes('note', hexToBytes(hex))\n}\n\nfunction encodeBech32<Prefix extends string>(prefix: Prefix, data: Uint8Array): `${Prefix}1${string}` {\n let words = bech32.toWords(data)\n return bech32.encode(prefix, words, Bech32MaxSize) as `${Prefix}1${string}`\n}\n\nexport function encodeBytes<Prefix extends string>(prefix: Prefix, bytes: Uint8Array): `${Prefix}1${string}` {\n return encodeBech32(prefix, bytes)\n}\n\nexport function nprofileEncode(profile: ProfilePointer): NProfile {\n let data = encodeTLV({\n 0: [hexToBytes(profile.pubkey)],\n 1: (profile.relays || []).map(url => utf8Encoder.encode(url)),\n })\n return encodeBech32('nprofile', data)\n}\n\nexport function neventEncode(event: EventPointer): NEvent {\n let kindArray\n if (event.kind !== undefined) {\n kindArray = integerToUint8Array(event.kind)\n }\n\n let data = encodeTLV({\n 0: [hexToBytes(event.id)],\n 1: (event.relays || []).map(url => utf8Encoder.encode(url)),\n 2: event.author ? [hexToBytes(event.author)] : [],\n 3: kindArray ? [new Uint8Array(kindArray)] : [],\n })\n\n return encodeBech32('nevent', data)\n}\n\nexport function naddrEncode(addr: AddressPointer): NAddr {\n let kind = new ArrayBuffer(4)\n new DataView(kind).setUint32(0, addr.kind, false)\n\n let data = encodeTLV({\n 0: [utf8Encoder.encode(addr.identifier)],\n 1: (addr.relays || []).map(url => utf8Encoder.encode(url)),\n 2: [hexToBytes(addr.pubkey)],\n 3: [new Uint8Array(kind)],\n })\n return encodeBech32('naddr', data)\n}\n\nfunction encodeTLV(tlv: TLV): Uint8Array {\n let entries: Uint8Array[] = []\n\n Object.entries(tlv)\n .reverse()\n .forEach(([t, vs]) => {\n vs.forEach(v => {\n let entry = new Uint8Array(v.length + 2)\n entry.set([parseInt(t)], 0)\n entry.set([v.length], 1)\n entry.set(v, 2)\n entries.push(entry)\n })\n })\n\n return concatBytes(...entries)\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { decode, type AddressPointer, type ProfilePointer, type EventPointer } from './nip19.ts'\n\nimport type { Event } from './core.ts'\n\ntype Reference = {\n text: string\n profile?: ProfilePointer\n event?: EventPointer\n address?: AddressPointer\n}\n\nconst mentionRegex = /\\bnostr:((note|npub|naddr|nevent|nprofile)1\\w+)\\b|#\\[(\\d+)\\]/g\n\nexport function parseReferences(evt: Event): Reference[] {\n let references: Reference[] = []\n for (let ref of evt.content.matchAll(mentionRegex)) {\n if (ref[2]) {\n // it's a NIP-27 mention\n try {\n let { type, data } = decode(ref[1])\n switch (type) {\n case 'npub': {\n references.push({\n text: ref[0],\n profile: { pubkey: data as string, relays: [] },\n })\n break\n }\n case 'nprofile': {\n references.push({\n text: ref[0],\n profile: data as ProfilePointer,\n })\n break\n }\n case 'note': {\n references.push({\n text: ref[0],\n event: { id: data as string, relays: [] },\n })\n break\n }\n case 'nevent': {\n references.push({\n text: ref[0],\n event: data as EventPointer,\n })\n break\n }\n case 'naddr': {\n references.push({\n text: ref[0],\n address: data as AddressPointer,\n })\n break\n }\n }\n } catch (err) {\n /***/\n }\n } else if (ref[3]) {\n // it's a NIP-10 mention\n let idx = parseInt(ref[3], 10)\n let tag = evt.tags[idx]\n if (!tag) continue\n\n switch (tag[0]) {\n case 'p': {\n references.push({\n text: ref[0],\n profile: { pubkey: tag[1], relays: tag[2] ? [tag[2]] : [] },\n })\n break\n }\n case 'e': {\n references.push({\n text: ref[0],\n event: { id: tag[1], relays: tag[2] ? [tag[2]] : [] },\n })\n break\n }\n case 'a': {\n try {\n let [kind, pubkey, identifier] = tag[1].split(':')\n references.push({\n text: ref[0],\n address: {\n identifier,\n pubkey,\n kind: parseInt(kind, 10),\n relays: tag[2] ? [tag[2]] : [],\n },\n })\n } catch (err) {\n /***/\n }\n break\n }\n }\n }\n }\n\n return references\n}\n"],
+ "mappings": "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",
"names": ["bytesToHex", "hexToBytes", "bytesToHex"]
} Index: package/lib/cjs/relay.js.map
===================================================================
--- package/lib/cjs/relay.js.map
+++ package/lib/cjs/relay.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../relay.ts", "../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts", "../../helpers.ts", "../../abstract-relay.ts"],
- "sourcesContent": ["/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractRelay, type AbstractRelayConstructorOptions } from './abstract-relay.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class Relay extends AbstractRelay {\n constructor(url: string, options?: Pick<AbstractRelayConstructorOptions, 'enablePing' | 'enableReconnect'>) {\n super(url, { verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n\n static async connect(\n url: string,\n options?: Pick<AbstractRelayConstructorOptions, 'enablePing' | 'enableReconnect'>,\n ): Promise<Relay> {\n const relay = new Relay(url, options)\n await relay.connect()\n return relay\n }\n}\n\nexport type RelayRecord = Record<string, { read: boolean; write: boolean }>\n\nexport * from './abstract-relay.ts'\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractRelay, type AbstractRelayConstructorOptions } from './abstract-relay.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class Relay extends AbstractRelay {\n constructor(url: string, options?: Pick<AbstractRelayConstructorOptions, 'enablePing' | 'enableReconnect'>) {\n super(url, { verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n\n static async connect(\n url: string,\n options?: Pick<AbstractRelayConstructorOptions, 'enablePing' | 'enableReconnect'>,\n ): Promise<Relay> {\n const relay = new Relay(url, options)\n await relay.connect()\n return relay\n }\n}\n\nexport type RelayRecord = Record<string, { read: boolean; write: boolean }>\n\nexport * from './abstract-relay.ts'\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n"],
+ "mappings": "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",
"names": ["import_utils", "i", "target", "i"]
} Index: package/lib/esm/relay.js.map
===================================================================
--- package/lib/esm/relay.js.map
+++ package/lib/esm/relay.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../pure.ts", "../../core.ts", "../../utils.ts", "../../kinds.ts", "../../filter.ts", "../../fakejson.ts", "../../nip42.ts", "../../helpers.ts", "../../abstract-relay.ts", "../../relay.ts"],
- "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractRelay, type AbstractRelayConstructorOptions } from './abstract-relay.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class Relay extends AbstractRelay {\n constructor(url: string, options?: Pick<AbstractRelayConstructorOptions, 'enablePing' | 'enableReconnect'>) {\n super(url, { verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n\n static async connect(\n url: string,\n options?: Pick<AbstractRelayConstructorOptions, 'enablePing' | 'enableReconnect'>,\n ): Promise<Relay> {\n const relay = new Relay(url, options)\n await relay.connect()\n return relay\n }\n}\n\nexport type RelayRecord = Record<string, { read: boolean; write: boolean }>\n\nexport * from './abstract-relay.ts'\n"],
- "mappings": "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",
- "names": ["bytesToHex", "i", "target", "bytesToHex", "i"]
+ "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { NostrEvent, validateEvent } from './pure.ts'\n\n/** Events are **regular**, which means they're all expected to be stored by relays. */\nexport function isRegularKind(kind: number): boolean {\n return kind < 10000 && kind !== 0 && kind !== 3\n}\n\n/** Events are **replaceable**, which means that, for each combination of `pubkey` and `kind`, only the latest event is expected to (SHOULD) be stored by relays, older versions are expected to be discarded. */\nexport function isReplaceableKind(kind: number): boolean {\n return kind === 0 || kind === 3 || (10000 <= kind && kind < 20000)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nexport function isEphemeralKind(kind: number): boolean {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **addressable**, which means that, for each combination of `pubkey`, `kind` and the `d` tag, only the latest event is expected to be stored by relays, older versions are expected to be discarded. */\nexport function isAddressableKind(kind: number): boolean {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\nexport type KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nexport function classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isAddressableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport function isKind<T extends number>(event: unknown, kind: T | Array<T>): event is NostrEvent & { kind: T } {\n const kindAsArray: number[] = kind instanceof Array ? kind : [kind]\n return (validateEvent(event) && kindAsArray.includes(event.kind)) || false\n}\n\nexport const Metadata = 0\nexport type Metadata = typeof Metadata\nexport const ShortTextNote = 1\nexport type ShortTextNote = typeof ShortTextNote\nexport const RecommendRelay = 2\nexport type RecommendRelay = typeof RecommendRelay\nexport const Contacts = 3\nexport type Contacts = typeof Contacts\nexport const EncryptedDirectMessage = 4\nexport type EncryptedDirectMessage = typeof EncryptedDirectMessage\nexport const EventDeletion = 5\nexport type EventDeletion = typeof EventDeletion\nexport const Repost = 6\nexport type Repost = typeof Repost\nexport const Reaction = 7\nexport type Reaction = typeof Reaction\nexport const BadgeAward = 8\nexport type BadgeAward = typeof BadgeAward\nexport const ChatMessage = 9\nexport type ChatMessage = typeof ChatMessage\nexport const ForumThread = 11\nexport type ForumThread = typeof ForumThread\nexport const Seal = 13\nexport type Seal = typeof Seal\nexport const PrivateDirectMessage = 14\nexport type PrivateDirectMessage = typeof PrivateDirectMessage\nexport const FileMessage = 15\nexport type FileMessage = typeof FileMessage\nexport const GenericRepost = 16\nexport type GenericRepost = typeof GenericRepost\nexport const Photo = 20\nexport type Photo = typeof Photo\nexport const NormalVideo = 21\nexport type NormalVideo = typeof NormalVideo\nexport const ShortVideo = 22\nexport type ShortVideo = typeof ShortVideo\nexport const ChannelCreation = 40\nexport type ChannelCreation = typeof ChannelCreation\nexport const ChannelMetadata = 41\nexport type ChannelMetadata = typeof ChannelMetadata\nexport const ChannelMessage = 42\nexport type ChannelMessage = typeof ChannelMessage\nexport const ChannelHideMessage = 43\nexport type ChannelHideMessage = typeof ChannelHideMessage\nexport const ChannelMuteUser = 44\nexport type ChannelMuteUser = typeof ChannelMuteUser\nexport const OpenTimestamps = 1040\nexport type OpenTimestamps = typeof OpenTimestamps\nexport const GiftWrap = 1059\nexport type GiftWrap = typeof GiftWrap\nexport const Poll = 1068\nexport type Poll = typeof Poll\nexport const FileMetadata = 1063\nexport type FileMetadata = typeof FileMetadata\nexport const Comment = 1111\nexport type Comment = typeof Comment\nexport const LiveChatMessage = 1311\nexport type LiveChatMessage = typeof LiveChatMessage\nexport const Voice = 1222\nexport type Voice = typeof Voice\nexport const VoiceComment = 1244\nexport type VoiceComment = typeof VoiceComment\nexport const ProblemTracker = 1971\nexport type ProblemTracker = typeof ProblemTracker\nexport const Report = 1984\nexport type Report = typeof Report\nexport const Reporting = 1984\nexport type Reporting = typeof Reporting\nexport const Label = 1985\nexport type Label = typeof Label\nexport const CommunityPostApproval = 4550\nexport type CommunityPostApproval = typeof CommunityPostApproval\nexport const JobRequest = 5999\nexport type JobRequest = typeof JobRequest\nexport const JobResult = 6999\nexport type JobResult = typeof JobResult\nexport const JobFeedback = 7000\nexport type JobFeedback = typeof JobFeedback\nexport const ZapGoal = 9041\nexport type ZapGoal = typeof ZapGoal\nexport const ZapRequest = 9734\nexport type ZapRequest = typeof ZapRequest\nexport const Zap = 9735\nexport type Zap = typeof Zap\nexport const Highlights = 9802\nexport type Highlights = typeof Highlights\nexport const PollResponse = 1018\nexport type PollResponse = typeof PollResponse\nexport const Mutelist = 10000\nexport type Mutelist = typeof Mutelist\nexport const Pinlist = 10001\nexport type Pinlist = typeof Pinlist\nexport const RelayList = 10002\nexport type RelayList = typeof RelayList\nexport const BookmarkList = 10003\nexport type BookmarkList = typeof BookmarkList\nexport const CommunitiesList = 10004\nexport type CommunitiesList = typeof CommunitiesList\nexport const PublicChatsList = 10005\nexport type PublicChatsList = typeof PublicChatsList\nexport const BlockedRelaysList = 10006\nexport type BlockedRelaysList = typeof BlockedRelaysList\nexport const SearchRelaysList = 10007\nexport type SearchRelaysList = typeof SearchRelaysList\nexport const FavoriteRelays = 10012\nexport type FavoriteRelays = typeof FavoriteRelays\nexport const InterestsList = 10015\nexport type InterestsList = typeof InterestsList\nexport const UserEmojiList = 10030\nexport type UserEmojiList = typeof UserEmojiList\nexport const DirectMessageRelaysList = 10050\nexport type DirectMessageRelaysList = typeof DirectMessageRelaysList\nexport const FileServerPreference = 10096\nexport type FileServerPreference = typeof FileServerPreference\nexport const BlossomServerList = 10063\nexport type BlossomServerList = typeof BlossomServerList\nexport const NWCWalletInfo = 13194\nexport type NWCWalletInfo = typeof NWCWalletInfo\nexport const LightningPubRPC = 21000\nexport type LightningPubRPC = typeof LightningPubRPC\nexport const ClientAuth = 22242\nexport type ClientAuth = typeof ClientAuth\nexport const NWCWalletRequest = 23194\nexport type NWCWalletRequest = typeof NWCWalletRequest\nexport const NWCWalletResponse = 23195\nexport type NWCWalletResponse = typeof NWCWalletResponse\nexport const NostrConnect = 24133\nexport type NostrConnect = typeof NostrConnect\nexport const HTTPAuth = 27235\nexport type HTTPAuth = typeof HTTPAuth\nexport const Followsets = 30000\nexport type Followsets = typeof Followsets\nexport const Genericlists = 30001\nexport type Genericlists = typeof Genericlists\nexport const Relaysets = 30002\nexport type Relaysets = typeof Relaysets\nexport const Bookmarksets = 30003\nexport type Bookmarksets = typeof Bookmarksets\nexport const Curationsets = 30004\nexport type Curationsets = typeof Curationsets\nexport const ProfileBadges = 30008\nexport type ProfileBadges = typeof ProfileBadges\nexport const BadgeDefinition = 30009\nexport type BadgeDefinition = typeof BadgeDefinition\nexport const Interestsets = 30015\nexport type Interestsets = typeof Interestsets\nexport const CreateOrUpdateStall = 30017\nexport type CreateOrUpdateStall = typeof CreateOrUpdateStall\nexport const CreateOrUpdateProduct = 30018\nexport type CreateOrUpdateProduct = typeof CreateOrUpdateProduct\nexport const LongFormArticle = 30023\nexport type LongFormArticle = typeof LongFormArticle\nexport const DraftLong = 30024\nexport type DraftLong = typeof DraftLong\nexport const Emojisets = 30030\nexport type Emojisets = typeof Emojisets\nexport const Application = 30078\nexport type Application = typeof Application\nexport const LiveEvent = 30311\nexport type LiveEvent = typeof LiveEvent\nexport const UserStatuses = 30315\nexport type UserStatuses = typeof UserStatuses\nexport const ClassifiedListing = 30402\nexport type ClassifiedListing = typeof ClassifiedListing\nexport const DraftClassifiedListing = 30403\nexport type DraftClassifiedListing = typeof DraftClassifiedListing\nexport const Date = 31922\nexport type Date = typeof Date\nexport const Time = 31923\nexport type Time = typeof Time\nexport const Calendar = 31924\nexport type Calendar = typeof Calendar\nexport const CalendarEventRSVP = 31925\nexport type CalendarEventRSVP = typeof CalendarEventRSVP\nexport const RelayReview = 31987\nexport type RelayReview = typeof RelayReview\nexport const Handlerrecommendation = 31989\nexport type Handlerrecommendation = typeof Handlerrecommendation\nexport const Handlerinformation = 31990\nexport type Handlerinformation = typeof Handlerinformation\nexport const CommunityDefinition = 34550\nexport type CommunityDefinition = typeof CommunityDefinition\nexport const GroupMetadata = 39000\nexport type GroupMetadata = typeof GroupMetadata\n", "import { Event } from './core.ts'\nimport { isAddressableKind, isReplaceableKind } from './kinds.ts'\n\nexport type Filter = {\n ids?: string[]\n kinds?: number[]\n authors?: string[]\n since?: number\n until?: number\n limit?: number\n search?: string\n [key: `#${string}`]: string[] | undefined\n}\n\nexport function matchFilter(filter: Filter, event: Event): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n return false\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {\n return false\n }\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n return false\n }\n\n for (let f in filter) {\n if (f[0] === '#') {\n let tagName = f.slice(1)\n let values = filter[`#${tagName}`]\n if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values!.indexOf(v) !== -1)) return false\n }\n }\n\n if (filter.since && event.created_at < filter.since) return false\n if (filter.until && event.created_at > filter.until) return false\n\n return true\n}\n\nexport function matchFilters(filters: Filter[], event: Event): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) {\n return true\n }\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter[]): Filter {\n let result: Filter = {}\n for (let i = 0; i < filters.length; i++) {\n let filter = filters[i]\n Object.entries(filter).forEach(([property, values]) => {\n if (property === 'kinds' || property === 'ids' || property === 'authors' || property[0] === '#') {\n // @ts-ignore\n result[property] = result[property] || []\n // @ts-ignore\n for (let v = 0; v < values.length; v++) {\n // @ts-ignore\n let value = values[v]\n // @ts-ignore\n if (!result[property].includes(value)) result[property].push(value)\n }\n }\n })\n\n if (filter.limit && (!result.limit || filter.limit > result.limit)) result.limit = filter.limit\n if (filter.until && (!result.until || filter.until > result.until)) result.until = filter.until\n if (filter.since && (!result.since || filter.since < result.since)) result.since = filter.since\n }\n\n return result\n}\n\n/**\n * Calculate the intrinsic limit of a filter.\n * This function returns a positive integer, or `Infinity` if there is no intrinsic limit.\n */\nexport function getFilterLimit(filter: Filter): number {\n if (filter.ids && !filter.ids.length) return 0\n if (filter.kinds && !filter.kinds.length) return 0\n if (filter.authors && !filter.authors.length) return 0\n\n for (const [key, value] of Object.entries(filter)) {\n if (key[0] === '#' && Array.isArray(value) && !value.length) return 0\n }\n\n return Math.min(\n // The `limit` property creates an artificial limit.\n Math.max(0, filter.limit ?? Infinity),\n\n // There can only be one event per `id`.\n filter.ids?.length ?? Infinity,\n\n // Replaceable events are limited by the number of authors and kinds.\n filter.authors?.length && filter.kinds?.every(kind => isReplaceableKind(kind))\n ? filter.authors.length * filter.kinds.length\n : Infinity,\n\n // Parameterized replaceable events are limited by the number of authors, kinds, and \"d\" tags.\n filter.authors?.length && filter.kinds?.every(kind => isAddressableKind(kind)) && filter['#d']?.length\n ? filter.authors.length * filter.kinds.length * filter['#d'].length\n : Infinity,\n )\n}\n", "export function getHex64(json: string, field: string): string {\n let len = field.length + 3\n let idx = json.indexOf(`\"${field}\":`) + len\n let s = json.slice(idx).indexOf(`\"`) + idx + 1\n return json.slice(s, s + 64)\n}\n\nexport function getInt(json: string, field: string): number {\n let len = field.length\n let idx = json.indexOf(`\"${field}\":`) + len + 3\n let sliced = json.slice(idx)\n let end = Math.min(sliced.indexOf(','), sliced.indexOf('}'))\n return parseInt(sliced.slice(0, end), 10)\n}\n\nexport function getSubscriptionId(json: string): string | null {\n let idx = json.slice(0, 22).indexOf(`\"EVENT\"`)\n if (idx === -1) return null\n\n let pstart = json.slice(idx + 7 + 1).indexOf(`\"`)\n if (pstart === -1) return null\n let start = idx + 7 + 1 + pstart\n\n let pend = json.slice(start + 1, 80).indexOf(`\"`)\n if (pend === -1) return null\n let end = start + 1 + pend\n\n return json.slice(start + 1, end)\n}\n\nexport function matchEventId(json: string, id: string): boolean {\n return id === getHex64(json, 'id')\n}\n\nexport function matchEventPubkey(json: string, pubkey: string): boolean {\n return pubkey === getHex64(json, 'pubkey')\n}\n\nexport function matchEventKind(json: string, kind: number): boolean {\n return kind === getInt(json, 'kind')\n}\n", "import { EventTemplate } from './core.ts'\nimport { ClientAuth } from './kinds.ts'\n\n/**\n * creates an EventTemplate for an AUTH event to be signed.\n */\nexport function makeAuthEvent(relayURL: string, challenge: string): EventTemplate {\n return {\n kind: ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relayURL],\n ['challenge', challenge],\n ],\n content: '',\n }\n}\n", "import { verifiedSymbol, type Event, type Nostr, VerifiedEvent } from './core.ts'\n\nexport async function yieldThread() {\n return new Promise<void>((resolve, reject) => {\n try {\n // Check if MessageChannel is available\n if (typeof MessageChannel !== 'undefined') {\n const ch = new MessageChannel()\n const handler = () => {\n // @ts-ignore (typescript thinks this property should be called `removeListener`, but in fact it's `removeEventListener`)\n ch.port1.removeEventListener('message', handler)\n resolve()\n }\n // @ts-ignore (typescript thinks this property should be called `addListener`, but in fact it's `addEventListener`)\n ch.port1.addEventListener('message', handler)\n ch.port2.postMessage(0)\n ch.port1.start()\n } else {\n if (typeof setImmediate !== 'undefined') {\n setImmediate(resolve)\n } else if (typeof setTimeout !== 'undefined') {\n setTimeout(resolve, 0)\n } else {\n // Last resort - resolve immediately\n resolve()\n }\n }\n } catch (e) {\n console.error('during yield: ', e)\n reject(e)\n }\n })\n}\n\nexport const alwaysTrue: Nostr['verifyEvent'] = (t: Event): t is VerifiedEvent => {\n t[verifiedSymbol] = true\n return true\n}\n", "/* global WebSocket */\n\nimport type { Event, EventTemplate, VerifiedEvent, Nostr, NostrEvent } from './core.ts'\nimport { matchFilters, type Filter } from './filter.ts'\nimport { getHex64, getSubscriptionId } from './fakejson.ts'\nimport { Queue, normalizeURL } from './utils.ts'\nimport { makeAuthEvent } from './nip42.ts'\nimport { yieldThread } from './helpers.ts'\n\ntype RelayWebSocket = WebSocket & {\n ping?(): void\n on?(event: 'pong', listener: () => void): any\n}\n\nexport type AbstractRelayConstructorOptions = {\n verifyEvent: Nostr['verifyEvent']\n websocketImplementation?: typeof WebSocket\n enablePing?: boolean\n enableReconnect?: boolean\n}\n\nexport class SendingOnClosedConnection extends Error {\n constructor(message: string, relay: string) {\n super(`Tried to send message '${message} on a closed connection to ${relay}.`)\n this.name = 'SendingOnClosedConnection'\n }\n}\n\nexport class AbstractRelay {\n public readonly url: string\n private _connected: boolean = false\n\n public onclose: (() => void) | null = null\n public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)\n public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)\n\n public baseEoseTimeout: number = 4400\n public publishTimeout: number = 4400\n public pingFrequency: number = 29000\n public pingTimeout: number = 20000\n public resubscribeBackoff: number[] = [10000, 10000, 10000, 20000, 20000, 30000, 60000]\n public openSubs: Map<string, Subscription> = new Map()\n public enablePing: boolean | undefined\n public enableReconnect: boolean\n private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n private pingIntervalHandle: ReturnType<typeof setInterval> | undefined\n private reconnectAttempts: number = 0\n private closedIntentionally: boolean = false\n\n private connectionPromise: Promise<void> | undefined\n private openCountRequests = new Map<string, CountResolver>()\n private openEventPublishes = new Map<string, EventPublishResolver>()\n private ws: RelayWebSocket | undefined\n private incomingMessageQueue = new Queue<string>()\n private queueRunning = false\n private challenge: string | undefined\n private authPromise: Promise<string> | undefined\n private serial: number = 0\n private verifyEvent: Nostr['verifyEvent']\n\n private _WebSocket: typeof WebSocket\n\n constructor(url: string, opts: AbstractRelayConstructorOptions) {\n this.url = normalizeURL(url)\n this.verifyEvent = opts.verifyEvent\n this._WebSocket = opts.websocketImplementation || WebSocket\n this.enablePing = opts.enablePing\n this.enableReconnect = opts.enableReconnect || false\n }\n\n static async connect(\n url: string,\n opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],\n ): Promise<AbstractRelay> {\n const relay = new AbstractRelay(url, opts)\n await relay.connect(opts)\n return relay\n }\n\n private closeAllSubscriptions(reason: string) {\n for (let [_, sub] of this.openSubs) {\n sub.close(reason)\n }\n this.openSubs.clear()\n\n for (let [_, ep] of this.openEventPublishes) {\n ep.reject(new Error(reason))\n }\n this.openEventPublishes.clear()\n\n for (let [_, cr] of this.openCountRequests) {\n cr.reject(new Error(reason))\n }\n this.openCountRequests.clear()\n }\n\n public get connected(): boolean {\n return this._connected\n }\n\n private async reconnect(): Promise<void> {\n const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)]\n this.reconnectAttempts++\n\n this.reconnectTimeoutHandle = setTimeout(async () => {\n try {\n await this.connect()\n } catch (err) {\n // this will be called again through onclose/onerror\n }\n }, backoff)\n }\n\n private handleHardClose(reason: string) {\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n\n this._connected = false\n this.connectionPromise = undefined\n\n const wasIntentional = this.closedIntentionally\n this.closedIntentionally = false // reset for next time\n\n this.onclose?.()\n\n if (this.enableReconnect && !wasIntentional) {\n this.reconnect()\n } else {\n this.closeAllSubscriptions(reason)\n }\n }\n\n public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {\n let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n if (this.connectionPromise) return this.connectionPromise\n\n this.challenge = undefined\n this.authPromise = undefined\n this.connectionPromise = new Promise((resolve, reject) => {\n if (opts?.timeout) {\n connectionTimeoutHandle = setTimeout(() => {\n reject('connection timed out')\n this.connectionPromise = undefined\n this.onclose?.()\n this.closeAllSubscriptions('relay connection timed out')\n }, opts.timeout)\n }\n\n if (opts?.abort) {\n opts.abort.onabort = reject\n }\n\n try {\n this.ws = new this._WebSocket(this.url)\n } catch (err) {\n clearTimeout(connectionTimeoutHandle)\n reject(err)\n return\n }\n\n this.ws.onopen = () => {\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n clearTimeout(connectionTimeoutHandle)\n this._connected = true\n\n const isReconnection = this.reconnectAttempts > 0\n this.reconnectAttempts = 0\n\n // resubscribe to all open subscriptions\n for (const sub of this.openSubs.values()) {\n sub.eosed = false\n if (isReconnection) {\n for (let f = 0; f < sub.filters.length; f++) {\n if (sub.lastEmitted) {\n sub.filters[f].since = sub.lastEmitted + 1\n }\n }\n }\n sub.fire()\n }\n\n if (this.enablePing) {\n this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency)\n }\n resolve()\n }\n\n this.ws.onerror = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket error')\n this.handleHardClose('relay connection errored')\n }\n\n this.ws.onclose = ev => {\n clearTimeout(connectionTimeoutHandle)\n reject((ev as any).message || 'websocket closed')\n this.handleHardClose('relay connection closed')\n }\n\n this.ws.onmessage = this._onmessage.bind(this)\n })\n\n return this.connectionPromise\n }\n\n private waitForPingPong() {\n return new Promise(resolve => {\n // listen for pong\n ;(this.ws as any).once('pong', () => resolve(true))\n // send a ping\n this.ws!.ping!()\n })\n }\n\n private waitForDummyReq() {\n return new Promise((resolve, reject) => {\n if (!this.connectionPromise) return reject(new Error(`no connection to ${this.url}, can't ping`))\n\n // make a dummy request with expected empty eose reply\n // [\"REQ\", \"_\", {\"ids\":[\"aaaa...aaaa\"], \"limit\": 0}]\n try {\n const sub = this.subscribe(\n [{ ids: ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'], limit: 0 }],\n {\n label: 'forced-ping',\n oneose: () => {\n resolve(true)\n sub.close()\n },\n onclose() {\n // if we get a CLOSED it's because the relay is alive\n resolve(true)\n },\n eoseTimeout: this.pingTimeout + 1000,\n },\n )\n } catch (err) {\n reject(err)\n }\n })\n }\n\n // nodejs requires this magic here to ensure connections are closed when internet goes off and stuff\n // in browsers it's done automatically. see https://github.com/nbd-wtf/nostr-tools/issues/491\n private async pingpong() {\n // if the websocket is connected\n if (this.ws?.readyState === 1) {\n // wait for either a ping-pong reply or a timeout\n const result = await Promise.any([\n // browsers don't have ping so use a dummy req\n this.ws && this.ws.ping && (this.ws as any).once ? this.waitForPingPong() : this.waitForDummyReq(),\n new Promise(res => setTimeout(() => res(false), this.pingTimeout)),\n ])\n\n if (!result) {\n // pingpong closing socket\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n }\n }\n\n private async runQueue() {\n this.queueRunning = true\n while (true) {\n if (false === this.handleNext()) {\n break\n }\n await yieldThread()\n }\n this.queueRunning = false\n }\n\n private handleNext(): undefined | false {\n const json = this.incomingMessageQueue.dequeue()\n if (!json) {\n return false\n }\n\n // shortcut EVENT sub\n const subid = getSubscriptionId(json)\n if (subid) {\n const so = this.openSubs.get(subid as string)\n if (!so) {\n // this is an EVENT message, but for a subscription we don't have, so just stop here\n return\n }\n\n // this will be called only when this message is a EVENT message for a subscription we have\n // we do this before parsing the JSON to not have to do that for duplicate events\n // since JSON parsing is slow\n const id = getHex64(json, 'id')\n const alreadyHave = so.alreadyHaveEvent?.(id)\n\n // notify any interested client that the relay has this event\n // (do this after alreadyHaveEvent() because the client may rely on this to answer that)\n so.receivedEvent?.(this, id)\n\n if (alreadyHave) {\n // if we had already seen this event we can just stop here\n return\n }\n }\n\n try {\n let data = JSON.parse(json)\n // we won't do any checks against the data since all failures (i.e. invalid messages from relays)\n // will naturally be caught by the encompassing try..catch block\n\n switch (data[0]) {\n case 'EVENT': {\n const so = this.openSubs.get(data[1] as string) as Subscription\n const event = data[2] as NostrEvent\n if (this.verifyEvent(event) && matchFilters(so.filters, event)) {\n so.onevent(event)\n }\n if (!so.lastEmitted || so.lastEmitted < event.created_at) so.lastEmitted = event.created_at\n return\n }\n case 'COUNT': {\n const id: string = data[1]\n const payload = data[2] as { count: number }\n const cr = this.openCountRequests.get(id) as CountResolver\n if (cr) {\n cr.resolve(payload.count)\n this.openCountRequests.delete(id)\n }\n return\n }\n case 'EOSE': {\n const so = this.openSubs.get(data[1] as string)\n if (!so) return\n so.receivedEose()\n return\n }\n case 'OK': {\n const id: string = data[1]\n const ok: boolean = data[2]\n const reason: string = data[3]\n const ep = this.openEventPublishes.get(id) as EventPublishResolver\n if (ep) {\n clearTimeout(ep.timeout)\n if (ok) ep.resolve(reason)\n else ep.reject(new Error(reason))\n this.openEventPublishes.delete(id)\n }\n return\n }\n case 'CLOSED': {\n const id: string = data[1]\n const so = this.openSubs.get(id)\n if (!so) return\n so.closed = true\n so.close(data[2] as string)\n return\n }\n case 'NOTICE': {\n this.onnotice(data[1] as string)\n return\n }\n case 'AUTH': {\n this.challenge = data[1] as string\n if (this.onauth) {\n this.auth(this.onauth)\n }\n return\n }\n default: {\n const so = this.openSubs.get(data[1])\n so?.oncustom?.(data)\n return\n }\n }\n } catch (err) {\n return\n }\n }\n\n public async send(message: string) {\n if (!this.connectionPromise) throw new SendingOnClosedConnection(message, this.url)\n\n this.connectionPromise.then(() => {\n this.ws?.send(message)\n })\n }\n\n public async auth(signAuthEvent: (evt: EventTemplate) => Promise<VerifiedEvent>): Promise<string> {\n const challenge = this.challenge\n if (!challenge) throw new Error(\"can't perform auth, no challenge was received\")\n if (this.authPromise) return this.authPromise\n\n this.authPromise = new Promise<string>(async (resolve, reject) => {\n try {\n let evt = await signAuthEvent(makeAuthEvent(this.url, challenge))\n let timeout = setTimeout(() => {\n let ep = this.openEventPublishes.get(evt.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('auth timed out'))\n this.openEventPublishes.delete(evt.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(evt.id, { resolve, reject, timeout })\n this.send('[\"AUTH\",' + JSON.stringify(evt) + ']')\n } catch (err) {\n console.warn('subscribe auth function failed:', err)\n }\n })\n return this.authPromise\n }\n\n public async publish(event: Event): Promise<string> {\n const ret = new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n const ep = this.openEventPublishes.get(event.id) as EventPublishResolver\n if (ep) {\n ep.reject(new Error('publish timed out'))\n this.openEventPublishes.delete(event.id)\n }\n }, this.publishTimeout)\n this.openEventPublishes.set(event.id, { resolve, reject, timeout })\n })\n this.send('[\"EVENT\",' + JSON.stringify(event) + ']')\n return ret\n }\n\n public async count(filters: Filter[], params: { id?: string | null }): Promise<number> {\n this.serial++\n const id = params?.id || 'count:' + this.serial\n const ret = new Promise<number>((resolve, reject) => {\n this.openCountRequests.set(id, { resolve, reject })\n })\n this.send('[\"COUNT\",\"' + id + '\",' + JSON.stringify(filters).substring(1))\n return ret\n }\n\n public subscribe(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n const sub = this.prepareSubscription(filters, params)\n sub.fire()\n\n if (params.abort) {\n params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))\n }\n\n return sub\n }\n\n public prepareSubscription(\n filters: Filter[],\n params: Partial<SubscriptionParams> & { label?: string; id?: string },\n ): Subscription {\n this.serial++\n const id = params.id || (params.label ? params.label + ':' : 'sub:') + this.serial\n const subscription = new Subscription(this, id, filters, params)\n this.openSubs.set(id, subscription)\n return subscription\n }\n\n public close() {\n this.closedIntentionally = true\n if (this.reconnectTimeoutHandle) {\n clearTimeout(this.reconnectTimeoutHandle)\n this.reconnectTimeoutHandle = undefined\n }\n if (this.pingIntervalHandle) {\n clearInterval(this.pingIntervalHandle)\n this.pingIntervalHandle = undefined\n }\n this.closeAllSubscriptions('relay connection closed by us')\n this._connected = false\n this.onclose?.()\n if (this.ws?.readyState === this._WebSocket.OPEN) {\n this.ws?.close()\n }\n }\n\n // this is the function assigned to this.ws.onmessage\n // it's exposed for testing and debugging purposes\n public _onmessage(ev: MessageEvent<any>) {\n this.incomingMessageQueue.enqueue(ev.data as string)\n if (!this.queueRunning) {\n this.runQueue()\n }\n }\n}\n\nexport class Subscription {\n public readonly relay: AbstractRelay\n public readonly id: string\n\n public lastEmitted: number | undefined\n public closed: boolean = false\n public eosed: boolean = false\n public filters: Filter[]\n public alreadyHaveEvent: ((id: string) => boolean) | undefined\n public receivedEvent: ((relay: AbstractRelay, id: string) => void) | undefined\n\n public onevent: (evt: Event) => void\n public oneose: (() => void) | undefined\n public onclose: ((reason: string) => void) | undefined\n\n // will get any messages that have this subscription id as their second item and are not default standard\n public oncustom: ((msg: string[]) => void) | undefined\n\n public eoseTimeout: number\n private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined\n\n constructor(relay: AbstractRelay, id: string, filters: Filter[], params: SubscriptionParams) {\n if (filters.length === 0) throw new Error(\"subscription can't be created with zero filters\")\n\n this.relay = relay\n this.filters = filters\n this.id = id\n this.alreadyHaveEvent = params.alreadyHaveEvent\n this.receivedEvent = params.receivedEvent\n this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout\n\n this.oneose = params.oneose\n this.onclose = params.onclose\n this.onevent =\n params.onevent ||\n (event => {\n console.warn(\n `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,\n event,\n )\n })\n }\n\n public fire() {\n this.relay.send('[\"REQ\",\"' + this.id + '\",' + JSON.stringify(this.filters).substring(1))\n\n // only now we start counting the eoseTimeout\n this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout)\n }\n\n public receivedEose() {\n if (this.eosed) return\n clearTimeout(this.eoseTimeoutHandle)\n this.eosed = true\n this.oneose?.()\n }\n\n public close(reason: string = 'closed by caller') {\n if (!this.closed && this.relay.connected) {\n // if the connection was closed by the user calling .close() we will send a CLOSE message\n // otherwise this._open will be already set to false so we will skip this\n try {\n this.relay.send('[\"CLOSE\",' + JSON.stringify(this.id) + ']')\n } catch (err) {\n if (err instanceof SendingOnClosedConnection) {\n /* doesn't matter, it's ok */\n } else {\n throw err\n }\n }\n this.closed = true\n }\n this.relay.openSubs.delete(this.id)\n this.onclose?.(reason)\n }\n}\n\nexport type SubscriptionParams = {\n onevent?: (evt: Event) => void\n oneose?: () => void\n onclose?: (reason: string) => void\n alreadyHaveEvent?: (id: string) => boolean\n receivedEvent?: (relay: AbstractRelay, id: string) => void\n eoseTimeout?: number\n abort?: AbortSignal\n}\n\nexport type CountResolver = {\n resolve: (count: number) => void\n reject: (err: Error) => void\n}\n\nexport type EventPublishResolver = {\n resolve: (reason: string) => void\n reject: (err: Error) => void\n timeout: ReturnType<typeof setTimeout>\n}\n", "/* global WebSocket */\n\nimport { verifyEvent } from './pure.ts'\nimport { AbstractRelay, type AbstractRelayConstructorOptions } from './abstract-relay.ts'\n\nvar _WebSocket: typeof WebSocket\n\ntry {\n _WebSocket = WebSocket\n} catch {}\n\nexport function useWebSocketImplementation(websocketImplementation: any) {\n _WebSocket = websocketImplementation\n}\n\nexport class Relay extends AbstractRelay {\n constructor(url: string, options?: Pick<AbstractRelayConstructorOptions, 'enablePing' | 'enableReconnect'>) {\n super(url, { verifyEvent, websocketImplementation: _WebSocket, ...options })\n }\n\n static async connect(\n url: string,\n options?: Pick<AbstractRelayConstructorOptions, 'enablePing' | 'enableReconnect'>,\n ): Promise<Relay> {\n const relay = new Relay(url, options)\n await relay.connect()\n return relay\n }\n}\n\nexport type RelayRecord = Record<string, { read: boolean; write: boolean }>\n\nexport * from './abstract-relay.ts'\n"],
+ "mappings": "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",
+ "names": ["bytesToHex", "hexToBytes", "i", "target", "bytesToHex", "hexToBytes", "i"]
} Index: package/lib/cjs/signer.js.map
===================================================================
--- package/lib/cjs/signer.js.map
+++ package/lib/cjs/signer.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../signer.ts", "../../pure.ts", "../../core.ts", "../../utils.ts"],
- "sourcesContent": ["import { EventTemplate, VerifiedEvent } from './core.ts'\nimport { finalizeEvent, getPublicKey } from './pure.ts'\n\nexport interface Signer {\n getPublicKey(): Promise<string>\n signEvent(event: EventTemplate): Promise<VerifiedEvent>\n}\n\nexport class PlainKeySigner implements Signer {\n private secretKey: Uint8Array\n\n constructor(secretKey: Uint8Array) {\n this.secretKey = secretKey\n }\n\n async getPublicKey(): Promise<string> {\n return getPublicKey(this.secretKey)\n }\n\n async signEvent(event: EventTemplate): Promise<VerifiedEvent> {\n return finalizeEvent(event, this.secretKey)\n }\n}\n", "import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
- "mappings": "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",
+ "sourcesContent": ["import { EventTemplate, VerifiedEvent } from './core.ts'\nimport { finalizeEvent, getPublicKey } from './pure.ts'\n\nexport interface Signer {\n getPublicKey(): Promise<string>\n signEvent(event: EventTemplate): Promise<VerifiedEvent>\n}\n\nexport class PlainKeySigner implements Signer {\n private secretKey: Uint8Array\n\n constructor(secretKey: Uint8Array) {\n this.secretKey = secretKey\n }\n\n async getPublicKey(): Promise<string> {\n return getPublicKey(this.secretKey)\n }\n\n async signEvent(event: EventTemplate): Promise<VerifiedEvent> {\n return finalizeEvent(event, this.secretKey)\n }\n}\n", "import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "mappings": "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",
"names": ["import_utils", "i"]
} Index: package/lib/esm/signer.js.map
===================================================================
--- package/lib/esm/signer.js.map
+++ package/lib/esm/signer.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../pure.ts", "../../core.ts", "../../utils.ts", "../../signer.ts"],
- "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha256'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomPrivateKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(getEventHash(event), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(event.sig, hash, event.pubkey)\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { EventTemplate, VerifiedEvent } from './core.ts'\nimport { finalizeEvent, getPublicKey } from './pure.ts'\n\nexport interface Signer {\n getPublicKey(): Promise<string>\n signEvent(event: EventTemplate): Promise<VerifiedEvent>\n}\n\nexport class PlainKeySigner implements Signer {\n private secretKey: Uint8Array\n\n constructor(secretKey: Uint8Array) {\n this.secretKey = secretKey\n }\n\n async getPublicKey(): Promise<string> {\n return getPublicKey(this.secretKey)\n }\n\n async signEvent(event: EventTemplate): Promise<VerifiedEvent> {\n return finalizeEvent(event, this.secretKey)\n }\n}\n"],
- "mappings": ";AAAA,SAAS,eAAe;AACxB,SAAS,cAAAA,mBAAkB;;;ACOpB,IAAM,iBAAiB,OAAO,UAAU;AAsB/C,IAAM,WAAW,CAAC,QAAiD,eAAe;AAE3E,SAAS,cAAiB,OAAsC;AACrE,MAAI,CAAC,SAAS,KAAK;AAAG,WAAO;AAC7B,MAAI,OAAO,MAAM,SAAS;AAAU,WAAO;AAC3C,MAAI,OAAO,MAAM,YAAY;AAAU,WAAO;AAC9C,MAAI,OAAO,MAAM,eAAe;AAAU,WAAO;AACjD,MAAI,OAAO,MAAM,WAAW;AAAU,WAAO;AAC7C,MAAI,CAAC,MAAM,OAAO,MAAM,gBAAgB;AAAG,WAAO;AAElD,MAAI,CAAC,MAAM,QAAQ,MAAM,IAAI;AAAG,WAAO;AACvC,WAASC,KAAI,GAAGA,KAAI,MAAM,KAAK,QAAQA,MAAK;AAC1C,QAAI,MAAM,MAAM,KAAKA;AACrB,QAAI,CAAC,MAAM,QAAQ,GAAG;AAAG,aAAO;AAChC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAI,OAAO,IAAI,OAAO;AAAU,eAAO;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AACT;;;AD/CA,SAAS,cAAc;;;AEEvB,SAAS,YAAY,kBAAkB;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;AFIxD,IAAM,KAAN,MAA0B;AAAA,EACxB,oBAAgC;AAC9B,WAAO,QAAQ,MAAM,iBAAiB;AAAA,EACxC;AAAA,EACA,aAAa,WAA+B;AAC1C,WAAOC,YAAW,QAAQ,aAAa,SAAS,CAAC;AAAA,EACnD;AAAA,EACA,cAAc,GAAkB,WAAsC;AACpE,UAAM,QAAQ;AACd,UAAM,SAASA,YAAW,QAAQ,aAAa,SAAS,CAAC;AACzD,UAAM,KAAK,aAAa,KAAK;AAC7B,UAAM,MAAMA,YAAW,QAAQ,KAAK,aAAa,KAAK,GAAG,SAAS,CAAC;AACnE,UAAM,kBAAkB;AACxB,WAAO;AAAA,EACT;AAAA,EACA,YAAY,OAAsC;AAChD,QAAI,OAAO,MAAM,oBAAoB;AAAW,aAAO,MAAM;AAE7D,UAAM,OAAO,aAAa,KAAK;AAC/B,QAAI,SAAS,MAAM,IAAI;AACrB,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,QAAQ,QAAQ,OAAO,MAAM,KAAK,MAAM,MAAM,MAAM;AAC1D,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT,SAAS,KAAP;AACA,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,eAAe,KAA4B;AACzD,MAAI,CAAC,cAAc,GAAG;AAAG,UAAM,IAAI,MAAM,wDAAwD;AACjG,SAAO,KAAK,UAAU,CAAC,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,CAAC;AACxF;AAEO,SAAS,aAAa,OAA8B;AACzD,MAAI,YAAY,OAAO,YAAY,OAAO,eAAe,KAAK,CAAC,CAAC;AAChE,SAAOA,YAAW,SAAS;AAC7B;AAEA,IAAM,IAAQ,IAAI,GAAG;AAEd,IAAM,oBAAoB,EAAE;AAC5B,IAAM,eAAe,EAAE;AACvB,IAAM,gBAAgB,EAAE;AACxB,IAAM,cAAc,EAAE;;;AGjDtB,IAAM,iBAAN,MAAuC;AAAA,EACpC;AAAA,EAER,YAAY,WAAuB;AACjC,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,eAAgC;AACpC,WAAO,aAAa,KAAK,SAAS;AAAA,EACpC;AAAA,EAEA,MAAM,UAAU,OAA8C;AAC5D,WAAO,cAAc,OAAO,KAAK,SAAS;AAAA,EAC5C;AACF;",
- "names": ["bytesToHex", "i", "bytesToHex"]
+ "sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1.js'\nimport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\nimport { Nostr, Event, EventTemplate, UnsignedEvent, VerifiedEvent, verifiedSymbol, validateEvent } from './core.ts'\nimport { sha256 } from '@noble/hashes/sha2.js'\n\nimport { utf8Encoder } from './utils.ts'\n\nclass JS implements Nostr {\n generateSecretKey(): Uint8Array {\n return schnorr.utils.randomSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(schnorr.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n const event = t as VerifiedEvent\n event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey))\n event.id = getEventHash(event)\n event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey))\n event[verifiedSymbol] = true\n return event\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n if (typeof event[verifiedSymbol] === 'boolean') return event[verifiedSymbol]\n\n const hash = getEventHash(event)\n if (hash !== event.id) {\n event[verifiedSymbol] = false\n return false\n }\n\n try {\n const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey))\n event[verifiedSymbol] = valid\n return valid\n } catch (err) {\n event[verifiedSymbol] = false\n return false\n }\n }\n}\n\nexport function serializeEvent(evt: UnsignedEvent): string {\n if (!validateEvent(evt)) throw new Error(\"can't serialize event with wrong or missing properties\")\n return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content])\n}\n\nexport function getEventHash(event: UnsignedEvent): string {\n let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)))\n return bytesToHex(eventHash)\n}\n\nconst i: JS = new JS()\n\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n", "import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n", "import { EventTemplate, VerifiedEvent } from './core.ts'\nimport { finalizeEvent, getPublicKey } from './pure.ts'\n\nexport interface Signer {\n getPublicKey(): Promise<string>\n signEvent(event: EventTemplate): Promise<VerifiedEvent>\n}\n\nexport class PlainKeySigner implements Signer {\n private secretKey: Uint8Array\n\n constructor(secretKey: Uint8Array) {\n this.secretKey = secretKey\n }\n\n async getPublicKey(): Promise<string> {\n return getPublicKey(this.secretKey)\n }\n\n async signEvent(event: EventTemplate): Promise<VerifiedEvent> {\n return finalizeEvent(event, this.secretKey)\n }\n}\n"],
+ "mappings": ";AAAA,SAAS,eAAe;AACxB,SAAS,cAAAA,aAAY,cAAAC,mBAAkB;;;ACOhC,IAAM,iBAAiB,OAAO,UAAU;AAsB/C,IAAM,WAAW,CAAC,QAAiD,eAAe;AAE3E,SAAS,cAAiB,OAAsC;AACrE,MAAI,CAAC,SAAS,KAAK;AAAG,WAAO;AAC7B,MAAI,OAAO,MAAM,SAAS;AAAU,WAAO;AAC3C,MAAI,OAAO,MAAM,YAAY;AAAU,WAAO;AAC9C,MAAI,OAAO,MAAM,eAAe;AAAU,WAAO;AACjD,MAAI,OAAO,MAAM,WAAW;AAAU,WAAO;AAC7C,MAAI,CAAC,MAAM,OAAO,MAAM,gBAAgB;AAAG,WAAO;AAElD,MAAI,CAAC,MAAM,QAAQ,MAAM,IAAI;AAAG,WAAO;AACvC,WAASC,KAAI,GAAGA,KAAI,MAAM,KAAK,QAAQA,MAAK;AAC1C,QAAI,MAAM,MAAM,KAAKA;AACrB,QAAI,CAAC,MAAM,QAAQ,GAAG;AAAG,aAAO;AAChC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAI,OAAO,IAAI,OAAO;AAAU,eAAO;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AACT;;;AD/CA,SAAS,cAAc;;;AEEvB,SAAS,YAAY,kBAAkB;AAHhC,IAAM,cAA2B,IAAI,YAAY,OAAO;AACxD,IAAM,cAA2B,IAAI,YAAY;;;AFIxD,IAAM,KAAN,MAA0B;AAAA,EACxB,oBAAgC;AAC9B,WAAO,QAAQ,MAAM,gBAAgB;AAAA,EACvC;AAAA,EACA,aAAa,WAA+B;AAC1C,WAAOC,YAAW,QAAQ,aAAa,SAAS,CAAC;AAAA,EACnD;AAAA,EACA,cAAc,GAAkB,WAAsC;AACpE,UAAM,QAAQ;AACd,UAAM,SAASA,YAAW,QAAQ,aAAa,SAAS,CAAC;AACzD,UAAM,KAAK,aAAa,KAAK;AAC7B,UAAM,MAAMA,YAAW,QAAQ,KAAKC,YAAW,aAAa,KAAK,CAAC,GAAG,SAAS,CAAC;AAC/E,UAAM,kBAAkB;AACxB,WAAO;AAAA,EACT;AAAA,EACA,YAAY,OAAsC;AAChD,QAAI,OAAO,MAAM,oBAAoB;AAAW,aAAO,MAAM;AAE7D,UAAM,OAAO,aAAa,KAAK;AAC/B,QAAI,SAAS,MAAM,IAAI;AACrB,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,QAAQ,QAAQ,OAAOA,YAAW,MAAM,GAAG,GAAGA,YAAW,IAAI,GAAGA,YAAW,MAAM,MAAM,CAAC;AAC9F,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT,SAAS,KAAP;AACA,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,eAAe,KAA4B;AACzD,MAAI,CAAC,cAAc,GAAG;AAAG,UAAM,IAAI,MAAM,wDAAwD;AACjG,SAAO,KAAK,UAAU,CAAC,GAAG,IAAI,QAAQ,IAAI,YAAY,IAAI,MAAM,IAAI,MAAM,IAAI,OAAO,CAAC;AACxF;AAEO,SAAS,aAAa,OAA8B;AACzD,MAAI,YAAY,OAAO,YAAY,OAAO,eAAe,KAAK,CAAC,CAAC;AAChE,SAAOD,YAAW,SAAS;AAC7B;AAEA,IAAM,IAAQ,IAAI,GAAG;AAEd,IAAM,oBAAoB,EAAE;AAC5B,IAAM,eAAe,EAAE;AACvB,IAAM,gBAAgB,EAAE;AACxB,IAAM,cAAc,EAAE;;;AGjDtB,IAAM,iBAAN,MAAuC;AAAA,EACpC;AAAA,EAER,YAAY,WAAuB;AACjC,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,eAAgC;AACpC,WAAO,aAAa,KAAK,SAAS;AAAA,EACpC;AAAA,EAEA,MAAM,UAAU,OAA8C;AAC5D,WAAO,cAAc,OAAO,KAAK,SAAS;AAAA,EAC5C;AACF;",
+ "names": ["bytesToHex", "hexToBytes", "i", "bytesToHex", "hexToBytes"]
} Index: package/lib/cjs/utils.js.map
===================================================================
--- package/lib/cjs/utils.js.map
+++ package/lib/cjs/utils.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../utils.ts"],
- "sourcesContent": ["import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "sourcesContent": ["import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
"mappings": "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",
"names": ["target"]
} Index: package/lib/esm/utils.js.map
===================================================================
--- package/lib/esm/utils.js.map
+++ package/lib/esm/utils.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../utils.ts"],
- "sourcesContent": ["import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
+ "sourcesContent": ["import type { Event } from './core.ts'\n\nexport const utf8Decoder: TextDecoder = new TextDecoder('utf-8')\nexport const utf8Encoder: TextEncoder = new TextEncoder()\n\nexport { bytesToHex, hexToBytes } from '@noble/hashes/utils.js'\n\nexport function normalizeURL(url: string): string {\n try {\n if (url.indexOf('://') === -1) url = 'wss://' + url\n let p = new URL(url)\n if (p.protocol === 'http:') p.protocol = 'ws:'\n else if (p.protocol === 'https:') p.protocol = 'wss:'\n p.pathname = p.pathname.replace(/\\/+/g, '/')\n if (p.pathname.endsWith('/')) p.pathname = p.pathname.slice(0, -1)\n if ((p.port === '80' && p.protocol === 'ws:') || (p.port === '443' && p.protocol === 'wss:')) p.port = ''\n p.searchParams.sort()\n p.hash = ''\n return p.toString()\n } catch (e) {\n throw new Error(`Invalid URL: ${url}`)\n }\n}\n\nexport function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return b.created_at - event.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[] {\n const [idx, found] = binarySearch(sortedArray, b => {\n if (event.id === b.id) return 0\n if (event.created_at === b.created_at) return -1\n return event.created_at - b.created_at\n })\n if (!found) {\n sortedArray.splice(idx, 0, event)\n }\n return sortedArray\n}\n\nexport function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean] {\n let start = 0\n let end = arr.length - 1\n\n while (start <= end) {\n const mid = Math.floor((start + end) / 2)\n const cmp = compare(arr[mid])\n\n if (cmp === 0) {\n return [mid, true]\n }\n\n if (cmp < 0) {\n end = mid - 1\n } else {\n start = mid + 1\n }\n }\n\n return [start, false]\n}\n\nexport class QueueNode<V> {\n public value: V\n public next: QueueNode<V> | null = null\n public prev: QueueNode<V> | null = null\n\n constructor(message: V) {\n this.value = message\n }\n}\n\nexport class Queue<V> {\n public first: QueueNode<V> | null\n public last: QueueNode<V> | null\n\n constructor() {\n this.first = null\n this.last = null\n }\n\n enqueue(value: V): boolean {\n const newNode = new QueueNode(value)\n if (!this.last) {\n // list is empty\n this.first = newNode\n this.last = newNode\n } else if (this.last === this.first) {\n // list has a single element\n this.last = newNode\n this.last.prev = this.first\n this.first.next = newNode\n } else {\n // list has elements, add as last\n newNode.prev = this.last\n this.last.next = newNode\n this.last = newNode\n }\n return true\n }\n\n dequeue(): V | null {\n if (!this.first) return null\n\n if (this.first === this.last) {\n const target = this.first\n this.first = null\n this.last = null\n return target.value\n }\n\n const target = this.first\n this.first = target.next\n if (this.first) {\n this.first.prev = null // fix: clean up prev pointer\n }\n\n return target.value\n }\n}\n"],
"mappings": "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",
"names": ["target"]
} Index: package/lib/cjs/wasm.js.map
===================================================================
--- package/lib/cjs/wasm.js.map
+++ package/lib/cjs/wasm.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../wasm.ts", "../../core.ts"],
- "sourcesContent": ["import { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr as NostrWasm } from 'nostr-wasm'\nimport { EventTemplate, Event, Nostr, VerifiedEvent, verifiedSymbol } from './core.ts'\n\nlet nw: NostrWasm\n\nexport function setNostrWasm(x: NostrWasm) {\n nw = x\n}\n\nclass Wasm implements Nostr {\n generateSecretKey(): Uint8Array {\n return nw.generateSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(nw.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n nw.finalizeEvent(t as any, secretKey)\n return t as VerifiedEvent\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n try {\n nw.verifyEvent(event)\n event[verifiedSymbol] = true\n return true\n } catch (err) {\n return false\n }\n }\n}\n\nconst i: Wasm = new Wasm()\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n"],
+ "sourcesContent": ["import { bytesToHex } from '@noble/hashes/utils.js'\nimport { Nostr as NostrWasm } from 'nostr-wasm'\nimport { EventTemplate, Event, Nostr, VerifiedEvent, verifiedSymbol } from './core.ts'\n\nlet nw: NostrWasm\n\nexport function setNostrWasm(x: NostrWasm) {\n nw = x\n}\n\nclass Wasm implements Nostr {\n generateSecretKey(): Uint8Array {\n return nw.generateSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(nw.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n nw.finalizeEvent(t as any, secretKey)\n return t as VerifiedEvent\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n try {\n nw.verifyEvent(event)\n event[verifiedSymbol] = true\n return true\n } catch (err) {\n return false\n }\n }\n}\n\nconst i: Wasm = new Wasm()\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n"],
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA2B;;;ACQpB,IAAM,iBAAiB,OAAO,UAAU;AAsB/C,IAAM,WAAW,CAAC,QAAiD,eAAe;AAE3E,SAAS,cAAiB,OAAsC;AACrE,MAAI,CAAC,SAAS,KAAK;AAAG,WAAO;AAC7B,MAAI,OAAO,MAAM,SAAS;AAAU,WAAO;AAC3C,MAAI,OAAO,MAAM,YAAY;AAAU,WAAO;AAC9C,MAAI,OAAO,MAAM,eAAe;AAAU,WAAO;AACjD,MAAI,OAAO,MAAM,WAAW;AAAU,WAAO;AAC7C,MAAI,CAAC,MAAM,OAAO,MAAM,gBAAgB;AAAG,WAAO;AAElD,MAAI,CAAC,MAAM,QAAQ,MAAM,IAAI;AAAG,WAAO;AACvC,WAASA,KAAI,GAAGA,KAAI,MAAM,KAAK,QAAQA,MAAK;AAC1C,QAAI,MAAM,MAAM,KAAKA;AACrB,QAAI,CAAC,MAAM,QAAQ,GAAG;AAAG,aAAO;AAChC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAI,OAAO,IAAI,OAAO;AAAU,eAAO;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AACT;AAOO,SAAS,WAAW,QAA0B;AACnD,SAAO,OAAO,KAAK,CAAC,GAAe,MAA0B;AAC3D,QAAI,EAAE,eAAe,EAAE,YAAY;AACjC,aAAO,EAAE,aAAa,EAAE;AAAA,IAC1B;AACA,WAAO,EAAE,GAAG,cAAc,EAAE,EAAE;AAAA,EAChC,CAAC;AACH;;;AD5DA,IAAI;AAEG,SAAS,aAAa,GAAc;AACzC,OAAK;AACP;AAEA,IAAM,OAAN,MAA4B;AAAA,EAC1B,oBAAgC;AAC9B,WAAO,GAAG,kBAAkB;AAAA,EAC9B;AAAA,EACA,aAAa,WAA+B;AAC1C,eAAO,yBAAW,GAAG,aAAa,SAAS,CAAC;AAAA,EAC9C;AAAA,EACA,cAAc,GAAkB,WAAsC;AACpE,OAAG,cAAc,GAAU,SAAS;AACpC,WAAO;AAAA,EACT;AAAA,EACA,YAAY,OAAsC;AAChD,QAAI;AACF,SAAG,YAAY,KAAK;AACpB,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT,SAAS,KAAP;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,IAAM,IAAU,IAAI,KAAK;AAClB,IAAM,oBAAoB,EAAE;AAC5B,IAAM,eAAe,EAAE;AACvB,IAAM,gBAAgB,EAAE;AACxB,IAAM,cAAc,EAAE;",
"names": ["i"]
} Index: package/lib/esm/wasm.js.map
===================================================================
--- package/lib/esm/wasm.js.map
+++ package/lib/esm/wasm.js.map
@@ -1,7 +1,7 @@
{
"version": 3,
"sources": ["../../wasm.ts", "../../core.ts"],
- "sourcesContent": ["import { bytesToHex } from '@noble/hashes/utils'\nimport { Nostr as NostrWasm } from 'nostr-wasm'\nimport { EventTemplate, Event, Nostr, VerifiedEvent, verifiedSymbol } from './core.ts'\n\nlet nw: NostrWasm\n\nexport function setNostrWasm(x: NostrWasm) {\n nw = x\n}\n\nclass Wasm implements Nostr {\n generateSecretKey(): Uint8Array {\n return nw.generateSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(nw.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n nw.finalizeEvent(t as any, secretKey)\n return t as VerifiedEvent\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n try {\n nw.verifyEvent(event)\n event[verifiedSymbol] = true\n return true\n } catch (err) {\n return false\n }\n }\n}\n\nconst i: Wasm = new Wasm()\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n"],
+ "sourcesContent": ["import { bytesToHex } from '@noble/hashes/utils.js'\nimport { Nostr as NostrWasm } from 'nostr-wasm'\nimport { EventTemplate, Event, Nostr, VerifiedEvent, verifiedSymbol } from './core.ts'\n\nlet nw: NostrWasm\n\nexport function setNostrWasm(x: NostrWasm) {\n nw = x\n}\n\nclass Wasm implements Nostr {\n generateSecretKey(): Uint8Array {\n return nw.generateSecretKey()\n }\n getPublicKey(secretKey: Uint8Array): string {\n return bytesToHex(nw.getPublicKey(secretKey))\n }\n finalizeEvent(t: EventTemplate, secretKey: Uint8Array): VerifiedEvent {\n nw.finalizeEvent(t as any, secretKey)\n return t as VerifiedEvent\n }\n verifyEvent(event: Event): event is VerifiedEvent {\n try {\n nw.verifyEvent(event)\n event[verifiedSymbol] = true\n return true\n } catch (err) {\n return false\n }\n }\n}\n\nconst i: Wasm = new Wasm()\nexport const generateSecretKey = i.generateSecretKey\nexport const getPublicKey = i.getPublicKey\nexport const finalizeEvent = i.finalizeEvent\nexport const verifyEvent = i.verifyEvent\nexport * from './core.ts'\n", "export interface Nostr {\n generateSecretKey(): Uint8Array\n getPublicKey(secretKey: Uint8Array): string\n finalizeEvent(event: EventTemplate, secretKey: Uint8Array): VerifiedEvent\n verifyEvent(event: Event): event is VerifiedEvent\n}\n\n/** Designates a verified event signature. */\nexport const verifiedSymbol = Symbol('verified')\n\nexport type NostrEvent = {\n kind: number\n tags: string[][]\n content: string\n created_at: number\n pubkey: string\n id: string\n sig: string\n [verifiedSymbol]?: boolean\n}\n\nexport type Event = NostrEvent\nexport type EventTemplate = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at'>\nexport type UnsignedEvent = Pick<Event, 'kind' | 'tags' | 'content' | 'created_at' | 'pubkey'>\n\n/** An event whose signature has been verified. */\nexport interface VerifiedEvent extends Event {\n [verifiedSymbol]: true\n}\n\nconst isRecord = (obj: unknown): obj is Record<string, unknown> => obj instanceof Object\n\nexport function validateEvent<T>(event: T): event is T & UnsignedEvent {\n if (!isRecord(event)) return false\n if (typeof event.kind !== 'number') return false\n if (typeof event.content !== 'string') return false\n if (typeof event.created_at !== 'number') return false\n if (typeof event.pubkey !== 'string') return false\n if (!event.pubkey.match(/^[a-f0-9]{64}$/)) return false\n\n if (!Array.isArray(event.tags)) return false\n for (let i = 0; i < event.tags.length; i++) {\n let tag = event.tags[i]\n if (!Array.isArray(tag)) return false\n for (let j = 0; j < tag.length; j++) {\n if (typeof tag[j] !== 'string') return false\n }\n }\n\n return true\n}\n\n/**\n * Sort events in reverse-chronological order by the `created_at` timestamp,\n * and then by the event `id` (lexicographically) in case of ties.\n * This mutates the array.\n */\nexport function sortEvents(events: Event[]): Event[] {\n return events.sort((a: NostrEvent, b: NostrEvent): number => {\n if (a.created_at !== b.created_at) {\n return b.created_at - a.created_at\n }\n return a.id.localeCompare(b.id)\n })\n}\n"],
"mappings": ";AAAA,SAAS,kBAAkB;;;ACQpB,IAAM,iBAAiB,OAAO,UAAU;AAsB/C,IAAM,WAAW,CAAC,QAAiD,eAAe;AAE3E,SAAS,cAAiB,OAAsC;AACrE,MAAI,CAAC,SAAS,KAAK;AAAG,WAAO;AAC7B,MAAI,OAAO,MAAM,SAAS;AAAU,WAAO;AAC3C,MAAI,OAAO,MAAM,YAAY;AAAU,WAAO;AAC9C,MAAI,OAAO,MAAM,eAAe;AAAU,WAAO;AACjD,MAAI,OAAO,MAAM,WAAW;AAAU,WAAO;AAC7C,MAAI,CAAC,MAAM,OAAO,MAAM,gBAAgB;AAAG,WAAO;AAElD,MAAI,CAAC,MAAM,QAAQ,MAAM,IAAI;AAAG,WAAO;AACvC,WAASA,KAAI,GAAGA,KAAI,MAAM,KAAK,QAAQA,MAAK;AAC1C,QAAI,MAAM,MAAM,KAAKA;AACrB,QAAI,CAAC,MAAM,QAAQ,GAAG;AAAG,aAAO;AAChC,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAI,OAAO,IAAI,OAAO;AAAU,eAAO;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AACT;AAOO,SAAS,WAAW,QAA0B;AACnD,SAAO,OAAO,KAAK,CAAC,GAAe,MAA0B;AAC3D,QAAI,EAAE,eAAe,EAAE,YAAY;AACjC,aAAO,EAAE,aAAa,EAAE;AAAA,IAC1B;AACA,WAAO,EAAE,GAAG,cAAc,EAAE,EAAE;AAAA,EAChC,CAAC;AACH;;;AD5DA,IAAI;AAEG,SAAS,aAAa,GAAc;AACzC,OAAK;AACP;AAEA,IAAM,OAAN,MAA4B;AAAA,EAC1B,oBAAgC;AAC9B,WAAO,GAAG,kBAAkB;AAAA,EAC9B;AAAA,EACA,aAAa,WAA+B;AAC1C,WAAO,WAAW,GAAG,aAAa,SAAS,CAAC;AAAA,EAC9C;AAAA,EACA,cAAc,GAAkB,WAAsC;AACpE,OAAG,cAAc,GAAU,SAAS;AACpC,WAAO;AAAA,EACT;AAAA,EACA,YAAY,OAAsC;AAChD,QAAI;AACF,SAAG,YAAY,KAAK;AACpB,YAAM,kBAAkB;AACxB,aAAO;AAAA,IACT,SAAS,KAAP;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAEA,IAAM,IAAU,IAAI,KAAK;AAClB,IAAM,oBAAoB,EAAE;AAC5B,IAAM,eAAe,EAAE;AACvB,IAAM,gBAAgB,EAAE;AACxB,IAAM,cAAc,EAAE;",
"names": ["i"]
} Index: package/lib/types/utils.d.ts
===================================================================
--- package/lib/types/utils.d.ts
+++ package/lib/types/utils.d.ts
@@ -1,8 +1,8 @@
import type { Event } from './core.ts';
export declare const utf8Decoder: TextDecoder;
export declare const utf8Encoder: TextEncoder;
-export { bytesToHex, hexToBytes } from '@noble/hashes/utils';
+export { bytesToHex, hexToBytes } from '@noble/hashes/utils.js';
export declare function normalizeURL(url: string): string;
export declare function insertEventIntoDescendingList(sortedArray: Event[], event: Event): Event[];
export declare function insertEventIntoAscendingList(sortedArray: Event[], event: Event): Event[];
export declare function binarySearch<T>(arr: T[], compare: (b: T) => number): [number, boolean];