- TypeScript 97.8%
- Dockerfile 2.2%
|
All checks were successful
Build and Push Container Image / build-and-push-1 (push) Successful in 1m31s
Build and Push Container Image / build-and-push (push) Successful in 0s
Build and Push Container Image / deploy-1 (push) Successful in 4s
Build and Push Container Image / deploy (push) Successful in 0s
Signed-off-by: alex <alex@noreply.forge.l3x.in> |
||
|---|---|---|
| .forgejo/workflows | ||
| .zed | ||
| scripts | ||
| src | ||
| .env.example | ||
| .fallowrc.json | ||
| .gitignore | ||
| Containerfile | ||
| deno.json | ||
| deno.lock | ||
| fallow.schema.json | ||
| LICENSE | ||
| README.md | ||
| renovate.json | ||
irc-greeter-bot
A small Deno IRC bot that greets newcomers to a channel with a fixed message. The bot remembers who it has already greeted by persisting nicks to a JSON file on disk, so the same person is not re-greeted — even after a restart.
Requirements
Configuration
Configuration is loaded from a .env file and the process environment.
Process environment variables take precedence over .env values. Every
variable below is required (there are no built-in defaults); a missing or empty
value is a fatal error.
Copy .env.example to .env to get started:
cp .env.example .env # then edit .env
| Variable | Description |
|---|---|
IRC_SERVER |
IRC server hostname. |
IRC_PORT |
IRC server port (1–65535). |
IRC_TLS |
Connect with TLS (true/false). |
IRC_NICK |
Nickname the bot registers as. |
IRC_CHANNELS |
Comma-separated channels to join and greet in (≥1). |
IRC_GREETING |
Greeting template; {nick} substituted. |
IRC_STORE_PATH |
Path to the file that persists greeted nicks. Optional; defaults to greeted-nicks.json. |
IRC_PASSWORD |
Account password for NickServ/SASL auth. Optional; unset = anonymous. |
IRC_AUTH_METHOD |
Auth method when IRC_PASSWORD is set: NickServ (default), sasl, saslThenNickServ, or saslExternal. |
CHATTO_BASE_URL |
Chatto server origin for notifications (e.g. https://chat.example.com). Optional; see below. |
CHATTO_TOKEN |
Bearer token for the Chatto API. Optional. |
CHATTO_ROOM_ID |
ID of the Chatto room to post newcomer notifications into. Optional. |
CHATTO_MESSAGE |
Notification template with {nick} and {channel} placeholders. Optional; defaults to a sensible message. |
NickServ / SASL registration
The bot supports authenticating against a registered account using the built-in
mechanisms provided by @irc/client. Set
IRC_PASSWORD and pick an IRC_AUTH_METHOD:
| Method | Description |
|---|---|
NickServ |
Non-standard NickServ IDENTIFY after connect. Default. Requires IRC_PASSWORD. |
sasl |
SASL PLAIN during registration; aborts if SASL fails. Requires IRC_PASSWORD. |
saslThenNickServ |
SASL PLAIN, falling back to NickServ. Requires IRC_PASSWORD. |
saslExternal |
SASL EXTERNAL via a TLS client certificate (no password). Requires IRC_TLS=true plus a client cert. |
sasl / saslThenNickServ are recommended on networks that support them (e.g.
Libera.Chat) — they authenticate before the bot is visible on the network,
avoiding enforcer kills on a nick-protected account.
Example (SASL PLAIN):
IRC_PASSWORD=your-account-password
IRC_AUTH_METHOD=sasl
Leave IRC_PASSWORD unset (or empty) to connect anonymously — in that case
IRC_AUTH_METHOD is ignored.
Note:
saslExternalauthenticates with a TLS client certificate rather than a password. Certificate file paths are not currently exposed via env vars; use plainsaslfor password-based auth. Open an issue if you needsaslExternalwired up.
Chatto newcomer notifications
When an untracked user is greeted in IRC, the bot can mirror a notification into
a Chatto room via the
ConnectRPC API. The feature
is off by default — set all three of CHATTO_BASE_URL, CHATTO_TOKEN, and
CHATTO_ROOM_ID to enable it. Setting only some of them is a fatal error (so a
misconfiguration is caught at startup rather than failing silently per-join).
The notification is fire-and-forget: a Chatto failure is logged and never affects IRC greeting behavior.
Obtaining a CHATTO_TOKEN
Chatto has no "create API token" button. Bearer tokens (cht_AT…) are only
minted through the OAuth 2.0 Authorization Code + PKCE flow
(ADR-024).
The included chatto:token task automates this once against a loopback callback
(loopback origins are always trusted by Chatto, so no server-side allow-listing
is needed):
deno task chatto:token --base-url https://chat.example.com
# → opens a browser; log in as the bot account and approve consent
# → prints: CHATTO_TOKEN=cht_AT...
The resulting token has a 90-day inactivity TTL with a sliding window —
every successful API call resets it — so a token used regularly by the bot
effectively never expires. It is revoked by a password change/reset on the
account or by explicit revocation, at which point the bot logs a clear 401
message pointing back here.
Usage
Run the bot (it needs network, environment, and filesystem access):
cp .env.example .env # then edit .env
deno task start
For development with automatic reload on file changes:
deno task dev
Compile a standalone binary:
deno task compile
./dist/bot
Development
This project follows standard Deno conventions. Common tasks (defined in
deno.json):
| Task | Description |
|---|---|
deno task dev |
Run the bot with --watch. |
deno task start |
Run the bot. |
deno task test |
Run the test suite. |
deno task lint |
Lint the source. |
deno task fmt |
Format the source. |
deno task check |
Type-check the entry point. |
deno task compile |
Build a standalone binary. |
deno task chatto:token |
Obtain a Chatto bearer token via OAuth + PKCE (see below). |
deno task fallow |
Run Fallow static analysis. |
Project structure
src/
main.ts Entry point: connects to IRC and wires up the greeter.
config.ts Loads and validates configuration from .env + env vars.
greet.ts Pure greeting / who-to-greet logic (no I/O).
chatto.ts Posts newcomer notifications to a Chatto room (Connect JSON).
storage.ts Disk-backed store of already-greeted nicks.
*_test.ts Unit tests (Deno's built-in test runner); one per module.
scripts/
chatto-token.ts Obtains a Chatto bearer token via the OAuth + PKCE flow.
Every module in src/ has a corresponding *_test.ts file. The greeting and
join-handling logic live in src/greet.ts and the
handleJoin export of src/main.ts, both kept free of network
I/O so they can be tested with in-memory fakes.
Codebase analysis (Fallow)
This project is configured for Fallow, a
TypeScript/JavaScript codebase-intelligence tool. It detects dead code,
duplication, and complexity issues. Configuration lives in
.fallowrc.json (with editor autocomplete via
fallow.schema.json); test files are excluded from
analysis.
# Dead-code check (also what CI runs)
deno task fallow
# Duplication and health reports
npx fallow dupes
npx fallow health