A Discord bot that tracks user timezones and tells you if someone is likely awake. Built on Cloudflare Workers with Hono, Drizzle ORM, Cloudflare D1 and with help from Claude Code.
- Invite Reva to your server
- Run
/set-timezoneto set your timezone - Ask others to do the same, then anyone can check anyone's local time with
/time @user
| Command | Description |
|---|---|
/time [@user] |
Show a user's local time. Omit @user to see your own. |
/set-timezone |
Set your timezone via an interactive select menu |
/help |
Show all available commands |
- Node.js 18+
- pnpm
- Cloudflare account
- Discord application with a bot (Discord Developer Portal)
pnpm installCreate .dev.vars in the project root for local development:
DISCORD_PUBLIC_KEY=your_bot_public_key
DISCORD_APPLICATION_ID=your_application_id
DISCORD_BOT_TOKEN=your_bot_token
DISCORD_GUILD_ID=your_guild_id # optional — for instant guild-scoped registrationDISCORD_BOT_TOKEN and DISCORD_GUILD_ID are only used by the command registration script, not the worker itself.
pnpm db:local:migrate # creates the local D1 databasepnpm discordSelect Guild scope for instant updates during development, Global for production.
pnpm devThe worker starts at http://localhost:8787. Point your Discord application's Interactions Endpoint URL to your ngrok/tunnel URL + /api/interactions.
pnpm deploySet production secrets in Cloudflare:
wrangler secret put DISCORD_PUBLIC_KEY
wrangler secret put DISCORD_APPLICATION_IDApply the database migration to production:
pnpm db:prod:migratesrc/
bot/ Discord interaction handling (commands, components, router)
db/ Schema, Drizzle factory, and query functions
content/ Response templates and render utility
ui/ Discord component builders (select menus)
scripts/ CLI for managing Discord slash commands
- Create
src/bot/commands/<name>.ts:
import { ResponseType, type ApplicationCommandInteraction } from "../discord"
import type { Context } from "hono"
import type { Bindings } from "../../types/binding"
export const definition = {
name: "my-command",
description: "Does something",
} as const
export async function handler(c: Context<{ Bindings: Bindings }>, interaction: ApplicationCommandInteraction): Promise<Response> {
return c.json({ type: ResponseType.CHANNEL_MESSAGE, data: { content: "Hello!" } })
}- Add it to
src/bot/registry.ts:
import * as myCommand from "./commands/my-command"
const modules = [awake, setTimezone, help, myCommand] as const- Register with Discord:
pnpm discord# 1. Edit src/db/schema.ts
# 2. Generate migration
pnpm db:generate
# 3. Apply locally
pnpm db:local:migrate
# 4. Apply to production when ready
pnpm db:prod:migratepnpm testTests run inside the actual Cloudflare Workers runtime via @cloudflare/vitest-pool-workers.