mv3-keepalive
v1.0.0
Published
Chrome extension service worker keepalive for Manifest V3 (MV3) — keep MV3 service workers alive during async work and schedule durable chrome.alarms. Zero dependencies, fully typed.
Maintainers
Readme
mv3-keepalive
Chrome extension service worker keepalive for Manifest V3 (MV3) — keep service workers alive during async work, and schedule durable
chrome.alarmsthat survive SW termination. Zero dependencies, fully typed.
Two tiny utilities for Chrome / Edge / Firefox MV3 extensions:
startKeepAlive/withKeepAlive— prevent the SW from being killed mid-task.scheduleAlarm— recurring jobs that survive SW termination.
Zero runtime dependencies. ESM + CJS. Fully typed.
Why
MV3 service workers get killed by Chrome after ~30s of inactivity. setInterval
and setTimeout die with them. chrome.alarms survives but has a 0.5-minute
floor and an awkward listener API. This package wraps both patterns behind
small, ergonomic functions.
Install
pnpm add mv3-keepalive
# or: npm i mv3-keepalive
# or: yarn add mv3-keepaliveUsage
Keep the SW alive during async work
import { withKeepAlive } from "mv3-keepalive";
chrome.runtime.onMessage.addListener((msg, _sender, sendResponse) => {
withKeepAlive(async () => {
const result = await someLongRunningFetch();
sendResponse(result);
});
return true; // async response
});Or manage the loop manually:
import { startKeepAlive } from "mv3-keepalive";
const alive = startKeepAlive({ intervalSeconds: 20 });
try {
await doWork();
} finally {
alive.stop();
}Schedule durable recurring work
import { scheduleAlarm } from "mv3-keepalive";
scheduleAlarm({
name: "sync-inbox",
periodMinutes: 5,
handler: async () => {
await pullNewMessages();
},
});Cancel it later:
import { cancelAlarm } from "mv3-keepalive";
await cancelAlarm("sync-inbox");Re-calling scheduleAlarm with the same name replaces the previous alarm.
API
startKeepAlive(options?) → { stop }
| Option | Type | Default | Notes |
| --- | --- | --- | --- |
| intervalSeconds | number | 20 | Must be < 30. |
| name | string | — | Optional label for debugging. |
withKeepAlive(work, options?) → Promise<T>
Runs work() with a keepalive loop. Stops the loop on settle (success or
rejection). Re-throws.
scheduleAlarm(options) → { name, cancel }
| Option | Type | Notes |
| --- | --- | --- |
| name | string | Unique. Reusing replaces. |
| periodMinutes | number | >= 0.5 in release builds. |
| delayMinutes | number? | First fire delay. Default 0. |
| handler | () => void \| Promise<void> | Errors are swallowed — wrap your own try/catch if needed. |
cancelAlarm(name) → Promise<boolean>
Resolves to whether an alarm was cleared.
Caveats
- Hard ceiling. Chrome 110+ enforces a ~5-minute maximum SW lifetime even
with active ports. Don't use
startKeepAliveto keep the SW running indefinitely — usescheduleAlarmfor that. - No port-based variant. Some keepalive guides recommend opening a
chrome.runtime.connect()port. That requires content scripts and broader permissions. This package keeps things permission-free by calling a cheapchrome.runtime.*API on a timer.
Permissions
startKeepAlive/withKeepAlive: none.scheduleAlarm/cancelAlarm:"alarms"in your manifest.
Demo extension
A runnable demo lives in example/. It loads as an unpacked
Chrome extension and exercises both withKeepAlive (a 35-second background
task) and scheduleAlarm (a counter that ticks every 30 seconds and
survives service-worker termination).
cd example
pnpm install
pnpm build
# then load example/dist/ via chrome://extensions → "Load unpacked"See example/README.md for full instructions.
Related packages
Part of a small MV3 toolkit for Chrome / Edge / Firefox extensions by @graybearo:
mv3-message-router— type-safechrome.runtimemessage passingmv3-content-bridge— content-script ↔ page-context typed bridgemv3-storage— typedchrome.storagewrappermv3-wait-for-element— MutationObserver-backedwaitForElementfor content scriptschrome-extension-vite-react— MV3 starter (Vite + React + TS) that uses this packagechrome-extension-vite-svelte— MV3 starter (Vite + Svelte + TS)chrome-extension-webpack-react— MV3 starter (webpack + React + TS)chrome-extension-side-panel— Side Panel API starter (Chrome 114+)webpack-ext-reloader-next— auto-reload for webpack-based MV3 extensionsawesome-mv3— curated list of MV3 tools, libraries, and resources
License
MIT — see LICENSE.
