feat(desktop): storage.sync, onInstalled and lasting context menus for browser extensions

Merged
KI
6d ago
+1878-101

Stacked on #9329. Makes Vimium and Google Translate work, and reconciles that with the file check.

Why

  • Vimium is broken: Electron 44's chrome.storage.sync exists, but every call fails. The extension package hid that by aliasing sync to local, so keys collided, and content scripts still got the error.
  • Google Translate has no right-click item: runtime.onInstalled never fires in Electron, and Translate creates the item only there. Context menus also lived in memory only.

Changes

  • storage.sync: it is its own area, stored in storage.local under a prefix so the two can't collide. It covers every get form, quotas, both callback and promise forms, onChanged with area "sync", and a read-only managed.
    • Content scripts and in-iframe extension pages get no preload, so the shim is written into the extension folder as superset-storage-shim.js and added first to the manifest's content scripts and to each page.
    • The file check accepts exactly that change: the shim file must match the app's copy byte for byte, and a shim tag anywhere else, or any other edit, still counts as tampering.
  • chrome.extension.inIncognitoContext is false where missing. Vimium's find mode needs it.
  • runtime.onInstalled: the app fires it with reason install, update or chrome_update. The worker confirms once its listeners ran, and only then is the version recorded, so a worker that stops early gets the event again.
  • Context menus are saved per extension and version, restored on load, and dropped on update or remove. contextMenus.update now works.
  • Removing a turned-off extension also clears its DNR rules and saved state.
  • Patch notes in patches/README.md now cover this patch's native messaging change.

Testing

  • Unit:
    • the storage areas stay apart
    • shim placement
    • the file check across install → shim → restart → tamper
    • onInstalled re-delivery after a worker stops early
    • menus restored per version
  • Dev app:
    • Vimium shows link hints on f
    • all 8 extensions load across restarts with the shim in place, and none are turned off
    • Google Translate's item was created and saved after the recovery below

Recovery for profiles from intermediate builds

If a Translate install shows no menu item, set installed.<id> to null in browser-extension-state.json with the app closed.

Known gaps

  • Vimium settings saved under the old sync→local alias look unset.
  • In-iframe extension pages still lack the package's other APIs.

Summary by cubic

Makes Vimium and Google Translate work in the browser pane: chrome.storage.sync no longer fails, runtime.onInstalled fires, and right-click menu items survive restarts.

  • chrome.storage.sync is its own area, stored in storage.local under a prefix so the two can't collide; it covers Chrome's quota, callback and promise forms, and onChanged with area "sync". managed is a read-only empty area.
  • Content scripts and extension pages in website iframes get no preload, so the shim is written into the extension folder as superset-storage-shim.js, first in each content script and page. The shim also gives content scripts chrome.extension.inIncognitoContext false, which Vimium's find mode reads.
  • The file check accepts exactly these changes: the shim must match the app's copy byte for byte, and any other edit still turns the extension off.
  • The app fires runtime.onInstalled with reason install, update, or chrome_update. The worker asks for the event, runs a snapshot of its listeners, and confirms only once they ran, so a failed ask, listeners that left early, or a worker that stopped gets the event again. Unreadable state is never overwritten, and corrupt state is moved aside.
  • Context menus are saved per extension and version, restored on load, and dropped on update or remove. contextMenus.update works instead of being a no-op.
  • Removing a turned-off extension clears its DNR rules and saved state even when clearing its data fails.
  • The package's runtime.connectNative and runtime.sendNativeMessage are dropped; the app's native messaging path is the only one left.

Recovery

  • For profiles from intermediate builds: if Google Translate has no menu item, set installed.<id> to null in browser-extension-state.json with the app closed.

Known gaps

  • Vimium settings saved under the old sync→local alias look unset.
  • Extension pages in website iframes still lack the package's other APIs.

Summary by CodeRabbit

  • New Features
    • Improved browser-extension compatibility for local, sync, and managed storage areas.
    • Extension install and update events now report the appropriate lifecycle details. Context-menu items can be restored after a restart when the extension version is unchanged.
  • Bug Fixes
    • Extension removal now completes cleanup and updates the app even when storage or rule cleanup fails.
    • Browser-extension APIs enforce permissions more consistently, including access to tab and cookie information.
  • Changes
    • Native-messaging APIs are no longer available to extensions.