mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2025-12-10 17:18:51 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f992c9c967 | ||
|
|
dbf625d6ac | ||
|
|
8622bd11dd | ||
|
|
0970eee70f | ||
|
|
086f8830e3 | ||
|
|
e48d722227 | ||
|
|
0d77013aab | ||
|
|
4c415280aa | ||
|
|
4188aaf7c8 | ||
|
|
673f4abab8 | ||
|
|
bcefaa0757 | ||
|
|
649af36a86 | ||
|
|
96a6f7af87 | ||
|
|
a4c713efcb |
1
.github/workflows/npm-publish.yml
vendored
1
.github/workflows/npm-publish.yml
vendored
@@ -16,6 +16,7 @@ jobs:
|
|||||||
- run: just install-dependencies
|
- run: just install-dependencies
|
||||||
- run: just build
|
- run: just build
|
||||||
- run: just test
|
- run: just test
|
||||||
|
- run: just emit-types
|
||||||
- uses: JS-DevTools/npm-publish@v1
|
- uses: JS-DevTools/npm-publish@v1
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.NPM_TOKEN }}
|
token: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|||||||
25
README.md
25
README.md
@@ -10,7 +10,6 @@ Only depends on _@scure_ and _@noble_ packages.
|
|||||||
npm install nostr-tools # or yarn add nostr-tools
|
npm install nostr-tools # or yarn add nostr-tools
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Generating a private key and a public key
|
### Generating a private key and a public key
|
||||||
@@ -138,11 +137,16 @@ const pool = new SimplePool()
|
|||||||
|
|
||||||
let relays = ['wss://relay.example.com', 'wss://relay.example2.com']
|
let relays = ['wss://relay.example.com', 'wss://relay.example2.com']
|
||||||
|
|
||||||
let relay = await pool.ensureRelay('wss://relay.example3.com')
|
let sub = pool.sub(
|
||||||
|
[...relays, 'wss://relay.example3.com'],
|
||||||
let sub = pool.sub([...relays, relay], [{
|
[
|
||||||
authors: ['32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245']
|
{
|
||||||
}])
|
authors: [
|
||||||
|
'32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
sub.on('event', event => {
|
sub.on('event', event => {
|
||||||
// this will only be called once the first time the event is received
|
// this will only be called once the first time the event is received
|
||||||
@@ -150,11 +154,10 @@ sub.on('event', event => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
let pubs = pool.publish(relays, newEvent)
|
let pubs = pool.publish(relays, newEvent)
|
||||||
pubs.forEach(pub =>
|
pubs.on('ok', () => {
|
||||||
pub.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 events = await pool.list(relays, [{kinds: [0, 1]}])
|
||||||
let event = await pool.get(relays, {
|
let event = await pool.get(relays, {
|
||||||
|
|||||||
2
build.js
2
build.js
@@ -17,7 +17,7 @@ esbuild
|
|||||||
packages: 'external'
|
packages: 'external'
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const packageJson = JSON.stringify({ type: 'module' })
|
const packageJson = JSON.stringify({type: 'module'})
|
||||||
fs.writeFileSync(`${__dirname}/lib/esm/package.json`, packageJson, 'utf8')
|
fs.writeFileSync(`${__dirname}/lib/esm/package.json`, packageJson, 'utf8')
|
||||||
|
|
||||||
console.log('esm build success.')
|
console.log('esm build success.')
|
||||||
|
|||||||
1
event.ts
1
event.ts
@@ -80,6 +80,7 @@ export function getEventHash(event: UnsignedEvent): string {
|
|||||||
|
|
||||||
export function validateEvent(event: UnsignedEvent): boolean {
|
export function validateEvent(event: UnsignedEvent): boolean {
|
||||||
if (typeof event !== 'object') return false
|
if (typeof event !== 'object') return false
|
||||||
|
if (typeof event.kind !== 'number') return false
|
||||||
if (typeof event.content !== 'string') return false
|
if (typeof event.content !== 'string') return false
|
||||||
if (typeof event.created_at !== 'number') return false
|
if (typeof event.created_at !== 'number') return false
|
||||||
if (typeof event.pubkey !== 'string') return false
|
if (typeof event.pubkey !== 'string') return false
|
||||||
|
|||||||
11
justfile
11
justfile
@@ -4,13 +4,20 @@ install-dependencies:
|
|||||||
yarn --ignore-engines
|
yarn --ignore-engines
|
||||||
|
|
||||||
build:
|
build:
|
||||||
|
rm -rf lib
|
||||||
node build.js
|
node build.js
|
||||||
|
|
||||||
test: build
|
test: build
|
||||||
jest
|
jest
|
||||||
|
|
||||||
testOnly file: build
|
test-only file: build
|
||||||
jest {{file}}
|
jest {{file}}
|
||||||
|
|
||||||
publish: build
|
emit-types:
|
||||||
|
tsc # see tsconfig.json
|
||||||
|
|
||||||
|
publish: build emit-types
|
||||||
npm publish
|
npm publish
|
||||||
|
|
||||||
|
format:
|
||||||
|
prettier --plugin-search-dir . --write .
|
||||||
|
|||||||
11
nip05.ts
11
nip05.ts
@@ -38,9 +38,14 @@ export async function queryProfile(
|
|||||||
|
|
||||||
if (!name.match(/^[A-Za-z0-9-_]+$/)) return null
|
if (!name.match(/^[A-Za-z0-9-_]+$/)) return null
|
||||||
|
|
||||||
let res = await (
|
let res
|
||||||
await _fetch(`https://${domain}/.well-known/nostr.json?name=${name}`)
|
try {
|
||||||
).json()
|
res = await (
|
||||||
|
await _fetch(`https://${domain}/.well-known/nostr.json?name=${name}`)
|
||||||
|
).json()
|
||||||
|
} catch (err) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
if (!res?.names?.[name]) return null
|
if (!res?.names?.[name]) return null
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,16 @@ const {nip06} = require('./lib/nostr.cjs')
|
|||||||
test('generate private key from a mnemonic', async () => {
|
test('generate private key from a mnemonic', async () => {
|
||||||
const mnemonic = 'zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong'
|
const mnemonic = 'zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong'
|
||||||
const privateKey = nip06.privateKeyFromSeedWords(mnemonic)
|
const privateKey = nip06.privateKeyFromSeedWords(mnemonic)
|
||||||
expect(privateKey).toEqual('c26cf31d8ba425b555ca27d00ca71b5008004f2f662470f8c8131822ec129fe2')
|
expect(privateKey).toEqual(
|
||||||
|
'c26cf31d8ba425b555ca27d00ca71b5008004f2f662470f8c8131822ec129fe2'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('generate private key from a mnemonic and passphrase', async () => {
|
test('generate private key from a mnemonic and passphrase', async () => {
|
||||||
const mnemonic = 'zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong'
|
const mnemonic = 'zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong'
|
||||||
const passphrase = '123'
|
const passphrase = '123'
|
||||||
const privateKey = nip06.privateKeyFromSeedWords(mnemonic, passphrase)
|
const privateKey = nip06.privateKeyFromSeedWords(mnemonic, passphrase)
|
||||||
expect(privateKey).toEqual('55a22b8203273d0aaf24c22c8fbe99608e70c524b17265641074281c8b978ae4')
|
expect(privateKey).toEqual(
|
||||||
|
'55a22b8203273d0aaf24c22c8fbe99608e70c524b17265641074281c8b978ae4'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
5
nip06.ts
5
nip06.ts
@@ -7,7 +7,10 @@ import {
|
|||||||
} from '@scure/bip39'
|
} from '@scure/bip39'
|
||||||
import {HDKey} from '@scure/bip32'
|
import {HDKey} from '@scure/bip32'
|
||||||
|
|
||||||
export function privateKeyFromSeedWords(mnemonic: string, passphrase?: string): string {
|
export function privateKeyFromSeedWords(
|
||||||
|
mnemonic: string,
|
||||||
|
passphrase?: string
|
||||||
|
): string {
|
||||||
let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))
|
let root = HDKey.fromMasterSeed(mnemonicToSeedSync(mnemonic, passphrase))
|
||||||
let privateKey = root.derive(`m/44'/1237'/0'/0/0`).privateKey
|
let privateKey = root.derive(`m/44'/1237'/0'/0/0`).privateKey
|
||||||
if (!privateKey) throw new Error('could not derive private key')
|
if (!privateKey) throw new Error('could not derive private key')
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ test('encode and decode naddr', () => {
|
|||||||
expect(data.identifier).toEqual('banana')
|
expect(data.identifier).toEqual('banana')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('encode and decode naddr from habla.news', () => {
|
test('decode naddr from habla.news', () => {
|
||||||
let {type, data} = nip19.decode(
|
let {type, data} = nip19.decode(
|
||||||
'naddr1qq98yetxv4ex2mnrv4esygrl54h466tz4v0re4pyuavvxqptsejl0vxcmnhfl60z3rth2xkpjspsgqqqw4rsf34vl5'
|
'naddr1qq98yetxv4ex2mnrv4esygrl54h466tz4v0re4pyuavvxqptsejl0vxcmnhfl60z3rth2xkpjspsgqqqw4rsf34vl5'
|
||||||
)
|
)
|
||||||
@@ -68,3 +68,20 @@ test('encode and decode naddr from habla.news', () => {
|
|||||||
expect(data.kind).toEqual(30023)
|
expect(data.kind).toEqual(30023)
|
||||||
expect(data.identifier).toEqual('references')
|
expect(data.identifier).toEqual('references')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('decode naddr from go-nostr with different TLV ordering', () => {
|
||||||
|
let {type, data} = nip19.decode(
|
||||||
|
'naddr1qqrxyctwv9hxzq3q80cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsxpqqqp65wqfwwaehxw309aex2mrp0yhxummnw3ezuetcv9khqmr99ekhjer0d4skjm3wv4uxzmtsd3jjucm0d5q3vamnwvaz7tmwdaehgu3wvfskuctwvyhxxmmd0zfmwx'
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(type).toEqual('naddr')
|
||||||
|
expect(data.pubkey).toEqual(
|
||||||
|
'3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d'
|
||||||
|
)
|
||||||
|
expect(data.relays).toContain(
|
||||||
|
'wss://relay.nostr.example.mydomain.example.com'
|
||||||
|
)
|
||||||
|
expect(data.relays).toContain('wss://nostr.banana.com')
|
||||||
|
expect(data.kind).toEqual(30023)
|
||||||
|
expect(data.identifier).toEqual('banana')
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "nostr-tools",
|
"name": "nostr-tools",
|
||||||
"version": "1.7.1",
|
"version": "1.7.4",
|
||||||
"description": "Tools for making a Nostr client.",
|
"description": "Tools for making a Nostr client.",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/fiatjaf/nostr-tools.git"
|
"url": "https://github.com/nbd-wtf/nostr-tools.git"
|
||||||
},
|
},
|
||||||
|
"files": [
|
||||||
|
"./lib/**/*"
|
||||||
|
],
|
||||||
|
"types": "./lib/index.d.ts",
|
||||||
"main": "lib/nostr.cjs.js",
|
"main": "lib/nostr.cjs.js",
|
||||||
"module": "lib/esm/nostr.mjs",
|
"module": "lib/esm/nostr.mjs",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|||||||
@@ -12,17 +12,17 @@ const {
|
|||||||
let pool = new SimplePool()
|
let pool = new SimplePool()
|
||||||
|
|
||||||
let relays = [
|
let relays = [
|
||||||
'wss://nostr-dev.wellorder.net/',
|
'wss://relay.damus.io/',
|
||||||
'wss://relay.nostr.bg/',
|
'wss://relay.nostr.bg/',
|
||||||
'wss://nostr.fmt.wiz.biz/',
|
'wss://nostr.fmt.wiz.biz/',
|
||||||
'wss://relay.nostr.band/',
|
'wss://relay.nostr.band/',
|
||||||
'wss://nostr.zebedee.cloud/'
|
'wss://nos.lol/'
|
||||||
]
|
]
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
pool.close([
|
pool.close([
|
||||||
...relays,
|
...relays,
|
||||||
'wss://nostr-relay.untethr.me',
|
'wss://nostr.wine',
|
||||||
'wss://offchain.pub',
|
'wss://offchain.pub',
|
||||||
'wss://eden.nostr.land'
|
'wss://eden.nostr.land'
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const {
|
|||||||
signEvent
|
signEvent
|
||||||
} = require('./lib/nostr.cjs')
|
} = require('./lib/nostr.cjs')
|
||||||
|
|
||||||
let relay = relayInit('wss://nostr-dev.wellorder.net/')
|
let relay = relayInit('wss://relay.damus.io/')
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
relay.connect()
|
relay.connect()
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"emitDeclarationOnly": true,
|
"emitDeclarationOnly": true,
|
||||||
"outDir": "dist",
|
"outDir": "lib",
|
||||||
"rootDir": "."
|
"rootDir": "."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user