@devchitchat/chat
v4.2.0
Published
A small chat app. p2p video and screenshare.
Downloads
1,026
Readme
Dev Chit Chat
In 2009, at the Velocity conference, a couple of guys who worked at Flickr presented how development and operations fits toghether and gets along ... at Flickr.
The premise is kinda of dumb. Like, why was there even a Devs vs Ops mentality? Regardless, it was real. We were all working on systems and under pressure to build stuff that, quite frankly, was hard.
Anyways, that was the inspiration. Since then, I've championed just collaborating with each other as we build things together.
Along with this, Agile had already been getting traction in corporate America. Scrum was being used to run teams. And Daily Standups were becoing the norm.
In 2013 Github released Hubot as open source, it's home grown chat bot.
I was at GameStop at this time, managing my first team. I saw first hand what a DevOps culture felt like. We deployed the system every week. It was amazing.
Dev Chit Chat came out of that experience and time. Developers meeting daily chit chatting about what they were going to do today, what they learned, etc.
A Story
I want a chat system that works like Discord, but I don't need the scalability of Discord. I'm just using it for my friends, small teams, not 1000 member community.
Bun is fast and javascript is fine. So let's leverage the accessiblity of both to build a small chat system that does video, audio and screenshare live streaming.
I run bun start the first time and I see a bootstrapping invite code in the console. I double-click on it and copy it to pasteboard. Then I visit https://joey-mac-mini.local:3000 (use your machine name instead of mine in hte URL) and enter it on the signup page to create the first account, it's the admin.
Upon signing in the first time, there's no communication hubs or channels. So we need to create the first ones first so the app can be in a useable state.
The system should just create a default hub and channel. That way, on bootstrap, the system is useable right off the bat. I can start chatting in a channel.
Getting Started
Install as a package
bun add @devchitchat/chatThen start it from your own server file:
// server.mjs
import { start } from '@devchitchat/chat'
const server = await start({
port: 3000,
basePath: '/chat', // mount at example.com/chat — omit for root
dbPath: './data/chat.db',
})
console.log(`chat listening on port ${server.port}`)All config options and their defaults:
| Option | Env var fallback | Default |
|---|---|---|
| port | PORT | 3000 |
| dbPath | DB_PATH | ./data/chat.db |
| basePath | BASE_PATH | "" (root) |
| dev | NODE_ENV !== 'production' | true |
| tlsCert | TLS_CERT | ./certs/dev-cert.pem |
| tlsKey | TLS_KEY | ./certs/dev-key.pem |
Every option falls back to its environment variable, so you can configure via env instead of passing a config object:
BASE_PATH=/chat PORT=3000 DB_PATH=./data/chat.db bun server.mjsstart() returns the Bun server instance — you can inspect server.port, stop it with server.stop(), etc.
Migrations run automatically on every call to start() — no separate migration step needed.
Run standalone
To run the chat app directly without writing a wrapper:
bunx devchitchatOr install globally:
bun install -g @devchitchat/chat
devchitchatRun from source
Prerequisites
- Bun v1.0 or later
Install
bun installHTTPS requirement
Text chat works over plain HTTP. However, browsers block camera, microphone, and screen-share access on non-secure origins, so HTTPS is required for video and audio calls.
Create a self-signed certificate
First, find your machine's hostname and LAN IP:
# macOS
hostname # e.g. joey-mac-mini.local
ipconfig getifaddr en0 # e.g. 192.168.1.10
# Linux
hostname -f
hostname -I | awk '{print $1}'Then generate the certificate, substituting your actual hostname and IP:
mkdir -p certs
openssl req -x509 -newkey rsa:2048 -sha256 -nodes -days 365 \
-keyout certs/dev-key.pem \
-out certs/dev-cert.pem \
-subj "/CN=joey-mac-mini.local" \
-addext "subjectAltName = IP:192.168.1.10"The server looks for certs/dev-cert.pem and certs/dev-key.pem by default. You can override the paths with TLS_CERT and TLS_KEY environment variables (see below).
On first visit the browser will warn about the self-signed cert — proceed past it and the warning won't reappear.
Trust the cert (optional but recommended)
Trusting the cert silences the browser warning permanently.
macOS:
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain certs/dev-cert.pemLinux (Debian/Ubuntu):
sudo cp certs/dev-cert.pem /usr/local/share/ca-certificates/devchitchat.crt
sudo update-ca-certificatesWindows: Double-click certs/dev-cert.pem, choose "Install Certificate", place it in the "Trusted Root Certification Authorities" store.
Start the server
# Production
bun start
# Development (auto-restarts on file changes)
bun devThe server starts on port 3000 by default. Visit https://<your-machine>.local:3000.
First-time bootstrap
On the very first run, an invite code is printed to the console:
Invite code: https://<your-machine>.local:3000/signup?code=<token>Copy that URL and open it in a browser to create the first account, which becomes the admin. From there you can invite other users and set up hubs and channels.
Environment variables
| Variable | Default | Description |
|---|---|---|
| PORT | 3000 | Port the server listens on |
| DB_PATH | data/chat.db | Path to the SQLite database file |
| BASE_PATH | "" | URL subpath to mount the app at (e.g. /chat) |
| NODE_ENV | development | Set to production in production |
| TLS_CERT | certs/dev-cert.pem | Path to the TLS certificate |
| TLS_KEY | certs/dev-key.pem | Path to the TLS private key |
Run tests
bun testBackup and restore
Backup
Database:
bun backupCreates a clean binary copy of the database at data/backups/chat-<timestamp>.db using SQLite's VACUUM INTO. Safe to run against a live server.
| Variable | Default | Description |
|---|---|---|
| DB_PATH | data/chat.db | Path to the source database |
| BACKUP_DIR | data/backups | Directory where backups are written |
Uploads:
bun backup-uploadsMirrors the uploads directory to a backup location. Not versioned — overwrites the destination with the current state.
| Variable | Default | Description |
|---|---|---|
| UPLOAD_DIR | data/uploads | Source uploads directory |
| UPLOADS_BACKUP_DIR | data/backups/uploads | Backup destination |
Restore
Local (bare Bun process)
Database:
- Stop the server.
- Copy the backup over the live database:
cp data/backups/chat-<timestamp>.db data/chat.db - Restart the server.
Uploads:
cp -r data/backups/uploads data/uploadsKubernetes (k3s)
Database:
bun restore path/to/chat-<timestamp>.dbscripts/restore.js handles the full sequence automatically:
- Switches to the correct kubectl context
- Scales
chat-webdown to 0 and waits for termination - Starts a temporary
busyboxhelper pod mounting thechat-web-sqlitePVC - Uploads the backup file to the pod
- Moves it into place as
/var/lib/chat/chat.db - Fixes file permissions so the app can write to the restored database
- Removes stale WAL/SHM files so SQLite opens cleanly
- Removes the temporary upload file
- Deletes the helper pod
- Scales
chat-webback to 1 and waits for rollout
If any step fails, the helper pod is cleaned up and the deployment is scaled back to 1 before exiting.
Uploads:
bun restore-uploads path/to/uploads-backupCopies the uploads directory into the PVC via a temporary helper pod. The deployment is not scaled down — uploads are static files and the copy is safe against a live server.
Cluster env vars (both restore scripts):
| Variable | Default | Description |
|---|---|---|
| KUBE_CONTEXT | k3s-local | kubectl context |
| KUBE_NAMESPACE | default | Kubernetes namespace |
Useful k8s backup operations
# Trigger the backup CronJob immediately (instead of waiting for the schedule)
bun backup-now
# Pull backups from the running pod to your local ../backups directory
bun backup-pullDocker / Kubernetes (k3s)
The included scripts build a Docker image and load it into a local k3s cluster.
Cluster setup
The cluster runs k3s inside a Lima VM. Lima auto-starts on boot via launchd, so the cluster survives power outages without requiring a user login.
One-time setup:
brew install lima
limactl start --name=k3s template://k3sMerge the kubeconfig so kubectl can reach the cluster:
limactl kubeconfig k3s >> ~/.kube/config
# or set KUBECONFIG directly:
export KUBECONFIG="$HOME/.kube/config:$(limactl list k3s --format '{{.Dir}}/copied-from-guest/kubeconfig.yaml')"The context is named k3s-local by default in this project's scripts. Rename it to match if yours differs:
kubectl config rename-context default k3s-localBackup paths:
Lima mounts your home directory into the VM at the same path, so backup paths in charts/web/values.local.yaml are regular host paths — no special volume flags needed at cluster creation. Set them in values.local.yaml (gitignored):
dbBackupNodePath: /Users/yourname/backups/chat-web/db-backups
uploadsBackupNodePath: /Users/yourname/backups/chat-web/uploads-backupsBuild and import into k3s
bun run docker-build
# or directly:
./docker-build-k3s.shThis will:
- Bump the patch version in
package.json - Update the image tag in
charts/web/deployment.yaml - Build the Docker image (
local/chat-web:<version>) - Import the image into the Lima k3s instance via
limactl shell
LIMA_INSTANCE controls which Lima VM the image is imported into — it maps to the <name> in limactl shell <name>. If you started your VM with limactl start --name=k3s, you never need to set it. Only set it if you named your VM something other than k3s:
LIMA_INSTANCE=my-instance bun run docker-buildDeploy to local cluster
bun run local-deployApplies charts/web/deployment.yaml to the default namespace of the k3s-local context.
Build + deploy in one step
bun run pushKubernetes environment variables
Override defaults via charts/web/deployment.yaml:
| Variable | Value in chart | Description |
|---|---|---|
| PORT | 8080 | Port the container exposes |
| NODE_ENV | production | Runtime environment |
| DB_PATH | /var/lib/chat/chat.db | SQLite path (backed by a 2 Gi PVC) |
