::title::

JevRouterについて

Yusuke Wada

Cloudflare Workers実践LT 〜移行から運用、コストの話まで〜 ・ September 24, 2026


Yusuke Wada

::right::

me


::center::

Jev!!


::center::

JevRouterを作った話


JevRouter


Honoでルーターを変更する方法

import { PatternRouter } from 'hono/router/pattern-router'

const app = new Hono({
  router: new PatternRouter()
})

JevRouterを使う

import { Hono } from 'hono'
import { JevRouter } from 'hono-jev-router'

const app = new Hono({
  router: new JevRouter()
})

ユースケース例


コード

app.on('jev', 'AIエージェントからのリクエストだよ', (c) => {
  return c.text('# Documentation', 200, { 'Content-Type': 'text/markdown' })
})

app.on('jev', '人間からのリクエストだよ', (c) => {
  return c.html('<h1>Documentation</h1>')
})

app.on('jev', '自動化されたアクセスだよ', (c) => {
  return c.text('Forbidden', 403)
})

仕組み

リクエスト => Jev => ルートを選ぶ


Jevに渡すもの

{
  "state": {
    "method": "GET",
    "url": "https://example.com/docs",
    "headers": {
      "user-agent": "claude-code/2.0",
      "accept": "text/markdown",
      "cookie": "[redacted]"
    }
  },
  "questions": {
    "route_1": {
      "type": "noul",
      "instructions": "A router has a handler for requests described as \"AIエージェントからのリクエストだよ\". Is this HTTP request one that the handler should receive?"
    }
  }
}

Jevから返るもの

{
  "answers": {
    "route_1": { "noul": 0.94 },
    "route_2": { "noul": 0.2 },
    "route_3": { "noul": 0.05 }
  }
}

::center::

デモ

-# https://hono-jev-router.yusuke.run


npx hono request /docs -H 'user-agent: claude-code/2.0' -H 'accept: text/markdown'

npx hono request /docs -H 'user-agent: Mozilla/5.0 (Macintosh) Safari/605.1' -H 'accept: text/html'

npx hono request /docs -H 'user-agent: python-requests/2.31' -H 'accept: */*'

npx hono request /support -X POST \
  -d '先月の請求額が2回引き落とされてるみたいなんですが、確認できますか?'

npx hono request /support -X POST \
  -d 'もう使わないので解約したいです。手続きを教えてください。'

npx hono request /support -X POST \
  -d '3回問い合わせてるのに返事がない。いい加減にしてください。今すぐ対応して。'

npx hono request /support -X POST \
  -d 'ダークモードって対応予定ありますか?'

ミドルウェアというアプローチ

import { createMiddleware } from 'hono/factory'

export const jevMiddleware = (question: string, threshold = 0.8) =>
  createMiddleware(async (c, next) => {
    const state = await c.req.text()
    const res = await c.env.AI.run('typesafe/jev', {
      state,
      questions: { flag: { type: 'noul', instructions: question } }
    })
    const p = (res.result ?? res).answers.flag.noul
    if (p > threshold) {
      return c.json({ blocked: true, probability: p }, 400)
    }
    await next()
  })

使い方

import { Hono } from 'hono'
import { jevMiddleware } from './middleware'

const app = new Hono()

app.post('/comments', jevMiddleware('これはスパムですか?'), (c) => {
  return c.json({ posted: true })
})

export default app

スパム判定されるリクエスト

npx hono request -X POST -d "副業で月収100万円!スマホだけで誰でも簡単!今すぐLINE登録" /comments ./src/using-middleware.ts

まとめ


← → / space ・ o: overview ・ f: fullscreen