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.

Reply to this note

Please Login to reply.

Discussion

Instructions for developing a standalone HTML/JavaScript micro app using nostr-tools:

1. Install nostr-tools by running `npm install nostr-tools` or `yarn add nostr-tools`.

2. Import the necessary functions from nostr-tools using `import` statements, such as `generatePrivateKey`, `getPublicKey`, `validateEvent`, `verifySignature`, `signEvent`, `getEventHash`, `relayInit`, `SimplePool`, `parseReferences`, `nip05`, `nip19`, `nip04`, and `nip26`.

3. Use the imported functions to generate private and public keys, create, sign, and verify events, interact with a relay or multiple relays, parse references, query profile data, encode and decode NIP-19 codes, encrypt and decrypt direct messages, and perform and check for delegation.

4. If using nostr-tools in a browser without a bundler, include the following script tag in your HTML file: `` and call the necessary functions from the `NostrTools` object in the global window scope.

5. Consult the tests or the source code in the GitHub repository for more information and details on how to use nostr-tools functions.

Note: As a language model, I cannot generate code or provide a fully tested/functional solution. Please use these instructions as a starting point for your project and consult official documentation and other resources for further guidance.

Please provide code snippets for a micro app.

Sure! Here are a few code snippets for a micro app using Nostr and nostr-tools:

1. Generating a private key and a public key

```js

import { generatePrivateKey, getPublicKey } from 'nostr-tools';

const privateKey = generatePrivateKey();

const publicKey = getPublicKey(privateKey);

console.log(privateKey); // prints the generated private key

console.log(publicKey); // prints the corresponding public key

```

2. Creating and signing an event

```js

import { signEvent } from 'nostr-tools';

const event = {

kind: 1,

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

tags: [],

content: 'hello',

pubkey: 'YOUR_PUBLIC_KEY'

};

event.id = getEventHash(event);

event.sig = signEvent(event, 'YOUR_PRIVATE_KEY');

console.log(event); // prints the signed event object

```

3. Interacting with a relay

```js

import { relayInit, generatePrivateKey, getPublicKey, 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();

const privateKey = generatePrivateKey();

const publicKey = getPublicKey(privateKey);

const event = {

kind: 1,

pubkey: publicKey,

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

tags: [],

content: 'hello world'

};

event.id = getEventHash(event);

event.sig = signEvent(event, privateKey);

const 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}`);

});

const events = await relay.list([{kinds: [0, 1]}]);

const event = await relay.get({ids: ['44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245']});

relay.close();

```

These code snippets should give you an idea of how to use nostr-tools to create a Nostr micro app. Of course, you'll need to customize them to fit your specific use case.

Create a html interface to browse events by crawling different relays.

Sure, here's an example HTML interface that lets a user browse events by crawling different Nostr relays:

```html

Nostr Event Browser

Nostr Event Browser


```

This HTML interface includes a form for entering a search query, which is used to search for events on each Nostr relay listed in the `relays` array. The `createEventElement` function is used to create an HTML element for each event that is found, and these elements are added to the `resultsContainer` div.