@better-i18n/webhook
v0.0.1
Published
GitHub Webhook Service - Receives and queues GitHub events
Maintainers
Readme
🔗 Better i18n Webhook Service
Lightweight GitHub webhook receiver built with Hono and Cloudflare Workers.
Responsibility: Receive GitHub events → Verify signature → Queue for sync-worker
🎯 What It Does
GitHub Webhook Event
↓
Signature Verification (HMAC-SHA256)
↓
Idempotency Check (KV Cache)
↓
Queue Message (Cloudflare Queue)
↓
Return 202 Accepted (< 50ms)
↓
sync-worker processes asynchronously📋 Supported Events
installation- App installed/uninstalled/suspendedpush- Code pushed to repositorypull_request- PR opened/closed/updated
🚀 Development
Setup
# Install dependencies
cd apps/webhook
bun install
# Set environment variables
cp .env.example .env.local
# Edit .env.local with your GitHub App webhook secret
echo "GITHUB_WEBHOOK_SECRET=your_secret" >> .env.localRun Locally
# Start development server
bun run dev
# Server runs on http://localhost:8790Test Health Check
curl http://localhost:8790/health
# Response: { "status": "ok", "timestamp": "...", "environment": "development" }Test Signature Verification
curl -X POST http://localhost:8790/test/webhook
# Should return: { "test": "signature_verification", "result": "passed" }Manual Webhook Test
# Using ngrok to expose localhost to GitHub
ngrok http 8790
# Copy the ngrok URL: https://xxxxx.ngrok.io
# Update GitHub App settings:
# Webhook URL: https://xxxxx.ngrok.io/webhook
# Secret: (use same as .env.local)
# Then trigger a GitHub event:
# - Push to repo, or
# - Install/uninstall the app, or
# - Create a PR🔒 Security
Signature Verification
- ✅ HMAC-SHA256 verification
- ✅ crypto.timingSafeEqual (prevents timing attacks)
- ✅ Reference: https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries
Test Values (from GitHub docs)
Secret: "It's a Secret to Everybody"
Payload: "Hello, World!"
Expected: "sha256=757107ea0eb2509fc211221cce984b8a37570b6d7586c22c46f4379c8b043e17"Idempotency
- Delivery ID tracking in KV cache (24h TTL)
- Prevents duplicate webhook processing
- GitHub may retry failed deliveries
📊 Performance
- Signature verification: ~5ms
- JSON parse: ~1ms
- Queue send: ~10ms
- Total response time: < 20ms
- Response status: 202 Accepted (async)
🔧 Configuration
Environment Variables
GITHUB_WEBHOOK_SECRET # GitHub App webhook secret (required)
ENVIRONMENT # development | production
LOG_LEVEL # debug | info | warn | errorCloudflare Configuration
# wrangler.toml
[[queues.bindings]]
binding = "SYNC_QUEUE"
queue = "sync-queue"
[[kv_namespaces]]
binding = "WEBHOOK_CACHE"
id = "webhook-delivery-cache"📤 Queue Message Format
Messages sent to SYNC_QUEUE:
interface QueueMessage {
type: "WEBHOOK_EVENT";
delivery_id: string; // GitHub delivery ID (for idempotency)
event_type: string; // installation, push, pull_request
received_at: string; // ISO timestamp
payload: unknown; // Full GitHub webhook payload
}🚢 Deployment
To Production
# Build and deploy to Cloudflare Workers
bun run deploy
# Set secrets in Cloudflare
wrangler secret put GITHUB_WEBHOOK_SECRET
# Enter your GitHub App webhook secret when prompted
# Verify deployment
curl https://webhook.better-i18n.com/healthGitHub App Configuration
- Go to GitHub → Settings → Developer settings → GitHub Apps → Your App
- Webhook settings:
- Webhook URL:
https://webhook.better-i18n.com/webhook - Secret: Same as
GITHUB_WEBHOOK_SECRET - SSL verification: Enable
- Events:
- Installation
- Push
- Pull request
- Active: ✅ Enabled
- Webhook URL:
📊 Monitoring
Log Levels
DEBUG: All requests and detailed processing
INFO: Normal operations and important events
WARN: Warning-level issues (invalid signatures, etc.)
ERROR: Errors that need attentionCheck Webhook Deliveries
- GitHub → Your App → Recent Deliveries
- See delivery status, response, and logs
- Can manually redeliver if needed
Monitor Queue
# Check queue status in Cloudflare Dashboard
# Workers → Queues → sync-queue
# View messages, retries, and processing🔗 Related Services
- Main API:
api.better-i18n.com(tRPC) - Sync Worker:
apps/sync-worker/(processes queue messages) - Database: Neon PostgreSQL (via sync-worker)
📚 References
- Hono: https://hono.dev
- Cloudflare Workers: https://workers.cloudflare.com
- GitHub Webhooks: https://docs.github.com/en/webhooks
- GitHub App Documentation: https://docs.github.com/en/developers/apps
🆘 Troubleshooting
Webhook Not Received
- Check GitHub App webhook URL is correct
- Verify secret matches
GITHUB_WEBHOOK_SECRET - Check Cloudflare Workers logs
- Verify route in
wrangler.tomlmatches GitHub webhook domain
Signature Verification Fails
- Verify secret is correct
- Check that raw body is being used (not parsed)
- Test with
/test/webhookendpoint
Messages Not Being Processed
- Check
sync-workeris running and consuming queue - Verify
SYNC_QUEUEbinding is configured - Check Cloudflare Queue status in dashboard
Cold Starts
Cloudflare Workers are deployed to edge globally - no cold starts!
📝 License
Copyright © 2024-present better-i18n. Licensed under MIT.
