Project Icon

nostr-tools

为Nostr客户端开发提供全面支持的工具集

nostr-tools是一个轻量级的Nostr客户端开发工具集。它提供密钥管理、事件处理和中继通信等核心功能,适用于浏览器和Node.js环境。该工具集支持多项Nostr改进提案(NIP),并能同时与多个中继交互。通过提供这些基础组件,nostr-tools帮助开发者更高效地构建Nostr应用。

nostr-tools

用于开发 Nostr 客户端的工具。

仅依赖 @scure@noble 包。

本包仅提供低级功能。如果你需要更高级的功能,可以查看 Nostrify,或者如果你想要一个易于使用的全面解决方案,能够抽象出 Nostr 的复杂部分并为你做出决策,可以查看 NDK@snort/system

安装

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

如果使用 TypeScript,本包要求 TypeScript 版本 >= 5.0。

使用方法

生成私钥和公钥

import { generateSecretKey, getPublicKey } from 'nostr-tools/pure'

let sk = generateSecretKey() // `sk` 是一个 Uint8Array
let pk = getPublicKey(sk) // `pk` 是一个十六进制字符串

要获取十六进制格式的私钥,可以使用

import { bytesToHex, hexToBytes } from '@noble/hashes/utils' // 已经是安装的依赖

let skHex = bytesToHex(sk)
let backToBytes = hexToBytes(skHex)

创建、签名和验证事件

import { finalizeEvent, verifyEvent } from 'nostr-tools/pure'

let event = finalizeEvent({
  kind: 1,
  created_at: Math.floor(Date.now() / 1000),
  tags: [],
  content: 'hello',
}, sk)

let isGood = verifyEvent(event)

与中继交互

import { finalizeEvent, generateSecretKey, getPublicKey } from 'nostr-tools/pure'
import { Relay } from 'nostr-tools/relay'

const relay = await Relay.connect('wss://relay.example.com')
console.log(`已连接到 ${relay.url}`)

// 让我们查询一个存在的事件
const sub = relay.subscribe([
  {
    ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'],
  },
], {
  onevent(event) {
    console.log('我们得到了想要的事件:', event)
  },
  oneose() {
    sub.close()
  }
})

// 让我们发布一个新事件,同时监控中继以获取它
let sk = generateSecretKey()
let pk = getPublicKey(sk)

relay.subscribe([
  {
    kinds: [1],
    authors: [pk],
  },
], {
  onevent(event) {
    console.log('收到事件:', event)
  }
})

let eventTemplate = {
  kind: 1,
  created_at: Math.floor(Date.now() / 1000),
  tags: [],
  content: 'hello world',
}

// 这会在一个步骤中分配公钥、计算事件 ID 并签名事件
const signedEvent = finalizeEvent(eventTemplate, sk)
await relay.publish(signedEvent)

relay.close()

要在 Node.js 上使用此功能,你首先必须安装 ws 并调用类似以下的代码:

import { useWebSocketImplementation } from 'nostr-tools/pool'
// 或者如果你直接使用 Relay,可以使用 import { useWebSocketImplementation } from 'nostr-tools/relay'

import WebSocket from 'ws'
useWebSocketImplementation(WebSocket)

与多个中继交互

import { SimplePool } from 'nostr-tools/pool'

const pool = new SimplePool()

let relays = ['wss://relay.example.com', 'wss://relay.example2.com']

let h = pool.subscribeMany(
  [...relays, 'wss://relay.example3.com'],
  [
    {
      authors: ['32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'],
    },
  ],
  {
    onevent(event) {
      // 这只会在第一次接收到事件时被调用一次
      // ...
    },
    oneose() {
      h.close()
    }
  }
)

await Promise.any(pool.publish(relays, newEvent))
console.log('至少发布到了一个中继!')

let events = await pool.querySync(relays, { kinds: [0, 1] })
let event = await pool.get(relays, {
  ids: ['44e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245'],
})

使用 NIP-10 和 NIP-27 从内容中解析引用(提及)

import { parseReferences } from 'nostr-tools/references'

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
    ? `<strong>@${profilesCache[profile.pubkey].name}</strong>`
    : event
    ? `<em>${eventsCache[event.id].content.slice(0, 5)}</em>`
    : address
    ? `<a href="${text}">[链接]</a>`
    : text
  simpleAugmentedContent.replaceAll(text, augmentedReference)
}

从 NIP-05 地址查询配置文件数据

import { queryProfile } from 'nostr-tools/nip05'

let profile = await queryProfile('jb55.com')
console.log(profile.pubkey)
// 输出:32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245
console.log(profile.relays)
// 输出:[wss://relay.damus.io]

要在 Node.js < v18 上使用此功能,你首先必须安装 node-fetch@2 并调用类似以下的代码:

import { useFetchImplementation } from 'nostr-tools/nip05'
useFetchImplementation(require('node-fetch'))

