mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2025-12-08 16:28:49 +00:00
split relay and pool into pure and wasm modules.
This commit is contained in:
13
README.md
13
README.md
@@ -43,9 +43,9 @@ let isGood = verifyEvent(event)
|
|||||||
### Interacting with a relay
|
### Interacting with a relay
|
||||||
|
|
||||||
```js
|
```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}`)
|
console.log(`connected to ${relay.url}`)
|
||||||
|
|
||||||
// let's query for an event that exists
|
// 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
|
```js
|
||||||
import { generateSecretKey, finalizeEvent, verifyEvent } from 'nostr-tools/pure'
|
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 { matchFilter } from 'nostr-tools/filter'
|
||||||
import { decode, nprofileEncode, neventEncode, npubEncode } from 'nostr-tools/nip19'
|
import { decode, nprofileEncode, neventEncode, npubEncode } from 'nostr-tools/nip19'
|
||||||
// and so on and so forth
|
// and so on and so forth
|
||||||
@@ -230,6 +232,13 @@ initNostrWasm().then(setNostrWasm)
|
|||||||
// see https://www.npmjs.com/package/nostr-wasm for options
|
// 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`.
|
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)
|
### Using from the browser (if you don't want to use a bundler)
|
||||||
|
|||||||
5
index.ts
5
index.ts
@@ -1,8 +1,7 @@
|
|||||||
export * from './pure.ts'
|
export * from './pure.ts'
|
||||||
export * from './relay.ts'
|
export * from './relay-pure.ts'
|
||||||
export * from './pure.ts'
|
|
||||||
export * from './filter.ts'
|
export * from './filter.ts'
|
||||||
export * from './pool.ts'
|
export * from './pool-pure.ts'
|
||||||
export * from './references.ts'
|
export * from './references.ts'
|
||||||
|
|
||||||
export * as nip04 from './nip04.ts'
|
export * as nip04 from './nip04.ts'
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { test, expect } from 'bun:test'
|
import { test, expect } from 'bun:test'
|
||||||
|
|
||||||
import { makeAuthEvent } from './nip42.ts'
|
import { makeAuthEvent } from './nip42.ts'
|
||||||
import { relayConnect } from './relay.ts'
|
import Relay from './relay-pure.ts'
|
||||||
|
|
||||||
test('auth flow', async () => {
|
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')
|
const auth = makeAuthEvent(relay.url, 'chachacha')
|
||||||
expect(auth.tags).toHaveLength(2)
|
expect(auth.tags).toHaveLength(2)
|
||||||
|
|||||||
38
package.json
38
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nostr-tools",
|
"name": "nostr-tools",
|
||||||
"version": "2.0.3",
|
"version": "2.1.0",
|
||||||
"description": "Tools for making a Nostr client.",
|
"description": "Tools for making a Nostr client.",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -39,15 +39,35 @@
|
|||||||
"require": "./lib/cjs/filter.js",
|
"require": "./lib/cjs/filter.js",
|
||||||
"types": "./lib/types/filter.d.ts"
|
"types": "./lib/types/filter.d.ts"
|
||||||
},
|
},
|
||||||
"./relay": {
|
"./trusted-relay": {
|
||||||
"import": "./lib/esm/relay.js",
|
"import": "./lib/esm/trusted-relay.js",
|
||||||
"require": "./lib/cjs/relay.js",
|
"require": "./lib/cjs/trusted-relay.js",
|
||||||
"types": "./lib/types/relay.d.ts"
|
"types": "./lib/types/trusted-relay.d.ts"
|
||||||
},
|
},
|
||||||
"./pool": {
|
"./relay-wasm": {
|
||||||
"import": "./lib/esm/pool.js",
|
"import": "./lib/esm/relay-wasm.js",
|
||||||
"require": "./lib/cjs/pool.js",
|
"require": "./lib/cjs/relay-wasm.js",
|
||||||
"types": "./lib/types/pool.d.ts"
|
"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": {
|
"./references": {
|
||||||
"import": "./lib/esm/references.js",
|
"import": "./lib/esm/references.js",
|
||||||
|
|||||||
10
pool-pure.ts
Normal file
10
pool-pure.ts
Normal file
@@ -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'
|
||||||
10
pool-wasm.ts
Normal file
10
pool-wasm.ts
Normal file
@@ -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'
|
||||||
16
relay-pure.ts
Normal file
16
relay-pure.ts
Normal file
@@ -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'
|
||||||
16
relay-wasm.ts
Normal file
16
relay-wasm.ts
Normal file
@@ -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'
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { afterEach, expect, test } from 'bun:test'
|
import { afterEach, expect, test } from 'bun:test'
|
||||||
|
|
||||||
import { finalizeEvent, generateSecretKey, getPublicKey } from './pure.ts'
|
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')
|
let relay = new Relay('wss://public.relaying.io')
|
||||||
|
|
||||||
@@ -14,8 +14,8 @@ test('connectivity', async () => {
|
|||||||
expect(relay.connected).toBeTrue()
|
expect(relay.connected).toBeTrue()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('connectivity, with relayConnect()', async () => {
|
test('connectivity, with Relay.connect()', async () => {
|
||||||
const relay = await relayConnect('wss://public.relaying.io')
|
const relay = await Relay.connect('wss://public.relaying.io')
|
||||||
expect(relay.connected).toBeTrue()
|
expect(relay.connected).toBeTrue()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -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 { normalizeURL } from './utils.ts'
|
||||||
|
|
||||||
import type { Event } from './core.ts'
|
import type { Event, Nostr } from './core.ts'
|
||||||
import { type Filter } from './filter.ts'
|
import { type Filter } from './filter.ts'
|
||||||
|
|
||||||
export type SubCloser = { close: () => void }
|
export type SubCloser = { close: () => void }
|
||||||
@@ -12,21 +12,27 @@ export type SubscribeManyParams = Omit<SubscriptionParams, 'onclose' | 'id'> & {
|
|||||||
id?: string
|
id?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SimplePool {
|
export default class TrustedSimplePool {
|
||||||
private relays = new Map<string, Relay>()
|
private relays = new Map<string, Relay>()
|
||||||
public seenOn = new Map<string, Set<Relay>>()
|
public seenOn = new Map<string, Set<Relay>>()
|
||||||
public trackRelays: boolean = false
|
public trackRelays: boolean = false
|
||||||
|
|
||||||
|
public verifyEvent: Nostr['verifyEvent'] | undefined
|
||||||
public trustedRelayURLs = new Set<string>()
|
public trustedRelayURLs = new Set<string>()
|
||||||
|
|
||||||
|
constructor(opts: { verifyEvent?: Nostr['verifyEvent'] } = {}) {
|
||||||
|
this.verifyEvent = opts.verifyEvent
|
||||||
|
}
|
||||||
|
|
||||||
async ensureRelay(url: string, params?: { connectionTimeout?: number }): Promise<Relay> {
|
async ensureRelay(url: string, params?: { connectionTimeout?: number }): Promise<Relay> {
|
||||||
url = normalizeURL(url)
|
url = normalizeURL(url)
|
||||||
|
|
||||||
let relay = this.relays.get(url)
|
let relay = this.relays.get(url)
|
||||||
if (!relay) {
|
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 (params?.connectionTimeout) relay.connectionTimeout = params.connectionTimeout
|
||||||
if (this.trustedRelayURLs.has(relay.url)) relay.trusted = true
|
|
||||||
this.relays.set(url, relay)
|
this.relays.set(url, relay)
|
||||||
}
|
}
|
||||||
await relay.connect()
|
await relay.connect()
|
||||||
@@ -1,23 +1,16 @@
|
|||||||
/* global WebSocket */
|
/* 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 { matchFilters, type Filter } from './filter.ts'
|
||||||
import { getHex64, getSubscriptionId } from './fakejson.ts'
|
import { getHex64, getSubscriptionId } from './fakejson.ts'
|
||||||
import { Queue, normalizeURL } from './utils.ts'
|
import { Queue, normalizeURL } from './utils.ts'
|
||||||
import { nip42 } from './index.ts'
|
import { nip42 } from './index.ts'
|
||||||
import { yieldThread } from './helpers.ts'
|
import { yieldThread } from './helpers.ts'
|
||||||
|
|
||||||
export async function relayConnect(url: string) {
|
export default class TrustedRelay {
|
||||||
const relay = new Relay(url)
|
|
||||||
await relay.connect()
|
|
||||||
return relay
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Relay {
|
|
||||||
public readonly url: string
|
public readonly url: string
|
||||||
private _connected: boolean = false
|
private _connected: boolean = false
|
||||||
|
|
||||||
public trusted: boolean = false
|
|
||||||
public onclose: (() => void) | null = null
|
public onclose: (() => void) | null = null
|
||||||
public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)
|
public onnotice: (msg: string) => void = msg => console.debug(`NOTICE from ${this.url}: ${msg}`)
|
||||||
|
|
||||||
@@ -34,9 +27,17 @@ export class Relay {
|
|||||||
private queueRunning = false
|
private queueRunning = false
|
||||||
private challenge: string | undefined
|
private challenge: string | undefined
|
||||||
private serial: number = 0
|
private serial: number = 0
|
||||||
|
private verifyEvent: Nostr['verifyEvent'] | undefined
|
||||||
|
|
||||||
constructor(url: string) {
|
constructor(url: string, opts: { verifyEvent?: Nostr['verifyEvent'] } = {}) {
|
||||||
this.url = normalizeURL(url)
|
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) {
|
private closeAllSubscriptions(reason: string) {
|
||||||
@@ -162,7 +163,7 @@ export class Relay {
|
|||||||
case 'EVENT': {
|
case 'EVENT': {
|
||||||
const so = this.openSubs.get(data[1] as string) as Subscription
|
const so = this.openSubs.get(data[1] as string) as Subscription
|
||||||
const event = data[2] as Event
|
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)
|
so.onevent(event)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -270,14 +271,14 @@ export class Relay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Subscription {
|
export class Subscription {
|
||||||
public readonly relay: Relay
|
public readonly relay: TrustedRelay
|
||||||
public readonly id: string
|
public readonly id: string
|
||||||
|
|
||||||
public closed: boolean = false
|
public closed: boolean = false
|
||||||
public eosed: boolean = false
|
public eosed: boolean = false
|
||||||
public filters: Filter[]
|
public filters: Filter[]
|
||||||
public alreadyHaveEvent: ((id: string) => boolean) | undefined
|
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 onevent: (evt: Event) => void
|
||||||
public oneose: (() => void) | undefined
|
public oneose: (() => void) | undefined
|
||||||
@@ -286,7 +287,7 @@ export class Subscription {
|
|||||||
public eoseTimeout: number
|
public eoseTimeout: number
|
||||||
private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined
|
private eoseTimeoutHandle: ReturnType<typeof setTimeout> | undefined
|
||||||
|
|
||||||
constructor(relay: Relay, id: string, filters: Filter[], params: SubscriptionParams) {
|
constructor(relay: TrustedRelay, id: string, filters: Filter[], params: SubscriptionParams) {
|
||||||
this.relay = relay
|
this.relay = relay
|
||||||
this.filters = filters
|
this.filters = filters
|
||||||
this.id = id
|
this.id = id
|
||||||
@@ -336,7 +337,7 @@ export type SubscriptionParams = {
|
|||||||
oneose?: () => void
|
oneose?: () => void
|
||||||
onclose?: (reason: string) => void
|
onclose?: (reason: string) => void
|
||||||
alreadyHaveEvent?: (id: string) => boolean
|
alreadyHaveEvent?: (id: string) => boolean
|
||||||
receivedEvent?: (relay: Relay, id: string) => void
|
receivedEvent?: (relay: TrustedRelay, id: string) => void
|
||||||
eoseTimeout?: number
|
eoseTimeout?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user