From d6099f6f08fb1bb90367214487a92a9ff95df077 Mon Sep 17 00:00:00 2001 From: hensm Date: Sun, 8 Mar 2026 12:40:56 +0000 Subject: [PATCH] Convert extension to manifest v3 --- .vscode/launch.json | 17 ++ bridge/src/bridge/components/cast/remote.ts | 6 +- extension/bin/build.js | 13 +- extension/package-lock.json | 17 +- extension/package.json | 2 +- extension/src/background/action.ts | 6 +- extension/src/background/menus.ts | 259 ++++++++++---------- extension/src/background/whitelist.ts | 50 ++-- extension/src/cast/content.ts | 8 +- extension/src/cast/export.ts | 117 ++------- extension/src/cast/senders/media.ts | 5 +- extension/src/global.d.ts | 17 -- extension/src/lib/utils.ts | 20 -- extension/src/manifest.json | 20 +- extension/src/menuIds.ts | 51 ++-- extension/src/ui/options/Whitelist.svelte | 16 +- extension/src/ui/options/styles/index.css | 3 +- extension/src/ui/popup/Popup.svelte | 17 +- extension/src/ui/popup/Receiver.svelte | 59 +++-- 19 files changed, 343 insertions(+), 360 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..7e68ee9 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Bridge (daemon)", + "type": "node", + "request": "launch", + "program": "${workspaceFolder}/dist/bridge/src/main.js", + "args": ["--__name", "fx_cast_bridge", "--daemon"], + "env": { + "NODE_PATH": "${workspaceFolder}/bridge/node_modules" + }, + "cwd": "${workspaceFolder}/dist/bridge", + "console": "integratedTerminal" + } + ] +} diff --git a/bridge/src/bridge/components/cast/remote.ts b/bridge/src/bridge/components/cast/remote.ts index 37fbb21..60ad302 100644 --- a/bridge/src/bridge/components/cast/remote.ts +++ b/bridge/src/bridge/components/cast/remote.ts @@ -64,16 +64,20 @@ export default class Remote extends CastClient { if (!application || application.isIdleScreen) { // Handle app close if (this.transportClient) { + this.transportClient.disconnect(); this.transportClient = undefined; this.options?.onApplicationClose?.(); } + + this.options?.onReceiverStatusUpdate?.(message.status); + return; } // Update status before possible transport init this.options?.onReceiverStatusUpdate?.(message.status); // Handle app creation/discovery - if (application && !this.transportClient) { + if (!this.transportClient) { this.transportClient = new RemoteTransport( application.transportId, message => this.onMediaMessage(message) diff --git a/extension/bin/build.js b/extension/bin/build.js index 4e481ca..94752d0 100644 --- a/extension/bin/build.js +++ b/extension/bin/build.js @@ -55,7 +55,7 @@ const outPath = argv.package ? unpackedPath : distPath; /** @type esbuild.BuildOptions */ const buildOpts = { bundle: true, - target: "firefox64", + target: "firefox109", logLevel: "info", sourcemap: "inline", @@ -113,10 +113,13 @@ const buildOpts = { }) ); - manifest.content_security_policy = - argv.mode === "production" - ? "script-src 'self'; object-src 'self'" - : "script-src 'self' 'unsafe-eval'; object-src 'self'"; + // In development, allow eval for source maps + if (argv.mode !== "production") { + manifest.content_security_policy = { + extension_pages: + "script-src 'self' 'unsafe-eval'; object-src 'self'" + }; + } fs.writeFileSync( `${outPath}/manifest.json`, diff --git a/extension/package-lock.json b/extension/package-lock.json index 5d03c58..123d681 100644 --- a/extension/package-lock.json +++ b/extension/package-lock.json @@ -5,7 +5,7 @@ "packages": { "": { "devDependencies": { - "@types/firefox-webext-browser": "^94.0.1", + "@types/firefox-webext-browser": "^143.0.0", "@types/semver": "^7.3.9", "@types/uuid": "^8.3.4", "esbuild": "^0.25.0", @@ -881,10 +881,11 @@ "peer": true }, "node_modules/@types/firefox-webext-browser": { - "version": "94.0.1", - "resolved": "https://registry.npmjs.org/@types/firefox-webext-browser/-/firefox-webext-browser-94.0.1.tgz", - "integrity": "sha512-I6iHRQJSTZ+gYt2IxdH2RRAMvcUyK8v5Ig7fHQR0IwUNYP7hz9+cziBVIKxLCO6XI7fiyRsNOWObfl3/4Js2Lg==", - "dev": true + "version": "143.0.0", + "resolved": "https://registry.npmjs.org/@types/firefox-webext-browser/-/firefox-webext-browser-143.0.0.tgz", + "integrity": "sha512-865dYKMOP0CllFyHmgXV4IQgVL51OSQQCwSoihQ17EwugePKFSAZRc0EI+y7Ly4q7j5KyURlA7LgRpFieO4JOw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/http-cache-semantics": { "version": "4.0.1", @@ -7509,9 +7510,9 @@ "peer": true }, "@types/firefox-webext-browser": { - "version": "94.0.1", - "resolved": "https://registry.npmjs.org/@types/firefox-webext-browser/-/firefox-webext-browser-94.0.1.tgz", - "integrity": "sha512-I6iHRQJSTZ+gYt2IxdH2RRAMvcUyK8v5Ig7fHQR0IwUNYP7hz9+cziBVIKxLCO6XI7fiyRsNOWObfl3/4Js2Lg==", + "version": "143.0.0", + "resolved": "https://registry.npmjs.org/@types/firefox-webext-browser/-/firefox-webext-browser-143.0.0.tgz", + "integrity": "sha512-865dYKMOP0CllFyHmgXV4IQgVL51OSQQCwSoihQ17EwugePKFSAZRc0EI+y7Ly4q7j5KyURlA7LgRpFieO4JOw==", "dev": true }, "@types/http-cache-semantics": { diff --git a/extension/package.json b/extension/package.json index 687a645..24b27c9 100644 --- a/extension/package.json +++ b/extension/package.json @@ -8,7 +8,7 @@ "lint": "eslint src --ext .ts,.tsx" }, "devDependencies": { - "@types/firefox-webext-browser": "^94.0.1", + "@types/firefox-webext-browser": "^143.0.0", "@types/semver": "^7.3.9", "@types/uuid": "^8.3.4", "esbuild": "^0.25.0", diff --git a/extension/src/background/action.ts b/extension/src/background/action.ts index 3afc8b7..e5b3e6a 100644 --- a/extension/src/background/action.ts +++ b/extension/src/background/action.ts @@ -40,8 +40,8 @@ export function updateActionState(state: ActionState, tabId?: number) { break; } - browser.browserAction.setTitle({ tabId, title }); - browser.browserAction.setIcon({ tabId, path }); + browser.action.setTitle({ tabId, title }); + browser.action.setIcon({ tabId, path }); } export function initAction() { @@ -49,7 +49,7 @@ export function initAction() { updateActionState(ActionState.Default); - browser.browserAction.onClicked.addListener(async tab => { + browser.action.onClicked.addListener(async tab => { if (tab.id === undefined) { logger.error("Tab ID not found in browser action handler."); return; diff --git a/extension/src/background/menus.ts b/extension/src/background/menus.ts index 7ed3149..9977159 100644 --- a/extension/src/background/menus.ts +++ b/extension/src/background/menus.ts @@ -1,8 +1,8 @@ import logger from "../lib/logger"; import options from "../lib/options"; -import { stringify } from "../lib/utils"; import * as menuIds from "../menuIds"; +import { MenuId } from "../menuIds"; import castManager from "./castManager"; @@ -15,32 +15,30 @@ const URL_PATTERN_FILE = "file://*/*"; const URL_PATTERNS_REMOTE = [URL_PATTERN_HTTP, URL_PATTERN_HTTPS]; const URL_PATTERNS_ALL = [...URL_PATTERNS_REMOTE, URL_PATTERN_FILE]; -type MenuId = string | number; - -let menuIdCast: MenuId; -let menuIdCastMedia: MenuId; -let menuIdWhitelist: MenuId; -let menuIdWhitelistRecommended: MenuId; - /** Match patterns for the whitelist option menus. */ -const whitelistChildMenuPatterns = new Map(); +const whitelistChildMenuPatterns = new Map(); /** Handles initial menu setup. */ export async function initMenus() { logger.info("init (menus)"); + // Clear any existing menus from a previous event page load + await browser.menus.removeAll(); + const opts = await options.getAll(); // Global "Cast..." menu item - menuIdCast = browser.menus.create({ - contexts: ["browser_action", "page", "tools_menu"], + browser.menus.create({ + id: MenuId.Cast, + contexts: ["action", "page", "tools_menu"], title: _("contextCast"), documentUrlPatterns: ["http://*/*", "https://*/*"], - icons: { "16": "icons/icon.svg" } // browser_action context + icons: { "16": "icons/icon.svg" } }); //