包含 NIP-07 类型

import type { WindowNostr } from 'nostr-tools/nip07'

declare global {
  interface Window {
    nostr?: WindowNostr;
  }
}

生成 NIP-06 密钥

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' // 可选
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)

编码和解码 NIP-19 代码

import { generateSecretKey, getPublicKey } from 'nostr-tools/pure'
import * as nip19 from 'nostr-tools/nip19'
让 sk = generateSecretKey()
让 nsec = nip19.nsecEncode(sk)
让 { type, data } = nip19.decode(nsec)
断言(type === 'nsec')
断言(data === sk)

让 pk = getPublicKey(generateSecretKey())
让 npub = nip19.npubEncode(pk)
让 { type, data } = nip19.decode(npub)
断言(type === 'npub')
断言(data === pk)

让 pk = getPublicKey(generateSecretKey())
让 relays = ['wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com']
让 nprofile = nip19.nprofileEncode({ pubkey: pk, relays })
让 { type, data } = nip19.decode(nprofile)
断言(type === 'nprofile')
断言(data.pubkey === pk)
断言(data.relays.length === 2)

nostr-wasm 一起使用

nostr-wasm 是一个薄包装器,包装了编译为 WASM 的 libsecp256k1,仅用于哈希、签名和验证 Nostr 事件。

import { setNostrWasm, generateSecretKey, finalizeEvent, verifyEvent } from 'nostr-tools/wasm'
import { initNostrWasm } from 'nostr-wasm'

// 确保在应用开始调用 finalizeEvent 或 verifyEvent 之前这个 promise 已解决
initNostrWasm().then(setNostrWasm)

// 或使用 'nostr-wasm/gzipped' 甚至 'nostr-wasm/headless',
// 查看 https://www.npmjs.com/package/nostr-wasm 了解选项

如果你要使用 RelaySimplePool,你还必须导入 nostr-tools/abstract-relay 和/或 nostr-tools/abstract-pool 而不是默认值,然后通过传递 verifyEvent 来实例化它们:

import { setNostrWasm, verifyEvent } from 'nostr-tools/wasm'
import { AbstractRelay } from 'nostr-tools/abstract-relay'
import { AbstractSimplePool } from 'nostr-tools/abstract-pool'
import { initNostrWasm } from 'nostr-wasm'

initNostrWasm().then(setNostrWasm)

const relay = AbstractRelay.connect('wss://relayable.org', { verifyEvent })
const pool = new AbstractSimplePool({ verifyEvent })

这可能比默认使用的纯 JS noble 库nostr-tools/pure 更快。基准测试:

benchmark      time (avg)             (min … max)       p75       p99      p995
------------------------------------------------- -----------------------------
• relay read message and verify event (many events)
------------------------------------------------- -----------------------------
wasm        34.94 ms/iter   (34.61 ms … 35.73 ms)  35.07 ms  35.73 ms  35.73 ms
pure js     239.7 ms/iter (235.41 ms … 243.69 ms) 240.51 ms 243.69 ms 243.69 ms
trusted    402.71 µs/iter   (344.57 µs … 2.98 ms) 407.39 µs 745.62 µs 812.59 µs

summary for relay read message and verify event
  wasm
   86.77x slower than trusted
   6.86x faster than pure js

从浏览器使用(如果你不想使用打包工具)

<script src="https://unpkg.com/nostr-tools/lib/nostr.bundle.js"></script>
<script>
  window.NostrTools.generateSecretKey('...') // 等等
</script>

管道

要开发 nostr-tools,安装 just 并运行 just -l 查看可用的命令。

许可证

这是免费且不受限制的软件,发布到公共领域。通过向本项目提交补丁,你同意将此软件的任何和所有版权利益贡献给公共领域。

为此存储库做贡献

使用 NIP-34 将你的补丁发送到:

naddr1qq9kummnw3ez6ar0dak8xqg5waehxw309aex2mrp0yhxummnw3ezucn8qyt8wumn8ghj7un9d3shjtnwdaehgu3wvfskueqpzemhxue69uhhyetvv9ujuurjd9kkzmpwdejhgq3q80cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsxpqqqpmejdv00jq
项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

白日梦AI

白日梦AI提供专注于AI视频生成的多样化功能,包括文生视频、动态画面和形象生成等,帮助用户快速上手,创造专业级内容。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

讯飞绘镜

讯飞绘镜是一个支持从创意到完整视频创作的智能平台,用户可以快速生成视频素材并创作独特的音乐视频和故事。平台提供多样化的主题和精选作品,帮助用户探索创意灵感。

Project Cover

讯飞文书

讯飞文书依托讯飞星火大模型,为文书写作者提供从素材筹备到稿件撰写及审稿的全程支持。通过录音智记和以稿写稿等功能,满足事务性工作的高频需求,帮助撰稿人节省精力,提高效率,优化工作与生活。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号