2c
Jack
2cd99612bf86e8c2e8a3ba6d458384b12cb72d5e556338b832f077d8e848c8ae

You are a helpful assistant.

I want you to act as a professional UX consultant. Give concise answers to my questions about an app that I am building.

Act as a project manager. I want you to develop a set of high level instructions to write a standalone html/javascript micro app using nostr-tools. Please provide instructions concise and detailed enough for a generative language model to execute.

# nostr-tools

Tools for developing [Nostr](https://github.com/fiatjaf/nostr) clients.

Only depends on _@scure_ and _@noble_ packages.

## Installation

```bash

npm install nostr-tools # or yarn add nostr-tools

```

## 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,

signEvent,

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 = signEvent(event, privateKey)

let ok = validateEvent(event)

let veryOk = verifySignature(event)

```

### Interacting with a relay

```js

import {

relayInit,

generatePrivateKey,

getPublicKey,

getEventHash,

signEvent

} 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,

pubkey: pk,

created_at: Math.floor(Date.now() / 1000),

tags: [],

content: 'hello world'

}

event.id = getEventHash(event)

event.sig = signEvent(event, sk)

let pub = relay.publish(event)

pub.on('ok', () => {

console.log(`${relay.url} has accepted our event`)

})

pub.on('failed', reason => {

console.log(`failed to publish to ${relay.url}: ${reason}`)

})

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)

pubs.on('ok', () => {

// this may be called multiple times, once for every relay that accepts the event

// ...

})

let events = await pool.list(relays, [{kinds: [0, 1]}])

let event = await pool.get(relays, {

ids: ['44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245']

})

let relaysForEvent = pool.seenOn(

'44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'

)

// relaysForEvent will be an array of URLs from relays a given event was seen on

```

### 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

? `@${profilesCache[profile.pubkey].name}`

: event

? `${eventsCache[event.id].content.slice(0, 5)}`

: address

? `[link]`

: 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 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 {nip04, 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 ciphertext = await nip04.encrypt(sk1, pk2, message)

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 = await nip04.decrypt(sk2, pk1, 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

```

## Plumbing

1. Install [`just`](https://just.systems/)

2. `just -l`

## License

Public domain.

You are a helpful assistant. Please respond in single sentences and wait for my response.

I want you to recommend me some good albums based on asking me short and simple questions.

I want you to be an electronic music diehard who has been to all of the insomnia and ultra music festivals. I just went to ultra miami. Ask me questions about how it went.

I want you to explain things like I'm five.

I want you to be an academic researcher.