Library

Nimstr

Nostr SDK for Nim

About

Nimstrは、Nim言語のための Nostr SDK だにゃん。 鍵生成、イベントの署名・送信、リレー接続、Bech32エンコードなど、 Nostrプロトコルを扱うための機能を提供するにゃ。MITライセンス。バージョン 0.2.0。 GitHub で公開中にゃ。

Installation

nimble install https://github.com/LunaYoineko/nimstr

.nimbleのdependenciesに requires "nimstr" を追加してにゃ。

Quick Start

import std/asyncdispatch
import nimstr

proc main() {.async.} =
  let keypair = generateKeypair()
  echo "npub: ", keypair.npub

  let relay = newRelayClient("wss://relay.damus.io")
  await relay.connect()

  let ok = await relay.sendTextNote(keypair.seckeyHex, "Hello, Nostr!")
  echo "Sent: ", ok

  await relay.close()

waitFor main()

Types

NostrKeypair

seckeyHex, pubkeyHex, nsec, npub

鍵ペアを保持するオブジェクト

NostrEvent

id, pubkey, createdAt, kind, tags, content, sig

Nostrイベントのデータ構造

NostrFilter

ids, authors, kinds, since, until, limit

イベント購読フィルター

RelayClient

url, ws, connected

単一リレーへの接続を管理

RelayPool

relays

複数リレーを束ねて管理

UserProfile

name, display_name, about, picture, nip05, banner, website, lightning_address, rawJson

ユーザープロフィール

ReplyTarget

eventId, relayUrl, authorPubkey

返信先イベントの指定

ThreadContext

rootEventId, replyEventId, mentionedPubkeys

スレッドコンテキスト

API Reference

Key Generation

generateKeypair(): NostrKeypair

新しい鍵ペアを生成。nsec/npubも同時に生成。

keypairFromSecret(secretInput: string): NostrKeypair

16進数の秘密鍵またはnsecから鍵ペアを復元。

Relay / Pool Management

newRelayClient(url: string): RelayClient

単一リレークライアントを作成

newRelayPool(urls: seq[string]): RelayPool

複数リレークライアントを作成

connect(relay: RelayClient)

リレーにWebSocket接続

connectAll(pool: RelayPool)

プール内の全リレーに接続

close(relay: RelayClient)

切断

closeAll(pool: RelayPool)

全リレー切断

Event Publishing

sendEvent(relay, seckeyHex, kind, tags, content): Future[bool]

任意のkindのイベントを送信

sendEventAll(pool, seckeyHex, kind, tags, content): Future[int]

全リレーにイベントをブロードキャスト

sendTextNote(relay, seckeyHex, content, extraTags=nil): Future[bool]

テキストノート(kind 1)を送信

sendTextNoteAll(pool, seckeyHex, content, extraTags=nil): Future[int]

全リレーにテキストノートをブロードキャスト

sendReply(relay, seckeyHex, content, replyTo, extraTags=nil): Future[bool]

イベントに返信(reply)

sendRootReply(relay, seckeyHex, content, replyTo, extraTags=nil): Future[bool]

イベントに返信(root)

sendReplyAll(pool, seckeyHex, content, replyTo, extraTags=nil): Future[int]

全リレーに返信をブロードキャスト

sendRootReplyAll(pool, seckeyHex, content, replyTo, extraTags=nil): Future[int]

全リレーにroot返信をブロードキャスト

deleteEvent(relay, seckeyHex, eventIdHex, reason=""): Future[bool]

イベント削除(kind 5)

deleteEventAll(pool, seckeyHex, eventIdHex, reason=""): Future[int]

全リレーでイベント削除

sendProfile(relay, seckeyHex, profile): Future[bool]

プロフィール更新(kind 0)

fetchProfile(relay, subscriptionId, pubkeyHex)

プロフィール購読

Subscription

subscribe(relay, subscriptionId, filter)

フィルターでイベント購読開始 (REQ)

subscribeAll(pool, subscriptionId, filter)

全リレーで購読開始

closeSubscription(relay, subscriptionId)

購読終了 (CLOSE)

closeSubscriptionAll(pool, subscriptionId)

全リレーで購読終了

Crypto / Utility

computeEventId(pubkey, createdAt, kind, tags, content): string

イベントIDの計算

signEventId(seckeyHex, eventIdHex): string

イベントIDにSchnorr署名

toBech32(hrp, hexStr): string

16進数文字列をBech32エンコード

fromBech32(bechStr): tuple[hrp, hex]

Bech32文字列をデコード

parseUserProfile(contentStr): Option[UserProfile]

JSONからプロフィールをパース

parseThreadContext(eventTags): ThreadContext

イベントタグからスレッドコンテキストを解析

Examples

basic.nim — 基本操作

import std/[asyncdispatch, json]
import nimstr

proc main() {.async.} =
  let alice = generateKeypair()
  echo "Alice npub: ", alice.npub

  let restored = keypairFromSecret(alice.nsec)
  assert restored.pubkeyHex == alice.pubkeyHex

  let relay = newRelayClient("wss://relay.damus.io")
  await relay.connect()

  let ok = await relay.sendTextNote(alice.seckeyHex, "Hello from Nimstr!")

  var filter = NostrFilter(kinds: @[1], limit: 3)
  await relay.subscribe("test", filter)

  for i in 0..<10:
    let msg = await relay.ws.receiveStrPacket()
    let json = parseJson(msg)
    if json[0].getStr() == "EVENT":
      echo "Received: ", json[2]["content"].getStr()
    elif json[0].getStr() == "EOSE":
      break

  await relay.closeSubscription("test")
  await relay.close()

waitFor main()

鍵生成 → リレー接続 → テキストノート送信 → イベント購読 → 受信 → 切断

reply_bot.nim — 自動返信ボット

import std/[asyncdispatch, json, strutils]
import nimstr

proc replyToMentions(botKeypair: NostrKeypair) {.async.} =
  let relay = newRelayClient("wss://relay.damus.io")
  await relay.connect()

  await relay.subscribe("bot", NostrFilter(kinds: @[1]))

  while true:
    let msg = await relay.ws.receiveStrPacket()
    let json = parseJson(msg)
    if json[0].getStr() != "EVENT": continue
    let pubkey = json[2]["pubkey"].getStr()
    if pubkey == botKeypair.pubkeyHex: continue
    let target = ReplyTarget(
      eventId: json[2]["id"].getStr(),
      relayUrl: "wss://relay.damus.io",
      authorPubkey: pubkey
    )
    let ok = await relay.sendReply(
      botKeypair.seckeyHex,
      "Echo: " & json[2]["content"].getStr(),
      target
    )

イベントを監視して自動返信するボット。ReplyTargetで返信先を指定。

Dependencies

nim >= 2.0.0wssecp256k1nimSHA2

Links