🐥
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