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
{
"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
- 01Service worker wakes
- 02Tracking state restored from chrome.storage
- 03Queue drained to the API
- 04Heartbeat sent
- 05Pending remote control command polled
Tab events
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
cd extension
npm run build
# then chrome://extensions -> Load unpacked -> dist/