A Google Chrome extension that calculates the cost of your Google Meet calls, built as a pnpm monorepo with a supporting backend API.
apps/extension— Chrome (Manifest V3) extension, built with Vite, that connects to the server. This is where the CallCost UI lives (a clean popup with an eye toggle to enable/disable the plugin).apps/server— Express + TypeScript API.packages/shared— TypeScript types shared as the API contract between both apps.
.
├── apps/
│ ├── server/ # Express API (tsx dev, tsup build)
│ └── extension/ # Chrome MV3 extension (Vite + @crxjs/vite-plugin)
└── packages/
└── shared/ # Shared API types (@workation/shared)
- Node.js >= 20
- pnpm >= 9 (
corepack enableornpm i -g pnpm)
pnpm installRun both apps together:
pnpm devOr individually:
pnpm dev:server # http://localhost:3000
pnpm dev:extension # Vite dev server on http://localhost:5173- Start the server:
pnpm dev:server. - Build (or dev) the extension:
pnpm dev:extension(orpnpm --filter extension build). - Open
chrome://extensions, enable Developer mode. - Click Load unpacked and select
apps/extension/dist. - Open the extension popup — the badge should read connected, and you can send messages to the server.
After editing extension files, return to chrome://extensions and click the
reload (↻) icon on the extension card. Reopen the popup to see your changes.
(HTML/CSS/JS changes to the popup take effect the next time you open it; a
reload is only strictly required for manifest.json changes.)
pnpm build # builds both apps
pnpm --filter server build
pnpm --filter extension build| Method | Route | Description |
|---|---|---|
| GET | /api/health |
Health/uptime check |
| GET | /api/messages |
List messages |
| POST | /api/messages |
Create a message |
The server keeps messages in memory; swap the in-memory store in
apps/server/src/index.ts for a database when needed.
- Server port:
PORTenv var (default3000). - Server URL used by the extension:
apps/extension/src/config.tsand thehost_permissionsentry inapps/extension/manifest.config.ts. Update both when deploying the server elsewhere.
- Polished popup window that opens from the toolbar icon.
- A single eye toggle: press it to enable (open eye) or disable (crossed eye) the plugin.
- The enabled/disabled state is remembered between sessions via
chrome.storage, and reflected on the toolbar icon (anoffbadge when paused).
- Detect active Google Meet tabs.
- Track participants and call duration.
- Compute an estimated cost from configurable hourly rates.