Skip to content

v1.3.4

Choose a tag to compare

@ml3dev ml3dev released this 16 May 03:37

Small quality update from a full audit pass: bug fixes, polish, accessibility, and one minor code-quality cleanup. No new permissions, no new strings, no schema changes.

Fixed

  • Startup suspend pass could be skipped when the service worker died before the 5s timer fired. onStartup scheduled suspendAllOnStartup via setTimeout(..., 5000). Once onStartup's awaits resolve, the service worker has no pending events keeping it alive; Chrome can terminate it after ~30s of idle, and a setTimeout doesn't count as keepalive. On a cold browser launch where the worker has no other work, the 5s deadline was usually hit, but not guaranteed. Replaced with chrome.alarms.create('startup-suspend', { delayInMinutes: 0.1 }) which Chrome clamps to ~30s in production and survives a worker restart. The onAlarm handler now dispatches the startup-suspend alarm to suspendAllOnStartup (after re-fetching settings, in case the user toggled "Suspend on startup" off between the schedule and the fire).
  • handleSuspendCurrent fell back to candidates[length - 1] when no next tab existed, which could land far from the active tab (the last candidate in the filtered list, not necessarily the previous tab). Now it explicitly looks for the closest previous tab (largest index below activeTab.index), then falls back to any candidate only if both next and previous are absent. Triggered when you suspend the active tab via Alt+S / context menu while it's the rightmost tab in a window.

Changed

  • MB_PER_TAB is now defined once per file rather than scattered as a magic 150 in three places in popup.js. The constant must stay in sync with background.js's MB_PER_TAB; comment in popup.js calls this out. No user-visible change; defensive cleanup so a future tuning is a one-line edit.

Polish

  • prefers-reduced-motion honored on the onboarding page. The popup, side panel, changelog, and privacy-policy pages all already had the media query that flattens animations and transitions to 1ms; onboarding.html was the only page that didn't, so a user with reduced-motion enabled would still see the 0.4s fade-up of the welcome container. Added the same * { animation-duration: 1ms !important; ... } block to onboarding.html's inline style.
  • Whitelist input HTML placeholder synced with the i18n value. The 1.3.3 release updated en/messages.json#whitelistPlaceholder to "example.com, full URL, or site.com/path/*" but the static placeholder= attribute in popup.html and sidepanel.html was still "example.com or site.com/path/*". Localization overwrites it at popup-open, so users normally see the new wording, but a failed i18n pass (extension reload race, unusual locale) would leave the old text visible. HTML defaults now match en exactly.

Audit

  • Full read-through of all source files. background.js, popup.js/html/css, sidepanel.html, formcheck.js, icons.js, onboarding.html/js, changelog.html/js, privacy-policy.html/js. No additional bugs found beyond the two fixed above; the 1.3.2 / 1.3.3 polish work held up.
  • All 57 locale files validated for JSON validity, key parity against en (175 keys, no missing/extra in any locale), and placeholder structure (every $COUNT$ / $RAM$ / $VERSION$ / $DATE$ substitution token present in en is also present in the corresponding translated value). No locale repairs needed.
  • i18n key reference scan confirms every data-i18n* attribute and chrome.i18n.getMessage / t(...) call resolves to a real key, and every key in en/messages.json is reachable from source (including the dynamic ones referenced via variable interpolation: t(statusKey) for the current-tab status and BADGES[reason].labelKey for the protect-reason badges).
  • Chrome MV3 best practices verified for the suspend pipeline: chrome.tabs.discard() remains the canonical API; tab.lastAccessed (Chrome 121+) is feature-detected with typeof === 'number' and gracefully falls back on 120; chrome.storage.session correctly used for the in-memory tabTimestamps cache that survives worker restarts via re-seeding from tab.lastAccessed; chrome.alarms minimum delay (0.5 min in production) respected. The known quirk that tab.lastAccessed becomes undefined for discarded tabs is handled correctly: every code path that reads it either guards with the typeof check or has already early-returned on tab.discarded.

Verifying this build

This release attaches the exact .zip uploaded to the Chrome Web Store. To verify it hasn't been tampered with:

sha256: ad5e3179f250108483b27ba5781c79bbbaa506d3726e3601ecb75842be0f677f

You can reproduce the build yourself by checking out v1.3.4 and zipping the extension files (everything except .git/, .github/, *.md, docs/).