mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2025-12-09 16:48:50 +00:00
updated readme with nicer examples.
This commit is contained in:
177
README.md
177
README.md
@@ -4,108 +4,105 @@ Tools for developing [Nostr](https://github.com/fiatjaf/nostr) clients.
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
### Generating a private key and a public key
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import {relayPool} from 'nostr-tools'
|
import { generatePrivateKey, getPublicKey } from 'nostr-tools'
|
||||||
|
|
||||||
const pool = relayPool()
|
let sk = generatePrivateKey() # `sk` is a hex string
|
||||||
|
let pk = getPublicKey(sk) # `pk` is a hex string
|
||||||
pool.setPrivateKey('<hex>') // optional
|
|
||||||
|
|
||||||
pool.addRelay('ws://some.relay.com', {read: true, write: true})
|
|
||||||
pool.addRelay('ws://other.relay.cool', {read: true, write: true})
|
|
||||||
|
|
||||||
// example callback functions for listeners
|
|
||||||
// callback functions take an object argument with following keys:
|
|
||||||
// - relay: relay url
|
|
||||||
// - type: type of listener
|
|
||||||
// - id: sub id for sub specific listeners ('EVENT' or 'EOSE')
|
|
||||||
// - event: event object, only for 'event' listener
|
|
||||||
// - notice: notice message, only for 'notice' listener
|
|
||||||
function onEvent({event, relay, type, id}) {
|
|
||||||
console.log(`got an event from ${relay} which is already validated.`, event)
|
|
||||||
}
|
|
||||||
function onEose({relay, type, id}) { /* callback function here */}
|
|
||||||
function onNotice({relay, type, notice}) { /* callback function here */}
|
|
||||||
function onConnection({relay, type}) { /* callback function here */}
|
|
||||||
|
|
||||||
// listen for messages for pool
|
|
||||||
pool.on('event', onEvent)
|
|
||||||
pool.on('connection', onConnection)
|
|
||||||
pool.on('notice', onNotice)
|
|
||||||
|
|
||||||
// subscribing to a single user
|
|
||||||
// author is the user's public key
|
|
||||||
pool.sub({filter: {author: '<hex>'}})
|
|
||||||
|
|
||||||
// or bulk follow
|
|
||||||
pool.sub({filter: {authors: ['<hex1>', '<hex2>', ..., '<hexn>']}})
|
|
||||||
|
|
||||||
// reuse a subscription channel
|
|
||||||
const mySubscription = pool.sub({filter: ...., skipVerification: false, beforeSend: ....})
|
|
||||||
mySubscription.sub({filter: ....})
|
|
||||||
mySubscription.sub({skipVerification: true})
|
|
||||||
|
|
||||||
// listen for messages for subscription
|
|
||||||
mySubscription.on('event', onEvent)
|
|
||||||
mySubscription.on('eose', onEose)
|
|
||||||
|
|
||||||
// close subscription
|
|
||||||
mySubscription.unsub()
|
|
||||||
|
|
||||||
// get specific event
|
|
||||||
const specificChannel = pool.sub({ filter: {id: '<hex>'}})
|
|
||||||
.on('event', ({event, relay}) => {
|
|
||||||
console.log('got specific event from relay', event, relay)
|
|
||||||
specificChannel.unsub()
|
|
||||||
})
|
|
||||||
|
|
||||||
// or get a specific event plus all the events that reference it in the 'e' tag
|
|
||||||
pool.sub({ filter: [{id: '<hex>'}, {'#e': '<hex>'}] })
|
|
||||||
|
|
||||||
// get all events
|
|
||||||
pool.sub({ filter: {} })
|
|
||||||
|
|
||||||
// get recent events
|
|
||||||
pool.sub({ filter: {since: timestamp} })
|
|
||||||
|
|
||||||
// publishing events(inside an async function):
|
|
||||||
const ev = await pool.publish(eventObject, (status, url) => {
|
|
||||||
if (status === 0) {
|
|
||||||
console.log(`publish request sent to ${url}`)
|
|
||||||
}
|
|
||||||
if (status === 1) {
|
|
||||||
console.log(`event published by ${url}`, ev)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// it will be signed automatically with the key supplied above
|
|
||||||
// or pass an already signed event to bypass this
|
|
||||||
|
|
||||||
// subscribing to a new relay
|
|
||||||
pool.addRelay('<url>')
|
|
||||||
// will automatically subscribe to the all the events called with .sub above
|
|
||||||
```
|
```
|
||||||
|
|
||||||
All functions expect bytearrays as hex strings and output bytearrays as hex strings.
|
### Creating, signing and verifying events
|
||||||
|
|
||||||
For other utils please read the source (for now).
|
```js
|
||||||
|
const {
|
||||||
|
validateEvent,
|
||||||
|
verifySignature,
|
||||||
|
signEvent,
|
||||||
|
getEventHash,
|
||||||
|
getPublicKey
|
||||||
|
} = require('./cjs')
|
||||||
|
|
||||||
|
let event = {
|
||||||
|
kind: 1,
|
||||||
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
|
tags: [],
|
||||||
|
content: 'hello'
|
||||||
|
}
|
||||||
|
|
||||||
|
event.id = getEventHash(event.id)
|
||||||
|
event.pubkey = getPublicKey(privateKey)
|
||||||
|
event.sig = await signEvent(event, privateKey)
|
||||||
|
|
||||||
|
let ok = validateEvent(event)
|
||||||
|
let veryOk = await verifySignature(event)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Validating events received from relays
|
||||||
|
|
||||||
|
```js
|
||||||
|
const {matchFilters} = require('./cjs')
|
||||||
|
|
||||||
|
let event = {kind: 1, pubkey: 'abcdef...', ...otherProperties}
|
||||||
|
let ok = matchFilters(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
kinds: [0, 1, 3, 6],
|
||||||
|
authors: ['abcdef...', '123456...']
|
||||||
|
}
|
||||||
|
],
|
||||||
|
event
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Encrypting and decrypting direct messages
|
||||||
|
|
||||||
|
```js
|
||||||
|
const {nip04, getPublicKey, generatePrivateKey} = require('./cjs')
|
||||||
|
|
||||||
|
// sender
|
||||||
|
let sk1 = generatePrivateKey()
|
||||||
|
let pk1 = getPublicKey(sk1)
|
||||||
|
|
||||||
|
// receiver
|
||||||
|
let sk2 = generatePrivateKey()
|
||||||
|
let pk2 = getPublicKey(sk2)
|
||||||
|
|
||||||
|
// on the sender side
|
||||||
|
let message = 'hello'
|
||||||
|
let ciphertext = nip04.encrypt(sk1, pk2, 'hello')
|
||||||
|
|
||||||
|
let event = {
|
||||||
|
kind: 4,
|
||||||
|
pubkey: pk1,
|
||||||
|
tags: [['p', pk2]],
|
||||||
|
content: ciphertext,
|
||||||
|
...otherProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
sendEvent(event)
|
||||||
|
|
||||||
|
// on the receiver side
|
||||||
|
|
||||||
|
sub.on('event', (event) => {
|
||||||
|
let sender = event.tags.find(([k, v]) => k === 'p' && && v && v !== '')[1]
|
||||||
|
pk1 === sender
|
||||||
|
let plaintext = nip04.decrypt(sk2, pk1, event.content)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
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)
|
### Using from the browser (if you don't want to use a bundler)
|
||||||
|
|
||||||
You can import nostr-tools as an ES module. Just add a script tag like this:
|
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script type="module">
|
<script src="https://unpkg.com/nostr-tools/standalone/index.js"></script>
|
||||||
import {generatePrivateKey} from 'https://unpkg.com/nostr-tools/nostr.js'
|
<script>
|
||||||
console.log(generatePrivateKey())
|
window.NostrTools.generatePrivateKey('...') // and so on
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
And import whatever function you would import from `"nostr-tools"` in a bundler.
|
|
||||||
|
|
||||||
## TypeScript
|
|
||||||
|
|
||||||
This module has hand-authored TypeScript declarations. `npm run check-ts` will run a lint-check script to ensure the typings can be loaded and call at least a few standard library functions. It's not at all comprehensive and likely to contain bugs. Issues welcome; tag @rcoder as needed.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Public domain.
|
Public domain.
|
||||||
|
|||||||
Reference in New Issue
Block a user