update readme and add more examples.

This commit is contained in:
fiatjaf
2025-04-02 10:46:50 -03:00
parent 303c35120c
commit 42d47abba1

203
README.md
View File

@@ -57,43 +57,43 @@ let event = finalizeEvent({
let isGood = verifyEvent(event) let isGood = verifyEvent(event)
``` ```
### Interacting with a relay ### Interacting with one or multiple relays
Doesn't matter what you do, you always should be using a `SimplePool`:
```js ```js
import { finalizeEvent, generateSecretKey, getPublicKey } from 'nostr-tools/pure' import { finalizeEvent, generateSecretKey, getPublicKey } from 'nostr-tools/pure'
import { Relay } from 'nostr-tools/relay' import { SimplePool } from 'nostr-tools/pool'
const relay = await Relay.connect('wss://relay.example.com') const pool = new SimplePool()
console.log(`connected to ${relay.url}`)
// let's query for an event that exists // let's query for an event that exists
const sub = relay.subscribe([ const event = relay.get(
['wss://relay.example.com'],
{ {
ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'], ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'],
}, },
], { )
onevent(event) { if (event) {
console.log('we got the event we wanted:', event) console.log('it exists indeed on this relay:', event)
}, }
oneose() {
sub.close()
}
})
// let's publish a new event while simultaneously monitoring the relay for it // let's publish a new event while simultaneously monitoring the relay for it
let sk = generateSecretKey() let sk = generateSecretKey()
let pk = getPublicKey(sk) let pk = getPublicKey(sk)
relay.subscribe([ pool.subscribe(
['wss://a.com', 'wss://b.com', 'wss://c.com'],
{ {
kinds: [1], kinds: [1],
authors: [pk], authors: [pk],
}, },
], { {
onevent(event) { onevent(event) {
console.log('got event:', event) console.log('got event:', event)
} }
}) }
)
let eventTemplate = { let eventTemplate = {
kind: 1, kind: 1,
@@ -104,7 +104,7 @@ let eventTemplate = {
// this assigns the pubkey, calculates the event id and signs the event in a single step // this assigns the pubkey, calculates the event id and signs the event in a single step
const signedEvent = finalizeEvent(eventTemplate, sk) const signedEvent = finalizeEvent(eventTemplate, sk)
await relay.publish(signedEvent) await pool.publish(['wss://a.com', 'wss://b.com'], signedEvent)
relay.close() relay.close()
``` ```
@@ -119,59 +119,116 @@ import WebSocket from 'ws'
useWebSocketImplementation(WebSocket) useWebSocketImplementation(WebSocket)
``` ```
### Interacting with multiple relays ### Parsing references (mentions) from a content based on NIP-27
```js ```js
import { SimplePool } from 'nostr-tools/pool' import * as nip27 from '@nostr/tools/nip27'
const pool = new SimplePool() for (let block of nip27.parse(evt.content)) {
switch (block.type) {
let relays = ['wss://relay.example.com', 'wss://relay.example2.com'] case 'text':
console.log(block.text)
let h = pool.subscribeMany( break
[...relays, 'wss://relay.example3.com'], case 'reference': {
[ if ('id' in block.pointer) {
{ console.log("it's a nevent1 uri", block.pointer)
authors: ['32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'], } else if ('identifier' in block.pointer) {
}, console.log("it's a naddr1 uri", block.pointer)
], } else {
{ console.log("it's an npub1 or nprofile1 uri", block.pointer)
onevent(event) {
// this will only be called once the first time the event is received
// ...
},
oneose() {
h.close()
} }
break
} }
) case 'url': {
console.log("it's a normal url:", block.url)
await Promise.any(pool.publish(relays, newEvent)) break
console.log('published to at least one relay!') }
case 'image':
let events = await pool.querySync(relays, { kinds: [0, 1] }) case 'video':
let event = await pool.get(relays, { case 'audio':
ids: ['44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'], console.log("it's a media url:", block.url)
}) case 'relay':
console.log("it's a websocket url, probably a relay address:", block.url)
default:
break
}
}
``` ```
### Parsing references (mentions) from a content using NIP-10 and NIP-27 ### Connecting to a bunker using NIP-46
```js ```js
import { parseReferences } from 'nostr-tools/references' import { generateSecretKey, getPublicKey } from '@nostr/tools/pure'
import { BunkerSigner, parseBunkerInput } from '@nostr/tools/nip46'
import { SimplePool } from '@nostr/tools/pool'
let references = parseReferences(event) // the client needs a local secret key (which is generally persisted) for communicating with the bunker
let simpleAugmentedContent = event.content const localSecretKey = generateSecretKey()
for (let i = 0; i < references.length; i++) {
let { text, profile, event, address } = references[i] // parse a bunker URI
let augmentedReference = profile const bunkerPointer = await parseBunkerInput('bunker://abcd...?relay=wss://relay.example.com')
? `<strong>@${profilesCache[profile.pubkey].name}</strong>` if (!bunkerPointer) {
: event throw new Error('Invalid bunker input')
? `<em>${eventsCache[event.id].content.slice(0, 5)}</em>` }
: address
? `<a href="${text}">[link]</a>` // create the bunker instance
: text const pool = new SimplePool()
simpleAugmentedContent.replaceAll(text, augmentedReference) const bunker = new BunkerSigner(localSecretKey, bunkerPointer, { pool })
await bunker.connect()
// and use it
const pubkey = await bunker.getPublicKey()
const event = await bunker.signEvent({
kind: 1,
created_at: Math.floor(Date.now() / 1000),
tags: [],
content: 'Hello from bunker!'
})
// cleanup
await signer.close()
pool.close([])
```
### Parsing thread from any note based on NIP-10
```js
import * as nip10 from '@nostr/tools/nip10'
// event is a nostr event with tags
const refs = nip10.parse(event)
// get the root event of the thread
if (refs.root) {
console.log('root event:', refs.root.id)
console.log('root event relay hints:', refs.root.relays)
console.log('root event author:', refs.root.author)
}
// get the immediate parent being replied to
if (refs.reply) {
console.log('reply to:', refs.reply.id)
console.log('reply relay hints:', refs.reply.relays)
console.log('reply author:', refs.reply.author)
}
// get any mentioned events
for (let mention of refs.mentions) {
console.log('mentioned event:', mention.id)
console.log('mention relay hints:', mention.relays)
console.log('mention author:', mention.author)
}
// get any quoted events
for (let quote of refs.quotes) {
console.log('quoted event:', quote.id)
console.log('quote relay hints:', quote.relays)
}
// get any referenced profiles
for (let profile of refs.profiles) {
console.log('referenced profile:', profile.pubkey)
console.log('profile relay hints:', profile.relays)
} }
``` ```
@@ -205,32 +262,6 @@ declare global {
} }
``` ```
### Generating NIP-06 keys
```js
import {
privateKeyFromSeedWords,
accountFromSeedWords,
extendedKeysFromSeedWords,
accountFromExtendedKey
} from 'nostr-tools/nip06'
const mnemonic = 'zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong'
const passphrase = '123' // optional
const accountIndex = 0
const sk0 = privateKeyFromSeedWords(mnemonic, passphrase, accountIndex)
const { privateKey: sk1, publicKey: pk1 } = accountFromSeedWords(mnemonic, passphrase, accountIndex)
const extendedAccountIndex = 0
const { privateExtendedKey, publicExtendedKey } = extendedKeysFromSeedWords(mnemonic, passphrase, extendedAccountIndex)
const { privateKey: sk2, publicKey: pk2 } = accountFromExtendedKey(privateExtendedKey)
const { publicKey: pk3 } = accountFromExtendedKey(publicExtendedKey)
```
### Encoding and decoding NIP-19 codes ### Encoding and decoding NIP-19 codes
```js ```js