Skip to content

Case study · 2026

ResistGate: blocking across service worker restarts

I built a local Chrome extension with typing challenges, timed access, schedules, and stronger locks. The engineering problem is keeping those rules consistent when the service worker restarts.

Access must expire on a stored deadline, even when the countdown page closes or the service worker restarts.

JavaScriptChrome Manifest V3declarativeNetRequestchrome.storage.localVitest
ResistGate: blocking across service worker restarts screenshot

My role and the product boundary

I built the extension's service worker, popup, settings, and challenge pages. ResistGate is published as a free, open-source Chrome extension. Its job is to interrupt an automatic visit to a distracting site, then offer a deliberate way to earn temporary access.

The extension keeps settings, access windows, and activity on the device. A server is not required to decide whether a site should open.

The decision: persist deadlines, then reconcile rules

A Manifest V3 service worker does not stay alive continuously. A JavaScript timer in a page or worker cannot be the authority for a temporary access window.

I store an expiry timestamp for each temporary grant in chrome.storage.local. The worker uses Chrome alarms to revisit those deadlines and declarativeNetRequest session rules to redirect blocked domains.

On initialization, the worker normalizes stored settings and access records, then queues a rule update. The update removes expired access and synchronizes managed alarms with the current state, so a restart does not depend on a timer from the previous run.

The boundary is:

Saved settings and deadlines
  → remove expired access
  → reconcile Chrome alarms
  → update redirect rules

When storage changes, the worker queues the same rule update. The worker owns that process; the popup and challenge pages request actions rather than maintaining separate copies of the blocking policy.

The tradeoff: local control has limits

Local storage avoids sending a person's blocklist or browsing habits to a backend. The extension cannot stop its owner from disabling or uninstalling it.

Strict Mode and Commitment Mode add friction within that boundary. They should not be described as an operating-system-level guarantee.

Verification in the repository

The Vitest suite loads extension scripts into isolated VM contexts with mocked Chrome APIs. It includes background integration, challenge-flow, setup, and UI-logic tests. The source exposes test hooks for state and policy functions.

Those tests check expiry and rule behavior without waiting out a real access window. Mocked APIs still need a browser check. Installing the extension, blocking a site, earning access, and watching it block again exercises Chrome's real lifecycle.

What this project demonstrates

The visible interaction is a typing challenge. The work is keeping stored deadlines, alarms, and redirect rules consistent after the worker stops.

I would carry that into other event-driven systems by storing the deadline, letting the worker own the policy, and rebuilding the alarms and redirects from that state when the worker starts again.