From a4ae964ee68e4783a3443fca39f1574420b9d655 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Thu, 21 Dec 2023 17:25:24 -0300 Subject: [PATCH] split relay and pool into pure and wasm modules. --- README.md | 13 ++++++++++-- index.ts | 5 ++--- nip42.test.ts | 4 ++-- package.json | 38 +++++++++++++++++++++++++++--------- pool-pure.ts | 10 ++++++++++ pool-wasm.ts | 10 ++++++++++ relay-pure.ts | 16 +++++++++++++++ relay-wasm.ts | 16 +++++++++++++++ relay.test.ts | 6 +++--- pool.ts => trusted-pool.ts | 16 ++++++++++----- relay.ts => trusted-relay.ts | 31 +++++++++++++++-------------- 11 files changed, 126 insertions(+), 39 deletions(-) create mode 100644 pool-pure.ts create mode 100644 pool-wasm.ts create mode 100644 relay-pure.ts create mode 100644 relay-wasm.ts rename pool.ts => trusted-pool.ts (91%) rename relay.ts => trusted-relay.ts (92%) diff --git a/README.md b/README.md index 3ca5e5a..93e0595 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,9 @@ let isGood = verifyEvent(event) ### Interacting with a relay ```js -import { relayConnect, finalizeEvent, generateSecretKey, getPublicKey } from 'nostr-tools' +import { Relay, finalizeEvent, generateSecretKey, getPublicKey } from 'nostr-tools' -const relay = await relayConnect('wss://relay.example.com') +const relay = await Relay.connect('wss://relay.example.com') console.log(`connected to ${relay.url}`) // let's query for an event that exists @@ -210,6 +210,8 @@ Importing the entirety of `nostr-tools` may bloat your build, so you should prob ```js import { generateSecretKey, finalizeEvent, verifyEvent } from 'nostr-tools/pure' +import SimplePool from 'nostr-tools/pool-pure' +import Relay, { Subscription } from 'nostr-tools/relay-pure' import { matchFilter } from 'nostr-tools/filter' import { decode, nprofileEncode, neventEncode, npubEncode } from 'nostr-tools/nip19' // and so on and so forth @@ -230,6 +232,13 @@ initNostrWasm().then(setNostrWasm) // see https://www.npmjs.com/package/nostr-wasm for options ``` +If you're going to use `Relay` and `SimplePool` you must also import `nostr-tools/relay-wasm` and/or `nostr-tools/pool-wasm` instead of the defaults: + +```js +import Relay, { Subscription } from 'nostr-tools/relay-wasm' +import SimplePool from 'nostr-tools/pool-wasm' +``` + This may be faster than the pure-JS [noble libraries](https://paulmillr.com/noble/) used by default and in `nostr-tools/pure`. ### Using from the browser (if you don't want to use a bundler) diff --git a/index.ts b/index.ts index 247c5ba..ca227f5 100644 --- a/index.ts +++ b/index.ts @@ -1,8 +1,7 @@ export * from './pure.ts' -export * from './relay.ts' -export * from './pure.ts' +export * from './relay-pure.ts' export * from './filter.ts' -export * from './pool.ts' +export * from './pool-pure.ts' export * from './references.ts' export * as nip04 from './nip04.ts' diff --git a/nip42.test.ts b/nip42.test.ts index 374b638..663829f 100644 --- a/nip42.test.ts +++ b/nip42.test.ts @@ -1,10 +1,10 @@ import { test, expect } from 'bun:test' import { makeAuthEvent } from './nip42.ts' -import { relayConnect } from './relay.ts' +import Relay from './relay-pure.ts' test('auth flow', async () => { - const relay = await relayConnect('wss://nostr.wine') + const relay = await Relay.connect('wss://nostr.wine') const auth = makeAuthEvent(relay.url, 'chachacha') expect(auth.tags).toHaveLength(2) diff --git a/package.json b/package.json index 76aef1e..cc79d9c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nostr-tools", - "version": "2.0.3", + "version": "2.1.0", "description": "Tools for making a Nostr client.", "repository": { "type": "git", @@ -39,15 +39,35 @@ "require": "./lib/cjs/filter.js", "types": "./lib/types/filter.d.ts" }, - "./relay": { - "import": "./lib/esm/relay.js", - "require": "./lib/cjs/relay.js", - "types": "./lib/types/relay.d.ts" + "./trusted-relay": { + "import": "./lib/esm/trusted-relay.js", + "require": "./lib/cjs/trusted-relay.js", + "types": "./lib/types/trusted-relay.d.ts" }, - "./pool": { - "import": "./lib/esm/pool.js", - "require": "./lib/cjs/pool.js", - "types": "./lib/types/pool.d.ts" + "./relay-wasm": { + "import": "./lib/esm/relay-wasm.js", + "require": "./lib/cjs/relay-wasm.js", + "types": "./lib/types/relay-wasm.d.ts" + }, + "./relay-pure": { + "import": "./lib/esm/relay-pure.js", + "require": "./lib/cjs/relay-pure.js", + "types": "./lib/types/relay-pure.d.ts" + }, + "./trusted-pool": { + "import": "./lib/esm/trusted-pool.js", + "require": "./lib/cjs/trusted-pool.js", + "types": "./lib/types/trusted-pool.d.ts" + }, + "./pool-wasm": { + "import": "./lib/esm/pool-wasm.js", + "require": "./lib/cjs/pool-wasm.js", + "types": "./lib/types/pool-wasm.d.ts" + }, + "./pool-pure": { + "import": "./lib/esm/pool-pure.js", + "require": "./lib/cjs/pool-pure.js", + "types": "./lib/types/pool-pure.d.ts" }, "./references": { "import": "./lib/esm/references.js", diff --git a/pool-pure.ts b/pool-pure.ts new file mode 100644 index 0000000..b33de08 --- /dev/null +++ b/pool-pure.ts @@ -0,0 +1,10 @@ +import { verifyEvent } from './pure.ts' +import TrustedSimplePool from './trusted-pool.ts' + +export default class PureSimplePool extends TrustedSimplePool { + constructor() { + super({ verifyEvent }) + } +} + +export * from './trusted-pool.ts' diff --git a/pool-wasm.ts b/pool-wasm.ts new file mode 100644 index 0000000..0e964eb --- /dev/null +++ b/pool-wasm.ts @@ -0,0 +1,10 @@ +import { verifyEvent } from './wasm.ts' +import TrustedSimplePool from './trusted-pool.ts' + +export default class WasmSimplePool extends TrustedSimplePool { + constructor() { + super({ verifyEvent }) + } +} + +export * from './trusted-pool.ts' diff --git a/relay-pure.ts b/relay-pure.ts new file mode 100644 index 0000000..4668855 --- /dev/null +++ b/relay-pure.ts @@ -0,0 +1,16 @@ +import { verifyEvent } from './pure.ts' +import TrustedRelay from './trusted-relay.ts' + +export default class PureRelay extends TrustedRelay { + constructor(url: string) { + super(url, { verifyEvent }) + } + + static async connect(url: string) { + const relay = new PureRelay(url) + await relay.connect() + return relay + } +} + +export * from './trusted-relay.ts' diff --git a/relay-wasm.ts b/relay-wasm.ts new file mode 100644 index 0000000..ef7d302 --- /dev/null +++ b/relay-wasm.ts @@ -0,0 +1,16 @@ +import { verifyEvent } from './wasm.ts' +import TrustedRelay from './trusted-relay.ts' + +export default class WasmRelay extends TrustedRelay { + constructor(url: string) { + super(url, { verifyEvent }) + } + + static async connect(url: string) { + const relay = new WasmRelay(url) + await relay.connect() + return relay + } +} + +export * from './trusted-relay.ts' diff --git a/relay.test.ts b/relay.test.ts index c165f67..d2900f8 100644 --- a/relay.test.ts +++ b/relay.test.ts @@ -1,7 +1,7 @@ import { afterEach, expect, test } from 'bun:test' import { finalizeEvent, generateSecretKey, getPublicKey } from './pure.ts' -import { Relay, relayConnect } from './relay.ts' +import Relay from './relay-pure.ts' let relay = new Relay('wss://public.relaying.io') @@ -14,8 +14,8 @@ test('connectivity', async () => { expect(relay.connected).toBeTrue() }) -test('connectivity, with relayConnect()', async () => { - const relay = await relayConnect('wss://public.relaying.io') +test('connectivity, with Relay.connect()', async () => { + const relay = await Relay.connect('wss://public.relaying.io') expect(relay.connected).toBeTrue() }) diff --git a/pool.ts b/trusted-pool.ts similarity index 91% rename from pool.ts rename to trusted-pool.ts index 1106e6b..90d92b0 100644 --- a/pool.ts +++ b/trusted-pool.ts @@ -1,7 +1,7 @@ -import { Relay, SubscriptionParams, Subscription } from './relay.ts' +import Relay, { SubscriptionParams, Subscription } from './trusted-relay.ts' import { normalizeURL } from './utils.ts' -import type { Event } from './core.ts' +import type { Event, Nostr } from './core.ts' import { type Filter } from './filter.ts' export type SubCloser = { close: () => void } @@ -12,21 +12,27 @@ export type SubscribeManyParams = Omit & { id?: string } -export class SimplePool { +export default class TrustedSimplePool { private relays = new Map() public seenOn = new Map>() public trackRelays: boolean = false + public verifyEvent: Nostr['verifyEvent'] | undefined public trustedRelayURLs = new Set() + constructor(opts: { verifyEvent?: Nostr['verifyEvent'] } = {}) { + this.verifyEvent = opts.verifyEvent + } + async ensureRelay(url: string, params?: { connectionTimeout?: number }): Promise { url = normalizeURL(url) let relay = this.relays.get(url) if (!relay) { - relay = new Relay(url) + relay = new Relay(url, { + verifyEvent: this.trustedRelayURLs.has(url) ? undefined : this.verifyEvent, + }) if (params?.connectionTimeout) relay.connectionTimeout = params.connectionTimeout - if (this.trustedRelayURLs.has(relay.url)) relay.trusted = true this.relays.set(url, relay) } await relay.connect() diff --git a/relay.ts b/trusted-relay.ts similarity index 92% rename from relay.ts rename to trusted-relay.ts index 9d7fd7d..981df8f 100644 --- a/relay.ts +++ b/trusted-relay.ts @@ -1,23 +1,16 @@ /* global WebSocket */ -import { verifyEvent, validateEvent, type Event, EventTemplate } from './pure.ts' +import type { Event, EventTemplate, Nostr } from './core.ts' import { matchFilters, type Filter } from './filter.ts' import { getHex64, getSubscriptionId } from './fakejson.ts' import { Queue, normalizeURL } from './utils.ts' import { nip42 } from './index.ts' import { yieldThread } from './helpers.ts' -export async function relayConnect(url: string) { - const relay = new Relay(url) - await relay.connect() - return relay -} - -export class Relay { +export default class TrustedRelay { public readonly url: string private _connected: boolean = false - public trusted: boolean = false public onclose: (() => void) | null = null public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`) @@ -34,9 +27,17 @@ export class Relay { private queueRunning = false private challenge: string | undefined private serial: number = 0 + private verifyEvent: Nostr['verifyEvent'] | undefined - constructor(url: string) { + constructor(url: string, opts: { verifyEvent?: Nostr['verifyEvent'] } = {}) { this.url = normalizeURL(url) + this.verifyEvent = opts.verifyEvent + } + + static async connect(url: string, opts: { verifyEvent?: Nostr['verifyEvent'] } = {}) { + const relay = new TrustedRelay(url, opts) + await relay.connect() + return relay } private closeAllSubscriptions(reason: string) { @@ -162,7 +163,7 @@ export class Relay { case 'EVENT': { const so = this.openSubs.get(data[1] as string) as Subscription const event = data[2] as Event - if ((this.trusted || (validateEvent(event) && verifyEvent(event))) && matchFilters(so.filters, event)) { + if ((this.verifyEvent ? this.verifyEvent(event) : true) && matchFilters(so.filters, event)) { so.onevent(event) } return @@ -270,14 +271,14 @@ export class Relay { } export class Subscription { - public readonly relay: Relay + public readonly relay: TrustedRelay public readonly id: string public closed: boolean = false public eosed: boolean = false public filters: Filter[] public alreadyHaveEvent: ((id: string) => boolean) | undefined - public receivedEvent: ((relay: Relay, id: string) => void) | undefined + public receivedEvent: ((relay: TrustedRelay, id: string) => void) | undefined public onevent: (evt: Event) => void public oneose: (() => void) | undefined @@ -286,7 +287,7 @@ export class Subscription { public eoseTimeout: number private eoseTimeoutHandle: ReturnType | undefined - constructor(relay: Relay, id: string, filters: Filter[], params: SubscriptionParams) { + constructor(relay: TrustedRelay, id: string, filters: Filter[], params: SubscriptionParams) { this.relay = relay this.filters = filters this.id = id @@ -336,7 +337,7 @@ export type SubscriptionParams = { oneose?: () => void onclose?: (reason: string) => void alreadyHaveEvent?: (id: string) => boolean - receivedEvent?: (relay: Relay, id: string) => void + receivedEvent?: (relay: TrustedRelay, id: string) => void eoseTimeout?: number }