🐥

node.js で Nostr に投稿するシンプルコード

に公開

こんにちは、びしょうじょです。js も nostr も初心者です。

node.js で nostr 投稿をシンプルに実行したかったところ、gpt とか claude に聞いてても ws で雑に沼っててうんちすぎたので書きました。( ES Modules なら useWebSocketImplementation なる便利関数が用意されてた & nostr-tools のREADMEをちゃんと読めって渡したのに…)

CommonJSです。

コマンド

$ npm i -g nostr-tools ws @noble/hashes
$ export NOSTR_NSEC="nsec..."
$ node post.js

コードの中身

post.js
relayUrl は適当に変えてください

const { finalizeEvent } = require('nostr-tools/pure')
const { SimplePool, useWebSocketImplementation } = require('nostr-tools/pool')
const nip19 = require('nostr-tools/nip19')
// const WebSocket = require('ws')


// Node.js用のWebSocket実装を設定  // ES Module (?)
// useWebSocketImplementation(WebSocket)

// 設定
const relayUrl = 'wss://relay.nostr.band'  // 投稿先のリレー
const nsec = process.env.NOSTR_NSEC  // 環境変数からnsecを取得
const message = 'Hello Nostr!'  // 投稿するメッセージ

// nsecの存在チェック
if (!nsec) {
  console.error('エラー: NOSTR_NSEC 環境変数が設定されていません')
  process.exit(1)
}

async function postToNostr() {
  // SimplePoolを作成
  const pool = new SimplePool()

  // nsecを秘密鍵のバイト配列に変換
  const { type, data } = nip19.decode(nsec)
  const secretKey = data

  // イベントテンプレートを作成
  const eventTemplate = {
    kind: 1,  // テキストメモ
    created_at: Math.floor(Date.now() / 1000),
    tags: [],
    content: message,
  }

  // イベントに署名
  const signedEvent = finalizeEvent(eventTemplate, secretKey)

  try {
    // リレーに投稿
    await Promise.any(pool.publish([relayUrl], signedEvent))
    console.log('投稿に成功しました!')
    console.log('イベントID:', signedEvent.id)
  } catch (error) {
    console.error('投稿に失敗しました:', error)
  } finally {
    // 接続を閉じる
    pool.close([relayUrl])
  }
}

// 実行
postToNostr()

ついでに受信のコードも

$ node receive.js

receive.js

const { SimplePool, useWebSocketImplementation } = require('nostr-tools/pool')
// const WebSocket = require('ws')


// Node.js用のWebSocket実装を設定  // ES Module (?)
// useWebSocketImplementation(WebSocket)

// 設定
const PAST_SECONDS = 60  // 過去n秒
const relayUrls = [
  'wss://relay.nostr.band'
]

async function receivePastPosts() {
  const pool = new SimplePool()

  // 現在時刻と過去n秒前の時刻を計算
  const now = Math.floor(Date.now() / 1000)
  const pastTime = now - PAST_SECONDS

  console.log(`過去${PAST_SECONDS}秒の投稿を検索中...`)
  console.log(`検索期間: ${new Date(pastTime * 1000).toLocaleString()} - ${new Date(now * 1000).toLocaleString()}`)

  try {
    // 過去n秒の投稿を取得
    const events = await pool.querySync(
      relayUrls,
      {
        kinds: [1], // テキストノート
        since: pastTime, // 過去n秒前から
        until: now, // 現在まで
        limit: 50 // 最大50件
      },
      { timeout: 10000 } // 10秒でタイムアウト
    )

    console.log(`${events.length}件の投稿を取得しました:\n`)

    // 投稿を時間順にソート(新しいものから)
    events.sort((a, b) => b.created_at - a.created_at)

    // 投稿を表示
    events.forEach((event, index) => {
      const date = new Date(event.created_at * 1000)
      console.log(`--- 投稿 ${index + 1} ---`)
      console.log(`時間: ${date.toLocaleString()}`)
      console.log(`作者: ${event.pubkey.slice(0, 16)}...`)
      console.log(`内容: ${event.content}`)
      console.log(`ID: ${event.id}`)
      console.log()
    })

  } catch (error) {
    console.error('投稿の取得に失敗しました:', error)
  } finally {
    // 接続を閉じる
    pool.close(relayUrls)
  }
}

// 実行
receivePastPosts()

以上!

あと、即席の nsec を作るのとかも簡単にできるっぽい

Discussion