remove node_modules and .gitignore them
This commit is contained in:
-24
@@ -1,24 +0,0 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
||||
-314
@@ -1,314 +0,0 @@
|
||||
# nostr-tools
|
||||
|
||||
Tools for developing [Nostr](https://github.com/fiatjaf/nostr) clients.
|
||||
|
||||
Only depends on _@scure_ and _@noble_ packages.
|
||||
|
||||
This package is only providing lower-level functionality. If you want an easy-to-use fully-fledged solution that abstracts the hard parts of Nostr and makes decisions on your behalf, take a look at [NDK](https://github.com/nostr-dev-kit/ndk) and [@snort/system](https://www.npmjs.com/package/@snort/system).
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install nostr-tools # or yarn add nostr-tools
|
||||
```
|
||||
|
||||
If using TypeScript, this package requires TypeScript >= 5.0.
|
||||
|
||||
## Usage
|
||||
|
||||
### Generating a private key and a public key
|
||||
|
||||
```js
|
||||
import { generatePrivateKey, getPublicKey } from 'nostr-tools'
|
||||
|
||||
let sk = generatePrivateKey() // `sk` is a hex string
|
||||
let pk = getPublicKey(sk) // `pk` is a hex string
|
||||
```
|
||||
|
||||
### Creating, signing and verifying events
|
||||
|
||||
```js
|
||||
import { validateEvent, verifySignature, getSignature, getEventHash, getPublicKey } from 'nostr-tools'
|
||||
|
||||
let event = {
|
||||
kind: 1,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
tags: [],
|
||||
content: 'hello',
|
||||
pubkey: getPublicKey(privateKey),
|
||||
}
|
||||
|
||||
event.id = getEventHash(event)
|
||||
event.sig = getSignature(event, privateKey)
|
||||
|
||||
let ok = validateEvent(event)
|
||||
let veryOk = verifySignature(event)
|
||||
```
|
||||
|
||||
### Interacting with a relay
|
||||
|
||||
```js
|
||||
import { relayInit, finishEvent, generatePrivateKey, getPublicKey } from 'nostr-tools'
|
||||
|
||||
const relay = relayInit('wss://relay.example.com')
|
||||
relay.on('connect', () => {
|
||||
console.log(`connected to ${relay.url}`)
|
||||
})
|
||||
relay.on('error', () => {
|
||||
console.log(`failed to connect to ${relay.url}`)
|
||||
})
|
||||
|
||||
await relay.connect()
|
||||
|
||||
// let's query for an event that exists
|
||||
let sub = relay.sub([
|
||||
{
|
||||
ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'],
|
||||
},
|
||||
])
|
||||
sub.on('event', event => {
|
||||
console.log('we got the event we wanted:', event)
|
||||
})
|
||||
sub.on('eose', () => {
|
||||
sub.unsub()
|
||||
})
|
||||
|
||||
// let's publish a new event while simultaneously monitoring the relay for it
|
||||
let sk = generatePrivateKey()
|
||||
let pk = getPublicKey(sk)
|
||||
|
||||
let sub = relay.sub([
|
||||
{
|
||||
kinds: [1],
|
||||
authors: [pk],
|
||||
},
|
||||
])
|
||||
|
||||
sub.on('event', event => {
|
||||
console.log('got event:', event)
|
||||
})
|
||||
|
||||
let event = {
|
||||
kind: 1,
|
||||
created_at: Math.floor(Date.now() / 1000),
|
||||
tags: [],
|
||||
content: 'hello world',
|
||||
}
|
||||
|
||||
// this assigns the pubkey, calculates the event id and signs the event in a single step
|
||||
const signedEvent = finishEvent(event, sk)
|
||||
await relay.publish(signedEvent)
|
||||
|
||||
let events = await relay.list([{ kinds: [0, 1] }])
|
||||
let event = await relay.get({
|
||||
ids: ['44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'],
|
||||
})
|
||||
|
||||
relay.close()
|
||||
```
|
||||
|
||||
To use this on Node.js you first must install `websocket-polyfill` and import it:
|
||||
|
||||
```js
|
||||
import 'websocket-polyfill'
|
||||
```
|
||||
|
||||
### Interacting with multiple relays
|
||||
|
||||
```js
|
||||
import { SimplePool } from 'nostr-tools'
|
||||
|
||||
const pool = new SimplePool()
|
||||
|
||||
let relays = ['wss://relay.example.com', 'wss://relay.example2.com']
|
||||
|
||||
let sub = pool.sub(
|
||||
[...relays, 'wss://relay.example3.com'],
|
||||
[
|
||||
{
|
||||
authors: ['32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'],
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
sub.on('event', event => {
|
||||
// this will only be called once the first time the event is received
|
||||
// ...
|
||||
})
|
||||
|
||||
let pubs = pool.publish(relays, newEvent)
|
||||
await Promise.all(pubs)
|
||||
|
||||
let events = await pool.list(relays, [{ kinds: [0, 1] }])
|
||||
let event = await pool.get(relays, {
|
||||
ids: ['44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'],
|
||||
})
|
||||
|
||||
let batchedEvents = await pool.batchedList('notes', relays, [{ kinds: [1] }])
|
||||
// `batchedList` will wait for other function calls with the same `batchKey`
|
||||
// (e.g. 'notes', 'authors', etc) within a fixed amount of time (default: `100ms`) before sending
|
||||
// next ws request, and batch all requests with similar `batchKey`s together in a single request.
|
||||
|
||||
let relaysForEvent = pool.seenOn('44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245')
|
||||
// relaysForEvent will be an array of URLs from relays a given event was seen on
|
||||
|
||||
pool.close()
|
||||
```
|
||||
|
||||
read more details about `batchedList` on this pr: [https://github.com/nbd-wtf/nostr-tools/pull/279](https://github.com/nbd-wtf/nostr-tools/pull/279#issue-1859315757)
|
||||
|
||||
### Parsing references (mentions) from a content using NIP-10 and NIP-27
|
||||
|
||||
```js
|
||||
import { parseReferences } from 'nostr-tools'
|
||||
|
||||
let references = parseReferences(event)
|
||||
let simpleAugmentedContent = event.content
|
||||
for (let i = 0; i < references.length; i++) {
|
||||
let { text, profile, event, address } = references[i]
|
||||
let augmentedReference = profile
|
||||
? `<strong>@${profilesCache[profile.pubkey].name}</strong>`
|
||||
: event
|
||||
? `<em>${eventsCache[event.id].content.slice(0, 5)}</em>`
|
||||
: address
|
||||
? `<a href="${text}">[link]</a>`
|
||||
: text
|
||||
simpleAugmentedContent.replaceAll(text, augmentedReference)
|
||||
}
|
||||
```
|
||||
|
||||
### Querying profile data from a NIP-05 address
|
||||
|
||||
```js
|
||||
import { nip05 } from 'nostr-tools'
|
||||
|
||||
let profile = await nip05.queryProfile('jb55.com')
|
||||
console.log(profile.pubkey)
|
||||
// prints: 32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245
|
||||
console.log(profile.relays)
|
||||
// prints: [wss://relay.damus.io]
|
||||
```
|
||||
|
||||
To use this on Node.js < v18, you first must install `node-fetch@2` and call something like this:
|
||||
|
||||
```js
|
||||
nip05.useFetchImplementation(require('node-fetch'))
|
||||
```
|
||||
|
||||
### Encoding and decoding NIP-19 codes
|
||||
|
||||
```js
|
||||
import { nip19, generatePrivateKey, getPublicKey } from 'nostr-tools'
|
||||
|
||||
let sk = generatePrivateKey()
|
||||
let nsec = nip19.nsecEncode(sk)
|
||||
let { type, data } = nip19.decode(nsec)
|
||||
assert(type === 'nsec')
|
||||
assert(data === sk)
|
||||
|
||||
let pk = getPublicKey(generatePrivateKey())
|
||||
let npub = nip19.npubEncode(pk)
|
||||
let { type, data } = nip19.decode(npub)
|
||||
assert(type === 'npub')
|
||||
assert(data === pk)
|
||||
|
||||
let pk = getPublicKey(generatePrivateKey())
|
||||
let relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com']
|
||||
let nprofile = nip19.nprofileEncode({ pubkey: pk, relays })
|
||||
let { type, data } = nip19.decode(nprofile)
|
||||
assert(type === 'nprofile')
|
||||
assert(data.pubkey === pk)
|
||||
assert(data.relays.length === 2)
|
||||
```
|
||||
|
||||
### Encrypting and decrypting direct messages
|
||||
|
||||
```js
|
||||
import {nip44, getPublicKey, generatePrivateKey} from 'nostr-tools'
|
||||
|
||||
// sender
|
||||
let sk1 = generatePrivateKey()
|
||||
let pk1 = getPublicKey(sk1)
|
||||
|
||||
// receiver
|
||||
let sk2 = generatePrivateKey()
|
||||
let pk2 = getPublicKey(sk2)
|
||||
|
||||
// on the sender side
|
||||
let message = 'hello'
|
||||
let key = nip44.getSharedSecret(sk1, pk2)
|
||||
let ciphertext = nip44.encrypt(key, message)
|
||||
|
||||
let event = {
|
||||
kind: 4,
|
||||
pubkey: pk1,
|
||||
tags: [['p', pk2]],
|
||||
content: ciphertext,
|
||||
...otherProperties,
|
||||
}
|
||||
|
||||
sendEvent(event)
|
||||
|
||||
// on the receiver side
|
||||
sub.on('event', async event => {
|
||||
let sender = event.pubkey
|
||||
// pk1 === sender
|
||||
let _key = nip44.getSharedSecret(sk2, pk1)
|
||||
let plaintext = nip44.decrypt(_key, event.content)
|
||||
})
|
||||
```
|
||||
|
||||
### Performing and checking for delegation
|
||||
|
||||
```js
|
||||
import { nip26, getPublicKey, generatePrivateKey } from 'nostr-tools'
|
||||
|
||||
// delegator
|
||||
let sk1 = generatePrivateKey()
|
||||
let pk1 = getPublicKey(sk1)
|
||||
|
||||
// delegatee
|
||||
let sk2 = generatePrivateKey()
|
||||
let pk2 = getPublicKey(sk2)
|
||||
|
||||
// generate delegation
|
||||
let delegation = nip26.createDelegation(sk1, {
|
||||
pubkey: pk2,
|
||||
kind: 1,
|
||||
since: Math.round(Date.now() / 1000),
|
||||
until: Math.round(Date.now() / 1000) + 60 * 60 * 24 * 30 /* 30 days */,
|
||||
})
|
||||
|
||||
// the delegatee uses the delegation when building an event
|
||||
let event = {
|
||||
pubkey: pk2,
|
||||
kind: 1,
|
||||
created_at: Math.round(Date.now() / 1000),
|
||||
content: 'hello from a delegated key',
|
||||
tags: [['delegation', delegation.from, delegation.cond, delegation.sig]],
|
||||
}
|
||||
|
||||
// finally any receiver of this event can check for the presence of a valid delegation tag
|
||||
let delegator = nip26.getDelegator(event)
|
||||
assert(delegator === pk1) // will be null if there is no delegation tag or if it is invalid
|
||||
```
|
||||
|
||||
Please consult the tests or [the source code](https://github.com/fiatjaf/nostr-tools) for more information that isn't available here.
|
||||
|
||||
### Using from the browser (if you don't want to use a bundler)
|
||||
|
||||
```html
|
||||
<script src="https://unpkg.com/nostr-tools/lib/nostr.bundle.js"></script>
|
||||
<script>
|
||||
window.NostrTools.generatePrivateKey('...') // and so on
|
||||
</script>
|
||||
```
|
||||
|
||||
## Plumbing
|
||||
|
||||
1. Install [`just`](https://just.systems/)
|
||||
2. `just -l`
|
||||
|
||||
## License
|
||||
|
||||
This is free and unencumbered software released into the public domain. By submitting patches to this project, you agree to dedicate any and all copyright interest in this software to the public domain.
|
||||
-154
@@ -1,154 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// event.ts
|
||||
var event_exports = {};
|
||||
__export(event_exports, {
|
||||
Kind: () => Kind,
|
||||
finishEvent: () => finishEvent,
|
||||
getBlankEvent: () => getBlankEvent,
|
||||
getEventHash: () => getEventHash,
|
||||
getSignature: () => getSignature,
|
||||
serializeEvent: () => serializeEvent,
|
||||
signEvent: () => signEvent,
|
||||
validateEvent: () => validateEvent,
|
||||
verifiedSymbol: () => verifiedSymbol,
|
||||
verifySignature: () => verifySignature
|
||||
});
|
||||
module.exports = __toCommonJS(event_exports);
|
||||
var import_secp256k12 = require("@noble/curves/secp256k1");
|
||||
var import_sha256 = require("@noble/hashes/sha256");
|
||||
var import_utils2 = require("@noble/hashes/utils");
|
||||
|
||||
// keys.ts
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
function getPublicKey(privateKey) {
|
||||
return (0, import_utils.bytesToHex)(import_secp256k1.schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
var Kind = /* @__PURE__ */ ((Kind2) => {
|
||||
Kind2[Kind2["Metadata"] = 0] = "Metadata";
|
||||
Kind2[Kind2["Text"] = 1] = "Text";
|
||||
Kind2[Kind2["RecommendRelay"] = 2] = "RecommendRelay";
|
||||
Kind2[Kind2["Contacts"] = 3] = "Contacts";
|
||||
Kind2[Kind2["EncryptedDirectMessage"] = 4] = "EncryptedDirectMessage";
|
||||
Kind2[Kind2["EventDeletion"] = 5] = "EventDeletion";
|
||||
Kind2[Kind2["Repost"] = 6] = "Repost";
|
||||
Kind2[Kind2["Reaction"] = 7] = "Reaction";
|
||||
Kind2[Kind2["BadgeAward"] = 8] = "BadgeAward";
|
||||
Kind2[Kind2["ChannelCreation"] = 40] = "ChannelCreation";
|
||||
Kind2[Kind2["ChannelMetadata"] = 41] = "ChannelMetadata";
|
||||
Kind2[Kind2["ChannelMessage"] = 42] = "ChannelMessage";
|
||||
Kind2[Kind2["ChannelHideMessage"] = 43] = "ChannelHideMessage";
|
||||
Kind2[Kind2["ChannelMuteUser"] = 44] = "ChannelMuteUser";
|
||||
Kind2[Kind2["Blank"] = 255] = "Blank";
|
||||
Kind2[Kind2["Report"] = 1984] = "Report";
|
||||
Kind2[Kind2["ZapRequest"] = 9734] = "ZapRequest";
|
||||
Kind2[Kind2["Zap"] = 9735] = "Zap";
|
||||
Kind2[Kind2["RelayList"] = 10002] = "RelayList";
|
||||
Kind2[Kind2["ClientAuth"] = 22242] = "ClientAuth";
|
||||
Kind2[Kind2["NwcRequest"] = 23194] = "NwcRequest";
|
||||
Kind2[Kind2["HttpAuth"] = 27235] = "HttpAuth";
|
||||
Kind2[Kind2["ProfileBadge"] = 30008] = "ProfileBadge";
|
||||
Kind2[Kind2["BadgeDefinition"] = 30009] = "BadgeDefinition";
|
||||
Kind2[Kind2["Article"] = 30023] = "Article";
|
||||
Kind2[Kind2["FileMetadata"] = 1063] = "FileMetadata";
|
||||
return Kind2;
|
||||
})(Kind || {});
|
||||
function getBlankEvent(kind = 255 /* Blank */) {
|
||||
return {
|
||||
kind,
|
||||
content: "",
|
||||
tags: [],
|
||||
created_at: 0
|
||||
};
|
||||
}
|
||||
function finishEvent(t, privateKey) {
|
||||
const event = t;
|
||||
event.pubkey = getPublicKey(privateKey);
|
||||
event.id = getEventHash(event);
|
||||
event.sig = getSignature(event, privateKey);
|
||||
event[verifiedSymbol] = true;
|
||||
return event;
|
||||
}
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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)));
|
||||
return (0, import_utils2.bytesToHex)(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function verifySignature(event) {
|
||||
if (typeof event[verifiedSymbol] === "boolean")
|
||||
return event[verifiedSymbol];
|
||||
const hash = getEventHash(event);
|
||||
if (hash !== event.id) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
try {
|
||||
return event[verifiedSymbol] = import_secp256k12.schnorr.verify(event.sig, hash, event.pubkey);
|
||||
} catch (err) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
}
|
||||
function signEvent(event, key) {
|
||||
console.warn(
|
||||
"nostr-tools: `signEvent` is deprecated and will be removed or changed in the future. Please use `getSignature` instead."
|
||||
);
|
||||
return getSignature(event, key);
|
||||
}
|
||||
function getSignature(event, key) {
|
||||
return (0, import_utils2.bytesToHex)(import_secp256k12.schnorr.sign(getEventHash(event), key));
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-66
@@ -1,66 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// fakejson.ts
|
||||
var fakejson_exports = {};
|
||||
__export(fakejson_exports, {
|
||||
getHex64: () => getHex64,
|
||||
getInt: () => getInt,
|
||||
getSubscriptionId: () => getSubscriptionId,
|
||||
matchEventId: () => matchEventId,
|
||||
matchEventKind: () => matchEventKind,
|
||||
matchEventPubkey: () => matchEventPubkey
|
||||
});
|
||||
module.exports = __toCommonJS(fakejson_exports);
|
||||
function getHex64(json, field) {
|
||||
let len = field.length + 3;
|
||||
let idx = json.indexOf(`"${field}":`) + len;
|
||||
let s = json.slice(idx).indexOf(`"`) + idx + 1;
|
||||
return json.slice(s, s + 64);
|
||||
}
|
||||
function getInt(json, field) {
|
||||
let len = field.length;
|
||||
let idx = json.indexOf(`"${field}":`) + len + 3;
|
||||
let sliced = json.slice(idx);
|
||||
let end = Math.min(sliced.indexOf(","), sliced.indexOf("}"));
|
||||
return parseInt(sliced.slice(0, end), 10);
|
||||
}
|
||||
function getSubscriptionId(json) {
|
||||
let idx = json.slice(0, 22).indexOf(`"EVENT"`);
|
||||
if (idx === -1)
|
||||
return null;
|
||||
let pstart = json.slice(idx + 7 + 1).indexOf(`"`);
|
||||
if (pstart === -1)
|
||||
return null;
|
||||
let start = idx + 7 + 1 + pstart;
|
||||
let pend = json.slice(start + 1, 80).indexOf(`"`);
|
||||
if (pend === -1)
|
||||
return null;
|
||||
let end = start + 1 + pend;
|
||||
return json.slice(start + 1, end);
|
||||
}
|
||||
function matchEventId(json, id) {
|
||||
return id === getHex64(json, "id");
|
||||
}
|
||||
function matchEventPubkey(json, pubkey) {
|
||||
return pubkey === getHex64(json, "pubkey");
|
||||
}
|
||||
function matchEventKind(json, kind) {
|
||||
return kind === getInt(json, "kind");
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../fakejson.ts"],
|
||||
"sourcesContent": ["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"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,SAAS,SAAS,MAAc,OAAuB;AAC5D,MAAI,MAAM,MAAM,SAAS;AACzB,MAAI,MAAM,KAAK,QAAQ,IAAI,SAAS,IAAI;AACxC,MAAI,IAAI,KAAK,MAAM,GAAG,EAAE,QAAQ,GAAG,IAAI,MAAM;AAC7C,SAAO,KAAK,MAAM,GAAG,IAAI,EAAE;AAC7B;AAEO,SAAS,OAAO,MAAc,OAAuB;AAC1D,MAAI,MAAM,MAAM;AAChB,MAAI,MAAM,KAAK,QAAQ,IAAI,SAAS,IAAI,MAAM;AAC9C,MAAI,SAAS,KAAK,MAAM,GAAG;AAC3B,MAAI,MAAM,KAAK,IAAI,OAAO,QAAQ,GAAG,GAAG,OAAO,QAAQ,GAAG,CAAC;AAC3D,SAAO,SAAS,OAAO,MAAM,GAAG,GAAG,GAAG,EAAE;AAC1C;AAEO,SAAS,kBAAkB,MAA6B;AAC7D,MAAI,MAAM,KAAK,MAAM,GAAG,EAAE,EAAE,QAAQ,SAAS;AAC7C,MAAI,QAAQ;AAAI,WAAO;AAEvB,MAAI,SAAS,KAAK,MAAM,MAAM,IAAI,CAAC,EAAE,QAAQ,GAAG;AAChD,MAAI,WAAW;AAAI,WAAO;AAC1B,MAAI,QAAQ,MAAM,IAAI,IAAI;AAE1B,MAAI,OAAO,KAAK,MAAM,QAAQ,GAAG,EAAE,EAAE,QAAQ,GAAG;AAChD,MAAI,SAAS;AAAI,WAAO;AACxB,MAAI,MAAM,QAAQ,IAAI;AAEtB,SAAO,KAAK,MAAM,QAAQ,GAAG,GAAG;AAClC;AAEO,SAAS,aAAa,MAAc,IAAqB;AAC9D,SAAO,OAAO,SAAS,MAAM,IAAI;AACnC;AAEO,SAAS,iBAAiB,MAAc,QAAyB;AACtE,SAAO,WAAW,SAAS,MAAM,QAAQ;AAC3C;AAEO,SAAS,eAAe,MAAc,MAAuB;AAClE,SAAO,SAAS,OAAO,MAAM,MAAM;AACrC;",
|
||||
"names": []
|
||||
}
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// filter.ts
|
||||
var filter_exports = {};
|
||||
__export(filter_exports, {
|
||||
matchFilter: () => matchFilter,
|
||||
matchFilters: () => matchFilters,
|
||||
mergeFilters: () => mergeFilters
|
||||
});
|
||||
module.exports = __toCommonJS(filter_exports);
|
||||
function matchFilter(filter, event) {
|
||||
if (filter.ids && filter.ids.indexOf(event.id) === -1) {
|
||||
if (!filter.ids.some((prefix) => event.id.startsWith(prefix))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (filter.kinds && filter.kinds.indexOf(event.kind) === -1)
|
||||
return false;
|
||||
if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {
|
||||
if (!filter.authors.some((prefix) => event.pubkey.startsWith(prefix))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (let f in filter) {
|
||||
if (f[0] === "#") {
|
||||
let tagName = f.slice(1);
|
||||
let values = filter[`#${tagName}`];
|
||||
if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values.indexOf(v) !== -1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (filter.since && event.created_at < filter.since)
|
||||
return false;
|
||||
if (filter.until && event.created_at > filter.until)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
function matchFilters(filters, event) {
|
||||
for (let i = 0; i < filters.length; i++) {
|
||||
if (matchFilter(filters[i], event))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function mergeFilters(...filters) {
|
||||
let result = {};
|
||||
for (let i = 0; i < filters.length; i++) {
|
||||
let filter = filters[i];
|
||||
Object.entries(filter).forEach(([property, values]) => {
|
||||
if (property === "kinds" || property === "ids" || property === "authors" || property[0] === "#") {
|
||||
result[property] = result[property] || [];
|
||||
for (let v = 0; v < values.length; v++) {
|
||||
let value = values[v];
|
||||
if (!result[property].includes(value))
|
||||
result[property].push(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (filter.limit && (!result.limit || filter.limit > result.limit))
|
||||
result.limit = filter.limit;
|
||||
if (filter.until && (!result.until || filter.until > result.until))
|
||||
result.until = filter.until;
|
||||
if (filter.since && (!result.since || filter.since < result.since))
|
||||
result.since = filter.since;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../filter.ts"],
|
||||
"sourcesContent": ["import { Event } from './event.ts'\n\nexport type Filter<K extends number = number> = {\n ids?: string[]\n kinds?: K[]\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<number>, event: Event<number>): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n if (!filter.ids.some(prefix => event.id.startsWith(prefix))) {\n return false\n }\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) return false\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n if (!filter.authors.some(prefix => event.pubkey.startsWith(prefix))) {\n return false\n }\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<number>[], event: Event<number>): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) return true\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter<number>[]): Filter<number> {\n let result: Filter<number> = {}\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"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaO,SAAS,YAAY,QAAwB,OAA+B;AACjF,MAAI,OAAO,OAAO,OAAO,IAAI,QAAQ,MAAM,EAAE,MAAM,IAAI;AACrD,QAAI,CAAC,OAAO,IAAI,KAAK,YAAU,MAAM,GAAG,WAAW,MAAM,CAAC,GAAG;AAC3D,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,OAAO,SAAS,OAAO,MAAM,QAAQ,MAAM,IAAI,MAAM;AAAI,WAAO;AACpE,MAAI,OAAO,WAAW,OAAO,QAAQ,QAAQ,MAAM,MAAM,MAAM,IAAI;AACjE,QAAI,CAAC,OAAO,QAAQ,KAAK,YAAU,MAAM,OAAO,WAAW,MAAM,CAAC,GAAG;AACnE,aAAO;AAAA,IACT;AAAA,EACF;AAEA,WAAS,KAAK,QAAQ;AACpB,QAAI,EAAE,OAAO,KAAK;AAChB,UAAI,UAAU,EAAE,MAAM,CAAC;AACvB,UAAI,SAAS,OAAO,IAAI;AACxB,UAAI,UAAU,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,MAAM,EAAE,MAAM,CAAC,KAAK,OAAQ,QAAQ,CAAC,MAAM,EAAE;AAAG,eAAO;AAAA,IACpG;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,MAAM,aAAa,OAAO;AAAO,WAAO;AAC5D,MAAI,OAAO,SAAS,MAAM,aAAa,OAAO;AAAO,WAAO;AAE5D,SAAO;AACT;AAEO,SAAS,aAAa,SAA2B,OAA+B;AACrF,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,QAAI,YAAY,QAAQ,IAAI,KAAK;AAAG,aAAO;AAAA,EAC7C;AACA,SAAO;AACT;AAEO,SAAS,gBAAgB,SAA2C;AACzE,MAAI,SAAyB,CAAC;AAC9B,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,QAAI,SAAS,QAAQ;AACrB,WAAO,QAAQ,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU,MAAM,MAAM;AACrD,UAAI,aAAa,WAAW,aAAa,SAAS,aAAa,aAAa,SAAS,OAAO,KAAK;AAE/F,eAAO,YAAY,OAAO,aAAa,CAAC;AAExC,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AAEtC,cAAI,QAAQ,OAAO;AAEnB,cAAI,CAAC,OAAO,UAAU,SAAS,KAAK;AAAG,mBAAO,UAAU,KAAK,KAAK;AAAA,QACpE;AAAA,MACF;AAAA,IACF,CAAC;AAED,QAAI,OAAO,UAAU,CAAC,OAAO,SAAS,OAAO,QAAQ,OAAO;AAAQ,aAAO,QAAQ,OAAO;AAC1F,QAAI,OAAO,UAAU,CAAC,OAAO,SAAS,OAAO,QAAQ,OAAO;AAAQ,aAAO,QAAQ,OAAO;AAC1F,QAAI,OAAO,UAAU,CAAC,OAAO,SAAS,OAAO,QAAQ,OAAO;AAAQ,aAAO,QAAQ,OAAO;AAAA,EAC5F;AAEA,SAAO;AACT;",
|
||||
"names": []
|
||||
}
|
||||
-2126
File diff suppressed because it is too large
Load Diff
-7
File diff suppressed because one or more lines are too long
-34
@@ -1,34 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// keys.ts
|
||||
var keys_exports = {};
|
||||
__export(keys_exports, {
|
||||
generatePrivateKey: () => generatePrivateKey,
|
||||
getPublicKey: () => getPublicKey
|
||||
});
|
||||
module.exports = __toCommonJS(keys_exports);
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
function generatePrivateKey() {
|
||||
return (0, import_utils.bytesToHex)(import_secp256k1.schnorr.utils.randomPrivateKey());
|
||||
}
|
||||
function getPublicKey(privateKey) {
|
||||
return (0, import_utils.bytesToHex)(import_secp256k1.schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../keys.ts"],
|
||||
"sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\n\nexport function generatePrivateKey(): string {\n return bytesToHex(schnorr.utils.randomPrivateKey())\n}\n\nexport function getPublicKey(privateKey: string): string {\n return bytesToHex(schnorr.getPublicKey(privateKey))\n}\n"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAwB;AACxB,mBAA2B;AAEpB,SAAS,qBAA6B;AAC3C,aAAO,yBAAW,yBAAQ,MAAM,iBAAiB,CAAC;AACpD;AAEO,SAAS,aAAa,YAA4B;AACvD,aAAO,yBAAW,yBAAQ,aAAa,UAAU,CAAC;AACpD;",
|
||||
"names": []
|
||||
}
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// kinds.ts
|
||||
var kinds_exports = {};
|
||||
__export(kinds_exports, {
|
||||
classifyKind: () => classifyKind,
|
||||
isEphemeralKind: () => isEphemeralKind,
|
||||
isParameterizedReplaceableKind: () => isParameterizedReplaceableKind,
|
||||
isRegularKind: () => isRegularKind,
|
||||
isReplaceableKind: () => isReplaceableKind
|
||||
});
|
||||
module.exports = __toCommonJS(kinds_exports);
|
||||
function isRegularKind(kind) {
|
||||
return 1e3 <= kind && kind < 1e4 || [1, 2, 4, 5, 6, 7, 8, 16, 40, 41, 42, 43, 44].includes(kind);
|
||||
}
|
||||
function isReplaceableKind(kind) {
|
||||
return 1e4 <= kind && kind < 2e4 || [0, 3].includes(kind);
|
||||
}
|
||||
function isEphemeralKind(kind) {
|
||||
return 2e4 <= kind && kind < 3e4;
|
||||
}
|
||||
function isParameterizedReplaceableKind(kind) {
|
||||
return 3e4 <= kind && kind < 4e4;
|
||||
}
|
||||
function classifyKind(kind) {
|
||||
if (isRegularKind(kind))
|
||||
return "regular";
|
||||
if (isReplaceableKind(kind))
|
||||
return "replaceable";
|
||||
if (isEphemeralKind(kind))
|
||||
return "ephemeral";
|
||||
if (isParameterizedReplaceableKind(kind))
|
||||
return "parameterized";
|
||||
return "unknown";
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../kinds.ts"],
|
||||
"sourcesContent": ["/** Events are **regular**, which means they're all expected to be stored by relays. */\nfunction isRegularKind(kind: number) {\n return (1000 <= kind && kind < 10000) || [1, 2, 4, 5, 6, 7, 8, 16, 40, 41, 42, 43, 44].includes(kind)\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. */\nfunction isReplaceableKind(kind: number) {\n return (10000 <= kind && kind < 20000) || [0, 3].includes(kind)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nfunction isEphemeralKind(kind: number) {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **parameterized replaceable**, 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. */\nfunction isParameterizedReplaceableKind(kind: number) {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\ntype KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nfunction classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isParameterizedReplaceableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport {\n classifyKind,\n isEphemeralKind,\n isParameterizedReplaceableKind,\n isRegularKind,\n isReplaceableKind,\n type KindClassification,\n}\n"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,SAAS,cAAc,MAAc;AACnC,SAAQ,OAAQ,QAAQ,OAAO,OAAU,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,EAAE,SAAS,IAAI;AACtG;AAGA,SAAS,kBAAkB,MAAc;AACvC,SAAQ,OAAS,QAAQ,OAAO,OAAU,CAAC,GAAG,CAAC,EAAE,SAAS,IAAI;AAChE;AAGA,SAAS,gBAAgB,MAAc;AACrC,SAAO,OAAS,QAAQ,OAAO;AACjC;AAGA,SAAS,+BAA+B,MAAc;AACpD,SAAO,OAAS,QAAQ,OAAO;AACjC;AAMA,SAAS,aAAa,MAAkC;AACtD,MAAI,cAAc,IAAI;AAAG,WAAO;AAChC,MAAI,kBAAkB,IAAI;AAAG,WAAO;AACpC,MAAI,gBAAgB,IAAI;AAAG,WAAO;AAClC,MAAI,+BAA+B,IAAI;AAAG,WAAO;AACjD,SAAO;AACT;",
|
||||
"names": []
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip04.ts
|
||||
var nip04_exports = {};
|
||||
__export(nip04_exports, {
|
||||
decrypt: () => decrypt,
|
||||
encrypt: () => encrypt
|
||||
});
|
||||
module.exports = __toCommonJS(nip04_exports);
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_base = require("@scure/base");
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// nip04.ts
|
||||
if (typeof crypto !== "undefined" && !crypto.subtle && crypto.webcrypto) {
|
||||
crypto.subtle = crypto.webcrypto.subtle;
|
||||
}
|
||||
async function encrypt(privkey, pubkey, text) {
|
||||
const key = import_secp256k1.secp256k1.getSharedSecret(privkey, "02" + pubkey);
|
||||
const normalizedKey = getNormalizedX(key);
|
||||
let iv = Uint8Array.from((0, import_utils.randomBytes)(16));
|
||||
let plaintext = utf8Encoder.encode(text);
|
||||
let cryptoKey = await crypto.subtle.importKey("raw", normalizedKey, { name: "AES-CBC" }, false, ["encrypt"]);
|
||||
let ciphertext = await crypto.subtle.encrypt({ name: "AES-CBC", iv }, cryptoKey, plaintext);
|
||||
let ctb64 = import_base.base64.encode(new Uint8Array(ciphertext));
|
||||
let ivb64 = import_base.base64.encode(new Uint8Array(iv.buffer));
|
||||
return `${ctb64}?iv=${ivb64}`;
|
||||
}
|
||||
async function decrypt(privkey, pubkey, data) {
|
||||
let [ctb64, ivb64] = data.split("?iv=");
|
||||
let key = import_secp256k1.secp256k1.getSharedSecret(privkey, "02" + pubkey);
|
||||
let normalizedKey = getNormalizedX(key);
|
||||
let cryptoKey = await crypto.subtle.importKey("raw", normalizedKey, { name: "AES-CBC" }, false, ["decrypt"]);
|
||||
let ciphertext = import_base.base64.decode(ctb64);
|
||||
let iv = import_base.base64.decode(ivb64);
|
||||
let plaintext = await crypto.subtle.decrypt({ name: "AES-CBC", iv }, cryptoKey, ciphertext);
|
||||
let text = utf8Decoder.decode(plaintext);
|
||||
return text;
|
||||
}
|
||||
function getNormalizedX(key) {
|
||||
return key.slice(1, 33);
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-78
@@ -1,78 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip05.ts
|
||||
var nip05_exports = {};
|
||||
__export(nip05_exports, {
|
||||
NIP05_REGEX: () => NIP05_REGEX,
|
||||
queryProfile: () => queryProfile,
|
||||
searchDomain: () => searchDomain,
|
||||
useFetchImplementation: () => useFetchImplementation
|
||||
});
|
||||
module.exports = __toCommonJS(nip05_exports);
|
||||
var NIP05_REGEX = /^(?:([\w.+-]+)@)?([\w.-]+)$/;
|
||||
var _fetch;
|
||||
try {
|
||||
_fetch = fetch;
|
||||
} catch {
|
||||
}
|
||||
function useFetchImplementation(fetchImplementation) {
|
||||
_fetch = fetchImplementation;
|
||||
}
|
||||
async function searchDomain(domain, query = "") {
|
||||
try {
|
||||
let res = await (await _fetch(`https://${domain}/.well-known/nostr.json?name=${query}`)).json();
|
||||
return res.names;
|
||||
} catch (_) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
async function queryProfile(fullname) {
|
||||
const match = fullname.match(NIP05_REGEX);
|
||||
if (!match)
|
||||
return null;
|
||||
const [_, name = "_", domain] = match;
|
||||
try {
|
||||
const res = await _fetch(`https://${domain}/.well-known/nostr.json?name=${name}`);
|
||||
const { names, relays } = parseNIP05Result(await res.json());
|
||||
const pubkey = names[name];
|
||||
return pubkey ? { pubkey, relays: relays?.[pubkey] } : null;
|
||||
} catch (_e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function parseNIP05Result(json) {
|
||||
const result = {
|
||||
names: {}
|
||||
};
|
||||
for (const [name, pubkey] of Object.entries(json.names)) {
|
||||
if (typeof name === "string" && typeof pubkey === "string") {
|
||||
result.names[name] = pubkey;
|
||||
}
|
||||
}
|
||||
if (json.relays) {
|
||||
result.relays = {};
|
||||
for (const [pubkey, relays] of Object.entries(json.relays)) {
|
||||
if (typeof pubkey === "string" && Array.isArray(relays)) {
|
||||
result.relays[pubkey] = relays.filter((relay) => typeof relay === "string");
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../nip05.ts"],
|
||||
"sourcesContent": ["import { ProfilePointer } from './nip19.ts'\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.-]+)$/\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 searchDomain(domain: string, query = ''): Promise<{ [name: string]: string }> {\n try {\n let res = await (await _fetch(`https://${domain}/.well-known/nostr.json?name=${query}`)).json()\n\n return res.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 res = await _fetch(`https://${domain}/.well-known/nostr.json?name=${name}`)\n const { names, relays } = parseNIP05Result(await res.json())\n\n const pubkey = names[name]\n return pubkey ? { pubkey, relays: relays?.[pubkey] } : null\n } catch (_e) {\n return null\n }\n}\n\n/** nostr.json result. */\nexport interface NIP05Result {\n names: {\n [name: string]: string\n }\n relays?: {\n [pubkey: string]: string[]\n }\n}\n\n/** Parse the nostr.json and throw if it's not valid. */\nfunction parseNIP05Result(json: any): NIP05Result {\n const result: NIP05Result = {\n names: {},\n }\n\n for (const [name, pubkey] of Object.entries(json.names)) {\n if (typeof name === 'string' && typeof pubkey === 'string') {\n result.names[name] = pubkey\n }\n }\n\n if (json.relays) {\n result.relays = {}\n for (const [pubkey, relays] of Object.entries(json.relays)) {\n if (typeof pubkey === 'string' && Array.isArray(relays)) {\n result.relays[pubkey] = relays.filter((relay: unknown) => typeof relay === 'string')\n }\n }\n }\n\n return result\n}\n"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASO,IAAM,cAAc;AAE3B,IAAI;AAEJ,IAAI;AACF,WAAS;AACX,QAAE;AAAO;AAEF,SAAS,uBAAuB,qBAA0B;AAC/D,WAAS;AACX;AAEA,eAAsB,aAAa,QAAgB,QAAQ,IAAyC;AAClG,MAAI;AACF,QAAI,MAAM,OAAO,MAAM,OAAO,WAAW,sCAAsC,OAAO,GAAG,KAAK;AAE9F,WAAO,IAAI;AAAA,EACb,SAAS,GAAP;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,aAAa,UAAkD;AACnF,QAAM,QAAQ,SAAS,MAAM,WAAW;AACxC,MAAI,CAAC;AAAO,WAAO;AAEnB,QAAM,CAAC,GAAG,OAAO,KAAK,MAAM,IAAI;AAEhC,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,WAAW,sCAAsC,MAAM;AAChF,UAAM,EAAE,OAAO,OAAO,IAAI,iBAAiB,MAAM,IAAI,KAAK,CAAC;AAE3D,UAAM,SAAS,MAAM;AACrB,WAAO,SAAS,EAAE,QAAQ,QAAQ,SAAS,QAAQ,IAAI;AAAA,EACzD,SAAS,IAAP;AACA,WAAO;AAAA,EACT;AACF;AAaA,SAAS,iBAAiB,MAAwB;AAChD,QAAM,SAAsB;AAAA,IAC1B,OAAO,CAAC;AAAA,EACV;AAEA,aAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AACvD,QAAI,OAAO,SAAS,YAAY,OAAO,WAAW,UAAU;AAC1D,aAAO,MAAM,QAAQ;AAAA,IACvB;AAAA,EACF;AAEA,MAAI,KAAK,QAAQ;AACf,WAAO,SAAS,CAAC;AACjB,eAAW,CAAC,QAAQ,MAAM,KAAK,OAAO,QAAQ,KAAK,MAAM,GAAG;AAC1D,UAAI,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AACvD,eAAO,OAAO,UAAU,OAAO,OAAO,CAAC,UAAmB,OAAO,UAAU,QAAQ;AAAA,MACrF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;",
|
||||
"names": []
|
||||
}
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip06.ts
|
||||
var nip06_exports = {};
|
||||
__export(nip06_exports, {
|
||||
generateSeedWords: () => generateSeedWords,
|
||||
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_bip39 = require("@scure/bip39");
|
||||
var import_bip32 = require("@scure/bip32");
|
||||
function privateKeyFromSeedWords(mnemonic, passphrase) {
|
||||
let root = import_bip32.HDKey.fromMasterSeed((0, import_bip39.mnemonicToSeedSync)(mnemonic, passphrase));
|
||||
let privateKey = root.derive(`m/44'/1237'/0'/0/0`).privateKey;
|
||||
if (!privateKey)
|
||||
throw new Error("could not derive private key");
|
||||
return (0, import_utils.bytesToHex)(privateKey);
|
||||
}
|
||||
function generateSeedWords() {
|
||||
return (0, import_bip39.generateMnemonic)(import_english.wordlist);
|
||||
}
|
||||
function validateWords(words) {
|
||||
return (0, import_bip39.validateMnemonic)(words, import_english.wordlist);
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"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\nexport function privateKeyFromSeedWords(mnemonic: string, passphrase?: string): string {\n let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n let privateKey = root.derive(`m/44'/1237'/0'/0/0`).privateKey\n if (!privateKey) throw new Error('could not derive private key')\n return bytesToHex(privateKey)\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,mBAA2B;AAC3B,qBAAyB;AACzB,mBAAuE;AACvE,mBAAsB;AAEf,SAAS,wBAAwB,UAAkB,YAA6B;AACrF,MAAI,OAAO,mBAAM,mBAAe,iCAAmB,UAAU,UAAU,CAAC;AACxE,MAAI,aAAa,KAAK,OAAO,oBAAoB,EAAE;AACnD,MAAI,CAAC;AAAY,UAAM,IAAI,MAAM,8BAA8B;AAC/D,aAAO,yBAAW,UAAU;AAC9B;AAEO,SAAS,oBAA4B;AAC1C,aAAO,+BAAiB,uBAAQ;AAClC;AAEO,SAAS,cAAc,OAAwB;AACpD,aAAO,+BAAiB,OAAO,uBAAQ;AACzC;",
|
||||
"names": []
|
||||
}
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip10.ts
|
||||
var nip10_exports = {};
|
||||
__export(nip10_exports, {
|
||||
parse: () => parse
|
||||
});
|
||||
module.exports = __toCommonJS(nip10_exports);
|
||||
function parse(event) {
|
||||
const result = {
|
||||
reply: void 0,
|
||||
root: void 0,
|
||||
mentions: [],
|
||||
profiles: []
|
||||
};
|
||||
const eTags = [];
|
||||
for (const tag of event.tags) {
|
||||
if (tag[0] === "e" && tag[1]) {
|
||||
eTags.push(tag);
|
||||
}
|
||||
if (tag[0] === "p" && tag[1]) {
|
||||
result.profiles.push({
|
||||
pubkey: tag[1],
|
||||
relays: tag[2] ? [tag[2]] : []
|
||||
});
|
||||
}
|
||||
}
|
||||
for (let eTagIndex = 0; eTagIndex < eTags.length; eTagIndex++) {
|
||||
const eTag = eTags[eTagIndex];
|
||||
const [_, eTagEventId, eTagRelayUrl, eTagMarker] = eTag;
|
||||
const eventPointer = {
|
||||
id: eTagEventId,
|
||||
relays: eTagRelayUrl ? [eTagRelayUrl] : []
|
||||
};
|
||||
const isFirstETag = eTagIndex === 0;
|
||||
const isLastETag = eTagIndex === eTags.length - 1;
|
||||
if (eTagMarker === "root") {
|
||||
result.root = eventPointer;
|
||||
continue;
|
||||
}
|
||||
if (eTagMarker === "reply") {
|
||||
result.reply = eventPointer;
|
||||
continue;
|
||||
}
|
||||
if (eTagMarker === "mention") {
|
||||
result.mentions.push(eventPointer);
|
||||
continue;
|
||||
}
|
||||
if (isFirstETag) {
|
||||
result.root = eventPointer;
|
||||
continue;
|
||||
}
|
||||
if (isLastETag) {
|
||||
result.reply = eventPointer;
|
||||
continue;
|
||||
}
|
||||
result.mentions.push(eventPointer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../nip10.ts"],
|
||||
"sourcesContent": ["import type { Event } from './event.ts'\nimport type { EventPointer, ProfilePointer } from './nip19.ts'\n\nexport type NIP10Result = {\n /**\n * Pointer to the root of the thread.\n */\n root: EventPointer | undefined\n\n /**\n * Pointer to a \"parent\" event that parsed event replies to (responded to).\n */\n reply: EventPointer | undefined\n\n /**\n * Pointers to events which may or may not be in the reply chain.\n */\n mentions: EventPointer[]\n\n /**\n * List of pubkeys that are involved in the thread in no particular order.\n */\n profiles: ProfilePointer[]\n}\n\nexport function parse(event: Pick<Event, 'tags'>): NIP10Result {\n const result: NIP10Result = {\n reply: undefined,\n root: undefined,\n mentions: [],\n profiles: [],\n }\n\n const eTags: string[][] = []\n\n for (const tag of event.tags) {\n if (tag[0] === 'e' && tag[1]) {\n eTags.push(tag)\n }\n\n if (tag[0] === 'p' && tag[1]) {\n result.profiles.push({\n pubkey: tag[1],\n relays: tag[2] ? [tag[2]] : [],\n })\n }\n }\n\n for (let eTagIndex = 0; eTagIndex < eTags.length; eTagIndex++) {\n const eTag = eTags[eTagIndex]\n\n const [_, eTagEventId, eTagRelayUrl, eTagMarker] = eTag as [string, string, undefined | string, undefined | string]\n\n const eventPointer: EventPointer = {\n id: eTagEventId,\n relays: eTagRelayUrl ? [eTagRelayUrl] : [],\n }\n\n const isFirstETag = eTagIndex === 0\n const isLastETag = eTagIndex === eTags.length - 1\n\n if (eTagMarker === 'root') {\n result.root = eventPointer\n continue\n }\n\n if (eTagMarker === 'reply') {\n result.reply = eventPointer\n continue\n }\n\n if (eTagMarker === 'mention') {\n result.mentions.push(eventPointer)\n continue\n }\n\n if (isFirstETag) {\n result.root = eventPointer\n continue\n }\n\n if (isLastETag) {\n result.reply = eventPointer\n continue\n }\n\n result.mentions.push(eventPointer)\n }\n\n return result\n}\n"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAyBO,SAAS,MAAM,OAAyC;AAC7D,QAAM,SAAsB;AAAA,IAC1B,OAAO;AAAA,IACP,MAAM;AAAA,IACN,UAAU,CAAC;AAAA,IACX,UAAU,CAAC;AAAA,EACb;AAEA,QAAM,QAAoB,CAAC;AAE3B,aAAW,OAAO,MAAM,MAAM;AAC5B,QAAI,IAAI,OAAO,OAAO,IAAI,IAAI;AAC5B,YAAM,KAAK,GAAG;AAAA,IAChB;AAEA,QAAI,IAAI,OAAO,OAAO,IAAI,IAAI;AAC5B,aAAO,SAAS,KAAK;AAAA,QACnB,QAAQ,IAAI;AAAA,QACZ,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC;AAAA,MAC/B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,WAAS,YAAY,GAAG,YAAY,MAAM,QAAQ,aAAa;AAC7D,UAAM,OAAO,MAAM;AAEnB,UAAM,CAAC,GAAG,aAAa,cAAc,UAAU,IAAI;AAEnD,UAAM,eAA6B;AAAA,MACjC,IAAI;AAAA,MACJ,QAAQ,eAAe,CAAC,YAAY,IAAI,CAAC;AAAA,IAC3C;AAEA,UAAM,cAAc,cAAc;AAClC,UAAM,aAAa,cAAc,MAAM,SAAS;AAEhD,QAAI,eAAe,QAAQ;AACzB,aAAO,OAAO;AACd;AAAA,IACF;AAEA,QAAI,eAAe,SAAS;AAC1B,aAAO,QAAQ;AACf;AAAA,IACF;AAEA,QAAI,eAAe,WAAW;AAC5B,aAAO,SAAS,KAAK,YAAY;AACjC;AAAA,IACF;AAEA,QAAI,aAAa;AACf,aAAO,OAAO;AACd;AAAA,IACF;AAEA,QAAI,YAAY;AACd,aAAO,QAAQ;AACf;AAAA,IACF;AAEA,WAAO,SAAS,KAAK,YAAY;AAAA,EACnC;AAEA,SAAO;AACT;",
|
||||
"names": []
|
||||
}
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip13.ts
|
||||
var nip13_exports = {};
|
||||
__export(nip13_exports, {
|
||||
getPow: () => getPow,
|
||||
minePow: () => minePow
|
||||
});
|
||||
module.exports = __toCommonJS(nip13_exports);
|
||||
|
||||
// event.ts
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_sha256 = require("@noble/hashes/sha256");
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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)));
|
||||
return (0, import_utils.bytesToHex)(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// nip13.ts
|
||||
function getPow(hex) {
|
||||
let count = 0;
|
||||
for (let i = 0; i < hex.length; i++) {
|
||||
const nibble = parseInt(hex[i], 16);
|
||||
if (nibble === 0) {
|
||||
count += 4;
|
||||
} else {
|
||||
count += Math.clz32(nibble) - 28;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
function minePow(unsigned, difficulty) {
|
||||
let count = 0;
|
||||
const event = unsigned;
|
||||
const tag = ["nonce", count.toString(), difficulty.toString()];
|
||||
event.tags.push(tag);
|
||||
while (true) {
|
||||
const now = Math.floor(new Date().getTime() / 1e3);
|
||||
if (now !== event.created_at) {
|
||||
count = 0;
|
||||
event.created_at = now;
|
||||
}
|
||||
tag[1] = (++count).toString();
|
||||
event.id = getEventHash(event);
|
||||
if (getPow(event.id) >= difficulty) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return event;
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-163
@@ -1,163 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip18.ts
|
||||
var nip18_exports = {};
|
||||
__export(nip18_exports, {
|
||||
finishRepostEvent: () => finishRepostEvent,
|
||||
getRepostedEvent: () => getRepostedEvent,
|
||||
getRepostedEventPointer: () => getRepostedEventPointer
|
||||
});
|
||||
module.exports = __toCommonJS(nip18_exports);
|
||||
|
||||
// event.ts
|
||||
var import_secp256k12 = require("@noble/curves/secp256k1");
|
||||
var import_sha256 = require("@noble/hashes/sha256");
|
||||
var import_utils2 = require("@noble/hashes/utils");
|
||||
|
||||
// keys.ts
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
function getPublicKey(privateKey) {
|
||||
return (0, import_utils.bytesToHex)(import_secp256k1.schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function finishEvent(t, privateKey) {
|
||||
const event = t;
|
||||
event.pubkey = getPublicKey(privateKey);
|
||||
event.id = getEventHash(event);
|
||||
event.sig = getSignature(event, privateKey);
|
||||
event[verifiedSymbol] = true;
|
||||
return event;
|
||||
}
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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)));
|
||||
return (0, import_utils2.bytesToHex)(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function verifySignature(event) {
|
||||
if (typeof event[verifiedSymbol] === "boolean")
|
||||
return event[verifiedSymbol];
|
||||
const hash = getEventHash(event);
|
||||
if (hash !== event.id) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
try {
|
||||
return event[verifiedSymbol] = import_secp256k12.schnorr.verify(event.sig, hash, event.pubkey);
|
||||
} catch (err) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
}
|
||||
function getSignature(event, key) {
|
||||
return (0, import_utils2.bytesToHex)(import_secp256k12.schnorr.sign(getEventHash(event), key));
|
||||
}
|
||||
|
||||
// nip18.ts
|
||||
function finishRepostEvent(t, reposted, relayUrl, privateKey) {
|
||||
return finishEvent(
|
||||
{
|
||||
kind: 6 /* Repost */,
|
||||
tags: [...t.tags ?? [], ["e", reposted.id, relayUrl], ["p", reposted.pubkey]],
|
||||
content: t.content === "" ? "" : JSON.stringify(reposted),
|
||||
created_at: t.created_at
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
}
|
||||
function getRepostedEventPointer(event) {
|
||||
if (event.kind !== 6 /* Repost */) {
|
||||
return void 0;
|
||||
}
|
||||
let lastETag;
|
||||
let lastPTag;
|
||||
for (let i = event.tags.length - 1; i >= 0 && (lastETag === void 0 || lastPTag === void 0); i--) {
|
||||
const tag = event.tags[i];
|
||||
if (tag.length >= 2) {
|
||||
if (tag[0] === "e" && lastETag === void 0) {
|
||||
lastETag = tag;
|
||||
} else if (tag[0] === "p" && lastPTag === void 0) {
|
||||
lastPTag = tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastETag === void 0) {
|
||||
return void 0;
|
||||
}
|
||||
return {
|
||||
id: lastETag[1],
|
||||
relays: [lastETag[2], lastPTag?.[2]].filter((x) => typeof x === "string"),
|
||||
author: lastPTag?.[1]
|
||||
};
|
||||
}
|
||||
function getRepostedEvent(event, { skipVerification } = {}) {
|
||||
const pointer = getRepostedEventPointer(event);
|
||||
if (pointer === void 0 || event.content === "") {
|
||||
return void 0;
|
||||
}
|
||||
let repostedEvent;
|
||||
try {
|
||||
repostedEvent = JSON.parse(event.content);
|
||||
} catch (error) {
|
||||
return void 0;
|
||||
}
|
||||
if (repostedEvent.id !== pointer.id) {
|
||||
return void 0;
|
||||
}
|
||||
if (!skipVerification && !verifySignature(repostedEvent)) {
|
||||
return void 0;
|
||||
}
|
||||
return repostedEvent;
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-212
@@ -1,212 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip19.ts
|
||||
var nip19_exports = {};
|
||||
__export(nip19_exports, {
|
||||
BECH32_REGEX: () => BECH32_REGEX,
|
||||
decode: () => decode,
|
||||
naddrEncode: () => naddrEncode,
|
||||
neventEncode: () => neventEncode,
|
||||
noteEncode: () => noteEncode,
|
||||
nprofileEncode: () => nprofileEncode,
|
||||
npubEncode: () => npubEncode,
|
||||
nrelayEncode: () => nrelayEncode,
|
||||
nsecEncode: () => nsecEncode
|
||||
});
|
||||
module.exports = __toCommonJS(nip19_exports);
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
var import_base = require("@scure/base");
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// nip19.ts
|
||||
var Bech32MaxSize = 5e3;
|
||||
var BECH32_REGEX = /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/;
|
||||
function integerToUint8Array(number) {
|
||||
const uint8Array = new Uint8Array(4);
|
||||
uint8Array[0] = number >> 24 & 255;
|
||||
uint8Array[1] = number >> 16 & 255;
|
||||
uint8Array[2] = number >> 8 & 255;
|
||||
uint8Array[3] = number & 255;
|
||||
return uint8Array;
|
||||
}
|
||||
function decode(nip19) {
|
||||
let { prefix, words } = import_base.bech32.decode(nip19, Bech32MaxSize);
|
||||
let data = new Uint8Array(import_base.bech32.fromWords(words));
|
||||
switch (prefix) {
|
||||
case "nprofile": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nprofile");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
return {
|
||||
type: "nprofile",
|
||||
data: {
|
||||
pubkey: (0, import_utils.bytesToHex)(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nevent": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nevent");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
if (tlv[2] && tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (tlv[3] && tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "nevent",
|
||||
data: {
|
||||
id: (0, import_utils.bytesToHex)(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],
|
||||
author: tlv[2]?.[0] ? (0, import_utils.bytesToHex)(tlv[2][0]) : void 0,
|
||||
kind: tlv[3]?.[0] ? parseInt((0, import_utils.bytesToHex)(tlv[3][0]), 16) : void 0
|
||||
}
|
||||
};
|
||||
}
|
||||
case "naddr": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for naddr");
|
||||
if (!tlv[2]?.[0])
|
||||
throw new Error("missing TLV 2 for naddr");
|
||||
if (tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (!tlv[3]?.[0])
|
||||
throw new Error("missing TLV 3 for naddr");
|
||||
if (tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "naddr",
|
||||
data: {
|
||||
identifier: utf8Decoder.decode(tlv[0][0]),
|
||||
pubkey: (0, import_utils.bytesToHex)(tlv[2][0]),
|
||||
kind: parseInt((0, import_utils.bytesToHex)(tlv[3][0]), 16),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nrelay": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nrelay");
|
||||
return {
|
||||
type: "nrelay",
|
||||
data: utf8Decoder.decode(tlv[0][0])
|
||||
};
|
||||
}
|
||||
case "nsec":
|
||||
case "npub":
|
||||
case "note":
|
||||
return { type: prefix, data: (0, import_utils.bytesToHex)(data) };
|
||||
default:
|
||||
throw new Error(`unknown prefix ${prefix}`);
|
||||
}
|
||||
}
|
||||
function parseTLV(data) {
|
||||
let result = {};
|
||||
let rest = data;
|
||||
while (rest.length > 0) {
|
||||
let t = rest[0];
|
||||
let l = rest[1];
|
||||
if (!l)
|
||||
throw new Error(`malformed TLV ${t}`);
|
||||
let v = rest.slice(2, 2 + l);
|
||||
rest = rest.slice(2 + l);
|
||||
if (v.length < l)
|
||||
throw new Error(`not enough data to read on TLV ${t}`);
|
||||
result[t] = result[t] || [];
|
||||
result[t].push(v);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function nsecEncode(hex) {
|
||||
return encodeBytes("nsec", hex);
|
||||
}
|
||||
function npubEncode(hex) {
|
||||
return encodeBytes("npub", hex);
|
||||
}
|
||||
function noteEncode(hex) {
|
||||
return encodeBytes("note", hex);
|
||||
}
|
||||
function encodeBech32(prefix, data) {
|
||||
let words = import_base.bech32.toWords(data);
|
||||
return import_base.bech32.encode(prefix, words, Bech32MaxSize);
|
||||
}
|
||||
function encodeBytes(prefix, hex) {
|
||||
let data = (0, import_utils.hexToBytes)(hex);
|
||||
return encodeBech32(prefix, data);
|
||||
}
|
||||
function nprofileEncode(profile) {
|
||||
let data = encodeTLV({
|
||||
0: [(0, import_utils.hexToBytes)(profile.pubkey)],
|
||||
1: (profile.relays || []).map((url) => utf8Encoder.encode(url))
|
||||
});
|
||||
return encodeBech32("nprofile", data);
|
||||
}
|
||||
function neventEncode(event) {
|
||||
let kindArray;
|
||||
if (event.kind != void 0) {
|
||||
kindArray = integerToUint8Array(event.kind);
|
||||
}
|
||||
let data = encodeTLV({
|
||||
0: [(0, import_utils.hexToBytes)(event.id)],
|
||||
1: (event.relays || []).map((url) => utf8Encoder.encode(url)),
|
||||
2: event.author ? [(0, import_utils.hexToBytes)(event.author)] : [],
|
||||
3: kindArray ? [new Uint8Array(kindArray)] : []
|
||||
});
|
||||
return encodeBech32("nevent", data);
|
||||
}
|
||||
function naddrEncode(addr) {
|
||||
let kind = new ArrayBuffer(4);
|
||||
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: [(0, import_utils.hexToBytes)(addr.pubkey)],
|
||||
3: [new Uint8Array(kind)]
|
||||
});
|
||||
return encodeBech32("naddr", data);
|
||||
}
|
||||
function nrelayEncode(url) {
|
||||
let data = encodeTLV({
|
||||
0: [utf8Encoder.encode(url)]
|
||||
});
|
||||
return encodeBech32("nrelay", data);
|
||||
}
|
||||
function encodeTLV(tlv) {
|
||||
let entries = [];
|
||||
Object.entries(tlv).forEach(([t, vs]) => {
|
||||
vs.forEach((v) => {
|
||||
let entry = new Uint8Array(v.length + 2);
|
||||
entry.set([parseInt(t)], 0);
|
||||
entry.set([v.length], 1);
|
||||
entry.set(v, 2);
|
||||
entries.push(entry);
|
||||
});
|
||||
});
|
||||
return (0, import_utils.concatBytes)(...entries);
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-149
@@ -1,149 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip21.ts
|
||||
var nip21_exports = {};
|
||||
__export(nip21_exports, {
|
||||
NOSTR_URI_REGEX: () => NOSTR_URI_REGEX,
|
||||
parse: () => parse,
|
||||
test: () => test
|
||||
});
|
||||
module.exports = __toCommonJS(nip21_exports);
|
||||
|
||||
// nip19.ts
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
var import_base = require("@scure/base");
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// nip19.ts
|
||||
var Bech32MaxSize = 5e3;
|
||||
var BECH32_REGEX = /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/;
|
||||
function decode(nip19) {
|
||||
let { prefix, words } = import_base.bech32.decode(nip19, Bech32MaxSize);
|
||||
let data = new Uint8Array(import_base.bech32.fromWords(words));
|
||||
switch (prefix) {
|
||||
case "nprofile": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nprofile");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
return {
|
||||
type: "nprofile",
|
||||
data: {
|
||||
pubkey: (0, import_utils.bytesToHex)(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nevent": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nevent");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
if (tlv[2] && tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (tlv[3] && tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "nevent",
|
||||
data: {
|
||||
id: (0, import_utils.bytesToHex)(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],
|
||||
author: tlv[2]?.[0] ? (0, import_utils.bytesToHex)(tlv[2][0]) : void 0,
|
||||
kind: tlv[3]?.[0] ? parseInt((0, import_utils.bytesToHex)(tlv[3][0]), 16) : void 0
|
||||
}
|
||||
};
|
||||
}
|
||||
case "naddr": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for naddr");
|
||||
if (!tlv[2]?.[0])
|
||||
throw new Error("missing TLV 2 for naddr");
|
||||
if (tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (!tlv[3]?.[0])
|
||||
throw new Error("missing TLV 3 for naddr");
|
||||
if (tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "naddr",
|
||||
data: {
|
||||
identifier: utf8Decoder.decode(tlv[0][0]),
|
||||
pubkey: (0, import_utils.bytesToHex)(tlv[2][0]),
|
||||
kind: parseInt((0, import_utils.bytesToHex)(tlv[3][0]), 16),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nrelay": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nrelay");
|
||||
return {
|
||||
type: "nrelay",
|
||||
data: utf8Decoder.decode(tlv[0][0])
|
||||
};
|
||||
}
|
||||
case "nsec":
|
||||
case "npub":
|
||||
case "note":
|
||||
return { type: prefix, data: (0, import_utils.bytesToHex)(data) };
|
||||
default:
|
||||
throw new Error(`unknown prefix ${prefix}`);
|
||||
}
|
||||
}
|
||||
function parseTLV(data) {
|
||||
let result = {};
|
||||
let rest = data;
|
||||
while (rest.length > 0) {
|
||||
let t = rest[0];
|
||||
let l = rest[1];
|
||||
if (!l)
|
||||
throw new Error(`malformed TLV ${t}`);
|
||||
let v = rest.slice(2, 2 + l);
|
||||
rest = rest.slice(2 + l);
|
||||
if (v.length < l)
|
||||
throw new Error(`not enough data to read on TLV ${t}`);
|
||||
result[t] = result[t] || [];
|
||||
result[t].push(v);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// nip21.ts
|
||||
var NOSTR_URI_REGEX = new RegExp(`nostr:(${BECH32_REGEX.source})`);
|
||||
function test(value) {
|
||||
return typeof value === "string" && new RegExp(`^${NOSTR_URI_REGEX.source}$`).test(value);
|
||||
}
|
||||
function parse(uri) {
|
||||
const match = uri.match(new RegExp(`^${NOSTR_URI_REGEX.source}$`));
|
||||
if (!match)
|
||||
throw new Error(`Invalid Nostr URI: ${uri}`);
|
||||
return {
|
||||
uri: match[0],
|
||||
value: match[1],
|
||||
decoded: decode(match[1])
|
||||
};
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-131
@@ -1,131 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip25.ts
|
||||
var nip25_exports = {};
|
||||
__export(nip25_exports, {
|
||||
finishReactionEvent: () => finishReactionEvent,
|
||||
getReactedEventPointer: () => getReactedEventPointer
|
||||
});
|
||||
module.exports = __toCommonJS(nip25_exports);
|
||||
|
||||
// event.ts
|
||||
var import_secp256k12 = require("@noble/curves/secp256k1");
|
||||
var import_sha256 = require("@noble/hashes/sha256");
|
||||
var import_utils2 = require("@noble/hashes/utils");
|
||||
|
||||
// keys.ts
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
function getPublicKey(privateKey) {
|
||||
return (0, import_utils.bytesToHex)(import_secp256k1.schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function finishEvent(t, privateKey) {
|
||||
const event = t;
|
||||
event.pubkey = getPublicKey(privateKey);
|
||||
event.id = getEventHash(event);
|
||||
event.sig = getSignature(event, privateKey);
|
||||
event[verifiedSymbol] = true;
|
||||
return event;
|
||||
}
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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)));
|
||||
return (0, import_utils2.bytesToHex)(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function getSignature(event, key) {
|
||||
return (0, import_utils2.bytesToHex)(import_secp256k12.schnorr.sign(getEventHash(event), key));
|
||||
}
|
||||
|
||||
// nip25.ts
|
||||
function finishReactionEvent(t, reacted, privateKey) {
|
||||
const inheritedTags = reacted.tags.filter((tag) => tag.length >= 2 && (tag[0] === "e" || tag[0] === "p"));
|
||||
return finishEvent(
|
||||
{
|
||||
...t,
|
||||
kind: 7 /* Reaction */,
|
||||
tags: [...t.tags ?? [], ...inheritedTags, ["e", reacted.id], ["p", reacted.pubkey]],
|
||||
content: t.content ?? "+"
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
}
|
||||
function getReactedEventPointer(event) {
|
||||
if (event.kind !== 7 /* Reaction */) {
|
||||
return void 0;
|
||||
}
|
||||
let lastETag;
|
||||
let lastPTag;
|
||||
for (let i = event.tags.length - 1; i >= 0 && (lastETag === void 0 || lastPTag === void 0); i--) {
|
||||
const tag = event.tags[i];
|
||||
if (tag.length >= 2) {
|
||||
if (tag[0] === "e" && lastETag === void 0) {
|
||||
lastETag = tag;
|
||||
} else if (tag[0] === "p" && lastPTag === void 0) {
|
||||
lastPTag = tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastETag === void 0 || lastPTag === void 0) {
|
||||
return void 0;
|
||||
}
|
||||
return {
|
||||
id: lastETag[1],
|
||||
relays: [lastETag[2], lastPTag[2]].filter((x) => x !== void 0),
|
||||
author: lastPTag[1]
|
||||
};
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-86
@@ -1,86 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip26.ts
|
||||
var nip26_exports = {};
|
||||
__export(nip26_exports, {
|
||||
createDelegation: () => createDelegation,
|
||||
getDelegator: () => getDelegator
|
||||
});
|
||||
module.exports = __toCommonJS(nip26_exports);
|
||||
var import_secp256k12 = require("@noble/curves/secp256k1");
|
||||
var import_utils2 = require("@noble/hashes/utils");
|
||||
var import_sha256 = require("@noble/hashes/sha256");
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// keys.ts
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
function getPublicKey(privateKey) {
|
||||
return (0, import_utils.bytesToHex)(import_secp256k1.schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
|
||||
// nip26.ts
|
||||
function createDelegation(privateKey, parameters) {
|
||||
let conditions = [];
|
||||
if ((parameters.kind || -1) >= 0)
|
||||
conditions.push(`kind=${parameters.kind}`);
|
||||
if (parameters.until)
|
||||
conditions.push(`created_at<${parameters.until}`);
|
||||
if (parameters.since)
|
||||
conditions.push(`created_at>${parameters.since}`);
|
||||
let cond = conditions.join("&");
|
||||
if (cond === "")
|
||||
throw new Error("refusing to create a delegation without any conditions");
|
||||
let sighash = (0, import_sha256.sha256)(utf8Encoder.encode(`nostr:delegation:${parameters.pubkey}:${cond}`));
|
||||
let sig = (0, import_utils2.bytesToHex)(import_secp256k12.schnorr.sign(sighash, privateKey));
|
||||
return {
|
||||
from: getPublicKey(privateKey),
|
||||
to: parameters.pubkey,
|
||||
cond,
|
||||
sig
|
||||
};
|
||||
}
|
||||
function getDelegator(event) {
|
||||
let tag = event.tags.find((tag2) => tag2[0] === "delegation" && tag2.length >= 4);
|
||||
if (!tag)
|
||||
return null;
|
||||
let pubkey = tag[1];
|
||||
let cond = tag[2];
|
||||
let sig = tag[3];
|
||||
let conditions = cond.split("&");
|
||||
for (let i = 0; i < conditions.length; i++) {
|
||||
let [key, operator, value] = conditions[i].split(/\b/);
|
||||
if (key === "kind" && operator === "=" && event.kind === parseInt(value))
|
||||
continue;
|
||||
else if (key === "created_at" && operator === "<" && event.created_at < parseInt(value))
|
||||
continue;
|
||||
else if (key === "created_at" && operator === ">" && event.created_at > parseInt(value))
|
||||
continue;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
let sighash = (0, import_sha256.sha256)(utf8Encoder.encode(`nostr:delegation:${event.pubkey}:${cond}`));
|
||||
if (!import_secp256k12.schnorr.verify(sig, sighash, pubkey))
|
||||
return null;
|
||||
return pubkey;
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-164
@@ -1,164 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip27.ts
|
||||
var nip27_exports = {};
|
||||
__export(nip27_exports, {
|
||||
matchAll: () => matchAll,
|
||||
regex: () => regex,
|
||||
replaceAll: () => replaceAll
|
||||
});
|
||||
module.exports = __toCommonJS(nip27_exports);
|
||||
|
||||
// nip19.ts
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
var import_base = require("@scure/base");
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// nip19.ts
|
||||
var Bech32MaxSize = 5e3;
|
||||
var BECH32_REGEX = /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/;
|
||||
function decode(nip19) {
|
||||
let { prefix, words } = import_base.bech32.decode(nip19, Bech32MaxSize);
|
||||
let data = new Uint8Array(import_base.bech32.fromWords(words));
|
||||
switch (prefix) {
|
||||
case "nprofile": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nprofile");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
return {
|
||||
type: "nprofile",
|
||||
data: {
|
||||
pubkey: (0, import_utils.bytesToHex)(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nevent": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nevent");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
if (tlv[2] && tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (tlv[3] && tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "nevent",
|
||||
data: {
|
||||
id: (0, import_utils.bytesToHex)(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],
|
||||
author: tlv[2]?.[0] ? (0, import_utils.bytesToHex)(tlv[2][0]) : void 0,
|
||||
kind: tlv[3]?.[0] ? parseInt((0, import_utils.bytesToHex)(tlv[3][0]), 16) : void 0
|
||||
}
|
||||
};
|
||||
}
|
||||
case "naddr": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for naddr");
|
||||
if (!tlv[2]?.[0])
|
||||
throw new Error("missing TLV 2 for naddr");
|
||||
if (tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (!tlv[3]?.[0])
|
||||
throw new Error("missing TLV 3 for naddr");
|
||||
if (tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "naddr",
|
||||
data: {
|
||||
identifier: utf8Decoder.decode(tlv[0][0]),
|
||||
pubkey: (0, import_utils.bytesToHex)(tlv[2][0]),
|
||||
kind: parseInt((0, import_utils.bytesToHex)(tlv[3][0]), 16),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nrelay": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nrelay");
|
||||
return {
|
||||
type: "nrelay",
|
||||
data: utf8Decoder.decode(tlv[0][0])
|
||||
};
|
||||
}
|
||||
case "nsec":
|
||||
case "npub":
|
||||
case "note":
|
||||
return { type: prefix, data: (0, import_utils.bytesToHex)(data) };
|
||||
default:
|
||||
throw new Error(`unknown prefix ${prefix}`);
|
||||
}
|
||||
}
|
||||
function parseTLV(data) {
|
||||
let result = {};
|
||||
let rest = data;
|
||||
while (rest.length > 0) {
|
||||
let t = rest[0];
|
||||
let l = rest[1];
|
||||
if (!l)
|
||||
throw new Error(`malformed TLV ${t}`);
|
||||
let v = rest.slice(2, 2 + l);
|
||||
rest = rest.slice(2 + l);
|
||||
if (v.length < l)
|
||||
throw new Error(`not enough data to read on TLV ${t}`);
|
||||
result[t] = result[t] || [];
|
||||
result[t].push(v);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// nip21.ts
|
||||
var NOSTR_URI_REGEX = new RegExp(`nostr:(${BECH32_REGEX.source})`);
|
||||
|
||||
// nip27.ts
|
||||
var regex = () => new RegExp(`\\b${NOSTR_URI_REGEX.source}\\b`, "g");
|
||||
function* matchAll(content) {
|
||||
const matches = content.matchAll(regex());
|
||||
for (const match of matches) {
|
||||
try {
|
||||
const [uri, value] = match;
|
||||
yield {
|
||||
uri,
|
||||
value,
|
||||
decoded: decode(value),
|
||||
start: match.index,
|
||||
end: match.index + uri.length
|
||||
};
|
||||
} catch (_e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
function replaceAll(content, replacer) {
|
||||
return content.replaceAll(regex(), (uri, value) => {
|
||||
return replacer({
|
||||
uri,
|
||||
value,
|
||||
decoded: decode(value)
|
||||
});
|
||||
});
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-188
@@ -1,188 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip28.ts
|
||||
var nip28_exports = {};
|
||||
__export(nip28_exports, {
|
||||
channelCreateEvent: () => channelCreateEvent,
|
||||
channelHideMessageEvent: () => channelHideMessageEvent,
|
||||
channelMessageEvent: () => channelMessageEvent,
|
||||
channelMetadataEvent: () => channelMetadataEvent,
|
||||
channelMuteUserEvent: () => channelMuteUserEvent
|
||||
});
|
||||
module.exports = __toCommonJS(nip28_exports);
|
||||
|
||||
// event.ts
|
||||
var import_secp256k12 = require("@noble/curves/secp256k1");
|
||||
var import_sha256 = require("@noble/hashes/sha256");
|
||||
var import_utils2 = require("@noble/hashes/utils");
|
||||
|
||||
// keys.ts
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
function getPublicKey(privateKey) {
|
||||
return (0, import_utils.bytesToHex)(import_secp256k1.schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function finishEvent(t, privateKey) {
|
||||
const event = t;
|
||||
event.pubkey = getPublicKey(privateKey);
|
||||
event.id = getEventHash(event);
|
||||
event.sig = getSignature(event, privateKey);
|
||||
event[verifiedSymbol] = true;
|
||||
return event;
|
||||
}
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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)));
|
||||
return (0, import_utils2.bytesToHex)(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function getSignature(event, key) {
|
||||
return (0, import_utils2.bytesToHex)(import_secp256k12.schnorr.sign(getEventHash(event), key));
|
||||
}
|
||||
|
||||
// nip28.ts
|
||||
var channelCreateEvent = (t, privateKey) => {
|
||||
let content;
|
||||
if (typeof t.content === "object") {
|
||||
content = JSON.stringify(t.content);
|
||||
} else if (typeof t.content === "string") {
|
||||
content = t.content;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
return finishEvent(
|
||||
{
|
||||
kind: 40 /* ChannelCreation */,
|
||||
tags: [...t.tags ?? []],
|
||||
content,
|
||||
created_at: t.created_at
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
};
|
||||
var channelMetadataEvent = (t, privateKey) => {
|
||||
let content;
|
||||
if (typeof t.content === "object") {
|
||||
content = JSON.stringify(t.content);
|
||||
} else if (typeof t.content === "string") {
|
||||
content = t.content;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
return finishEvent(
|
||||
{
|
||||
kind: 41 /* ChannelMetadata */,
|
||||
tags: [["e", t.channel_create_event_id], ...t.tags ?? []],
|
||||
content,
|
||||
created_at: t.created_at
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
};
|
||||
var channelMessageEvent = (t, privateKey) => {
|
||||
const tags = [["e", t.channel_create_event_id, t.relay_url, "root"]];
|
||||
if (t.reply_to_channel_message_event_id) {
|
||||
tags.push(["e", t.reply_to_channel_message_event_id, t.relay_url, "reply"]);
|
||||
}
|
||||
return finishEvent(
|
||||
{
|
||||
kind: 42 /* ChannelMessage */,
|
||||
tags: [...tags, ...t.tags ?? []],
|
||||
content: t.content,
|
||||
created_at: t.created_at
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
};
|
||||
var channelHideMessageEvent = (t, privateKey) => {
|
||||
let content;
|
||||
if (typeof t.content === "object") {
|
||||
content = JSON.stringify(t.content);
|
||||
} else if (typeof t.content === "string") {
|
||||
content = t.content;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
return finishEvent(
|
||||
{
|
||||
kind: 43 /* ChannelHideMessage */,
|
||||
tags: [["e", t.channel_message_event_id], ...t.tags ?? []],
|
||||
content,
|
||||
created_at: t.created_at
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
};
|
||||
var channelMuteUserEvent = (t, privateKey) => {
|
||||
let content;
|
||||
if (typeof t.content === "object") {
|
||||
content = JSON.stringify(t.content);
|
||||
} else if (typeof t.content === "string") {
|
||||
content = t.content;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
return finishEvent(
|
||||
{
|
||||
kind: 44 /* ChannelMuteUser */,
|
||||
tags: [["p", t.pubkey_to_mute], ...t.tags ?? []],
|
||||
content,
|
||||
created_at: t.created_at
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
};
|
||||
-7
File diff suppressed because one or more lines are too long
-42
@@ -1,42 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip39.ts
|
||||
var nip39_exports = {};
|
||||
__export(nip39_exports, {
|
||||
useFetchImplementation: () => useFetchImplementation,
|
||||
validateGithub: () => validateGithub
|
||||
});
|
||||
module.exports = __toCommonJS(nip39_exports);
|
||||
var _fetch;
|
||||
try {
|
||||
_fetch = fetch;
|
||||
} catch {
|
||||
}
|
||||
function useFetchImplementation(fetchImplementation) {
|
||||
_fetch = fetchImplementation;
|
||||
}
|
||||
async function validateGithub(pubkey, username, proof) {
|
||||
try {
|
||||
let res = await (await _fetch(`https://gist.github.com/${username}/${proof}/raw`)).text();
|
||||
return res === `Verifying that I control the following Nostr public key: ${pubkey}`;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../nip39.ts"],
|
||||
"sourcesContent": ["var _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any) {\n _fetch = fetchImplementation\n}\n\nexport async function validateGithub(pubkey: string, username: string, proof: string): Promise<boolean> {\n try {\n let res = await (await _fetch(`https://gist.github.com/${username}/${proof}/raw`)).text()\n return res === `Verifying that I control the following Nostr public key: ${pubkey}`\n } catch (_) {\n return false\n }\n}\n"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAI;AAEJ,IAAI;AACF,WAAS;AACX,QAAE;AAAO;AAEF,SAAS,uBAAuB,qBAA0B;AAC/D,WAAS;AACX;AAEA,eAAsB,eAAe,QAAgB,UAAkB,OAAiC;AACtG,MAAI;AACF,QAAI,MAAM,OAAO,MAAM,OAAO,2BAA2B,YAAY,WAAW,GAAG,KAAK;AACxF,WAAO,QAAQ,4DAA4D;AAAA,EAC7E,SAAS,GAAP;AACA,WAAO;AAAA,EACT;AACF;",
|
||||
"names": []
|
||||
}
|
||||
-41
@@ -1,41 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip42.ts
|
||||
var nip42_exports = {};
|
||||
__export(nip42_exports, {
|
||||
authenticate: () => authenticate
|
||||
});
|
||||
module.exports = __toCommonJS(nip42_exports);
|
||||
var authenticate = async ({
|
||||
challenge,
|
||||
relay,
|
||||
sign
|
||||
}) => {
|
||||
const e = {
|
||||
kind: 22242 /* ClientAuth */,
|
||||
created_at: Math.floor(Date.now() / 1e3),
|
||||
tags: [
|
||||
["relay", relay.url],
|
||||
["challenge", challenge]
|
||||
],
|
||||
content: ""
|
||||
};
|
||||
return relay.auth(await sign(e));
|
||||
};
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../nip42.ts"],
|
||||
"sourcesContent": ["import { Kind, type EventTemplate, type Event } from './event.ts'\nimport { Relay } from './relay.ts'\n\n/**\n * Authenticate via NIP-42 flow.\n *\n * @example\n * const sign = window.nostr.signEvent\n * relay.on('auth', challenge =>\n * authenticate({ relay, sign, challenge })\n * )\n */\nexport const authenticate = async ({\n challenge,\n relay,\n sign,\n}: {\n challenge: string\n relay: Relay\n sign: <K extends number = number>(e: EventTemplate<K>) => Promise<Event<K>> | Event<K>\n}): Promise<void> => {\n const e: EventTemplate = {\n kind: Kind.ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relay.url],\n ['challenge', challenge],\n ],\n content: '',\n }\n return relay.auth(await sign(e))\n}\n"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAYO,IAAM,eAAe,OAAO;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AACF,MAIqB;AACnB,QAAM,IAAmB;AAAA,IACvB;AAAA,IACA,YAAY,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAAA,IACxC,MAAM;AAAA,MACJ,CAAC,SAAS,MAAM,GAAG;AAAA,MACnB,CAAC,aAAa,SAAS;AAAA,IACzB;AAAA,IACA,SAAS;AAAA,EACX;AACA,SAAO,MAAM,KAAK,MAAM,KAAK,CAAC,CAAC;AACjC;",
|
||||
"names": []
|
||||
}
|
||||
-126
@@ -1,126 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip44.ts
|
||||
var nip44_exports = {};
|
||||
__export(nip44_exports, {
|
||||
decrypt: () => decrypt,
|
||||
encrypt: () => encrypt,
|
||||
utils: () => utils
|
||||
});
|
||||
module.exports = __toCommonJS(nip44_exports);
|
||||
var import_chacha = require("@noble/ciphers/chacha");
|
||||
var import_utils = 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_utils2 = require("@noble/hashes/utils");
|
||||
var import_base = require("@scure/base");
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// nip44.ts
|
||||
var utils = {
|
||||
v2: {
|
||||
maxPlaintextSize: 65536 - 128,
|
||||
minCiphertextSize: 100,
|
||||
maxCiphertextSize: 102400,
|
||||
getConversationKey(privkeyA, pubkeyB) {
|
||||
const key = import_secp256k1.secp256k1.getSharedSecret(privkeyA, "02" + pubkeyB);
|
||||
return key.subarray(1, 33);
|
||||
},
|
||||
getMessageKeys(conversationKey, salt) {
|
||||
const keys = (0, import_hkdf.hkdf)(import_sha256.sha256, conversationKey, salt, "nip44-v2", 76);
|
||||
return {
|
||||
encryption: keys.subarray(0, 32),
|
||||
nonce: keys.subarray(32, 44),
|
||||
auth: keys.subarray(44, 76)
|
||||
};
|
||||
},
|
||||
calcPadding(len) {
|
||||
if (!Number.isSafeInteger(len) || len < 0)
|
||||
throw new Error("expected positive integer");
|
||||
if (len <= 32)
|
||||
return 32;
|
||||
const nextpower = 1 << Math.floor(Math.log2(len - 1)) + 1;
|
||||
const chunk = nextpower <= 256 ? 32 : nextpower / 8;
|
||||
return chunk * (Math.floor((len - 1) / chunk) + 1);
|
||||
},
|
||||
pad(unpadded) {
|
||||
const unpaddedB = utf8Encoder.encode(unpadded);
|
||||
const len = unpaddedB.length;
|
||||
if (len < 1 || len >= utils.v2.maxPlaintextSize)
|
||||
throw new Error("invalid plaintext length: must be between 1b and 64KB");
|
||||
const paddedLen = utils.v2.calcPadding(len);
|
||||
const zeros = new Uint8Array(paddedLen - len);
|
||||
const lenBuf = new Uint8Array(2);
|
||||
new DataView(lenBuf.buffer).setUint16(0, len);
|
||||
return (0, import_utils2.concatBytes)(lenBuf, unpaddedB, zeros);
|
||||
},
|
||||
unpad(padded) {
|
||||
const unpaddedLen = new DataView(padded.buffer).getUint16(0);
|
||||
const unpadded = padded.subarray(2, 2 + unpaddedLen);
|
||||
if (unpaddedLen === 0 || unpadded.length !== unpaddedLen || padded.length !== 2 + utils.v2.calcPadding(unpaddedLen))
|
||||
throw new Error("invalid padding");
|
||||
return utf8Decoder.decode(unpadded);
|
||||
}
|
||||
}
|
||||
};
|
||||
function encrypt(key, plaintext, options = {}) {
|
||||
const version = options.version ?? 2;
|
||||
if (version !== 2)
|
||||
throw new Error("unknown encryption version " + version);
|
||||
const salt = options.salt ?? (0, import_utils2.randomBytes)(32);
|
||||
(0, import_utils.ensureBytes)(salt, 32);
|
||||
const keys = utils.v2.getMessageKeys(key, salt);
|
||||
const padded = utils.v2.pad(plaintext);
|
||||
const ciphertext = (0, import_chacha.chacha20)(keys.encryption, keys.nonce, padded);
|
||||
const mac = (0, import_hmac.hmac)(import_sha256.sha256, keys.auth, ciphertext);
|
||||
return import_base.base64.encode((0, import_utils2.concatBytes)(new Uint8Array([version]), salt, ciphertext, mac));
|
||||
}
|
||||
function decrypt(key, ciphertext) {
|
||||
const u = utils.v2;
|
||||
(0, import_utils.ensureBytes)(key, 32);
|
||||
const clen = ciphertext.length;
|
||||
if (clen < u.minCiphertextSize || clen >= u.maxCiphertextSize)
|
||||
throw new Error("invalid ciphertext length: " + clen);
|
||||
if (ciphertext[0] === "#")
|
||||
throw new Error("unknown encryption version");
|
||||
let data;
|
||||
try {
|
||||
data = import_base.base64.decode(ciphertext);
|
||||
} catch (error) {
|
||||
throw new Error("invalid base64: " + error.message);
|
||||
}
|
||||
const vers = data.subarray(0, 1)[0];
|
||||
if (vers !== 2)
|
||||
throw new Error("unknown encryption version " + vers);
|
||||
const salt = data.subarray(1, 33);
|
||||
const ciphertext_ = data.subarray(33, -32);
|
||||
const mac = data.subarray(-32);
|
||||
const keys = u.getMessageKeys(key, salt);
|
||||
const calculatedMac = (0, import_hmac.hmac)(import_sha256.sha256, keys.auth, ciphertext_);
|
||||
if (!(0, import_utils.equalBytes)(calculatedMac, mac))
|
||||
throw new Error("invalid MAC");
|
||||
const padded = (0, import_chacha.chacha20)(keys.encryption, keys.nonce, ciphertext_);
|
||||
return u.unpad(padded);
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-146
@@ -1,146 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip47.ts
|
||||
var nip47_exports = {};
|
||||
__export(nip47_exports, {
|
||||
makeNwcRequestEvent: () => makeNwcRequestEvent,
|
||||
parseConnectionString: () => parseConnectionString
|
||||
});
|
||||
module.exports = __toCommonJS(nip47_exports);
|
||||
|
||||
// event.ts
|
||||
var import_secp256k12 = require("@noble/curves/secp256k1");
|
||||
var import_sha256 = require("@noble/hashes/sha256");
|
||||
var import_utils2 = require("@noble/hashes/utils");
|
||||
|
||||
// keys.ts
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
function getPublicKey(privateKey) {
|
||||
return (0, import_utils.bytesToHex)(import_secp256k1.schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function finishEvent(t, privateKey) {
|
||||
const event = t;
|
||||
event.pubkey = getPublicKey(privateKey);
|
||||
event.id = getEventHash(event);
|
||||
event.sig = getSignature(event, privateKey);
|
||||
event[verifiedSymbol] = true;
|
||||
return event;
|
||||
}
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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)));
|
||||
return (0, import_utils2.bytesToHex)(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function getSignature(event, key) {
|
||||
return (0, import_utils2.bytesToHex)(import_secp256k12.schnorr.sign(getEventHash(event), key));
|
||||
}
|
||||
|
||||
// nip04.ts
|
||||
var import_utils4 = require("@noble/hashes/utils");
|
||||
var import_secp256k13 = require("@noble/curves/secp256k1");
|
||||
var import_base = require("@scure/base");
|
||||
if (typeof crypto !== "undefined" && !crypto.subtle && crypto.webcrypto) {
|
||||
crypto.subtle = crypto.webcrypto.subtle;
|
||||
}
|
||||
async function encrypt(privkey, pubkey, text) {
|
||||
const key = import_secp256k13.secp256k1.getSharedSecret(privkey, "02" + pubkey);
|
||||
const normalizedKey = getNormalizedX(key);
|
||||
let iv = Uint8Array.from((0, import_utils4.randomBytes)(16));
|
||||
let plaintext = utf8Encoder.encode(text);
|
||||
let cryptoKey = await crypto.subtle.importKey("raw", normalizedKey, { name: "AES-CBC" }, false, ["encrypt"]);
|
||||
let ciphertext = await crypto.subtle.encrypt({ name: "AES-CBC", iv }, cryptoKey, plaintext);
|
||||
let ctb64 = import_base.base64.encode(new Uint8Array(ciphertext));
|
||||
let ivb64 = import_base.base64.encode(new Uint8Array(iv.buffer));
|
||||
return `${ctb64}?iv=${ivb64}`;
|
||||
}
|
||||
function getNormalizedX(key) {
|
||||
return key.slice(1, 33);
|
||||
}
|
||||
|
||||
// nip47.ts
|
||||
function parseConnectionString(connectionString) {
|
||||
const { pathname, searchParams } = new URL(connectionString);
|
||||
const pubkey = pathname;
|
||||
const relay = searchParams.get("relay");
|
||||
const secret = searchParams.get("secret");
|
||||
if (!pubkey || !relay || !secret) {
|
||||
throw new Error("invalid connection string");
|
||||
}
|
||||
return { pubkey, relay, secret };
|
||||
}
|
||||
async function makeNwcRequestEvent({
|
||||
pubkey,
|
||||
secret,
|
||||
invoice
|
||||
}) {
|
||||
const content = {
|
||||
method: "pay_invoice",
|
||||
params: {
|
||||
invoice
|
||||
}
|
||||
};
|
||||
const encryptedContent = await encrypt(secret, pubkey, JSON.stringify(content));
|
||||
const eventTemplate = {
|
||||
kind: 23194 /* NwcRequest */,
|
||||
created_at: Math.round(Date.now() / 1e3),
|
||||
content: encryptedContent,
|
||||
tags: [["p", pubkey]]
|
||||
};
|
||||
return finishEvent(eventTemplate, secret);
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-193
@@ -1,193 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip57.ts
|
||||
var nip57_exports = {};
|
||||
__export(nip57_exports, {
|
||||
getZapEndpoint: () => getZapEndpoint,
|
||||
makeZapReceipt: () => makeZapReceipt,
|
||||
makeZapRequest: () => makeZapRequest,
|
||||
useFetchImplementation: () => useFetchImplementation,
|
||||
validateZapRequest: () => validateZapRequest
|
||||
});
|
||||
module.exports = __toCommonJS(nip57_exports);
|
||||
var import_base = require("@scure/base");
|
||||
|
||||
// event.ts
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_sha256 = require("@noble/hashes/sha256");
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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)));
|
||||
return (0, import_utils.bytesToHex)(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function verifySignature(event) {
|
||||
if (typeof event[verifiedSymbol] === "boolean")
|
||||
return event[verifiedSymbol];
|
||||
const hash = getEventHash(event);
|
||||
if (hash !== event.id) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
try {
|
||||
return event[verifiedSymbol] = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
|
||||
} catch (err) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// nip57.ts
|
||||
var _fetch;
|
||||
try {
|
||||
_fetch = fetch;
|
||||
} catch {
|
||||
}
|
||||
function useFetchImplementation(fetchImplementation) {
|
||||
_fetch = fetchImplementation;
|
||||
}
|
||||
async function getZapEndpoint(metadata) {
|
||||
try {
|
||||
let lnurl = "";
|
||||
let { lud06, lud16 } = JSON.parse(metadata.content);
|
||||
if (lud06) {
|
||||
let { words } = import_base.bech32.decode(lud06, 1e3);
|
||||
let data = import_base.bech32.fromWords(words);
|
||||
lnurl = utf8Decoder.decode(data);
|
||||
} else if (lud16) {
|
||||
let [name, domain] = lud16.split("@");
|
||||
lnurl = `https://${domain}/.well-known/lnurlp/${name}`;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
let res = await _fetch(lnurl);
|
||||
let body = await res.json();
|
||||
if (body.allowsNostr && body.nostrPubkey) {
|
||||
return body.callback;
|
||||
}
|
||||
} catch (err) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function makeZapRequest({
|
||||
profile,
|
||||
event,
|
||||
amount,
|
||||
relays,
|
||||
comment = ""
|
||||
}) {
|
||||
if (!amount)
|
||||
throw new Error("amount not given");
|
||||
if (!profile)
|
||||
throw new Error("profile not given");
|
||||
let zr = {
|
||||
kind: 9734,
|
||||
created_at: Math.round(Date.now() / 1e3),
|
||||
content: comment,
|
||||
tags: [
|
||||
["p", profile],
|
||||
["amount", amount.toString()],
|
||||
["relays", ...relays]
|
||||
]
|
||||
};
|
||||
if (event) {
|
||||
zr.tags.push(["e", event]);
|
||||
}
|
||||
return zr;
|
||||
}
|
||||
function validateZapRequest(zapRequestString) {
|
||||
let zapRequest;
|
||||
try {
|
||||
zapRequest = JSON.parse(zapRequestString);
|
||||
} catch (err) {
|
||||
return "Invalid zap request JSON.";
|
||||
}
|
||||
if (!validateEvent(zapRequest))
|
||||
return "Zap request is not a valid Nostr event.";
|
||||
if (!verifySignature(zapRequest))
|
||||
return "Invalid signature on zap request.";
|
||||
let p = zapRequest.tags.find(([t, v]) => t === "p" && v);
|
||||
if (!p)
|
||||
return "Zap request doesn't have a 'p' tag.";
|
||||
if (!p[1].match(/^[a-f0-9]{64}$/))
|
||||
return "Zap request 'p' tag is not valid hex.";
|
||||
let e = zapRequest.tags.find(([t, v]) => t === "e" && v);
|
||||
if (e && !e[1].match(/^[a-f0-9]{64}$/))
|
||||
return "Zap request 'e' tag is not valid hex.";
|
||||
let relays = zapRequest.tags.find(([t, v]) => t === "relays" && v);
|
||||
if (!relays)
|
||||
return "Zap request doesn't have a 'relays' tag.";
|
||||
return null;
|
||||
}
|
||||
function makeZapReceipt({
|
||||
zapRequest,
|
||||
preimage,
|
||||
bolt11,
|
||||
paidAt
|
||||
}) {
|
||||
let zr = JSON.parse(zapRequest);
|
||||
let tagsFromZapRequest = zr.tags.filter(([t]) => t === "e" || t === "p" || t === "a");
|
||||
let zap = {
|
||||
kind: 9735,
|
||||
created_at: Math.round(paidAt.getTime() / 1e3),
|
||||
content: "",
|
||||
tags: [...tagsFromZapRequest, ["bolt11", bolt11], ["description", zapRequest]]
|
||||
};
|
||||
if (preimage) {
|
||||
zap.tags.push(["preimage", preimage]);
|
||||
}
|
||||
return zap;
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-161
@@ -1,161 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// nip98.ts
|
||||
var nip98_exports = {};
|
||||
__export(nip98_exports, {
|
||||
getToken: () => getToken,
|
||||
unpackEventFromToken: () => unpackEventFromToken,
|
||||
validateEvent: () => validateEvent2,
|
||||
validateToken: () => validateToken
|
||||
});
|
||||
module.exports = __toCommonJS(nip98_exports);
|
||||
var import_base = require("@scure/base");
|
||||
|
||||
// event.ts
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_sha256 = require("@noble/hashes/sha256");
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function getBlankEvent(kind = 255 /* Blank */) {
|
||||
return {
|
||||
kind,
|
||||
content: "",
|
||||
tags: [],
|
||||
created_at: 0
|
||||
};
|
||||
}
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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)));
|
||||
return (0, import_utils.bytesToHex)(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function verifySignature(event) {
|
||||
if (typeof event[verifiedSymbol] === "boolean")
|
||||
return event[verifiedSymbol];
|
||||
const hash = getEventHash(event);
|
||||
if (hash !== event.id) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
try {
|
||||
return event[verifiedSymbol] = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
|
||||
} catch (err) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// nip98.ts
|
||||
var _authorizationScheme = "Nostr ";
|
||||
async function getToken(loginUrl, httpMethod, sign, includeAuthorizationScheme = false) {
|
||||
if (!loginUrl || !httpMethod)
|
||||
throw new Error("Missing loginUrl or httpMethod");
|
||||
const event = getBlankEvent(27235 /* HttpAuth */);
|
||||
event.tags = [
|
||||
["u", loginUrl],
|
||||
["method", httpMethod]
|
||||
];
|
||||
event.created_at = Math.round(new Date().getTime() / 1e3);
|
||||
const signedEvent = await sign(event);
|
||||
const authorizationScheme = includeAuthorizationScheme ? _authorizationScheme : "";
|
||||
return authorizationScheme + import_base.base64.encode(utf8Encoder.encode(JSON.stringify(signedEvent)));
|
||||
}
|
||||
async function validateToken(token, url, method) {
|
||||
const event = await unpackEventFromToken(token).catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
const valid = await validateEvent2(event, url, method).catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
return valid;
|
||||
}
|
||||
async function unpackEventFromToken(token) {
|
||||
if (!token) {
|
||||
throw new Error("Missing token");
|
||||
}
|
||||
token = token.replace(_authorizationScheme, "");
|
||||
const eventB64 = utf8Decoder.decode(import_base.base64.decode(token));
|
||||
if (!eventB64 || eventB64.length === 0 || !eventB64.startsWith("{")) {
|
||||
throw new Error("Invalid token");
|
||||
}
|
||||
const event = JSON.parse(eventB64);
|
||||
return event;
|
||||
}
|
||||
async function validateEvent2(event, url, method) {
|
||||
if (!event) {
|
||||
throw new Error("Invalid nostr event");
|
||||
}
|
||||
if (!verifySignature(event)) {
|
||||
throw new Error("Invalid nostr event, signature invalid");
|
||||
}
|
||||
if (event.kind !== 27235 /* HttpAuth */) {
|
||||
throw new Error("Invalid nostr event, kind invalid");
|
||||
}
|
||||
if (!event.created_at) {
|
||||
throw new Error("Invalid nostr event, created_at invalid");
|
||||
}
|
||||
if (Math.round(new Date().getTime() / 1e3) - event.created_at > 60) {
|
||||
throw new Error("Invalid nostr event, expired");
|
||||
}
|
||||
const urlTag = event.tags.find((t) => t[0] === "u");
|
||||
if (urlTag?.length !== 1 && urlTag?.[1] !== url) {
|
||||
throw new Error("Invalid nostr event, url tag invalid");
|
||||
}
|
||||
const methodTag = event.tags.find((t) => t[0] === "method");
|
||||
if (methodTag?.length !== 1 && methodTag?.[1].toLowerCase() !== method.toLowerCase()) {
|
||||
throw new Error("Invalid nostr event, method tag invalid");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-747
@@ -1,747 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// pool.ts
|
||||
var pool_exports = {};
|
||||
__export(pool_exports, {
|
||||
SimplePool: () => SimplePool
|
||||
});
|
||||
module.exports = __toCommonJS(pool_exports);
|
||||
|
||||
// event.ts
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_sha256 = require("@noble/hashes/sha256");
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
function normalizeURL(url) {
|
||||
let p = new URL(url);
|
||||
p.pathname = p.pathname.replace(/\/+/g, "/");
|
||||
if (p.pathname.endsWith("/"))
|
||||
p.pathname = p.pathname.slice(0, -1);
|
||||
if (p.port === "80" && p.protocol === "ws:" || p.port === "443" && p.protocol === "wss:")
|
||||
p.port = "";
|
||||
p.searchParams.sort();
|
||||
p.hash = "";
|
||||
return p.toString();
|
||||
}
|
||||
var MessageNode = class {
|
||||
_value;
|
||||
_next;
|
||||
get value() {
|
||||
return this._value;
|
||||
}
|
||||
set value(message) {
|
||||
this._value = message;
|
||||
}
|
||||
get next() {
|
||||
return this._next;
|
||||
}
|
||||
set next(node) {
|
||||
this._next = node;
|
||||
}
|
||||
constructor(message) {
|
||||
this._value = message;
|
||||
this._next = null;
|
||||
}
|
||||
};
|
||||
var MessageQueue = class {
|
||||
_first;
|
||||
_last;
|
||||
get first() {
|
||||
return this._first;
|
||||
}
|
||||
set first(messageNode) {
|
||||
this._first = messageNode;
|
||||
}
|
||||
get last() {
|
||||
return this._last;
|
||||
}
|
||||
set last(messageNode) {
|
||||
this._last = messageNode;
|
||||
}
|
||||
_size;
|
||||
get size() {
|
||||
return this._size;
|
||||
}
|
||||
set size(v) {
|
||||
this._size = v;
|
||||
}
|
||||
constructor() {
|
||||
this._first = null;
|
||||
this._last = null;
|
||||
this._size = 0;
|
||||
}
|
||||
enqueue(message) {
|
||||
const newNode = new MessageNode(message);
|
||||
if (this._size === 0 || !this._last) {
|
||||
this._first = newNode;
|
||||
this._last = newNode;
|
||||
} else {
|
||||
this._last.next = newNode;
|
||||
this._last = newNode;
|
||||
}
|
||||
this._size++;
|
||||
return true;
|
||||
}
|
||||
dequeue() {
|
||||
if (this._size === 0 || !this._first)
|
||||
return null;
|
||||
let prev = this._first;
|
||||
this._first = prev.next;
|
||||
prev.next = null;
|
||||
this._size--;
|
||||
return prev.value;
|
||||
}
|
||||
};
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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)));
|
||||
return (0, import_utils.bytesToHex)(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function verifySignature(event) {
|
||||
if (typeof event[verifiedSymbol] === "boolean")
|
||||
return event[verifiedSymbol];
|
||||
const hash = getEventHash(event);
|
||||
if (hash !== event.id) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
try {
|
||||
return event[verifiedSymbol] = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
|
||||
} catch (err) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// filter.ts
|
||||
function matchFilter(filter, event) {
|
||||
if (filter.ids && filter.ids.indexOf(event.id) === -1) {
|
||||
if (!filter.ids.some((prefix) => event.id.startsWith(prefix))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (filter.kinds && filter.kinds.indexOf(event.kind) === -1)
|
||||
return false;
|
||||
if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {
|
||||
if (!filter.authors.some((prefix) => event.pubkey.startsWith(prefix))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (let f in filter) {
|
||||
if (f[0] === "#") {
|
||||
let tagName = f.slice(1);
|
||||
let values = filter[`#${tagName}`];
|
||||
if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values.indexOf(v) !== -1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (filter.since && event.created_at < filter.since)
|
||||
return false;
|
||||
if (filter.until && event.created_at > filter.until)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
function matchFilters(filters, event) {
|
||||
for (let i = 0; i < filters.length; i++) {
|
||||
if (matchFilter(filters[i], event))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function mergeFilters(...filters) {
|
||||
let result = {};
|
||||
for (let i = 0; i < filters.length; i++) {
|
||||
let filter = filters[i];
|
||||
Object.entries(filter).forEach(([property, values]) => {
|
||||
if (property === "kinds" || property === "ids" || property === "authors" || property[0] === "#") {
|
||||
result[property] = result[property] || [];
|
||||
for (let v = 0; v < values.length; v++) {
|
||||
let value = values[v];
|
||||
if (!result[property].includes(value))
|
||||
result[property].push(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (filter.limit && (!result.limit || filter.limit > result.limit))
|
||||
result.limit = filter.limit;
|
||||
if (filter.until && (!result.until || filter.until > result.until))
|
||||
result.until = filter.until;
|
||||
if (filter.since && (!result.since || filter.since < result.since))
|
||||
result.since = filter.since;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// fakejson.ts
|
||||
function getHex64(json, field) {
|
||||
let len = field.length + 3;
|
||||
let idx = json.indexOf(`"${field}":`) + len;
|
||||
let s = json.slice(idx).indexOf(`"`) + idx + 1;
|
||||
return json.slice(s, s + 64);
|
||||
}
|
||||
function getSubscriptionId(json) {
|
||||
let idx = json.slice(0, 22).indexOf(`"EVENT"`);
|
||||
if (idx === -1)
|
||||
return null;
|
||||
let pstart = json.slice(idx + 7 + 1).indexOf(`"`);
|
||||
if (pstart === -1)
|
||||
return null;
|
||||
let start = idx + 7 + 1 + pstart;
|
||||
let pend = json.slice(start + 1, 80).indexOf(`"`);
|
||||
if (pend === -1)
|
||||
return null;
|
||||
let end = start + 1 + pend;
|
||||
return json.slice(start + 1, end);
|
||||
}
|
||||
|
||||
// relay.ts
|
||||
var newListeners = () => ({
|
||||
connect: [],
|
||||
disconnect: [],
|
||||
error: [],
|
||||
notice: [],
|
||||
auth: []
|
||||
});
|
||||
function relayInit(url, options = {}) {
|
||||
let { listTimeout = 3e3, getTimeout = 3e3, countTimeout = 3e3 } = options;
|
||||
var ws;
|
||||
var openSubs = {};
|
||||
var listeners = newListeners();
|
||||
var subListeners = {};
|
||||
var pubListeners = {};
|
||||
var connectionPromise;
|
||||
async function connectRelay() {
|
||||
if (connectionPromise)
|
||||
return connectionPromise;
|
||||
connectionPromise = new Promise((resolve, reject) => {
|
||||
try {
|
||||
ws = new WebSocket(url);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
ws.onopen = () => {
|
||||
listeners.connect.forEach((cb) => cb());
|
||||
resolve();
|
||||
};
|
||||
ws.onerror = () => {
|
||||
connectionPromise = void 0;
|
||||
listeners.error.forEach((cb) => cb());
|
||||
reject();
|
||||
};
|
||||
ws.onclose = async () => {
|
||||
connectionPromise = void 0;
|
||||
listeners.disconnect.forEach((cb) => cb());
|
||||
};
|
||||
let incomingMessageQueue = new MessageQueue();
|
||||
let handleNextInterval;
|
||||
ws.onmessage = (e) => {
|
||||
incomingMessageQueue.enqueue(e.data);
|
||||
if (!handleNextInterval) {
|
||||
handleNextInterval = setInterval(handleNext, 0);
|
||||
}
|
||||
};
|
||||
function handleNext() {
|
||||
if (incomingMessageQueue.size === 0) {
|
||||
clearInterval(handleNextInterval);
|
||||
handleNextInterval = null;
|
||||
return;
|
||||
}
|
||||
var json = incomingMessageQueue.dequeue();
|
||||
if (!json)
|
||||
return;
|
||||
let subid = getSubscriptionId(json);
|
||||
if (subid) {
|
||||
let so = openSubs[subid];
|
||||
if (so && so.alreadyHaveEvent && so.alreadyHaveEvent(getHex64(json, "id"), url)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
let data = JSON.parse(json);
|
||||
switch (data[0]) {
|
||||
case "EVENT": {
|
||||
let id2 = data[1];
|
||||
let event = data[2];
|
||||
if (validateEvent(event) && openSubs[id2] && (openSubs[id2].skipVerification || verifySignature(event)) && matchFilters(openSubs[id2].filters, event)) {
|
||||
openSubs[id2];
|
||||
(subListeners[id2]?.event || []).forEach((cb) => cb(event));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "COUNT":
|
||||
let id = data[1];
|
||||
let payload = data[2];
|
||||
if (openSubs[id]) {
|
||||
;
|
||||
(subListeners[id]?.count || []).forEach((cb) => cb(payload));
|
||||
}
|
||||
return;
|
||||
case "EOSE": {
|
||||
let id2 = data[1];
|
||||
if (id2 in subListeners) {
|
||||
subListeners[id2].eose.forEach((cb) => cb());
|
||||
subListeners[id2].eose = [];
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "OK": {
|
||||
let id2 = data[1];
|
||||
let ok = data[2];
|
||||
let reason = data[3] || "";
|
||||
if (id2 in pubListeners) {
|
||||
let { resolve: resolve2, reject: reject2 } = pubListeners[id2];
|
||||
if (ok)
|
||||
resolve2(null);
|
||||
else
|
||||
reject2(new Error(reason));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "NOTICE":
|
||||
let notice = data[1];
|
||||
listeners.notice.forEach((cb) => cb(notice));
|
||||
return;
|
||||
case "AUTH": {
|
||||
let challenge = data[1];
|
||||
listeners.auth?.forEach((cb) => cb(challenge));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
return connectionPromise;
|
||||
}
|
||||
function connected() {
|
||||
return ws?.readyState === 1;
|
||||
}
|
||||
async function connect() {
|
||||
if (connected())
|
||||
return;
|
||||
await connectRelay();
|
||||
}
|
||||
async function trySend(params) {
|
||||
let msg = JSON.stringify(params);
|
||||
if (!connected()) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
||||
if (!connected()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
ws.send(msg);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
const sub = (filters, {
|
||||
verb = "REQ",
|
||||
skipVerification = false,
|
||||
alreadyHaveEvent = null,
|
||||
id = Math.random().toString().slice(2)
|
||||
} = {}) => {
|
||||
let subid = id;
|
||||
openSubs[subid] = {
|
||||
id: subid,
|
||||
filters,
|
||||
skipVerification,
|
||||
alreadyHaveEvent
|
||||
};
|
||||
trySend([verb, subid, ...filters]);
|
||||
let subscription = {
|
||||
sub: (newFilters, newOpts = {}) => sub(newFilters || filters, {
|
||||
skipVerification: newOpts.skipVerification || skipVerification,
|
||||
alreadyHaveEvent: newOpts.alreadyHaveEvent || alreadyHaveEvent,
|
||||
id: subid
|
||||
}),
|
||||
unsub: () => {
|
||||
delete openSubs[subid];
|
||||
delete subListeners[subid];
|
||||
trySend(["CLOSE", subid]);
|
||||
},
|
||||
on: (type, cb) => {
|
||||
subListeners[subid] = subListeners[subid] || {
|
||||
event: [],
|
||||
count: [],
|
||||
eose: []
|
||||
};
|
||||
subListeners[subid][type].push(cb);
|
||||
},
|
||||
off: (type, cb) => {
|
||||
let listeners2 = subListeners[subid];
|
||||
let idx = listeners2[type].indexOf(cb);
|
||||
if (idx >= 0)
|
||||
listeners2[type].splice(idx, 1);
|
||||
},
|
||||
get events() {
|
||||
return eventsGenerator(subscription);
|
||||
}
|
||||
};
|
||||
return subscription;
|
||||
};
|
||||
function _publishEvent(event, type) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!event.id) {
|
||||
reject(new Error(`event ${event} has no id`));
|
||||
return;
|
||||
}
|
||||
let id = event.id;
|
||||
trySend([type, event]);
|
||||
pubListeners[id] = { resolve, reject };
|
||||
});
|
||||
}
|
||||
return {
|
||||
url,
|
||||
sub,
|
||||
on: (type, cb) => {
|
||||
listeners[type].push(cb);
|
||||
if (type === "connect" && ws?.readyState === 1) {
|
||||
;
|
||||
cb();
|
||||
}
|
||||
},
|
||||
off: (type, cb) => {
|
||||
let index = listeners[type].indexOf(cb);
|
||||
if (index !== -1)
|
||||
listeners[type].splice(index, 1);
|
||||
},
|
||||
list: (filters, opts) => new Promise((resolve) => {
|
||||
let s = sub(filters, opts);
|
||||
let events = [];
|
||||
let timeout = setTimeout(() => {
|
||||
s.unsub();
|
||||
resolve(events);
|
||||
}, listTimeout);
|
||||
s.on("eose", () => {
|
||||
s.unsub();
|
||||
clearTimeout(timeout);
|
||||
resolve(events);
|
||||
});
|
||||
s.on("event", (event) => {
|
||||
events.push(event);
|
||||
});
|
||||
}),
|
||||
get: (filter, opts) => new Promise((resolve) => {
|
||||
let s = sub([filter], opts);
|
||||
let timeout = setTimeout(() => {
|
||||
s.unsub();
|
||||
resolve(null);
|
||||
}, getTimeout);
|
||||
s.on("event", (event) => {
|
||||
s.unsub();
|
||||
clearTimeout(timeout);
|
||||
resolve(event);
|
||||
});
|
||||
}),
|
||||
count: (filters) => new Promise((resolve) => {
|
||||
let s = sub(filters, { ...sub, verb: "COUNT" });
|
||||
let timeout = setTimeout(() => {
|
||||
s.unsub();
|
||||
resolve(null);
|
||||
}, countTimeout);
|
||||
s.on("count", (event) => {
|
||||
s.unsub();
|
||||
clearTimeout(timeout);
|
||||
resolve(event);
|
||||
});
|
||||
}),
|
||||
async publish(event) {
|
||||
await _publishEvent(event, "EVENT");
|
||||
},
|
||||
async auth(event) {
|
||||
await _publishEvent(event, "AUTH");
|
||||
},
|
||||
connect,
|
||||
close() {
|
||||
listeners = newListeners();
|
||||
subListeners = {};
|
||||
pubListeners = {};
|
||||
if (ws?.readyState === WebSocket.OPEN) {
|
||||
ws.close();
|
||||
}
|
||||
},
|
||||
get status() {
|
||||
return ws?.readyState ?? 3;
|
||||
}
|
||||
};
|
||||
}
|
||||
async function* eventsGenerator(sub) {
|
||||
let nextResolve;
|
||||
const eventQueue = [];
|
||||
const pushToQueue = (event) => {
|
||||
if (nextResolve) {
|
||||
nextResolve(event);
|
||||
nextResolve = void 0;
|
||||
} else {
|
||||
eventQueue.push(event);
|
||||
}
|
||||
};
|
||||
sub.on("event", pushToQueue);
|
||||
try {
|
||||
while (true) {
|
||||
if (eventQueue.length > 0) {
|
||||
yield eventQueue.shift();
|
||||
} else {
|
||||
const event = await new Promise((resolve) => {
|
||||
nextResolve = resolve;
|
||||
});
|
||||
yield event;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
sub.off("event", pushToQueue);
|
||||
}
|
||||
}
|
||||
|
||||
// pool.ts
|
||||
var SimplePool = class {
|
||||
_conn;
|
||||
_seenOn = {};
|
||||
batchedByKey = {};
|
||||
eoseSubTimeout;
|
||||
getTimeout;
|
||||
seenOnEnabled = true;
|
||||
batchInterval = 100;
|
||||
constructor(options = {}) {
|
||||
this._conn = {};
|
||||
this.eoseSubTimeout = options.eoseSubTimeout || 3400;
|
||||
this.getTimeout = options.getTimeout || 3400;
|
||||
this.seenOnEnabled = options.seenOnEnabled !== false;
|
||||
this.batchInterval = options.batchInterval || 100;
|
||||
}
|
||||
close(relays) {
|
||||
relays.forEach((url) => {
|
||||
let relay = this._conn[normalizeURL(url)];
|
||||
if (relay)
|
||||
relay.close();
|
||||
});
|
||||
}
|
||||
async ensureRelay(url) {
|
||||
const nm = normalizeURL(url);
|
||||
if (!this._conn[nm]) {
|
||||
this._conn[nm] = relayInit(nm, {
|
||||
getTimeout: this.getTimeout * 0.9,
|
||||
listTimeout: this.getTimeout * 0.9
|
||||
});
|
||||
}
|
||||
const relay = this._conn[nm];
|
||||
await relay.connect();
|
||||
return relay;
|
||||
}
|
||||
sub(relays, filters, opts) {
|
||||
let _knownIds = /* @__PURE__ */ new Set();
|
||||
let modifiedOpts = { ...opts || {} };
|
||||
modifiedOpts.alreadyHaveEvent = (id, url) => {
|
||||
if (opts?.alreadyHaveEvent?.(id, url)) {
|
||||
return true;
|
||||
}
|
||||
if (this.seenOnEnabled) {
|
||||
let set = this._seenOn[id] || /* @__PURE__ */ new Set();
|
||||
set.add(url);
|
||||
this._seenOn[id] = set;
|
||||
}
|
||||
return _knownIds.has(id);
|
||||
};
|
||||
let subs = [];
|
||||
let eventListeners = /* @__PURE__ */ new Set();
|
||||
let eoseListeners = /* @__PURE__ */ new Set();
|
||||
let eosesMissing = relays.length;
|
||||
let eoseSent = false;
|
||||
let eoseTimeout = setTimeout(
|
||||
() => {
|
||||
eoseSent = true;
|
||||
for (let cb of eoseListeners.values())
|
||||
cb();
|
||||
},
|
||||
opts?.eoseSubTimeout || this.eoseSubTimeout
|
||||
);
|
||||
relays.filter((r, i, a) => a.indexOf(r) === i).forEach(async (relay) => {
|
||||
let r;
|
||||
try {
|
||||
r = await this.ensureRelay(relay);
|
||||
} catch (err) {
|
||||
handleEose();
|
||||
return;
|
||||
}
|
||||
if (!r)
|
||||
return;
|
||||
let s = r.sub(filters, modifiedOpts);
|
||||
s.on("event", (event) => {
|
||||
_knownIds.add(event.id);
|
||||
for (let cb of eventListeners.values())
|
||||
cb(event);
|
||||
});
|
||||
s.on("eose", () => {
|
||||
if (eoseSent)
|
||||
return;
|
||||
handleEose();
|
||||
});
|
||||
subs.push(s);
|
||||
function handleEose() {
|
||||
eosesMissing--;
|
||||
if (eosesMissing === 0) {
|
||||
clearTimeout(eoseTimeout);
|
||||
for (let cb of eoseListeners.values())
|
||||
cb();
|
||||
}
|
||||
}
|
||||
});
|
||||
let greaterSub = {
|
||||
sub(filters2, opts2) {
|
||||
subs.forEach((sub) => sub.sub(filters2, opts2));
|
||||
return greaterSub;
|
||||
},
|
||||
unsub() {
|
||||
subs.forEach((sub) => sub.unsub());
|
||||
},
|
||||
on(type, cb) {
|
||||
if (type === "event") {
|
||||
eventListeners.add(cb);
|
||||
} else if (type === "eose") {
|
||||
eoseListeners.add(cb);
|
||||
}
|
||||
},
|
||||
off(type, cb) {
|
||||
if (type === "event") {
|
||||
eventListeners.delete(cb);
|
||||
} else if (type === "eose")
|
||||
eoseListeners.delete(cb);
|
||||
},
|
||||
get events() {
|
||||
return eventsGenerator(greaterSub);
|
||||
}
|
||||
};
|
||||
return greaterSub;
|
||||
}
|
||||
get(relays, filter, opts) {
|
||||
return new Promise((resolve) => {
|
||||
let sub = this.sub(relays, [filter], opts);
|
||||
let timeout = setTimeout(() => {
|
||||
sub.unsub();
|
||||
resolve(null);
|
||||
}, this.getTimeout);
|
||||
sub.on("event", (event) => {
|
||||
resolve(event);
|
||||
clearTimeout(timeout);
|
||||
sub.unsub();
|
||||
});
|
||||
});
|
||||
}
|
||||
list(relays, filters, opts) {
|
||||
return new Promise((resolve) => {
|
||||
let events = [];
|
||||
let sub = this.sub(relays, filters, opts);
|
||||
sub.on("event", (event) => {
|
||||
events.push(event);
|
||||
});
|
||||
sub.on("eose", () => {
|
||||
sub.unsub();
|
||||
resolve(events);
|
||||
});
|
||||
});
|
||||
}
|
||||
batchedList(batchKey, relays, filters) {
|
||||
return new Promise((resolve) => {
|
||||
if (!this.batchedByKey[batchKey]) {
|
||||
this.batchedByKey[batchKey] = [
|
||||
{
|
||||
filters,
|
||||
relays,
|
||||
resolve,
|
||||
events: []
|
||||
}
|
||||
];
|
||||
setTimeout(() => {
|
||||
Object.keys(this.batchedByKey).forEach(async (batchKey2) => {
|
||||
const batchedRequests = this.batchedByKey[batchKey2];
|
||||
const filters2 = [];
|
||||
const relays2 = [];
|
||||
batchedRequests.forEach((br) => {
|
||||
filters2.push(...br.filters);
|
||||
relays2.push(...br.relays);
|
||||
});
|
||||
const sub = this.sub(relays2, [mergeFilters(...filters2)]);
|
||||
sub.on("event", (event) => {
|
||||
batchedRequests.forEach((br) => matchFilters(br.filters, event) && br.events.push(event));
|
||||
});
|
||||
sub.on("eose", () => {
|
||||
sub.unsub();
|
||||
batchedRequests.forEach((br) => br.resolve(br.events));
|
||||
});
|
||||
delete this.batchedByKey[batchKey2];
|
||||
});
|
||||
}, this.batchInterval);
|
||||
} else {
|
||||
this.batchedByKey[batchKey].push({
|
||||
filters,
|
||||
relays,
|
||||
resolve,
|
||||
events: []
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
publish(relays, event) {
|
||||
return relays.map(async (relay) => {
|
||||
let r = await this.ensureRelay(relay);
|
||||
return r.publish(event);
|
||||
});
|
||||
}
|
||||
seenOn(id) {
|
||||
return Array.from(this._seenOn[id]?.values?.() || []);
|
||||
}
|
||||
};
|
||||
-7
File diff suppressed because one or more lines are too long
-219
@@ -1,219 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// references.ts
|
||||
var references_exports = {};
|
||||
__export(references_exports, {
|
||||
parseReferences: () => parseReferences
|
||||
});
|
||||
module.exports = __toCommonJS(references_exports);
|
||||
|
||||
// nip19.ts
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
var import_base = require("@scure/base");
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// nip19.ts
|
||||
var Bech32MaxSize = 5e3;
|
||||
function decode(nip19) {
|
||||
let { prefix, words } = import_base.bech32.decode(nip19, Bech32MaxSize);
|
||||
let data = new Uint8Array(import_base.bech32.fromWords(words));
|
||||
switch (prefix) {
|
||||
case "nprofile": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nprofile");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
return {
|
||||
type: "nprofile",
|
||||
data: {
|
||||
pubkey: (0, import_utils.bytesToHex)(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nevent": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nevent");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
if (tlv[2] && tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (tlv[3] && tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "nevent",
|
||||
data: {
|
||||
id: (0, import_utils.bytesToHex)(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],
|
||||
author: tlv[2]?.[0] ? (0, import_utils.bytesToHex)(tlv[2][0]) : void 0,
|
||||
kind: tlv[3]?.[0] ? parseInt((0, import_utils.bytesToHex)(tlv[3][0]), 16) : void 0
|
||||
}
|
||||
};
|
||||
}
|
||||
case "naddr": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for naddr");
|
||||
if (!tlv[2]?.[0])
|
||||
throw new Error("missing TLV 2 for naddr");
|
||||
if (tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (!tlv[3]?.[0])
|
||||
throw new Error("missing TLV 3 for naddr");
|
||||
if (tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "naddr",
|
||||
data: {
|
||||
identifier: utf8Decoder.decode(tlv[0][0]),
|
||||
pubkey: (0, import_utils.bytesToHex)(tlv[2][0]),
|
||||
kind: parseInt((0, import_utils.bytesToHex)(tlv[3][0]), 16),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nrelay": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nrelay");
|
||||
return {
|
||||
type: "nrelay",
|
||||
data: utf8Decoder.decode(tlv[0][0])
|
||||
};
|
||||
}
|
||||
case "nsec":
|
||||
case "npub":
|
||||
case "note":
|
||||
return { type: prefix, data: (0, import_utils.bytesToHex)(data) };
|
||||
default:
|
||||
throw new Error(`unknown prefix ${prefix}`);
|
||||
}
|
||||
}
|
||||
function parseTLV(data) {
|
||||
let result = {};
|
||||
let rest = data;
|
||||
while (rest.length > 0) {
|
||||
let t = rest[0];
|
||||
let l = rest[1];
|
||||
if (!l)
|
||||
throw new Error(`malformed TLV ${t}`);
|
||||
let v = rest.slice(2, 2 + l);
|
||||
rest = rest.slice(2 + l);
|
||||
if (v.length < l)
|
||||
throw new Error(`not enough data to read on TLV ${t}`);
|
||||
result[t] = result[t] || [];
|
||||
result[t].push(v);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// references.ts
|
||||
var mentionRegex = /\bnostr:((note|npub|naddr|nevent|nprofile)1\w+)\b|#\[(\d+)\]/g;
|
||||
function parseReferences(evt) {
|
||||
let references = [];
|
||||
for (let ref of evt.content.matchAll(mentionRegex)) {
|
||||
if (ref[2]) {
|
||||
try {
|
||||
let { type, data } = decode(ref[1]);
|
||||
switch (type) {
|
||||
case "npub": {
|
||||
references.push({
|
||||
text: ref[0],
|
||||
profile: { pubkey: data, relays: [] }
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "nprofile": {
|
||||
references.push({
|
||||
text: ref[0],
|
||||
profile: data
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "note": {
|
||||
references.push({
|
||||
text: ref[0],
|
||||
event: { id: data, relays: [] }
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "nevent": {
|
||||
references.push({
|
||||
text: ref[0],
|
||||
event: data
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "naddr": {
|
||||
references.push({
|
||||
text: ref[0],
|
||||
address: data
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
}
|
||||
} else if (ref[3]) {
|
||||
let idx = parseInt(ref[3], 10);
|
||||
let tag = evt.tags[idx];
|
||||
if (!tag)
|
||||
continue;
|
||||
switch (tag[0]) {
|
||||
case "p": {
|
||||
references.push({
|
||||
text: ref[0],
|
||||
profile: { pubkey: tag[1], relays: tag[2] ? [tag[2]] : [] }
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "e": {
|
||||
references.push({
|
||||
text: ref[0],
|
||||
event: { id: tag[1], relays: tag[2] ? [tag[2]] : [] }
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "a": {
|
||||
try {
|
||||
let [kind, pubkey, identifier] = tag[1].split(":");
|
||||
references.push({
|
||||
text: ref[0],
|
||||
address: {
|
||||
identifier,
|
||||
pubkey,
|
||||
kind: parseInt(kind, 10),
|
||||
relays: tag[2] ? [tag[2]] : []
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return references;
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-515
@@ -1,515 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// relay.ts
|
||||
var relay_exports = {};
|
||||
__export(relay_exports, {
|
||||
eventsGenerator: () => eventsGenerator,
|
||||
relayInit: () => relayInit
|
||||
});
|
||||
module.exports = __toCommonJS(relay_exports);
|
||||
|
||||
// event.ts
|
||||
var import_secp256k1 = require("@noble/curves/secp256k1");
|
||||
var import_sha256 = require("@noble/hashes/sha256");
|
||||
var import_utils = require("@noble/hashes/utils");
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
var MessageNode = class {
|
||||
_value;
|
||||
_next;
|
||||
get value() {
|
||||
return this._value;
|
||||
}
|
||||
set value(message) {
|
||||
this._value = message;
|
||||
}
|
||||
get next() {
|
||||
return this._next;
|
||||
}
|
||||
set next(node) {
|
||||
this._next = node;
|
||||
}
|
||||
constructor(message) {
|
||||
this._value = message;
|
||||
this._next = null;
|
||||
}
|
||||
};
|
||||
var MessageQueue = class {
|
||||
_first;
|
||||
_last;
|
||||
get first() {
|
||||
return this._first;
|
||||
}
|
||||
set first(messageNode) {
|
||||
this._first = messageNode;
|
||||
}
|
||||
get last() {
|
||||
return this._last;
|
||||
}
|
||||
set last(messageNode) {
|
||||
this._last = messageNode;
|
||||
}
|
||||
_size;
|
||||
get size() {
|
||||
return this._size;
|
||||
}
|
||||
set size(v) {
|
||||
this._size = v;
|
||||
}
|
||||
constructor() {
|
||||
this._first = null;
|
||||
this._last = null;
|
||||
this._size = 0;
|
||||
}
|
||||
enqueue(message) {
|
||||
const newNode = new MessageNode(message);
|
||||
if (this._size === 0 || !this._last) {
|
||||
this._first = newNode;
|
||||
this._last = newNode;
|
||||
} else {
|
||||
this._last.next = newNode;
|
||||
this._last = newNode;
|
||||
}
|
||||
this._size++;
|
||||
return true;
|
||||
}
|
||||
dequeue() {
|
||||
if (this._size === 0 || !this._first)
|
||||
return null;
|
||||
let prev = this._first;
|
||||
this._first = prev.next;
|
||||
prev.next = null;
|
||||
this._size--;
|
||||
return prev.value;
|
||||
}
|
||||
};
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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)));
|
||||
return (0, import_utils.bytesToHex)(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function verifySignature(event) {
|
||||
if (typeof event[verifiedSymbol] === "boolean")
|
||||
return event[verifiedSymbol];
|
||||
const hash = getEventHash(event);
|
||||
if (hash !== event.id) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
try {
|
||||
return event[verifiedSymbol] = import_secp256k1.schnorr.verify(event.sig, hash, event.pubkey);
|
||||
} catch (err) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
}
|
||||
|
||||
// filter.ts
|
||||
function matchFilter(filter, event) {
|
||||
if (filter.ids && filter.ids.indexOf(event.id) === -1) {
|
||||
if (!filter.ids.some((prefix) => event.id.startsWith(prefix))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (filter.kinds && filter.kinds.indexOf(event.kind) === -1)
|
||||
return false;
|
||||
if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {
|
||||
if (!filter.authors.some((prefix) => event.pubkey.startsWith(prefix))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (let f in filter) {
|
||||
if (f[0] === "#") {
|
||||
let tagName = f.slice(1);
|
||||
let values = filter[`#${tagName}`];
|
||||
if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values.indexOf(v) !== -1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (filter.since && event.created_at < filter.since)
|
||||
return false;
|
||||
if (filter.until && event.created_at > filter.until)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
function matchFilters(filters, event) {
|
||||
for (let i = 0; i < filters.length; i++) {
|
||||
if (matchFilter(filters[i], event))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// fakejson.ts
|
||||
function getHex64(json, field) {
|
||||
let len = field.length + 3;
|
||||
let idx = json.indexOf(`"${field}":`) + len;
|
||||
let s = json.slice(idx).indexOf(`"`) + idx + 1;
|
||||
return json.slice(s, s + 64);
|
||||
}
|
||||
function getSubscriptionId(json) {
|
||||
let idx = json.slice(0, 22).indexOf(`"EVENT"`);
|
||||
if (idx === -1)
|
||||
return null;
|
||||
let pstart = json.slice(idx + 7 + 1).indexOf(`"`);
|
||||
if (pstart === -1)
|
||||
return null;
|
||||
let start = idx + 7 + 1 + pstart;
|
||||
let pend = json.slice(start + 1, 80).indexOf(`"`);
|
||||
if (pend === -1)
|
||||
return null;
|
||||
let end = start + 1 + pend;
|
||||
return json.slice(start + 1, end);
|
||||
}
|
||||
|
||||
// relay.ts
|
||||
var newListeners = () => ({
|
||||
connect: [],
|
||||
disconnect: [],
|
||||
error: [],
|
||||
notice: [],
|
||||
auth: []
|
||||
});
|
||||
function relayInit(url, options = {}) {
|
||||
let { listTimeout = 3e3, getTimeout = 3e3, countTimeout = 3e3 } = options;
|
||||
var ws;
|
||||
var openSubs = {};
|
||||
var listeners = newListeners();
|
||||
var subListeners = {};
|
||||
var pubListeners = {};
|
||||
var connectionPromise;
|
||||
async function connectRelay() {
|
||||
if (connectionPromise)
|
||||
return connectionPromise;
|
||||
connectionPromise = new Promise((resolve, reject) => {
|
||||
try {
|
||||
ws = new WebSocket(url);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
ws.onopen = () => {
|
||||
listeners.connect.forEach((cb) => cb());
|
||||
resolve();
|
||||
};
|
||||
ws.onerror = () => {
|
||||
connectionPromise = void 0;
|
||||
listeners.error.forEach((cb) => cb());
|
||||
reject();
|
||||
};
|
||||
ws.onclose = async () => {
|
||||
connectionPromise = void 0;
|
||||
listeners.disconnect.forEach((cb) => cb());
|
||||
};
|
||||
let incomingMessageQueue = new MessageQueue();
|
||||
let handleNextInterval;
|
||||
ws.onmessage = (e) => {
|
||||
incomingMessageQueue.enqueue(e.data);
|
||||
if (!handleNextInterval) {
|
||||
handleNextInterval = setInterval(handleNext, 0);
|
||||
}
|
||||
};
|
||||
function handleNext() {
|
||||
if (incomingMessageQueue.size === 0) {
|
||||
clearInterval(handleNextInterval);
|
||||
handleNextInterval = null;
|
||||
return;
|
||||
}
|
||||
var json = incomingMessageQueue.dequeue();
|
||||
if (!json)
|
||||
return;
|
||||
let subid = getSubscriptionId(json);
|
||||
if (subid) {
|
||||
let so = openSubs[subid];
|
||||
if (so && so.alreadyHaveEvent && so.alreadyHaveEvent(getHex64(json, "id"), url)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
let data = JSON.parse(json);
|
||||
switch (data[0]) {
|
||||
case "EVENT": {
|
||||
let id2 = data[1];
|
||||
let event = data[2];
|
||||
if (validateEvent(event) && openSubs[id2] && (openSubs[id2].skipVerification || verifySignature(event)) && matchFilters(openSubs[id2].filters, event)) {
|
||||
openSubs[id2];
|
||||
(subListeners[id2]?.event || []).forEach((cb) => cb(event));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "COUNT":
|
||||
let id = data[1];
|
||||
let payload = data[2];
|
||||
if (openSubs[id]) {
|
||||
;
|
||||
(subListeners[id]?.count || []).forEach((cb) => cb(payload));
|
||||
}
|
||||
return;
|
||||
case "EOSE": {
|
||||
let id2 = data[1];
|
||||
if (id2 in subListeners) {
|
||||
subListeners[id2].eose.forEach((cb) => cb());
|
||||
subListeners[id2].eose = [];
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "OK": {
|
||||
let id2 = data[1];
|
||||
let ok = data[2];
|
||||
let reason = data[3] || "";
|
||||
if (id2 in pubListeners) {
|
||||
let { resolve: resolve2, reject: reject2 } = pubListeners[id2];
|
||||
if (ok)
|
||||
resolve2(null);
|
||||
else
|
||||
reject2(new Error(reason));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case "NOTICE":
|
||||
let notice = data[1];
|
||||
listeners.notice.forEach((cb) => cb(notice));
|
||||
return;
|
||||
case "AUTH": {
|
||||
let challenge = data[1];
|
||||
listeners.auth?.forEach((cb) => cb(challenge));
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
return connectionPromise;
|
||||
}
|
||||
function connected() {
|
||||
return ws?.readyState === 1;
|
||||
}
|
||||
async function connect() {
|
||||
if (connected())
|
||||
return;
|
||||
await connectRelay();
|
||||
}
|
||||
async function trySend(params) {
|
||||
let msg = JSON.stringify(params);
|
||||
if (!connected()) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
||||
if (!connected()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
ws.send(msg);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
const sub = (filters, {
|
||||
verb = "REQ",
|
||||
skipVerification = false,
|
||||
alreadyHaveEvent = null,
|
||||
id = Math.random().toString().slice(2)
|
||||
} = {}) => {
|
||||
let subid = id;
|
||||
openSubs[subid] = {
|
||||
id: subid,
|
||||
filters,
|
||||
skipVerification,
|
||||
alreadyHaveEvent
|
||||
};
|
||||
trySend([verb, subid, ...filters]);
|
||||
let subscription = {
|
||||
sub: (newFilters, newOpts = {}) => sub(newFilters || filters, {
|
||||
skipVerification: newOpts.skipVerification || skipVerification,
|
||||
alreadyHaveEvent: newOpts.alreadyHaveEvent || alreadyHaveEvent,
|
||||
id: subid
|
||||
}),
|
||||
unsub: () => {
|
||||
delete openSubs[subid];
|
||||
delete subListeners[subid];
|
||||
trySend(["CLOSE", subid]);
|
||||
},
|
||||
on: (type, cb) => {
|
||||
subListeners[subid] = subListeners[subid] || {
|
||||
event: [],
|
||||
count: [],
|
||||
eose: []
|
||||
};
|
||||
subListeners[subid][type].push(cb);
|
||||
},
|
||||
off: (type, cb) => {
|
||||
let listeners2 = subListeners[subid];
|
||||
let idx = listeners2[type].indexOf(cb);
|
||||
if (idx >= 0)
|
||||
listeners2[type].splice(idx, 1);
|
||||
},
|
||||
get events() {
|
||||
return eventsGenerator(subscription);
|
||||
}
|
||||
};
|
||||
return subscription;
|
||||
};
|
||||
function _publishEvent(event, type) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!event.id) {
|
||||
reject(new Error(`event ${event} has no id`));
|
||||
return;
|
||||
}
|
||||
let id = event.id;
|
||||
trySend([type, event]);
|
||||
pubListeners[id] = { resolve, reject };
|
||||
});
|
||||
}
|
||||
return {
|
||||
url,
|
||||
sub,
|
||||
on: (type, cb) => {
|
||||
listeners[type].push(cb);
|
||||
if (type === "connect" && ws?.readyState === 1) {
|
||||
;
|
||||
cb();
|
||||
}
|
||||
},
|
||||
off: (type, cb) => {
|
||||
let index = listeners[type].indexOf(cb);
|
||||
if (index !== -1)
|
||||
listeners[type].splice(index, 1);
|
||||
},
|
||||
list: (filters, opts) => new Promise((resolve) => {
|
||||
let s = sub(filters, opts);
|
||||
let events = [];
|
||||
let timeout = setTimeout(() => {
|
||||
s.unsub();
|
||||
resolve(events);
|
||||
}, listTimeout);
|
||||
s.on("eose", () => {
|
||||
s.unsub();
|
||||
clearTimeout(timeout);
|
||||
resolve(events);
|
||||
});
|
||||
s.on("event", (event) => {
|
||||
events.push(event);
|
||||
});
|
||||
}),
|
||||
get: (filter, opts) => new Promise((resolve) => {
|
||||
let s = sub([filter], opts);
|
||||
let timeout = setTimeout(() => {
|
||||
s.unsub();
|
||||
resolve(null);
|
||||
}, getTimeout);
|
||||
s.on("event", (event) => {
|
||||
s.unsub();
|
||||
clearTimeout(timeout);
|
||||
resolve(event);
|
||||
});
|
||||
}),
|
||||
count: (filters) => new Promise((resolve) => {
|
||||
let s = sub(filters, { ...sub, verb: "COUNT" });
|
||||
let timeout = setTimeout(() => {
|
||||
s.unsub();
|
||||
resolve(null);
|
||||
}, countTimeout);
|
||||
s.on("count", (event) => {
|
||||
s.unsub();
|
||||
clearTimeout(timeout);
|
||||
resolve(event);
|
||||
});
|
||||
}),
|
||||
async publish(event) {
|
||||
await _publishEvent(event, "EVENT");
|
||||
},
|
||||
async auth(event) {
|
||||
await _publishEvent(event, "AUTH");
|
||||
},
|
||||
connect,
|
||||
close() {
|
||||
listeners = newListeners();
|
||||
subListeners = {};
|
||||
pubListeners = {};
|
||||
if (ws?.readyState === WebSocket.OPEN) {
|
||||
ws.close();
|
||||
}
|
||||
},
|
||||
get status() {
|
||||
return ws?.readyState ?? 3;
|
||||
}
|
||||
};
|
||||
}
|
||||
async function* eventsGenerator(sub) {
|
||||
let nextResolve;
|
||||
const eventQueue = [];
|
||||
const pushToQueue = (event) => {
|
||||
if (nextResolve) {
|
||||
nextResolve(event);
|
||||
nextResolve = void 0;
|
||||
} else {
|
||||
eventQueue.push(event);
|
||||
}
|
||||
};
|
||||
sub.on("event", pushToQueue);
|
||||
try {
|
||||
while (true) {
|
||||
if (eventQueue.length > 0) {
|
||||
yield eventQueue.shift();
|
||||
} else {
|
||||
const event = await new Promise((resolve) => {
|
||||
nextResolve = resolve;
|
||||
});
|
||||
yield event;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
sub.off("event", pushToQueue);
|
||||
}
|
||||
}
|
||||
-7
File diff suppressed because one or more lines are too long
-37
@@ -1,37 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// test-helpers.ts
|
||||
var test_helpers_exports = {};
|
||||
__export(test_helpers_exports, {
|
||||
buildEvent: () => buildEvent
|
||||
});
|
||||
module.exports = __toCommonJS(test_helpers_exports);
|
||||
function buildEvent(params) {
|
||||
return {
|
||||
id: "",
|
||||
kind: 1,
|
||||
pubkey: "",
|
||||
created_at: 0,
|
||||
content: "",
|
||||
tags: [],
|
||||
sig: "",
|
||||
...params
|
||||
};
|
||||
}
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../test-helpers.ts"],
|
||||
"sourcesContent": ["import type { Event } from './event.ts'\n\ntype EventParams<K extends number> = Partial<Event<K>>\n\n/** Build an event for testing purposes. */\nexport function buildEvent<K extends number = 1>(params: EventParams<K>): Event<K> {\n return {\n id: '',\n kind: 1 as K,\n pubkey: '',\n created_at: 0,\n content: '',\n tags: [],\n sig: '',\n ...params,\n }\n}\n"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAKO,SAAS,WAAiC,QAAkC;AACjF,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,MAAM,CAAC;AAAA,IACP,KAAK;AAAA,IACL,GAAG;AAAA,EACL;AACF;",
|
||||
"names": []
|
||||
}
|
||||
-177
@@ -1,177 +0,0 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// utils.ts
|
||||
var utils_exports = {};
|
||||
__export(utils_exports, {
|
||||
MessageNode: () => MessageNode,
|
||||
MessageQueue: () => MessageQueue,
|
||||
insertEventIntoAscendingList: () => insertEventIntoAscendingList,
|
||||
insertEventIntoDescendingList: () => insertEventIntoDescendingList,
|
||||
normalizeURL: () => normalizeURL,
|
||||
utf8Decoder: () => utf8Decoder,
|
||||
utf8Encoder: () => utf8Encoder
|
||||
});
|
||||
module.exports = __toCommonJS(utils_exports);
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
function normalizeURL(url) {
|
||||
let p = new URL(url);
|
||||
p.pathname = p.pathname.replace(/\/+/g, "/");
|
||||
if (p.pathname.endsWith("/"))
|
||||
p.pathname = p.pathname.slice(0, -1);
|
||||
if (p.port === "80" && p.protocol === "ws:" || p.port === "443" && p.protocol === "wss:")
|
||||
p.port = "";
|
||||
p.searchParams.sort();
|
||||
p.hash = "";
|
||||
return p.toString();
|
||||
}
|
||||
function insertEventIntoDescendingList(sortedArray, event) {
|
||||
let start = 0;
|
||||
let end = sortedArray.length - 1;
|
||||
let midPoint;
|
||||
let position = start;
|
||||
if (end < 0) {
|
||||
position = 0;
|
||||
} else if (event.created_at < sortedArray[end].created_at) {
|
||||
position = end + 1;
|
||||
} else if (event.created_at >= sortedArray[start].created_at) {
|
||||
position = start;
|
||||
} else
|
||||
while (true) {
|
||||
if (end <= start + 1) {
|
||||
position = end;
|
||||
break;
|
||||
}
|
||||
midPoint = Math.floor(start + (end - start) / 2);
|
||||
if (sortedArray[midPoint].created_at > event.created_at) {
|
||||
start = midPoint;
|
||||
} else if (sortedArray[midPoint].created_at < event.created_at) {
|
||||
end = midPoint;
|
||||
} else {
|
||||
position = midPoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sortedArray[position]?.id !== event.id) {
|
||||
return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)];
|
||||
}
|
||||
return sortedArray;
|
||||
}
|
||||
function insertEventIntoAscendingList(sortedArray, event) {
|
||||
let start = 0;
|
||||
let end = sortedArray.length - 1;
|
||||
let midPoint;
|
||||
let position = start;
|
||||
if (end < 0) {
|
||||
position = 0;
|
||||
} else if (event.created_at > sortedArray[end].created_at) {
|
||||
position = end + 1;
|
||||
} else if (event.created_at <= sortedArray[start].created_at) {
|
||||
position = start;
|
||||
} else
|
||||
while (true) {
|
||||
if (end <= start + 1) {
|
||||
position = end;
|
||||
break;
|
||||
}
|
||||
midPoint = Math.floor(start + (end - start) / 2);
|
||||
if (sortedArray[midPoint].created_at < event.created_at) {
|
||||
start = midPoint;
|
||||
} else if (sortedArray[midPoint].created_at > event.created_at) {
|
||||
end = midPoint;
|
||||
} else {
|
||||
position = midPoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sortedArray[position]?.id !== event.id) {
|
||||
return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)];
|
||||
}
|
||||
return sortedArray;
|
||||
}
|
||||
var MessageNode = class {
|
||||
_value;
|
||||
_next;
|
||||
get value() {
|
||||
return this._value;
|
||||
}
|
||||
set value(message) {
|
||||
this._value = message;
|
||||
}
|
||||
get next() {
|
||||
return this._next;
|
||||
}
|
||||
set next(node) {
|
||||
this._next = node;
|
||||
}
|
||||
constructor(message) {
|
||||
this._value = message;
|
||||
this._next = null;
|
||||
}
|
||||
};
|
||||
var MessageQueue = class {
|
||||
_first;
|
||||
_last;
|
||||
get first() {
|
||||
return this._first;
|
||||
}
|
||||
set first(messageNode) {
|
||||
this._first = messageNode;
|
||||
}
|
||||
get last() {
|
||||
return this._last;
|
||||
}
|
||||
set last(messageNode) {
|
||||
this._last = messageNode;
|
||||
}
|
||||
_size;
|
||||
get size() {
|
||||
return this._size;
|
||||
}
|
||||
set size(v) {
|
||||
this._size = v;
|
||||
}
|
||||
constructor() {
|
||||
this._first = null;
|
||||
this._last = null;
|
||||
this._size = 0;
|
||||
}
|
||||
enqueue(message) {
|
||||
const newNode = new MessageNode(message);
|
||||
if (this._size === 0 || !this._last) {
|
||||
this._first = newNode;
|
||||
this._last = newNode;
|
||||
} else {
|
||||
this._last.next = newNode;
|
||||
this._last = newNode;
|
||||
}
|
||||
this._size++;
|
||||
return true;
|
||||
}
|
||||
dequeue() {
|
||||
if (this._size === 0 || !this._first)
|
||||
return null;
|
||||
let prev = this._first;
|
||||
this._first = prev.next;
|
||||
prev.next = null;
|
||||
this._size--;
|
||||
return prev.value;
|
||||
}
|
||||
};
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../utils.ts"],
|
||||
"sourcesContent": ["import type { Event } from './event.ts'\n\nexport const utf8Decoder = new TextDecoder('utf-8')\nexport const utf8Encoder = new TextEncoder()\n\nexport function normalizeURL(url: string): string {\n let p = new URL(url)\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}\n\n//\n// fast insert-into-sorted-array functions adapted from https://github.com/terrymorse58/fast-sorted-array\n//\nexport function insertEventIntoDescendingList(sortedArray: Event<number>[], event: Event<number>) {\n let start = 0\n let end = sortedArray.length - 1\n let midPoint\n let position = start\n\n if (end < 0) {\n position = 0\n } else if (event.created_at < sortedArray[end].created_at) {\n position = end + 1\n } else if (event.created_at >= sortedArray[start].created_at) {\n position = start\n } else\n while (true) {\n if (end <= start + 1) {\n position = end\n break\n }\n midPoint = Math.floor(start + (end - start) / 2)\n if (sortedArray[midPoint].created_at > event.created_at) {\n start = midPoint\n } else if (sortedArray[midPoint].created_at < event.created_at) {\n end = midPoint\n } else {\n // aMidPoint === num\n position = midPoint\n break\n }\n }\n\n // insert when num is NOT already in (no duplicates)\n if (sortedArray[position]?.id !== event.id) {\n return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)]\n }\n\n return sortedArray\n}\n\nexport function insertEventIntoAscendingList(sortedArray: Event<number>[], event: Event<number>) {\n let start = 0\n let end = sortedArray.length - 1\n let midPoint\n let position = start\n\n if (end < 0) {\n position = 0\n } else if (event.created_at > sortedArray[end].created_at) {\n position = end + 1\n } else if (event.created_at <= sortedArray[start].created_at) {\n position = start\n } else\n while (true) {\n if (end <= start + 1) {\n position = end\n break\n }\n midPoint = Math.floor(start + (end - start) / 2)\n if (sortedArray[midPoint].created_at < event.created_at) {\n start = midPoint\n } else if (sortedArray[midPoint].created_at > event.created_at) {\n end = midPoint\n } else {\n // aMidPoint === num\n position = midPoint\n break\n }\n }\n\n // insert when num is NOT already in (no duplicates)\n if (sortedArray[position]?.id !== event.id) {\n return [...sortedArray.slice(0, position), event, ...sortedArray.slice(position)]\n }\n\n return sortedArray\n}\n\nexport class MessageNode {\n private _value: string\n private _next: MessageNode | null\n\n public get value(): string {\n return this._value\n }\n public set value(message: string) {\n this._value = message\n }\n public get next(): MessageNode | null {\n return this._next\n }\n public set next(node: MessageNode | null) {\n this._next = node\n }\n\n constructor(message: string) {\n this._value = message\n this._next = null\n }\n}\n\nexport class MessageQueue {\n private _first: MessageNode | null\n private _last: MessageNode | null\n\n public get first(): MessageNode | null {\n return this._first\n }\n public set first(messageNode: MessageNode | null) {\n this._first = messageNode\n }\n public get last(): MessageNode | null {\n return this._last\n }\n public set last(messageNode: MessageNode | null) {\n this._last = messageNode\n }\n private _size: number\n public get size(): number {\n return this._size\n }\n public set size(v: number) {\n this._size = v\n }\n\n constructor() {\n this._first = null\n this._last = null\n this._size = 0\n }\n enqueue(message: string): boolean {\n const newNode = new MessageNode(message)\n if (this._size === 0 || !this._last) {\n this._first = newNode\n this._last = newNode\n } else {\n this._last.next = newNode\n this._last = newNode\n }\n this._size++\n return true\n }\n dequeue(): string | null {\n if (this._size === 0 || !this._first) return null\n\n let prev = this._first\n this._first = prev.next\n prev.next = null\n\n this._size--\n return prev.value\n }\n}\n"],
|
||||
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,IAAM,cAAc,IAAI,YAAY,OAAO;AAC3C,IAAM,cAAc,IAAI,YAAY;AAEpC,SAAS,aAAa,KAAqB;AAChD,MAAI,IAAI,IAAI,IAAI,GAAG;AACnB,IAAE,WAAW,EAAE,SAAS,QAAQ,QAAQ,GAAG;AAC3C,MAAI,EAAE,SAAS,SAAS,GAAG;AAAG,MAAE,WAAW,EAAE,SAAS,MAAM,GAAG,EAAE;AACjE,MAAK,EAAE,SAAS,QAAQ,EAAE,aAAa,SAAW,EAAE,SAAS,SAAS,EAAE,aAAa;AAAS,MAAE,OAAO;AACvG,IAAE,aAAa,KAAK;AACpB,IAAE,OAAO;AACT,SAAO,EAAE,SAAS;AACpB;AAKO,SAAS,8BAA8B,aAA8B,OAAsB;AAChG,MAAI,QAAQ;AACZ,MAAI,MAAM,YAAY,SAAS;AAC/B,MAAI;AACJ,MAAI,WAAW;AAEf,MAAI,MAAM,GAAG;AACX,eAAW;AAAA,EACb,WAAW,MAAM,aAAa,YAAY,KAAK,YAAY;AACzD,eAAW,MAAM;AAAA,EACnB,WAAW,MAAM,cAAc,YAAY,OAAO,YAAY;AAC5D,eAAW;AAAA,EACb;AACE,WAAO,MAAM;AACX,UAAI,OAAO,QAAQ,GAAG;AACpB,mBAAW;AACX;AAAA,MACF;AACA,iBAAW,KAAK,MAAM,SAAS,MAAM,SAAS,CAAC;AAC/C,UAAI,YAAY,UAAU,aAAa,MAAM,YAAY;AACvD,gBAAQ;AAAA,MACV,WAAW,YAAY,UAAU,aAAa,MAAM,YAAY;AAC9D,cAAM;AAAA,MACR,OAAO;AAEL,mBAAW;AACX;AAAA,MACF;AAAA,IACF;AAGF,MAAI,YAAY,WAAW,OAAO,MAAM,IAAI;AAC1C,WAAO,CAAC,GAAG,YAAY,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,MAAM,QAAQ,CAAC;AAAA,EAClF;AAEA,SAAO;AACT;AAEO,SAAS,6BAA6B,aAA8B,OAAsB;AAC/F,MAAI,QAAQ;AACZ,MAAI,MAAM,YAAY,SAAS;AAC/B,MAAI;AACJ,MAAI,WAAW;AAEf,MAAI,MAAM,GAAG;AACX,eAAW;AAAA,EACb,WAAW,MAAM,aAAa,YAAY,KAAK,YAAY;AACzD,eAAW,MAAM;AAAA,EACnB,WAAW,MAAM,cAAc,YAAY,OAAO,YAAY;AAC5D,eAAW;AAAA,EACb;AACE,WAAO,MAAM;AACX,UAAI,OAAO,QAAQ,GAAG;AACpB,mBAAW;AACX;AAAA,MACF;AACA,iBAAW,KAAK,MAAM,SAAS,MAAM,SAAS,CAAC;AAC/C,UAAI,YAAY,UAAU,aAAa,MAAM,YAAY;AACvD,gBAAQ;AAAA,MACV,WAAW,YAAY,UAAU,aAAa,MAAM,YAAY;AAC9D,cAAM;AAAA,MACR,OAAO;AAEL,mBAAW;AACX;AAAA,MACF;AAAA,IACF;AAGF,MAAI,YAAY,WAAW,OAAO,MAAM,IAAI;AAC1C,WAAO,CAAC,GAAG,YAAY,MAAM,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,MAAM,QAAQ,CAAC;AAAA,EAClF;AAEA,SAAO;AACT;AAEO,IAAM,cAAN,MAAkB;AAAA,EACf;AAAA,EACA;AAAA,EAER,IAAW,QAAgB;AACzB,WAAO,KAAK;AAAA,EACd;AAAA,EACA,IAAW,MAAM,SAAiB;AAChC,SAAK,SAAS;AAAA,EAChB;AAAA,EACA,IAAW,OAA2B;AACpC,WAAO,KAAK;AAAA,EACd;AAAA,EACA,IAAW,KAAK,MAA0B;AACxC,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,YAAY,SAAiB;AAC3B,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AACF;AAEO,IAAM,eAAN,MAAmB;AAAA,EAChB;AAAA,EACA;AAAA,EAER,IAAW,QAA4B;AACrC,WAAO,KAAK;AAAA,EACd;AAAA,EACA,IAAW,MAAM,aAAiC;AAChD,SAAK,SAAS;AAAA,EAChB;AAAA,EACA,IAAW,OAA2B;AACpC,WAAO,KAAK;AAAA,EACd;AAAA,EACA,IAAW,KAAK,aAAiC;AAC/C,SAAK,QAAQ;AAAA,EACf;AAAA,EACQ;AAAA,EACR,IAAW,OAAe;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EACA,IAAW,KAAK,GAAW;AACzB,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,cAAc;AACZ,SAAK,SAAS;AACd,SAAK,QAAQ;AACb,SAAK,QAAQ;AAAA,EACf;AAAA,EACA,QAAQ,SAA0B;AAChC,UAAM,UAAU,IAAI,YAAY,OAAO;AACvC,QAAI,KAAK,UAAU,KAAK,CAAC,KAAK,OAAO;AACnC,WAAK,SAAS;AACd,WAAK,QAAQ;AAAA,IACf,OAAO;AACL,WAAK,MAAM,OAAO;AAClB,WAAK,QAAQ;AAAA,IACf;AACA,SAAK;AACL,WAAO;AAAA,EACT;AAAA,EACA,UAAyB;AACvB,QAAI,KAAK,UAAU,KAAK,CAAC,KAAK;AAAQ,aAAO;AAE7C,QAAI,OAAO,KAAK;AAChB,SAAK,SAAS,KAAK;AACnB,SAAK,OAAO;AAEZ,SAAK;AACL,WAAO,KAAK;AAAA,EACd;AACF;",
|
||||
"names": []
|
||||
}
|
||||
-133
@@ -1,133 +0,0 @@
|
||||
// event.ts
|
||||
import { schnorr as schnorr2 } from "@noble/curves/secp256k1";
|
||||
import { sha256 } from "@noble/hashes/sha256";
|
||||
import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
|
||||
|
||||
// keys.ts
|
||||
import { schnorr } from "@noble/curves/secp256k1";
|
||||
import { bytesToHex } from "@noble/hashes/utils";
|
||||
function getPublicKey(privateKey) {
|
||||
return bytesToHex(schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
var Kind = /* @__PURE__ */ ((Kind2) => {
|
||||
Kind2[Kind2["Metadata"] = 0] = "Metadata";
|
||||
Kind2[Kind2["Text"] = 1] = "Text";
|
||||
Kind2[Kind2["RecommendRelay"] = 2] = "RecommendRelay";
|
||||
Kind2[Kind2["Contacts"] = 3] = "Contacts";
|
||||
Kind2[Kind2["EncryptedDirectMessage"] = 4] = "EncryptedDirectMessage";
|
||||
Kind2[Kind2["EventDeletion"] = 5] = "EventDeletion";
|
||||
Kind2[Kind2["Repost"] = 6] = "Repost";
|
||||
Kind2[Kind2["Reaction"] = 7] = "Reaction";
|
||||
Kind2[Kind2["BadgeAward"] = 8] = "BadgeAward";
|
||||
Kind2[Kind2["ChannelCreation"] = 40] = "ChannelCreation";
|
||||
Kind2[Kind2["ChannelMetadata"] = 41] = "ChannelMetadata";
|
||||
Kind2[Kind2["ChannelMessage"] = 42] = "ChannelMessage";
|
||||
Kind2[Kind2["ChannelHideMessage"] = 43] = "ChannelHideMessage";
|
||||
Kind2[Kind2["ChannelMuteUser"] = 44] = "ChannelMuteUser";
|
||||
Kind2[Kind2["Blank"] = 255] = "Blank";
|
||||
Kind2[Kind2["Report"] = 1984] = "Report";
|
||||
Kind2[Kind2["ZapRequest"] = 9734] = "ZapRequest";
|
||||
Kind2[Kind2["Zap"] = 9735] = "Zap";
|
||||
Kind2[Kind2["RelayList"] = 10002] = "RelayList";
|
||||
Kind2[Kind2["ClientAuth"] = 22242] = "ClientAuth";
|
||||
Kind2[Kind2["NwcRequest"] = 23194] = "NwcRequest";
|
||||
Kind2[Kind2["HttpAuth"] = 27235] = "HttpAuth";
|
||||
Kind2[Kind2["ProfileBadge"] = 30008] = "ProfileBadge";
|
||||
Kind2[Kind2["BadgeDefinition"] = 30009] = "BadgeDefinition";
|
||||
Kind2[Kind2["Article"] = 30023] = "Article";
|
||||
Kind2[Kind2["FileMetadata"] = 1063] = "FileMetadata";
|
||||
return Kind2;
|
||||
})(Kind || {});
|
||||
function getBlankEvent(kind = 255 /* Blank */) {
|
||||
return {
|
||||
kind,
|
||||
content: "",
|
||||
tags: [],
|
||||
created_at: 0
|
||||
};
|
||||
}
|
||||
function finishEvent(t, privateKey) {
|
||||
const event = t;
|
||||
event.pubkey = getPublicKey(privateKey);
|
||||
event.id = getEventHash(event);
|
||||
event.sig = getSignature(event, privateKey);
|
||||
event[verifiedSymbol] = true;
|
||||
return event;
|
||||
}
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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 = sha256(utf8Encoder.encode(serializeEvent(event)));
|
||||
return bytesToHex2(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function verifySignature(event) {
|
||||
if (typeof event[verifiedSymbol] === "boolean")
|
||||
return event[verifiedSymbol];
|
||||
const hash = getEventHash(event);
|
||||
if (hash !== event.id) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
try {
|
||||
return event[verifiedSymbol] = schnorr2.verify(event.sig, hash, event.pubkey);
|
||||
} catch (err) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
}
|
||||
function signEvent(event, key) {
|
||||
console.warn(
|
||||
"nostr-tools: `signEvent` is deprecated and will be removed or changed in the future. Please use `getSignature` instead."
|
||||
);
|
||||
return getSignature(event, key);
|
||||
}
|
||||
function getSignature(event, key) {
|
||||
return bytesToHex2(schnorr2.sign(getEventHash(event), key));
|
||||
}
|
||||
export {
|
||||
Kind,
|
||||
finishEvent,
|
||||
getBlankEvent,
|
||||
getEventHash,
|
||||
getSignature,
|
||||
serializeEvent,
|
||||
signEvent,
|
||||
validateEvent,
|
||||
verifiedSymbol,
|
||||
verifySignature
|
||||
};
|
||||
-7
File diff suppressed because one or more lines are too long
-45
@@ -1,45 +0,0 @@
|
||||
// fakejson.ts
|
||||
function getHex64(json, field) {
|
||||
let len = field.length + 3;
|
||||
let idx = json.indexOf(`"${field}":`) + len;
|
||||
let s = json.slice(idx).indexOf(`"`) + idx + 1;
|
||||
return json.slice(s, s + 64);
|
||||
}
|
||||
function getInt(json, field) {
|
||||
let len = field.length;
|
||||
let idx = json.indexOf(`"${field}":`) + len + 3;
|
||||
let sliced = json.slice(idx);
|
||||
let end = Math.min(sliced.indexOf(","), sliced.indexOf("}"));
|
||||
return parseInt(sliced.slice(0, end), 10);
|
||||
}
|
||||
function getSubscriptionId(json) {
|
||||
let idx = json.slice(0, 22).indexOf(`"EVENT"`);
|
||||
if (idx === -1)
|
||||
return null;
|
||||
let pstart = json.slice(idx + 7 + 1).indexOf(`"`);
|
||||
if (pstart === -1)
|
||||
return null;
|
||||
let start = idx + 7 + 1 + pstart;
|
||||
let pend = json.slice(start + 1, 80).indexOf(`"`);
|
||||
if (pend === -1)
|
||||
return null;
|
||||
let end = start + 1 + pend;
|
||||
return json.slice(start + 1, end);
|
||||
}
|
||||
function matchEventId(json, id) {
|
||||
return id === getHex64(json, "id");
|
||||
}
|
||||
function matchEventPubkey(json, pubkey) {
|
||||
return pubkey === getHex64(json, "pubkey");
|
||||
}
|
||||
function matchEventKind(json, kind) {
|
||||
return kind === getInt(json, "kind");
|
||||
}
|
||||
export {
|
||||
getHex64,
|
||||
getInt,
|
||||
getSubscriptionId,
|
||||
matchEventId,
|
||||
matchEventKind,
|
||||
matchEventPubkey
|
||||
};
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../fakejson.ts"],
|
||||
"sourcesContent": ["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"],
|
||||
"mappings": ";AAAO,SAAS,SAAS,MAAc,OAAuB;AAC5D,MAAI,MAAM,MAAM,SAAS;AACzB,MAAI,MAAM,KAAK,QAAQ,IAAI,SAAS,IAAI;AACxC,MAAI,IAAI,KAAK,MAAM,GAAG,EAAE,QAAQ,GAAG,IAAI,MAAM;AAC7C,SAAO,KAAK,MAAM,GAAG,IAAI,EAAE;AAC7B;AAEO,SAAS,OAAO,MAAc,OAAuB;AAC1D,MAAI,MAAM,MAAM;AAChB,MAAI,MAAM,KAAK,QAAQ,IAAI,SAAS,IAAI,MAAM;AAC9C,MAAI,SAAS,KAAK,MAAM,GAAG;AAC3B,MAAI,MAAM,KAAK,IAAI,OAAO,QAAQ,GAAG,GAAG,OAAO,QAAQ,GAAG,CAAC;AAC3D,SAAO,SAAS,OAAO,MAAM,GAAG,GAAG,GAAG,EAAE;AAC1C;AAEO,SAAS,kBAAkB,MAA6B;AAC7D,MAAI,MAAM,KAAK,MAAM,GAAG,EAAE,EAAE,QAAQ,SAAS;AAC7C,MAAI,QAAQ;AAAI,WAAO;AAEvB,MAAI,SAAS,KAAK,MAAM,MAAM,IAAI,CAAC,EAAE,QAAQ,GAAG;AAChD,MAAI,WAAW;AAAI,WAAO;AAC1B,MAAI,QAAQ,MAAM,IAAI,IAAI;AAE1B,MAAI,OAAO,KAAK,MAAM,QAAQ,GAAG,EAAE,EAAE,QAAQ,GAAG;AAChD,MAAI,SAAS;AAAI,WAAO;AACxB,MAAI,MAAM,QAAQ,IAAI;AAEtB,SAAO,KAAK,MAAM,QAAQ,GAAG,GAAG;AAClC;AAEO,SAAS,aAAa,MAAc,IAAqB;AAC9D,SAAO,OAAO,SAAS,MAAM,IAAI;AACnC;AAEO,SAAS,iBAAiB,MAAc,QAAyB;AACtE,SAAO,WAAW,SAAS,MAAM,QAAQ;AAC3C;AAEO,SAAS,eAAe,MAAc,MAAuB;AAClE,SAAO,SAAS,OAAO,MAAM,MAAM;AACrC;",
|
||||
"names": []
|
||||
}
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
// filter.ts
|
||||
function matchFilter(filter, event) {
|
||||
if (filter.ids && filter.ids.indexOf(event.id) === -1) {
|
||||
if (!filter.ids.some((prefix) => event.id.startsWith(prefix))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (filter.kinds && filter.kinds.indexOf(event.kind) === -1)
|
||||
return false;
|
||||
if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {
|
||||
if (!filter.authors.some((prefix) => event.pubkey.startsWith(prefix))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (let f in filter) {
|
||||
if (f[0] === "#") {
|
||||
let tagName = f.slice(1);
|
||||
let values = filter[`#${tagName}`];
|
||||
if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values.indexOf(v) !== -1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (filter.since && event.created_at < filter.since)
|
||||
return false;
|
||||
if (filter.until && event.created_at > filter.until)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
function matchFilters(filters, event) {
|
||||
for (let i = 0; i < filters.length; i++) {
|
||||
if (matchFilter(filters[i], event))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function mergeFilters(...filters) {
|
||||
let result = {};
|
||||
for (let i = 0; i < filters.length; i++) {
|
||||
let filter = filters[i];
|
||||
Object.entries(filter).forEach(([property, values]) => {
|
||||
if (property === "kinds" || property === "ids" || property === "authors" || property[0] === "#") {
|
||||
result[property] = result[property] || [];
|
||||
for (let v = 0; v < values.length; v++) {
|
||||
let value = values[v];
|
||||
if (!result[property].includes(value))
|
||||
result[property].push(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (filter.limit && (!result.limit || filter.limit > result.limit))
|
||||
result.limit = filter.limit;
|
||||
if (filter.until && (!result.until || filter.until > result.until))
|
||||
result.until = filter.until;
|
||||
if (filter.since && (!result.since || filter.since < result.since))
|
||||
result.since = filter.since;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
export {
|
||||
matchFilter,
|
||||
matchFilters,
|
||||
mergeFilters
|
||||
};
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../filter.ts"],
|
||||
"sourcesContent": ["import { Event } from './event.ts'\n\nexport type Filter<K extends number = number> = {\n ids?: string[]\n kinds?: K[]\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<number>, event: Event<number>): boolean {\n if (filter.ids && filter.ids.indexOf(event.id) === -1) {\n if (!filter.ids.some(prefix => event.id.startsWith(prefix))) {\n return false\n }\n }\n if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) return false\n if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {\n if (!filter.authors.some(prefix => event.pubkey.startsWith(prefix))) {\n return false\n }\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<number>[], event: Event<number>): boolean {\n for (let i = 0; i < filters.length; i++) {\n if (matchFilter(filters[i], event)) return true\n }\n return false\n}\n\nexport function mergeFilters(...filters: Filter<number>[]): Filter<number> {\n let result: Filter<number> = {}\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"],
|
||||
"mappings": ";AAaO,SAAS,YAAY,QAAwB,OAA+B;AACjF,MAAI,OAAO,OAAO,OAAO,IAAI,QAAQ,MAAM,EAAE,MAAM,IAAI;AACrD,QAAI,CAAC,OAAO,IAAI,KAAK,YAAU,MAAM,GAAG,WAAW,MAAM,CAAC,GAAG;AAC3D,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,OAAO,SAAS,OAAO,MAAM,QAAQ,MAAM,IAAI,MAAM;AAAI,WAAO;AACpE,MAAI,OAAO,WAAW,OAAO,QAAQ,QAAQ,MAAM,MAAM,MAAM,IAAI;AACjE,QAAI,CAAC,OAAO,QAAQ,KAAK,YAAU,MAAM,OAAO,WAAW,MAAM,CAAC,GAAG;AACnE,aAAO;AAAA,IACT;AAAA,EACF;AAEA,WAAS,KAAK,QAAQ;AACpB,QAAI,EAAE,OAAO,KAAK;AAChB,UAAI,UAAU,EAAE,MAAM,CAAC;AACvB,UAAI,SAAS,OAAO,IAAI;AACxB,UAAI,UAAU,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,MAAM,MAAM,EAAE,MAAM,CAAC,KAAK,OAAQ,QAAQ,CAAC,MAAM,EAAE;AAAG,eAAO;AAAA,IACpG;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,MAAM,aAAa,OAAO;AAAO,WAAO;AAC5D,MAAI,OAAO,SAAS,MAAM,aAAa,OAAO;AAAO,WAAO;AAE5D,SAAO;AACT;AAEO,SAAS,aAAa,SAA2B,OAA+B;AACrF,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,QAAI,YAAY,QAAQ,IAAI,KAAK;AAAG,aAAO;AAAA,EAC7C;AACA,SAAO;AACT;AAEO,SAAS,gBAAgB,SAA2C;AACzE,MAAI,SAAyB,CAAC;AAC9B,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,QAAI,SAAS,QAAQ;AACrB,WAAO,QAAQ,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU,MAAM,MAAM;AACrD,UAAI,aAAa,WAAW,aAAa,SAAS,aAAa,aAAa,SAAS,OAAO,KAAK;AAE/F,eAAO,YAAY,OAAO,aAAa,CAAC;AAExC,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AAEtC,cAAI,QAAQ,OAAO;AAEnB,cAAI,CAAC,OAAO,UAAU,SAAS,KAAK;AAAG,mBAAO,UAAU,KAAK,KAAK;AAAA,QACpE;AAAA,MACF;AAAA,IACF,CAAC;AAED,QAAI,OAAO,UAAU,CAAC,OAAO,SAAS,OAAO,QAAQ,OAAO;AAAQ,aAAO,QAAQ,OAAO;AAC1F,QAAI,OAAO,UAAU,CAAC,OAAO,SAAS,OAAO,QAAQ,OAAO;AAAQ,aAAO,QAAQ,OAAO;AAC1F,QAAI,OAAO,UAAU,CAAC,OAAO,SAAS,OAAO,QAAQ,OAAO;AAAQ,aAAO,QAAQ,OAAO;AAAA,EAC5F;AAEA,SAAO;AACT;",
|
||||
"names": []
|
||||
}
|
||||
-2109
File diff suppressed because it is too large
Load Diff
-7
File diff suppressed because one or more lines are too long
-13
@@ -1,13 +0,0 @@
|
||||
// keys.ts
|
||||
import { schnorr } from "@noble/curves/secp256k1";
|
||||
import { bytesToHex } from "@noble/hashes/utils";
|
||||
function generatePrivateKey() {
|
||||
return bytesToHex(schnorr.utils.randomPrivateKey());
|
||||
}
|
||||
function getPublicKey(privateKey) {
|
||||
return bytesToHex(schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
export {
|
||||
generatePrivateKey,
|
||||
getPublicKey
|
||||
};
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../keys.ts"],
|
||||
"sourcesContent": ["import { schnorr } from '@noble/curves/secp256k1'\nimport { bytesToHex } from '@noble/hashes/utils'\n\nexport function generatePrivateKey(): string {\n return bytesToHex(schnorr.utils.randomPrivateKey())\n}\n\nexport function getPublicKey(privateKey: string): string {\n return bytesToHex(schnorr.getPublicKey(privateKey))\n}\n"],
|
||||
"mappings": ";AAAA,SAAS,eAAe;AACxB,SAAS,kBAAkB;AAEpB,SAAS,qBAA6B;AAC3C,SAAO,WAAW,QAAQ,MAAM,iBAAiB,CAAC;AACpD;AAEO,SAAS,aAAa,YAA4B;AACvD,SAAO,WAAW,QAAQ,aAAa,UAAU,CAAC;AACpD;",
|
||||
"names": []
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
// kinds.ts
|
||||
function isRegularKind(kind) {
|
||||
return 1e3 <= kind && kind < 1e4 || [1, 2, 4, 5, 6, 7, 8, 16, 40, 41, 42, 43, 44].includes(kind);
|
||||
}
|
||||
function isReplaceableKind(kind) {
|
||||
return 1e4 <= kind && kind < 2e4 || [0, 3].includes(kind);
|
||||
}
|
||||
function isEphemeralKind(kind) {
|
||||
return 2e4 <= kind && kind < 3e4;
|
||||
}
|
||||
function isParameterizedReplaceableKind(kind) {
|
||||
return 3e4 <= kind && kind < 4e4;
|
||||
}
|
||||
function classifyKind(kind) {
|
||||
if (isRegularKind(kind))
|
||||
return "regular";
|
||||
if (isReplaceableKind(kind))
|
||||
return "replaceable";
|
||||
if (isEphemeralKind(kind))
|
||||
return "ephemeral";
|
||||
if (isParameterizedReplaceableKind(kind))
|
||||
return "parameterized";
|
||||
return "unknown";
|
||||
}
|
||||
export {
|
||||
classifyKind,
|
||||
isEphemeralKind,
|
||||
isParameterizedReplaceableKind,
|
||||
isRegularKind,
|
||||
isReplaceableKind
|
||||
};
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../kinds.ts"],
|
||||
"sourcesContent": ["/** Events are **regular**, which means they're all expected to be stored by relays. */\nfunction isRegularKind(kind: number) {\n return (1000 <= kind && kind < 10000) || [1, 2, 4, 5, 6, 7, 8, 16, 40, 41, 42, 43, 44].includes(kind)\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. */\nfunction isReplaceableKind(kind: number) {\n return (10000 <= kind && kind < 20000) || [0, 3].includes(kind)\n}\n\n/** Events are **ephemeral**, which means they are not expected to be stored by relays. */\nfunction isEphemeralKind(kind: number) {\n return 20000 <= kind && kind < 30000\n}\n\n/** Events are **parameterized replaceable**, 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. */\nfunction isParameterizedReplaceableKind(kind: number) {\n return 30000 <= kind && kind < 40000\n}\n\n/** Classification of the event kind. */\ntype KindClassification = 'regular' | 'replaceable' | 'ephemeral' | 'parameterized' | 'unknown'\n\n/** Determine the classification of this kind of event if known, or `unknown`. */\nfunction classifyKind(kind: number): KindClassification {\n if (isRegularKind(kind)) return 'regular'\n if (isReplaceableKind(kind)) return 'replaceable'\n if (isEphemeralKind(kind)) return 'ephemeral'\n if (isParameterizedReplaceableKind(kind)) return 'parameterized'\n return 'unknown'\n}\n\nexport {\n classifyKind,\n isEphemeralKind,\n isParameterizedReplaceableKind,\n isRegularKind,\n isReplaceableKind,\n type KindClassification,\n}\n"],
|
||||
"mappings": ";AACA,SAAS,cAAc,MAAc;AACnC,SAAQ,OAAQ,QAAQ,OAAO,OAAU,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI,IAAI,IAAI,IAAI,EAAE,EAAE,SAAS,IAAI;AACtG;AAGA,SAAS,kBAAkB,MAAc;AACvC,SAAQ,OAAS,QAAQ,OAAO,OAAU,CAAC,GAAG,CAAC,EAAE,SAAS,IAAI;AAChE;AAGA,SAAS,gBAAgB,MAAc;AACrC,SAAO,OAAS,QAAQ,OAAO;AACjC;AAGA,SAAS,+BAA+B,MAAc;AACpD,SAAO,OAAS,QAAQ,OAAO;AACjC;AAMA,SAAS,aAAa,MAAkC;AACtD,MAAI,cAAc,IAAI;AAAG,WAAO;AAChC,MAAI,kBAAkB,IAAI;AAAG,WAAO;AACpC,MAAI,gBAAgB,IAAI;AAAG,WAAO;AAClC,MAAI,+BAA+B,IAAI;AAAG,WAAO;AACjD,SAAO;AACT;",
|
||||
"names": []
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
// nip04.ts
|
||||
import { randomBytes } from "@noble/hashes/utils";
|
||||
import { secp256k1 } from "@noble/curves/secp256k1";
|
||||
import { base64 } from "@scure/base";
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// nip04.ts
|
||||
if (typeof crypto !== "undefined" && !crypto.subtle && crypto.webcrypto) {
|
||||
crypto.subtle = crypto.webcrypto.subtle;
|
||||
}
|
||||
async function encrypt(privkey, pubkey, text) {
|
||||
const key = secp256k1.getSharedSecret(privkey, "02" + pubkey);
|
||||
const normalizedKey = getNormalizedX(key);
|
||||
let iv = Uint8Array.from(randomBytes(16));
|
||||
let plaintext = utf8Encoder.encode(text);
|
||||
let cryptoKey = await crypto.subtle.importKey("raw", normalizedKey, { name: "AES-CBC" }, false, ["encrypt"]);
|
||||
let ciphertext = await crypto.subtle.encrypt({ name: "AES-CBC", iv }, cryptoKey, plaintext);
|
||||
let ctb64 = base64.encode(new Uint8Array(ciphertext));
|
||||
let ivb64 = base64.encode(new Uint8Array(iv.buffer));
|
||||
return `${ctb64}?iv=${ivb64}`;
|
||||
}
|
||||
async function decrypt(privkey, pubkey, data) {
|
||||
let [ctb64, ivb64] = data.split("?iv=");
|
||||
let key = secp256k1.getSharedSecret(privkey, "02" + pubkey);
|
||||
let normalizedKey = getNormalizedX(key);
|
||||
let cryptoKey = await crypto.subtle.importKey("raw", normalizedKey, { name: "AES-CBC" }, false, ["decrypt"]);
|
||||
let ciphertext = base64.decode(ctb64);
|
||||
let iv = base64.decode(ivb64);
|
||||
let plaintext = await crypto.subtle.decrypt({ name: "AES-CBC", iv }, cryptoKey, ciphertext);
|
||||
let text = utf8Decoder.decode(plaintext);
|
||||
return text;
|
||||
}
|
||||
function getNormalizedX(key) {
|
||||
return key.slice(1, 33);
|
||||
}
|
||||
export {
|
||||
decrypt,
|
||||
encrypt
|
||||
};
|
||||
-7
File diff suppressed because one or more lines are too long
-57
@@ -1,57 +0,0 @@
|
||||
// nip05.ts
|
||||
var NIP05_REGEX = /^(?:([\w.+-]+)@)?([\w.-]+)$/;
|
||||
var _fetch;
|
||||
try {
|
||||
_fetch = fetch;
|
||||
} catch {
|
||||
}
|
||||
function useFetchImplementation(fetchImplementation) {
|
||||
_fetch = fetchImplementation;
|
||||
}
|
||||
async function searchDomain(domain, query = "") {
|
||||
try {
|
||||
let res = await (await _fetch(`https://${domain}/.well-known/nostr.json?name=${query}`)).json();
|
||||
return res.names;
|
||||
} catch (_) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
async function queryProfile(fullname) {
|
||||
const match = fullname.match(NIP05_REGEX);
|
||||
if (!match)
|
||||
return null;
|
||||
const [_, name = "_", domain] = match;
|
||||
try {
|
||||
const res = await _fetch(`https://${domain}/.well-known/nostr.json?name=${name}`);
|
||||
const { names, relays } = parseNIP05Result(await res.json());
|
||||
const pubkey = names[name];
|
||||
return pubkey ? { pubkey, relays: relays?.[pubkey] } : null;
|
||||
} catch (_e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
function parseNIP05Result(json) {
|
||||
const result = {
|
||||
names: {}
|
||||
};
|
||||
for (const [name, pubkey] of Object.entries(json.names)) {
|
||||
if (typeof name === "string" && typeof pubkey === "string") {
|
||||
result.names[name] = pubkey;
|
||||
}
|
||||
}
|
||||
if (json.relays) {
|
||||
result.relays = {};
|
||||
for (const [pubkey, relays] of Object.entries(json.relays)) {
|
||||
if (typeof pubkey === "string" && Array.isArray(relays)) {
|
||||
result.relays[pubkey] = relays.filter((relay) => typeof relay === "string");
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
export {
|
||||
NIP05_REGEX,
|
||||
queryProfile,
|
||||
searchDomain,
|
||||
useFetchImplementation
|
||||
};
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../nip05.ts"],
|
||||
"sourcesContent": ["import { ProfilePointer } from './nip19.ts'\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.-]+)$/\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 searchDomain(domain: string, query = ''): Promise<{ [name: string]: string }> {\n try {\n let res = await (await _fetch(`https://${domain}/.well-known/nostr.json?name=${query}`)).json()\n\n return res.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 res = await _fetch(`https://${domain}/.well-known/nostr.json?name=${name}`)\n const { names, relays } = parseNIP05Result(await res.json())\n\n const pubkey = names[name]\n return pubkey ? { pubkey, relays: relays?.[pubkey] } : null\n } catch (_e) {\n return null\n }\n}\n\n/** nostr.json result. */\nexport interface NIP05Result {\n names: {\n [name: string]: string\n }\n relays?: {\n [pubkey: string]: string[]\n }\n}\n\n/** Parse the nostr.json and throw if it's not valid. */\nfunction parseNIP05Result(json: any): NIP05Result {\n const result: NIP05Result = {\n names: {},\n }\n\n for (const [name, pubkey] of Object.entries(json.names)) {\n if (typeof name === 'string' && typeof pubkey === 'string') {\n result.names[name] = pubkey\n }\n }\n\n if (json.relays) {\n result.relays = {}\n for (const [pubkey, relays] of Object.entries(json.relays)) {\n if (typeof pubkey === 'string' && Array.isArray(relays)) {\n result.relays[pubkey] = relays.filter((relay: unknown) => typeof relay === 'string')\n }\n }\n }\n\n return result\n}\n"],
|
||||
"mappings": ";AASO,IAAM,cAAc;AAE3B,IAAI;AAEJ,IAAI;AACF,WAAS;AACX,QAAE;AAAO;AAEF,SAAS,uBAAuB,qBAA0B;AAC/D,WAAS;AACX;AAEA,eAAsB,aAAa,QAAgB,QAAQ,IAAyC;AAClG,MAAI;AACF,QAAI,MAAM,OAAO,MAAM,OAAO,WAAW,sCAAsC,OAAO,GAAG,KAAK;AAE9F,WAAO,IAAI;AAAA,EACb,SAAS,GAAP;AACA,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,aAAa,UAAkD;AACnF,QAAM,QAAQ,SAAS,MAAM,WAAW;AACxC,MAAI,CAAC;AAAO,WAAO;AAEnB,QAAM,CAAC,GAAG,OAAO,KAAK,MAAM,IAAI;AAEhC,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,WAAW,sCAAsC,MAAM;AAChF,UAAM,EAAE,OAAO,OAAO,IAAI,iBAAiB,MAAM,IAAI,KAAK,CAAC;AAE3D,UAAM,SAAS,MAAM;AACrB,WAAO,SAAS,EAAE,QAAQ,QAAQ,SAAS,QAAQ,IAAI;AAAA,EACzD,SAAS,IAAP;AACA,WAAO;AAAA,EACT;AACF;AAaA,SAAS,iBAAiB,MAAwB;AAChD,QAAM,SAAsB;AAAA,IAC1B,OAAO,CAAC;AAAA,EACV;AAEA,aAAW,CAAC,MAAM,MAAM,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AACvD,QAAI,OAAO,SAAS,YAAY,OAAO,WAAW,UAAU;AAC1D,aAAO,MAAM,QAAQ;AAAA,IACvB;AAAA,EACF;AAEA,MAAI,KAAK,QAAQ;AACf,WAAO,SAAS,CAAC;AACjB,eAAW,CAAC,QAAQ,MAAM,KAAK,OAAO,QAAQ,KAAK,MAAM,GAAG;AAC1D,UAAI,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AACvD,eAAO,OAAO,UAAU,OAAO,OAAO,CAAC,UAAmB,OAAO,UAAU,QAAQ;AAAA,MACrF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;",
|
||||
"names": []
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
// nip06.ts
|
||||
import { bytesToHex } from "@noble/hashes/utils";
|
||||
import { wordlist } from "@scure/bip39/wordlists/english";
|
||||
import { generateMnemonic, mnemonicToSeedSync, validateMnemonic } from "@scure/bip39";
|
||||
import { HDKey } from "@scure/bip32";
|
||||
function privateKeyFromSeedWords(mnemonic, passphrase) {
|
||||
let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase));
|
||||
let privateKey = root.derive(`m/44'/1237'/0'/0/0`).privateKey;
|
||||
if (!privateKey)
|
||||
throw new Error("could not derive private key");
|
||||
return bytesToHex(privateKey);
|
||||
}
|
||||
function generateSeedWords() {
|
||||
return generateMnemonic(wordlist);
|
||||
}
|
||||
function validateWords(words) {
|
||||
return validateMnemonic(words, wordlist);
|
||||
}
|
||||
export {
|
||||
generateSeedWords,
|
||||
privateKeyFromSeedWords,
|
||||
validateWords
|
||||
};
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"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\nexport function privateKeyFromSeedWords(mnemonic: string, passphrase?: string): string {\n let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))\n let privateKey = root.derive(`m/44'/1237'/0'/0/0`).privateKey\n if (!privateKey) throw new Error('could not derive private key')\n return bytesToHex(privateKey)\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;AAEf,SAAS,wBAAwB,UAAkB,YAA6B;AACrF,MAAI,OAAO,MAAM,eAAe,mBAAmB,UAAU,UAAU,CAAC;AACxE,MAAI,aAAa,KAAK,OAAO,oBAAoB,EAAE;AACnD,MAAI,CAAC;AAAY,UAAM,IAAI,MAAM,8BAA8B;AAC/D,SAAO,WAAW,UAAU;AAC9B;AAEO,SAAS,oBAA4B;AAC1C,SAAO,iBAAiB,QAAQ;AAClC;AAEO,SAAS,cAAc,OAAwB;AACpD,SAAO,iBAAiB,OAAO,QAAQ;AACzC;",
|
||||
"names": []
|
||||
}
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
// nip10.ts
|
||||
function parse(event) {
|
||||
const result = {
|
||||
reply: void 0,
|
||||
root: void 0,
|
||||
mentions: [],
|
||||
profiles: []
|
||||
};
|
||||
const eTags = [];
|
||||
for (const tag of event.tags) {
|
||||
if (tag[0] === "e" && tag[1]) {
|
||||
eTags.push(tag);
|
||||
}
|
||||
if (tag[0] === "p" && tag[1]) {
|
||||
result.profiles.push({
|
||||
pubkey: tag[1],
|
||||
relays: tag[2] ? [tag[2]] : []
|
||||
});
|
||||
}
|
||||
}
|
||||
for (let eTagIndex = 0; eTagIndex < eTags.length; eTagIndex++) {
|
||||
const eTag = eTags[eTagIndex];
|
||||
const [_, eTagEventId, eTagRelayUrl, eTagMarker] = eTag;
|
||||
const eventPointer = {
|
||||
id: eTagEventId,
|
||||
relays: eTagRelayUrl ? [eTagRelayUrl] : []
|
||||
};
|
||||
const isFirstETag = eTagIndex === 0;
|
||||
const isLastETag = eTagIndex === eTags.length - 1;
|
||||
if (eTagMarker === "root") {
|
||||
result.root = eventPointer;
|
||||
continue;
|
||||
}
|
||||
if (eTagMarker === "reply") {
|
||||
result.reply = eventPointer;
|
||||
continue;
|
||||
}
|
||||
if (eTagMarker === "mention") {
|
||||
result.mentions.push(eventPointer);
|
||||
continue;
|
||||
}
|
||||
if (isFirstETag) {
|
||||
result.root = eventPointer;
|
||||
continue;
|
||||
}
|
||||
if (isLastETag) {
|
||||
result.reply = eventPointer;
|
||||
continue;
|
||||
}
|
||||
result.mentions.push(eventPointer);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
export {
|
||||
parse
|
||||
};
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../nip10.ts"],
|
||||
"sourcesContent": ["import type { Event } from './event.ts'\nimport type { EventPointer, ProfilePointer } from './nip19.ts'\n\nexport type NIP10Result = {\n /**\n * Pointer to the root of the thread.\n */\n root: EventPointer | undefined\n\n /**\n * Pointer to a \"parent\" event that parsed event replies to (responded to).\n */\n reply: EventPointer | undefined\n\n /**\n * Pointers to events which may or may not be in the reply chain.\n */\n mentions: EventPointer[]\n\n /**\n * List of pubkeys that are involved in the thread in no particular order.\n */\n profiles: ProfilePointer[]\n}\n\nexport function parse(event: Pick<Event, 'tags'>): NIP10Result {\n const result: NIP10Result = {\n reply: undefined,\n root: undefined,\n mentions: [],\n profiles: [],\n }\n\n const eTags: string[][] = []\n\n for (const tag of event.tags) {\n if (tag[0] === 'e' && tag[1]) {\n eTags.push(tag)\n }\n\n if (tag[0] === 'p' && tag[1]) {\n result.profiles.push({\n pubkey: tag[1],\n relays: tag[2] ? [tag[2]] : [],\n })\n }\n }\n\n for (let eTagIndex = 0; eTagIndex < eTags.length; eTagIndex++) {\n const eTag = eTags[eTagIndex]\n\n const [_, eTagEventId, eTagRelayUrl, eTagMarker] = eTag as [string, string, undefined | string, undefined | string]\n\n const eventPointer: EventPointer = {\n id: eTagEventId,\n relays: eTagRelayUrl ? [eTagRelayUrl] : [],\n }\n\n const isFirstETag = eTagIndex === 0\n const isLastETag = eTagIndex === eTags.length - 1\n\n if (eTagMarker === 'root') {\n result.root = eventPointer\n continue\n }\n\n if (eTagMarker === 'reply') {\n result.reply = eventPointer\n continue\n }\n\n if (eTagMarker === 'mention') {\n result.mentions.push(eventPointer)\n continue\n }\n\n if (isFirstETag) {\n result.root = eventPointer\n continue\n }\n\n if (isLastETag) {\n result.reply = eventPointer\n continue\n }\n\n result.mentions.push(eventPointer)\n }\n\n return result\n}\n"],
|
||||
"mappings": ";AAyBO,SAAS,MAAM,OAAyC;AAC7D,QAAM,SAAsB;AAAA,IAC1B,OAAO;AAAA,IACP,MAAM;AAAA,IACN,UAAU,CAAC;AAAA,IACX,UAAU,CAAC;AAAA,EACb;AAEA,QAAM,QAAoB,CAAC;AAE3B,aAAW,OAAO,MAAM,MAAM;AAC5B,QAAI,IAAI,OAAO,OAAO,IAAI,IAAI;AAC5B,YAAM,KAAK,GAAG;AAAA,IAChB;AAEA,QAAI,IAAI,OAAO,OAAO,IAAI,IAAI;AAC5B,aAAO,SAAS,KAAK;AAAA,QACnB,QAAQ,IAAI;AAAA,QACZ,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC;AAAA,MAC/B,CAAC;AAAA,IACH;AAAA,EACF;AAEA,WAAS,YAAY,GAAG,YAAY,MAAM,QAAQ,aAAa;AAC7D,UAAM,OAAO,MAAM;AAEnB,UAAM,CAAC,GAAG,aAAa,cAAc,UAAU,IAAI;AAEnD,UAAM,eAA6B;AAAA,MACjC,IAAI;AAAA,MACJ,QAAQ,eAAe,CAAC,YAAY,IAAI,CAAC;AAAA,IAC3C;AAEA,UAAM,cAAc,cAAc;AAClC,UAAM,aAAa,cAAc,MAAM,SAAS;AAEhD,QAAI,eAAe,QAAQ;AACzB,aAAO,OAAO;AACd;AAAA,IACF;AAEA,QAAI,eAAe,SAAS;AAC1B,aAAO,QAAQ;AACf;AAAA,IACF;AAEA,QAAI,eAAe,WAAW;AAC5B,aAAO,SAAS,KAAK,YAAY;AACjC;AAAA,IACF;AAEA,QAAI,aAAa;AACf,aAAO,OAAO;AACd;AAAA,IACF;AAEA,QAAI,YAAY;AACd,aAAO,QAAQ;AACf;AAAA,IACF;AAEA,WAAO,SAAS,KAAK,YAAY;AAAA,EACnC;AAEA,SAAO;AACT;",
|
||||
"names": []
|
||||
}
|
||||
-85
@@ -1,85 +0,0 @@
|
||||
// event.ts
|
||||
import { schnorr } from "@noble/curves/secp256k1";
|
||||
import { sha256 } from "@noble/hashes/sha256";
|
||||
import { bytesToHex } from "@noble/hashes/utils";
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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 = sha256(utf8Encoder.encode(serializeEvent(event)));
|
||||
return bytesToHex(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// nip13.ts
|
||||
function getPow(hex) {
|
||||
let count = 0;
|
||||
for (let i = 0; i < hex.length; i++) {
|
||||
const nibble = parseInt(hex[i], 16);
|
||||
if (nibble === 0) {
|
||||
count += 4;
|
||||
} else {
|
||||
count += Math.clz32(nibble) - 28;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
function minePow(unsigned, difficulty) {
|
||||
let count = 0;
|
||||
const event = unsigned;
|
||||
const tag = ["nonce", count.toString(), difficulty.toString()];
|
||||
event.tags.push(tag);
|
||||
while (true) {
|
||||
const now = Math.floor(new Date().getTime() / 1e3);
|
||||
if (now !== event.created_at) {
|
||||
count = 0;
|
||||
event.created_at = now;
|
||||
}
|
||||
tag[1] = (++count).toString();
|
||||
event.id = getEventHash(event);
|
||||
if (getPow(event.id) >= difficulty) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return event;
|
||||
}
|
||||
export {
|
||||
getPow,
|
||||
minePow
|
||||
};
|
||||
-7
File diff suppressed because one or more lines are too long
-140
@@ -1,140 +0,0 @@
|
||||
// event.ts
|
||||
import { schnorr as schnorr2 } from "@noble/curves/secp256k1";
|
||||
import { sha256 } from "@noble/hashes/sha256";
|
||||
import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
|
||||
|
||||
// keys.ts
|
||||
import { schnorr } from "@noble/curves/secp256k1";
|
||||
import { bytesToHex } from "@noble/hashes/utils";
|
||||
function getPublicKey(privateKey) {
|
||||
return bytesToHex(schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function finishEvent(t, privateKey) {
|
||||
const event = t;
|
||||
event.pubkey = getPublicKey(privateKey);
|
||||
event.id = getEventHash(event);
|
||||
event.sig = getSignature(event, privateKey);
|
||||
event[verifiedSymbol] = true;
|
||||
return event;
|
||||
}
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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 = sha256(utf8Encoder.encode(serializeEvent(event)));
|
||||
return bytesToHex2(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function verifySignature(event) {
|
||||
if (typeof event[verifiedSymbol] === "boolean")
|
||||
return event[verifiedSymbol];
|
||||
const hash = getEventHash(event);
|
||||
if (hash !== event.id) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
try {
|
||||
return event[verifiedSymbol] = schnorr2.verify(event.sig, hash, event.pubkey);
|
||||
} catch (err) {
|
||||
return event[verifiedSymbol] = false;
|
||||
}
|
||||
}
|
||||
function getSignature(event, key) {
|
||||
return bytesToHex2(schnorr2.sign(getEventHash(event), key));
|
||||
}
|
||||
|
||||
// nip18.ts
|
||||
function finishRepostEvent(t, reposted, relayUrl, privateKey) {
|
||||
return finishEvent(
|
||||
{
|
||||
kind: 6 /* Repost */,
|
||||
tags: [...t.tags ?? [], ["e", reposted.id, relayUrl], ["p", reposted.pubkey]],
|
||||
content: t.content === "" ? "" : JSON.stringify(reposted),
|
||||
created_at: t.created_at
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
}
|
||||
function getRepostedEventPointer(event) {
|
||||
if (event.kind !== 6 /* Repost */) {
|
||||
return void 0;
|
||||
}
|
||||
let lastETag;
|
||||
let lastPTag;
|
||||
for (let i = event.tags.length - 1; i >= 0 && (lastETag === void 0 || lastPTag === void 0); i--) {
|
||||
const tag = event.tags[i];
|
||||
if (tag.length >= 2) {
|
||||
if (tag[0] === "e" && lastETag === void 0) {
|
||||
lastETag = tag;
|
||||
} else if (tag[0] === "p" && lastPTag === void 0) {
|
||||
lastPTag = tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastETag === void 0) {
|
||||
return void 0;
|
||||
}
|
||||
return {
|
||||
id: lastETag[1],
|
||||
relays: [lastETag[2], lastPTag?.[2]].filter((x) => typeof x === "string"),
|
||||
author: lastPTag?.[1]
|
||||
};
|
||||
}
|
||||
function getRepostedEvent(event, { skipVerification } = {}) {
|
||||
const pointer = getRepostedEventPointer(event);
|
||||
if (pointer === void 0 || event.content === "") {
|
||||
return void 0;
|
||||
}
|
||||
let repostedEvent;
|
||||
try {
|
||||
repostedEvent = JSON.parse(event.content);
|
||||
} catch (error) {
|
||||
return void 0;
|
||||
}
|
||||
if (repostedEvent.id !== pointer.id) {
|
||||
return void 0;
|
||||
}
|
||||
if (!skipVerification && !verifySignature(repostedEvent)) {
|
||||
return void 0;
|
||||
}
|
||||
return repostedEvent;
|
||||
}
|
||||
export {
|
||||
finishRepostEvent,
|
||||
getRepostedEvent,
|
||||
getRepostedEventPointer
|
||||
};
|
||||
-7
File diff suppressed because one or more lines are too long
-191
@@ -1,191 +0,0 @@
|
||||
// nip19.ts
|
||||
import { bytesToHex, concatBytes, hexToBytes } from "@noble/hashes/utils";
|
||||
import { bech32 } from "@scure/base";
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// nip19.ts
|
||||
var Bech32MaxSize = 5e3;
|
||||
var BECH32_REGEX = /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/;
|
||||
function integerToUint8Array(number) {
|
||||
const uint8Array = new Uint8Array(4);
|
||||
uint8Array[0] = number >> 24 & 255;
|
||||
uint8Array[1] = number >> 16 & 255;
|
||||
uint8Array[2] = number >> 8 & 255;
|
||||
uint8Array[3] = number & 255;
|
||||
return uint8Array;
|
||||
}
|
||||
function decode(nip19) {
|
||||
let { prefix, words } = bech32.decode(nip19, Bech32MaxSize);
|
||||
let data = new Uint8Array(bech32.fromWords(words));
|
||||
switch (prefix) {
|
||||
case "nprofile": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nprofile");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
return {
|
||||
type: "nprofile",
|
||||
data: {
|
||||
pubkey: bytesToHex(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nevent": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nevent");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
if (tlv[2] && tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (tlv[3] && tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "nevent",
|
||||
data: {
|
||||
id: bytesToHex(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],
|
||||
author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : void 0,
|
||||
kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : void 0
|
||||
}
|
||||
};
|
||||
}
|
||||
case "naddr": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for naddr");
|
||||
if (!tlv[2]?.[0])
|
||||
throw new Error("missing TLV 2 for naddr");
|
||||
if (tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (!tlv[3]?.[0])
|
||||
throw new Error("missing TLV 3 for naddr");
|
||||
if (tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "naddr",
|
||||
data: {
|
||||
identifier: utf8Decoder.decode(tlv[0][0]),
|
||||
pubkey: bytesToHex(tlv[2][0]),
|
||||
kind: parseInt(bytesToHex(tlv[3][0]), 16),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nrelay": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nrelay");
|
||||
return {
|
||||
type: "nrelay",
|
||||
data: utf8Decoder.decode(tlv[0][0])
|
||||
};
|
||||
}
|
||||
case "nsec":
|
||||
case "npub":
|
||||
case "note":
|
||||
return { type: prefix, data: bytesToHex(data) };
|
||||
default:
|
||||
throw new Error(`unknown prefix ${prefix}`);
|
||||
}
|
||||
}
|
||||
function parseTLV(data) {
|
||||
let result = {};
|
||||
let rest = data;
|
||||
while (rest.length > 0) {
|
||||
let t = rest[0];
|
||||
let l = rest[1];
|
||||
if (!l)
|
||||
throw new Error(`malformed TLV ${t}`);
|
||||
let v = rest.slice(2, 2 + l);
|
||||
rest = rest.slice(2 + l);
|
||||
if (v.length < l)
|
||||
throw new Error(`not enough data to read on TLV ${t}`);
|
||||
result[t] = result[t] || [];
|
||||
result[t].push(v);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function nsecEncode(hex) {
|
||||
return encodeBytes("nsec", hex);
|
||||
}
|
||||
function npubEncode(hex) {
|
||||
return encodeBytes("npub", hex);
|
||||
}
|
||||
function noteEncode(hex) {
|
||||
return encodeBytes("note", hex);
|
||||
}
|
||||
function encodeBech32(prefix, data) {
|
||||
let words = bech32.toWords(data);
|
||||
return bech32.encode(prefix, words, Bech32MaxSize);
|
||||
}
|
||||
function encodeBytes(prefix, hex) {
|
||||
let data = hexToBytes(hex);
|
||||
return encodeBech32(prefix, data);
|
||||
}
|
||||
function nprofileEncode(profile) {
|
||||
let data = encodeTLV({
|
||||
0: [hexToBytes(profile.pubkey)],
|
||||
1: (profile.relays || []).map((url) => utf8Encoder.encode(url))
|
||||
});
|
||||
return encodeBech32("nprofile", data);
|
||||
}
|
||||
function neventEncode(event) {
|
||||
let kindArray;
|
||||
if (event.kind != void 0) {
|
||||
kindArray = integerToUint8Array(event.kind);
|
||||
}
|
||||
let data = encodeTLV({
|
||||
0: [hexToBytes(event.id)],
|
||||
1: (event.relays || []).map((url) => utf8Encoder.encode(url)),
|
||||
2: event.author ? [hexToBytes(event.author)] : [],
|
||||
3: kindArray ? [new Uint8Array(kindArray)] : []
|
||||
});
|
||||
return encodeBech32("nevent", data);
|
||||
}
|
||||
function naddrEncode(addr) {
|
||||
let kind = new ArrayBuffer(4);
|
||||
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: [hexToBytes(addr.pubkey)],
|
||||
3: [new Uint8Array(kind)]
|
||||
});
|
||||
return encodeBech32("naddr", data);
|
||||
}
|
||||
function nrelayEncode(url) {
|
||||
let data = encodeTLV({
|
||||
0: [utf8Encoder.encode(url)]
|
||||
});
|
||||
return encodeBech32("nrelay", data);
|
||||
}
|
||||
function encodeTLV(tlv) {
|
||||
let entries = [];
|
||||
Object.entries(tlv).forEach(([t, vs]) => {
|
||||
vs.forEach((v) => {
|
||||
let entry = new Uint8Array(v.length + 2);
|
||||
entry.set([parseInt(t)], 0);
|
||||
entry.set([v.length], 1);
|
||||
entry.set(v, 2);
|
||||
entries.push(entry);
|
||||
});
|
||||
});
|
||||
return concatBytes(...entries);
|
||||
}
|
||||
export {
|
||||
BECH32_REGEX,
|
||||
decode,
|
||||
naddrEncode,
|
||||
neventEncode,
|
||||
noteEncode,
|
||||
nprofileEncode,
|
||||
npubEncode,
|
||||
nrelayEncode,
|
||||
nsecEncode
|
||||
};
|
||||
-7
File diff suppressed because one or more lines are too long
-126
@@ -1,126 +0,0 @@
|
||||
// nip19.ts
|
||||
import { bytesToHex, concatBytes, hexToBytes } from "@noble/hashes/utils";
|
||||
import { bech32 } from "@scure/base";
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// nip19.ts
|
||||
var Bech32MaxSize = 5e3;
|
||||
var BECH32_REGEX = /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/;
|
||||
function decode(nip19) {
|
||||
let { prefix, words } = bech32.decode(nip19, Bech32MaxSize);
|
||||
let data = new Uint8Array(bech32.fromWords(words));
|
||||
switch (prefix) {
|
||||
case "nprofile": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nprofile");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
return {
|
||||
type: "nprofile",
|
||||
data: {
|
||||
pubkey: bytesToHex(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nevent": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nevent");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
if (tlv[2] && tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (tlv[3] && tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "nevent",
|
||||
data: {
|
||||
id: bytesToHex(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],
|
||||
author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : void 0,
|
||||
kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : void 0
|
||||
}
|
||||
};
|
||||
}
|
||||
case "naddr": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for naddr");
|
||||
if (!tlv[2]?.[0])
|
||||
throw new Error("missing TLV 2 for naddr");
|
||||
if (tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (!tlv[3]?.[0])
|
||||
throw new Error("missing TLV 3 for naddr");
|
||||
if (tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "naddr",
|
||||
data: {
|
||||
identifier: utf8Decoder.decode(tlv[0][0]),
|
||||
pubkey: bytesToHex(tlv[2][0]),
|
||||
kind: parseInt(bytesToHex(tlv[3][0]), 16),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nrelay": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nrelay");
|
||||
return {
|
||||
type: "nrelay",
|
||||
data: utf8Decoder.decode(tlv[0][0])
|
||||
};
|
||||
}
|
||||
case "nsec":
|
||||
case "npub":
|
||||
case "note":
|
||||
return { type: prefix, data: bytesToHex(data) };
|
||||
default:
|
||||
throw new Error(`unknown prefix ${prefix}`);
|
||||
}
|
||||
}
|
||||
function parseTLV(data) {
|
||||
let result = {};
|
||||
let rest = data;
|
||||
while (rest.length > 0) {
|
||||
let t = rest[0];
|
||||
let l = rest[1];
|
||||
if (!l)
|
||||
throw new Error(`malformed TLV ${t}`);
|
||||
let v = rest.slice(2, 2 + l);
|
||||
rest = rest.slice(2 + l);
|
||||
if (v.length < l)
|
||||
throw new Error(`not enough data to read on TLV ${t}`);
|
||||
result[t] = result[t] || [];
|
||||
result[t].push(v);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// nip21.ts
|
||||
var NOSTR_URI_REGEX = new RegExp(`nostr:(${BECH32_REGEX.source})`);
|
||||
function test(value) {
|
||||
return typeof value === "string" && new RegExp(`^${NOSTR_URI_REGEX.source}$`).test(value);
|
||||
}
|
||||
function parse(uri) {
|
||||
const match = uri.match(new RegExp(`^${NOSTR_URI_REGEX.source}$`));
|
||||
if (!match)
|
||||
throw new Error(`Invalid Nostr URI: ${uri}`);
|
||||
return {
|
||||
uri: match[0],
|
||||
value: match[1],
|
||||
decoded: decode(match[1])
|
||||
};
|
||||
}
|
||||
export {
|
||||
NOSTR_URI_REGEX,
|
||||
parse,
|
||||
test
|
||||
};
|
||||
-7
File diff suppressed because one or more lines are too long
-108
@@ -1,108 +0,0 @@
|
||||
// event.ts
|
||||
import { schnorr as schnorr2 } from "@noble/curves/secp256k1";
|
||||
import { sha256 } from "@noble/hashes/sha256";
|
||||
import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
|
||||
|
||||
// keys.ts
|
||||
import { schnorr } from "@noble/curves/secp256k1";
|
||||
import { bytesToHex } from "@noble/hashes/utils";
|
||||
function getPublicKey(privateKey) {
|
||||
return bytesToHex(schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function finishEvent(t, privateKey) {
|
||||
const event = t;
|
||||
event.pubkey = getPublicKey(privateKey);
|
||||
event.id = getEventHash(event);
|
||||
event.sig = getSignature(event, privateKey);
|
||||
event[verifiedSymbol] = true;
|
||||
return event;
|
||||
}
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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 = sha256(utf8Encoder.encode(serializeEvent(event)));
|
||||
return bytesToHex2(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function getSignature(event, key) {
|
||||
return bytesToHex2(schnorr2.sign(getEventHash(event), key));
|
||||
}
|
||||
|
||||
// nip25.ts
|
||||
function finishReactionEvent(t, reacted, privateKey) {
|
||||
const inheritedTags = reacted.tags.filter((tag) => tag.length >= 2 && (tag[0] === "e" || tag[0] === "p"));
|
||||
return finishEvent(
|
||||
{
|
||||
...t,
|
||||
kind: 7 /* Reaction */,
|
||||
tags: [...t.tags ?? [], ...inheritedTags, ["e", reacted.id], ["p", reacted.pubkey]],
|
||||
content: t.content ?? "+"
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
}
|
||||
function getReactedEventPointer(event) {
|
||||
if (event.kind !== 7 /* Reaction */) {
|
||||
return void 0;
|
||||
}
|
||||
let lastETag;
|
||||
let lastPTag;
|
||||
for (let i = event.tags.length - 1; i >= 0 && (lastETag === void 0 || lastPTag === void 0); i--) {
|
||||
const tag = event.tags[i];
|
||||
if (tag.length >= 2) {
|
||||
if (tag[0] === "e" && lastETag === void 0) {
|
||||
lastETag = tag;
|
||||
} else if (tag[0] === "p" && lastPTag === void 0) {
|
||||
lastPTag = tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lastETag === void 0 || lastPTag === void 0) {
|
||||
return void 0;
|
||||
}
|
||||
return {
|
||||
id: lastETag[1],
|
||||
relays: [lastETag[2], lastPTag[2]].filter((x) => x !== void 0),
|
||||
author: lastPTag[1]
|
||||
};
|
||||
}
|
||||
export {
|
||||
finishReactionEvent,
|
||||
getReactedEventPointer
|
||||
};
|
||||
-7
File diff suppressed because one or more lines are too long
-65
@@ -1,65 +0,0 @@
|
||||
// nip26.ts
|
||||
import { schnorr as schnorr2 } from "@noble/curves/secp256k1";
|
||||
import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
|
||||
import { sha256 } from "@noble/hashes/sha256";
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// keys.ts
|
||||
import { schnorr } from "@noble/curves/secp256k1";
|
||||
import { bytesToHex } from "@noble/hashes/utils";
|
||||
function getPublicKey(privateKey) {
|
||||
return bytesToHex(schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
|
||||
// nip26.ts
|
||||
function createDelegation(privateKey, parameters) {
|
||||
let conditions = [];
|
||||
if ((parameters.kind || -1) >= 0)
|
||||
conditions.push(`kind=${parameters.kind}`);
|
||||
if (parameters.until)
|
||||
conditions.push(`created_at<${parameters.until}`);
|
||||
if (parameters.since)
|
||||
conditions.push(`created_at>${parameters.since}`);
|
||||
let cond = conditions.join("&");
|
||||
if (cond === "")
|
||||
throw new Error("refusing to create a delegation without any conditions");
|
||||
let sighash = sha256(utf8Encoder.encode(`nostr:delegation:${parameters.pubkey}:${cond}`));
|
||||
let sig = bytesToHex2(schnorr2.sign(sighash, privateKey));
|
||||
return {
|
||||
from: getPublicKey(privateKey),
|
||||
to: parameters.pubkey,
|
||||
cond,
|
||||
sig
|
||||
};
|
||||
}
|
||||
function getDelegator(event) {
|
||||
let tag = event.tags.find((tag2) => tag2[0] === "delegation" && tag2.length >= 4);
|
||||
if (!tag)
|
||||
return null;
|
||||
let pubkey = tag[1];
|
||||
let cond = tag[2];
|
||||
let sig = tag[3];
|
||||
let conditions = cond.split("&");
|
||||
for (let i = 0; i < conditions.length; i++) {
|
||||
let [key, operator, value] = conditions[i].split(/\b/);
|
||||
if (key === "kind" && operator === "=" && event.kind === parseInt(value))
|
||||
continue;
|
||||
else if (key === "created_at" && operator === "<" && event.created_at < parseInt(value))
|
||||
continue;
|
||||
else if (key === "created_at" && operator === ">" && event.created_at > parseInt(value))
|
||||
continue;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
let sighash = sha256(utf8Encoder.encode(`nostr:delegation:${event.pubkey}:${cond}`));
|
||||
if (!schnorr2.verify(sig, sighash, pubkey))
|
||||
return null;
|
||||
return pubkey;
|
||||
}
|
||||
export {
|
||||
createDelegation,
|
||||
getDelegator
|
||||
};
|
||||
-7
File diff suppressed because one or more lines are too long
-141
@@ -1,141 +0,0 @@
|
||||
// nip19.ts
|
||||
import { bytesToHex, concatBytes, hexToBytes } from "@noble/hashes/utils";
|
||||
import { bech32 } from "@scure/base";
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// nip19.ts
|
||||
var Bech32MaxSize = 5e3;
|
||||
var BECH32_REGEX = /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/;
|
||||
function decode(nip19) {
|
||||
let { prefix, words } = bech32.decode(nip19, Bech32MaxSize);
|
||||
let data = new Uint8Array(bech32.fromWords(words));
|
||||
switch (prefix) {
|
||||
case "nprofile": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nprofile");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
return {
|
||||
type: "nprofile",
|
||||
data: {
|
||||
pubkey: bytesToHex(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nevent": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nevent");
|
||||
if (tlv[0][0].length !== 32)
|
||||
throw new Error("TLV 0 should be 32 bytes");
|
||||
if (tlv[2] && tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (tlv[3] && tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "nevent",
|
||||
data: {
|
||||
id: bytesToHex(tlv[0][0]),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : [],
|
||||
author: tlv[2]?.[0] ? bytesToHex(tlv[2][0]) : void 0,
|
||||
kind: tlv[3]?.[0] ? parseInt(bytesToHex(tlv[3][0]), 16) : void 0
|
||||
}
|
||||
};
|
||||
}
|
||||
case "naddr": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for naddr");
|
||||
if (!tlv[2]?.[0])
|
||||
throw new Error("missing TLV 2 for naddr");
|
||||
if (tlv[2][0].length !== 32)
|
||||
throw new Error("TLV 2 should be 32 bytes");
|
||||
if (!tlv[3]?.[0])
|
||||
throw new Error("missing TLV 3 for naddr");
|
||||
if (tlv[3][0].length !== 4)
|
||||
throw new Error("TLV 3 should be 4 bytes");
|
||||
return {
|
||||
type: "naddr",
|
||||
data: {
|
||||
identifier: utf8Decoder.decode(tlv[0][0]),
|
||||
pubkey: bytesToHex(tlv[2][0]),
|
||||
kind: parseInt(bytesToHex(tlv[3][0]), 16),
|
||||
relays: tlv[1] ? tlv[1].map((d) => utf8Decoder.decode(d)) : []
|
||||
}
|
||||
};
|
||||
}
|
||||
case "nrelay": {
|
||||
let tlv = parseTLV(data);
|
||||
if (!tlv[0]?.[0])
|
||||
throw new Error("missing TLV 0 for nrelay");
|
||||
return {
|
||||
type: "nrelay",
|
||||
data: utf8Decoder.decode(tlv[0][0])
|
||||
};
|
||||
}
|
||||
case "nsec":
|
||||
case "npub":
|
||||
case "note":
|
||||
return { type: prefix, data: bytesToHex(data) };
|
||||
default:
|
||||
throw new Error(`unknown prefix ${prefix}`);
|
||||
}
|
||||
}
|
||||
function parseTLV(data) {
|
||||
let result = {};
|
||||
let rest = data;
|
||||
while (rest.length > 0) {
|
||||
let t = rest[0];
|
||||
let l = rest[1];
|
||||
if (!l)
|
||||
throw new Error(`malformed TLV ${t}`);
|
||||
let v = rest.slice(2, 2 + l);
|
||||
rest = rest.slice(2 + l);
|
||||
if (v.length < l)
|
||||
throw new Error(`not enough data to read on TLV ${t}`);
|
||||
result[t] = result[t] || [];
|
||||
result[t].push(v);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// nip21.ts
|
||||
var NOSTR_URI_REGEX = new RegExp(`nostr:(${BECH32_REGEX.source})`);
|
||||
|
||||
// nip27.ts
|
||||
var regex = () => new RegExp(`\\b${NOSTR_URI_REGEX.source}\\b`, "g");
|
||||
function* matchAll(content) {
|
||||
const matches = content.matchAll(regex());
|
||||
for (const match of matches) {
|
||||
try {
|
||||
const [uri, value] = match;
|
||||
yield {
|
||||
uri,
|
||||
value,
|
||||
decoded: decode(value),
|
||||
start: match.index,
|
||||
end: match.index + uri.length
|
||||
};
|
||||
} catch (_e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
function replaceAll(content, replacer) {
|
||||
return content.replaceAll(regex(), (uri, value) => {
|
||||
return replacer({
|
||||
uri,
|
||||
value,
|
||||
decoded: decode(value)
|
||||
});
|
||||
});
|
||||
}
|
||||
export {
|
||||
matchAll,
|
||||
regex,
|
||||
replaceAll
|
||||
};
|
||||
-7
File diff suppressed because one or more lines are too long
-165
@@ -1,165 +0,0 @@
|
||||
// event.ts
|
||||
import { schnorr as schnorr2 } from "@noble/curves/secp256k1";
|
||||
import { sha256 } from "@noble/hashes/sha256";
|
||||
import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils";
|
||||
|
||||
// keys.ts
|
||||
import { schnorr } from "@noble/curves/secp256k1";
|
||||
import { bytesToHex } from "@noble/hashes/utils";
|
||||
function getPublicKey(privateKey) {
|
||||
return bytesToHex(schnorr.getPublicKey(privateKey));
|
||||
}
|
||||
|
||||
// utils.ts
|
||||
var utf8Decoder = new TextDecoder("utf-8");
|
||||
var utf8Encoder = new TextEncoder();
|
||||
|
||||
// event.ts
|
||||
var verifiedSymbol = Symbol("verified");
|
||||
function finishEvent(t, privateKey) {
|
||||
const event = t;
|
||||
event.pubkey = getPublicKey(privateKey);
|
||||
event.id = getEventHash(event);
|
||||
event.sig = getSignature(event, privateKey);
|
||||
event[verifiedSymbol] = true;
|
||||
return event;
|
||||
}
|
||||
function serializeEvent(evt) {
|
||||
if (!validateEvent(evt))
|
||||
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 = sha256(utf8Encoder.encode(serializeEvent(event)));
|
||||
return bytesToHex2(eventHash);
|
||||
}
|
||||
var isRecord = (obj) => obj instanceof Object;
|
||||
function validateEvent(event) {
|
||||
if (!isRecord(event))
|
||||
return false;
|
||||
if (typeof event.kind !== "number")
|
||||
return false;
|
||||
if (typeof event.content !== "string")
|
||||
return false;
|
||||
if (typeof event.created_at !== "number")
|
||||
return false;
|
||||
if (typeof event.pubkey !== "string")
|
||||
return false;
|
||||
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
||||
return false;
|
||||
if (!Array.isArray(event.tags))
|
||||
return false;
|
||||
for (let i = 0; i < event.tags.length; i++) {
|
||||
let tag = event.tags[i];
|
||||
if (!Array.isArray(tag))
|
||||
return false;
|
||||
for (let j = 0; j < tag.length; j++) {
|
||||
if (typeof tag[j] === "object")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function getSignature(event, key) {
|
||||
return bytesToHex2(schnorr2.sign(getEventHash(event), key));
|
||||
}
|
||||
|
||||
// nip28.ts
|
||||
var channelCreateEvent = (t, privateKey) => {
|
||||
let content;
|
||||
if (typeof t.content === "object") {
|
||||
content = JSON.stringify(t.content);
|
||||
} else if (typeof t.content === "string") {
|
||||
content = t.content;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
return finishEvent(
|
||||
{
|
||||
kind: 40 /* ChannelCreation */,
|
||||
tags: [...t.tags ?? []],
|
||||
content,
|
||||
created_at: t.created_at
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
};
|
||||
var channelMetadataEvent = (t, privateKey) => {
|
||||
let content;
|
||||
if (typeof t.content === "object") {
|
||||
content = JSON.stringify(t.content);
|
||||
} else if (typeof t.content === "string") {
|
||||
content = t.content;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
return finishEvent(
|
||||
{
|
||||
kind: 41 /* ChannelMetadata */,
|
||||
tags: [["e", t.channel_create_event_id], ...t.tags ?? []],
|
||||
content,
|
||||
created_at: t.created_at
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
};
|
||||
var channelMessageEvent = (t, privateKey) => {
|
||||
const tags = [["e", t.channel_create_event_id, t.relay_url, "root"]];
|
||||
if (t.reply_to_channel_message_event_id) {
|
||||
tags.push(["e", t.reply_to_channel_message_event_id, t.relay_url, "reply"]);
|
||||
}
|
||||
return finishEvent(
|
||||
{
|
||||
kind: 42 /* ChannelMessage */,
|
||||
tags: [...tags, ...t.tags ?? []],
|
||||
content: t.content,
|
||||
created_at: t.created_at
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
};
|
||||
var channelHideMessageEvent = (t, privateKey) => {
|
||||
let content;
|
||||
if (typeof t.content === "object") {
|
||||
content = JSON.stringify(t.content);
|
||||
} else if (typeof t.content === "string") {
|
||||
content = t.content;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
return finishEvent(
|
||||
{
|
||||
kind: 43 /* ChannelHideMessage */,
|
||||
tags: [["e", t.channel_message_event_id], ...t.tags ?? []],
|
||||
content,
|
||||
created_at: t.created_at
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
};
|
||||
var channelMuteUserEvent = (t, privateKey) => {
|
||||
let content;
|
||||
if (typeof t.content === "object") {
|
||||
content = JSON.stringify(t.content);
|
||||
} else if (typeof t.content === "string") {
|
||||
content = t.content;
|
||||
} else {
|
||||
return void 0;
|
||||
}
|
||||
return finishEvent(
|
||||
{
|
||||
kind: 44 /* ChannelMuteUser */,
|
||||
tags: [["p", t.pubkey_to_mute], ...t.tags ?? []],
|
||||
content,
|
||||
created_at: t.created_at
|
||||
},
|
||||
privateKey
|
||||
);
|
||||
};
|
||||
export {
|
||||
channelCreateEvent,
|
||||
channelHideMessageEvent,
|
||||
channelMessageEvent,
|
||||
channelMetadataEvent,
|
||||
channelMuteUserEvent
|
||||
};
|
||||
-7
File diff suppressed because one or more lines are too long
-21
@@ -1,21 +0,0 @@
|
||||
// nip39.ts
|
||||
var _fetch;
|
||||
try {
|
||||
_fetch = fetch;
|
||||
} catch {
|
||||
}
|
||||
function useFetchImplementation(fetchImplementation) {
|
||||
_fetch = fetchImplementation;
|
||||
}
|
||||
async function validateGithub(pubkey, username, proof) {
|
||||
try {
|
||||
let res = await (await _fetch(`https://gist.github.com/${username}/${proof}/raw`)).text();
|
||||
return res === `Verifying that I control the following Nostr public key: ${pubkey}`;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export {
|
||||
useFetchImplementation,
|
||||
validateGithub
|
||||
};
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../nip39.ts"],
|
||||
"sourcesContent": ["var _fetch: any\n\ntry {\n _fetch = fetch\n} catch {}\n\nexport function useFetchImplementation(fetchImplementation: any) {\n _fetch = fetchImplementation\n}\n\nexport async function validateGithub(pubkey: string, username: string, proof: string): Promise<boolean> {\n try {\n let res = await (await _fetch(`https://gist.github.com/${username}/${proof}/raw`)).text()\n return res === `Verifying that I control the following Nostr public key: ${pubkey}`\n } catch (_) {\n return false\n }\n}\n"],
|
||||
"mappings": ";AAAA,IAAI;AAEJ,IAAI;AACF,WAAS;AACX,QAAE;AAAO;AAEF,SAAS,uBAAuB,qBAA0B;AAC/D,WAAS;AACX;AAEA,eAAsB,eAAe,QAAgB,UAAkB,OAAiC;AACtG,MAAI;AACF,QAAI,MAAM,OAAO,MAAM,OAAO,2BAA2B,YAAY,WAAW,GAAG,KAAK;AACxF,WAAO,QAAQ,4DAA4D;AAAA,EAC7E,SAAS,GAAP;AACA,WAAO;AAAA,EACT;AACF;",
|
||||
"names": []
|
||||
}
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
// nip42.ts
|
||||
var authenticate = async ({
|
||||
challenge,
|
||||
relay,
|
||||
sign
|
||||
}) => {
|
||||
const e = {
|
||||
kind: 22242 /* ClientAuth */,
|
||||
created_at: Math.floor(Date.now() / 1e3),
|
||||
tags: [
|
||||
["relay", relay.url],
|
||||
["challenge", challenge]
|
||||
],
|
||||
content: ""
|
||||
};
|
||||
return relay.auth(await sign(e));
|
||||
};
|
||||
export {
|
||||
authenticate
|
||||
};
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../nip42.ts"],
|
||||
"sourcesContent": ["import { Kind, type EventTemplate, type Event } from './event.ts'\nimport { Relay } from './relay.ts'\n\n/**\n * Authenticate via NIP-42 flow.\n *\n * @example\n * const sign = window.nostr.signEvent\n * relay.on('auth', challenge =>\n * authenticate({ relay, sign, challenge })\n * )\n */\nexport const authenticate = async ({\n challenge,\n relay,\n sign,\n}: {\n challenge: string\n relay: Relay\n sign: <K extends number = number>(e: EventTemplate<K>) => Promise<Event<K>> | Event<K>\n}): Promise<void> => {\n const e: EventTemplate = {\n kind: Kind.ClientAuth,\n created_at: Math.floor(Date.now() / 1000),\n tags: [\n ['relay', relay.url],\n ['challenge', challenge],\n ],\n content: '',\n }\n return relay.auth(await sign(e))\n}\n"],
|
||||
"mappings": ";AAYO,IAAM,eAAe,OAAO;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AACF,MAIqB;AACnB,QAAM,IAAmB;AAAA,IACvB;AAAA,IACA,YAAY,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAAA,IACxC,MAAM;AAAA,MACJ,CAAC,SAAS,MAAM,GAAG;AAAA,MACnB,CAAC,aAAa,SAAS;AAAA,IACzB;AAAA,IACA,SAAS;AAAA,EACX;AACA,SAAO,MAAM,KAAK,MAAM,KAAK,CAAC,CAAC;AACjC;",
|
||||
"names": []
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user