Webhook サーバー
WebhookServer は Ed25519 署名検証付きの HTTP Webhook サーバーです。mixi2 からのイベントを安全に受信できます。
セットアップ
Section titled “セットアップ”// ESMimport { WebhookServer, EventType } from 'mixi2-js';import type { EventHandler, Event } from 'mixi2-js';// CJSconst { WebhookServer, EventType } = require('mixi2-js');import { WebhookServer, EventType } from '@otoneko1102/mixi2-js';import type { EventHandler, Event } from '@otoneko1102/mixi2-js';const handler: EventHandler = { handle: async (event: Event) => { switch (event.eventType) { case EventType.POST_CREATED: console.log("Post created:", event.postCreatedEvent?.post?.text); break; case EventType.CHAT_MESSAGE_RECEIVED: console.log("Chat message:", event.chatMessageReceivedEvent?.message?.text); break; } },};
// 公開鍵は Base64 からデコードconst publicKey = Buffer.from(process.env.SIGNATURE_PUBLIC_KEY!, "base64");
const server = new WebhookServer({ port: 8080, publicKey, handler,});
await server.start();console.log("Webhook server started on :8080");コンストラクタ
Section titled “コンストラクタ”new WebhookServer(options: WebhookServerOptions)| プロパティ | 型 | 必須 | デフォルト | 説明 |
|---|---|---|---|---|
publicKey |
Buffer |
○ | - | Ed25519 公開鍵(Base64 をデコードしたもの) |
handler |
EventHandler |
○ | - | イベントハンドラ |
port |
number |
- | 8080 |
リッスンポート |
syncHandling |
boolean |
- | false |
イベントを同期処理するか |
| メソッド | 戻り値 | 説明 |
|---|---|---|
start() |
Promise<void> |
サーバーを起動 |
shutdown() |
Promise<void> |
サーバーを停止 |
address |
string |
リッスンアドレス |
httpServer |
http.Server |
内部の HTTP サーバーインスタンス |
eventHandlerFunc |
Function |
イベントハンドラ関数(フレームワーク統合用) |
エンドポイント
Section titled “エンドポイント”| パス | メソッド | 説明 |
|---|---|---|
/events |
POST | イベント受信(署名検証 → protobuf デコード → ハンドラ呼出) |
/healthz |
GET | ヘルスチェック(常に 200 OK) |
署名検証の仕様
Section titled “署名検証の仕様”| 項目 | 値 |
|---|---|
| 署名ヘッダ | x-mixi2-application-event-signature(Base64) |
| タイムスタンプヘッダ | x-mixi2-application-event-timestamp(Unix 秒) |
| 署名対象 | リクエストボディ + タイムスタンプ |
| 許容時刻ズレ | ±300 秒(5 分) |
| 署名失敗レスポンス | HTTP 401 |
| 成功レスポンス | HTTP 204 |
Developer Platform で Webhook URL を登録して 接続確認を実行 を押すと、3 種類の Ping がランダムな順で送信されます。WebhookServer はそれぞれ期待どおりのレスポンスを自動で返します。
| リクエスト | レスポンス |
|---|---|
| 正しい署名 | HTTP 204 |
| 不正な署名 | HTTP 401 |
| 古いタイムスタンプ | HTTP 401 |
URL の要件
Section titled “URL の要件”- HTTPS で公開されていること
- 有効な CA 証明書を使っていること (自己署名証明書は不可)
WebhookServerを使う場合、パスは/events(例:https://YOUR_HOST_NAME/events)。createWebhookHandlerでは、ハンドラを置いたパスを登録します
1 つのアプリケーションに複数の Webhook URL は設定できません。
タイムアウトとリトライ
Section titled “タイムアウトとリトライ”| 項目 | 値 |
|---|---|
| タイムアウト | 3 秒 |
| リトライ回数 | 最大 3 回 |
| リトライ間隔 | 30 秒 |
リトライにより同じイベントが複数回届く場合があるため、ハンドラは冪等に実装してください。重複の除外には EventDeduplicator が使えます。
サーバーレス環境
Section titled “サーバーレス環境”Vercel、AWS Lambda などレスポンス後にプロセスが終了する環境では syncHandling: true を設定してください。ハンドラの完了まで処理が終わらないため、3 秒以内に完了できる処理が適しています:
const server = new WebhookServer({ port: 8080, publicKey, handler, syncHandling: true,});
export default server.httpServer;Cloudflare Workers
Section titled “Cloudflare Workers”Workers では wrangler の設定で nodejs_compat を有効にしたうえで、次のどちらかを使います。
createWebhookHandler(おすすめ):waitUntilでレスポンス後のハンドラ処理を Workers に引き継げます。使い方は次の節を参照してくださいWebhookServer:cloudflare:nodeのhttpServerHandlerで、Workers に届いたリクエストをnode:httpのサーバーに渡します。Node.js 向けのコードをそのまま使いたい場合に向いています
import { httpServerHandler } from "cloudflare:node";import { WebhookServer } from "mixi2-js";
const server = new WebhookServer({ port: 8080, publicKey: Buffer.from(SIGNATURE_PUBLIC_KEY, "base64"), handler, // Workers はレスポンス後に処理を止めることがあるため、ハンドラの完了を待つ syncHandling: true,});await server.start();
export default httpServerHandler({ port: 8080 });Fetch API で受け取る (createWebhookHandler)
Section titled “Fetch API で受け取る (createWebhookHandler)”createWebhookHandler は、Fetch API の Request を受け取って Response を返す Webhook ハンドラを作ります。Node.js の HTTP サーバーがない Cloudflare Workers のほか、Deno、Bun、Hono などでも使えます。署名とタイムスタンプの検証、Ping の扱い、レスポンスのステータスは WebhookServer と同じです。
// Cloudflare Workers (wrangler の設定で nodejs_compat を有効にする)import { createWebhookHandler } from "mixi2-js";
export default { fetch(request, env, ctx) { const handleWebhook = createWebhookHandler({ publicKey: env.SIGNATURE_PUBLIC_KEY, handler, waitUntil: (promise) => ctx.waitUntil(promise), }); return handleWebhook(request); },};// Deno / Bunconst handleWebhook = createWebhookHandler({ publicKey: SIGNATURE_PUBLIC_KEY, handler,});Deno.serve(handleWebhook); // Bun では Bun.serve({ fetch: handleWebhook })// Honoapp.post("/events", (c) => handleWebhook(c.req.raw));| オプション | 型 | 必須 | 説明 |
|---|---|---|---|
publicKey |
string | Uint8Array |
○ | 署名検証用の公開鍵。Developer Platform に表示される Base64 文字列をそのまま渡せます |
handler |
EventHandler |
○ | イベントハンドラ |
syncHandling |
boolean |
- | true にすると、ハンドラの完了を待ってからレスポンスを返します (デフォルト: false) |
waitUntil |
(promise: Promise<unknown>) => void |
- | レスポンス後のハンドラ処理をランタイムに引き継ぐ関数。Cloudflare Workers では ctx.waitUntil |
WebhookServer との違い:
- パスでの振り分けはしません。POST 以外のメソッドには HTTP 405 を返します
syncHandlingがfalseのとき、ハンドラはレスポンスを返した後も動き続けます。レスポンス後に処理が止まるランタイムでは、waitUntilを渡すかsyncHandling: trueにしてください- 署名検証に Web Crypto (
crypto.subtle) の Ed25519 を使います。Node.js 20 ではExperimentalWarningが出るため、Node.js ではWebhookServerをおすすめします
詳細は 公式ドキュメント を参照してください。