Documentation

Browser Extension

Manifest V3 service worker, tab event tracking, offline queueing, local categorization and remote control.

The extension supplies the website level half of TimeLet. It runs independently of the desktop app.

Manifest V3

extension/manifest.json
{
  "manifest_version": 3,
  "background": { "service_worker": "src/background/index.ts" },
  "permissions": ["tabs", "storage", "idle", "alarms"],
  "host_permissions": ["<all_urls>"],
  "action": { "default_popup": "src/popup/index.html" }
}

Service worker lifecycle

An MV3 service worker is killed aggressively. Nothing durable stays in memory: the tracker restores state from chrome.storage on every wake, and the queue is persisted before it is flushed.

Wake sequence

  1. Service worker wakes
    01
  2. Tracking state restored from chrome.storage
    02
  3. Queue drained to the API
    03
  4. Heartbeat sent
    04
  5. Pending remote control command polled
    05

Tab events

ts
chrome.tabs.onActivated.addListener(async ({ tabId }) => {
  const tab = await chrome.tabs.get(tabId);
  await session.flushCurrent();
  session.start(tab.url, tab.title);
});

chrome.tabs.onUpdated.addListener((tabId, info) => {
  if (info.url) session.navigate(info.url, info.title);
});

How a website gets categorised

The extension ships its own copy of the rules so it can label activity offline. The file is duplicated from the server on purpose, which means the two must change together.

Offline queueing

If the API is unreachable, completed blocks go to a bounded local queue and are retried on the next wake with backoff, oldest first, so ordering survives.

Remote control

The extension polls for a pending control command and acknowledges it after applying it. This is how pausing tracking on the dashboard stops the extension without the user touching the browser.

Build

bash
cd extension
npm run build
# then chrome://extensions -> Load unpacked -> dist/