heartbeat
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
A serverless monitoring solution for your home server with push notifications when it goes offline.
- Real-time Status: Check if your server is online/offline
- Push Notifications: Get notified when server goes down (1+ hour without heartbeat)
- PWA Support: Install as a Progressive Web App on mobile/desktop
- Clean Architecture: Static files served separately for better maintainability
heartbeat/
├── main.ts # Hono server with API routes
├── index.html # Static HTML page
├── client.js # Frontend JavaScript
├── sw.js # Service Worker for push notifications
├── monitor.ts # Interval val that checks for downtime
├── generate-vapid-keys.ts # Script to generate VAPID keys
└── README.md # This file
Run the generate-vapid-keys.ts script to generate your VAPID keys.
Add these to your Val Town environment:
VAPID_PUBLIC_KEY- Public key from step 1VAPID_PRIVATE_KEY- Private key from step 1
Add a cron job to your home server that pings the heartbeat endpoint every 15 minutes:
*/15 * * * * curl -X POST https://halffullheartbeat.val.run/heartbeat
- Visit your deployed app
- Click "Enable Notifications"
- Grant notification permission
Your server calls this endpoint to signal it's alive.
Returns current server status:
{ "lastHeartbeat": 1234567890000, "isOnline": true, "minutesSince": 5, "currentTime": 1234567890000 }
Subscribe to push notifications (called by frontend).
Get VAPID public key for push subscription.
- Heartbeat: Your server sends a POST request every 15 minutes to
/heartbeat - Monitoring: The
monitor.tsinterval val checks every 15 minutes if any heartbeat was received in the last hour - Notifications: If server is down (no heartbeat for 1+ hour), push notifications are sent to all subscribers
- Status: Frontend polls
/statusevery 30 seconds to show real-time status
This project now uses a clean separation of concerns:
- main.ts: Pure backend logic with Hono routes
- index.html: Static HTML served as-is (no React SSR needed)
- client.js: Frontend JavaScript in a separate file
- sw.js: Service Worker logic in its own file
Benefits:
- ✅ Better maintainability
- ✅ Easier debugging (proper file names in dev tools)
- ✅ Better caching (static files cached separately)
- ✅ No need for React imports or dangerouslySetInnerHTML
- ✅ Cleaner codebase
- Val Town: Serverless hosting
- Hono: Fast web framework
- SQLite: Database for heartbeats and subscriptions
- Push API: Browser push notifications
- Service Workers: Offline support and notifications