VOOZH about

URL: https://dev.to/zenovay/building-a-terminal-interface-for-my-analytics-saas-with-cloudflare-durable-objects-c8g

⇱ Building a terminal interface for my analytics SaaS with Cloudflare Durable Objects - DEV Community


Every analytics dashboard lives in a browser tab. My terminal is always open. So I built @zenovay/cli, a terminal interface for my analytics SaaS.

The killer command is zenovay events tail: a live stream of pageviews and events, filterable, pipeable, scriptable. Think stripe listen but for your web traffic.

This post covers how the live tail actually works.

The product surface

$ zenovay events tail --site mysite.com --path /pricing
[14:32:18] mysite.com pageview /pricing US Chrome
[14:32:21] mysite.com pageview /pricing DE Firefox
[14:32:24] mysite.com click /pricing#cta-pro US Chrome
[14:32:28] mysite.com pageview /pricing GB Safari

You can pipe it:

$ zenovay events tail --site mysite.com | jq .country | sort | uniq -c

The architecture

Three components:

  1. CLI binary (TypeScript, distributed via npm)
  2. WebSocket gateway (Cloudflare Worker with Durable Objects)
  3. Event broadcast (Workers pushing to subscribed Durable Objects)

The Durable Object as fanout point

Each tracked site gets a Durable Object that holds the list of active WebSocket subscribers.

export class SiteStream {
 constructor(private state: DurableObjectState) {
 this.sockets = new Set<WebSocket>()
 }

 async fetch(request: Request) {
 if (request.headers.get('Upgrade') === 'websocket') {
 const pair = new WebSocketPair()
 this.handleSocket(pair[1])
 return new Response(null, { 
 status: 101, 
 webSocket: pair[0] 
 })
 }

 if (request.method === 'POST') {
 const event = await request.json()
 this.broadcast(event)
 return new Response('ok')
 }
 }

 broadcast(event: unknown) {
 const data = JSON.stringify(event)
 for (const ws of this.sockets) {
 try { ws.send(data) }
 catch { this.sockets.delete(ws) }
 }
 }
}

The CLI side

Built with Commander for argument parsing and just plain WebSocket for the stream. Catppuccin Mocha palette via chalk hex codes.

Install

npm install -g @zenovay/cli
zenovay auth login
zenovay events tail --site yoursite.com

Free tier of Zenovay includes the CLI. Site is zenovay.com.

Anyone else building TUIs for SaaS products? Curious what patterns you have found.

Valerio