feat: implement M3 multi-browser support (Firefox, Edge, Safari)
Add browser abstraction layer (compat.ts) that normalizes Chrome/Firefox/ Edge/Safari extension APIs behind a unified promise-based interface. Replace all direct chrome.* calls with compat layer across service worker, sync engine, badge, storage, popup, and options modules. - Browser-specific manifests in manifests/ (Firefox MV3 with gecko settings, Edge/Safari variants) - Multi-target build system: `npm run build` produces all four browser builds in build/<browser>/ - Per-browser build scripts: build:chrome, build:firefox, build:edge, build:safari - Auto-detects browser at runtime for platform-specific device registration - All 38 existing tests pass, typecheck clean Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -1,6 +1,9 @@
|
||||
/**
|
||||
* Popup script — controls the popup UI interactions.
|
||||
* Uses the browser-agnostic compat layer.
|
||||
*/
|
||||
import { runtime, tabs } from "../lib/compat";
|
||||
|
||||
export {};
|
||||
|
||||
// --- Elements ---
|
||||
@@ -40,20 +43,12 @@ const btnPairingCancel = document.getElementById("btn-pairing-cancel") as HTMLBu
|
||||
|
||||
// --- Messaging helper ---
|
||||
|
||||
function sendMessage(type: string, payload?: unknown): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.runtime.sendMessage({ type, payload }, (response) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
reject(new Error(chrome.runtime.lastError.message));
|
||||
return;
|
||||
}
|
||||
if (response?.error) {
|
||||
reject(new Error(response.error));
|
||||
return;
|
||||
}
|
||||
resolve(response);
|
||||
});
|
||||
});
|
||||
async function sendMessage(type: string, payload?: unknown): Promise<any> {
|
||||
const response = await runtime.sendMessage({ type, payload });
|
||||
if (response?.error) {
|
||||
throw new Error(response.error);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
// --- UI Updates ---
|
||||
@@ -142,7 +137,7 @@ btnSyncTab.addEventListener("click", async () => {
|
||||
});
|
||||
|
||||
btnAddWhitelist.addEventListener("click", async () => {
|
||||
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||
const [tab] = await tabs.query({ active: true, currentWindow: true });
|
||||
if (!tab?.url) return;
|
||||
|
||||
try {
|
||||
@@ -198,7 +193,7 @@ btnPairingCancel.addEventListener("click", () => {
|
||||
|
||||
btnSettings.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
chrome.runtime.openOptionsPage();
|
||||
runtime.openOptionsPage();
|
||||
});
|
||||
|
||||
// --- Init ---
|
||||
|
||||
Reference in New Issue
Block a user