From 2396bb5353626b53a38ebe636fed4307fce28226 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 9 Dec 2025 12:15:07 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=E4=BB=A5=E7=B1=BB=E4=BC=BCbroadcast?= =?UTF-8?q?=E6=9C=BA=E5=88=B6=E9=87=8D=E6=9E=84=E9=80=9A=E8=AE=AF=E6=9C=BA?= =?UTF-8?q?=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/message/custom_event_message.ts | 122 ++++++++++------- packages/message/server.test.ts | 14 +- rspack.config.ts | 1 + src/app/service/content/content.ts | 28 ++-- src/app/service/content/utils.ts | 3 +- src/app/service/service_worker/runtime.ts | 66 +++++----- src/app/service/service_worker/value.ts | 53 ++++---- src/content.ts | 151 ++++++++++++++++------ src/inject.ts | 42 +++++- src/scripting.ts | 67 ++++++++++ 10 files changed, 385 insertions(+), 162 deletions(-) create mode 100644 src/scripting.ts diff --git a/packages/message/custom_event_message.ts b/packages/message/custom_event_message.ts index b3e8cf952..dc27d4fcf 100644 --- a/packages/message/custom_event_message.ts +++ b/packages/message/custom_event_message.ts @@ -1,13 +1,22 @@ import type { Message, MessageConnect, RuntimeMessageSender, TMessage } from "./types"; import { v4 as uuidv4 } from "uuid"; import { type PostMessage, type WindowMessageBody, WindowMessageConnect } from "./window_message"; -import LoggerCore from "@App/app/logger/core"; import EventEmitter from "eventemitter3"; import { DefinedFlags } from "@App/app/service/service_worker/runtime.consts"; // 避免页面载入后改动 EventTarget.prototype 的方法导致消息传递失败 -const pageDispatchEvent = performance.dispatchEvent.bind(performance); -const pageAddEventListener = performance.addEventListener.bind(performance); +export const pageDispatchEvent = performance.dispatchEvent.bind(performance); +export const pageAddEventListener = performance.addEventListener.bind(performance); +export const pageRemoveEventListener = performance.removeEventListener.bind(performance); +const detailClone = typeof cloneInto === "function" ? cloneInto : null; +export const pageDispatchCustomEvent = (eventType: string, detail: any) => { + if (detailClone && detail) detail = detailClone(detail, document.defaultView); + const ev = new CustomEventClone(eventType, { + detail, + cancelable: true, + }); + return pageDispatchEvent(ev); +}; // 避免页面载入后改动全域物件导致消息传递失败 const MouseEventClone = MouseEvent; @@ -30,28 +39,59 @@ export class CustomEventPostMessage implements PostMessage { } } +export type PageMessaging = { + et: string; + bindEmitter?: () => void; + waitReady?: Promise; + waitReadyResolve?: () => any; + onReady?: (callback: () => any) => any; +}; + +export const createPageMessaging = (et: string) => { + const pageMessaging = { et } as PageMessaging; + pageMessaging.waitReady = new Promise((resolve) => { + pageMessaging.waitReadyResolve = resolve; + }); + pageMessaging.onReady = (callback: () => any) => { + if (pageMessaging.et) { + callback(); + } else { + pageMessaging.waitReady!.then(callback); + } + }; + return pageMessaging; +}; + // 使用CustomEvent来进行通讯, 可以在content与inject中传递一些dom对象 export class CustomEventMessage implements Message { EE = new EventEmitter(); readonly receiveFlag: string; readonly sendFlag: string; + readonly pageMessagingHandler: (event: Event) => any; // 关联dom目标 relatedTarget: Map = new Map(); constructor( - messageFlag: string, + private pageMessaging: PageMessaging, protected readonly isContent: boolean ) { - this.receiveFlag = `evt${messageFlag}${isContent ? DefinedFlags.contentFlag : DefinedFlags.injectFlag}${DefinedFlags.domEvent}`; - this.sendFlag = `evt${messageFlag}${isContent ? DefinedFlags.injectFlag : DefinedFlags.contentFlag}${DefinedFlags.domEvent}`; - pageAddEventListener(this.receiveFlag, (event) => { + this.receiveFlag = `${isContent ? DefinedFlags.contentFlag : DefinedFlags.injectFlag}${DefinedFlags.domEvent}`; + this.sendFlag = `${isContent ? DefinedFlags.injectFlag : DefinedFlags.contentFlag}${DefinedFlags.domEvent}`; + this.pageMessagingHandler = (event: Event) => { if (event instanceof MouseEventClone && event.movementX && event.relatedTarget) { - relatedTargetMap.set(event.movementX, event.relatedTarget!); + relatedTargetMap.set(event.movementX, event.relatedTarget); } else if (event instanceof CustomEventClone) { this.messageHandle(event.detail, new CustomEventPostMessage(this)); } - }); + }; + } + + bindEmitter() { + if (!this.pageMessaging.et) throw new Error("bindEmitter() failed"); + const receiveFlag = `evt_${this.pageMessaging.et}_${this.receiveFlag}`; + pageRemoveEventListener(receiveFlag, this.pageMessagingHandler); // 避免重覆 + pageAddEventListener(receiveFlag, this.pageMessagingHandler); } messageHandle(data: WindowMessageBody, target: PostMessage) { @@ -95,49 +135,41 @@ export class CustomEventMessage implements Message { connect(data: TMessage): Promise { return new Promise((resolve) => { - const body: WindowMessageBody = { - messageId: uuidv4(), - type: "connect", - data, - }; - this.nativeSend(body); - // EventEmitter3 采用同步事件设计,callback会被马上执行而不像传统javascript架构以下一个macrotask 执行 - resolve(new WindowMessageConnect(body.messageId, this.EE, new CustomEventPostMessage(this))); + this.pageMessaging.onReady!(() => { + const body: WindowMessageBody = { + messageId: uuidv4(), + type: "connect", + data, + }; + this.nativeSend(body); + // EventEmitter3 采用同步事件设计,callback会被马上执行而不像传统javascript架构以下一个macrotask 执行 + resolve(new WindowMessageConnect(body.messageId, this.EE, new CustomEventPostMessage(this))); + }); }); } nativeSend(detail: any) { - if (typeof cloneInto !== "undefined") { - try { - LoggerCore.logger().info("nativeSend"); - detail = cloneInto(detail, document.defaultView); - } catch (e) { - console.log(e); - LoggerCore.logger().info("error data"); - } - } - - const ev = new CustomEventClone(this.sendFlag, { - detail, - }); - pageDispatchEvent(ev); + if (!this.pageMessaging.et) throw new Error("inject.js is not ready or destroyed."); + pageDispatchCustomEvent(`evt_${this.pageMessaging.et}_${this.sendFlag}`, detail); } sendMessage(data: TMessage): Promise { return new Promise((resolve: ((value: T) => void) | null) => { - const messageId = uuidv4(); - const body: WindowMessageBody = { - messageId, - type: "sendMessage", - data, - }; - const eventId = `response:${messageId}`; - this.EE.addListener(eventId, (body: WindowMessageBody) => { - this.EE.removeAllListeners(eventId); - resolve!(body.data as T); - resolve = null; // 设为 null 提醒JS引擎可以GC + this.pageMessaging.onReady!(() => { + const messageId = uuidv4(); + const body: WindowMessageBody = { + messageId, + type: "sendMessage", + data, + }; + const eventId = `response:${messageId}`; + this.EE.addListener(eventId, (body: WindowMessageBody) => { + this.EE.removeAllListeners(eventId); + resolve!(body.data as T); + resolve = null; // 设为 null 提醒JS引擎可以GC + }); + this.nativeSend(body); }); - this.nativeSend(body); }); } @@ -145,6 +177,7 @@ export class CustomEventMessage implements Message { // 与content页的消息通讯实际是同步,此方法不需要经过background // 但是请注意中间不要有promise syncSendMessage(data: TMessage): TMessage { + if (!this.pageMessaging.et) throw new Error("inject.js is not ready or destroyed."); const messageId = uuidv4(); const body: WindowMessageBody = { messageId, @@ -164,11 +197,12 @@ export class CustomEventMessage implements Message { } sendRelatedTarget(target: EventTarget): number { + if (!this.pageMessaging.et) throw new Error("inject.js is not ready or destroyed."); // 特殊处理relatedTarget,返回id进行关联 // 先将relatedTarget转换成id发送过去 const id = (relateId = relateId === maxInteger ? 1 : relateId + 1); // 可以使用此种方式交互element - const ev = new MouseEventClone(this.sendFlag, { + const ev = new MouseEventClone(`evt_${this.pageMessaging.et}_${this.sendFlag}`, { movementX: id, relatedTarget: target, }); diff --git a/packages/message/server.test.ts b/packages/message/server.test.ts index 5347ed823..6fa3e6fa2 100644 --- a/packages/message/server.test.ts +++ b/packages/message/server.test.ts @@ -1,8 +1,9 @@ import { describe, expect, it, beforeEach, vi, afterEach } from "vitest"; import { GetSenderType, SenderConnect, SenderRuntime, Server, type IGetSender } from "./server"; -import { CustomEventMessage } from "./custom_event_message"; +import { createPageMessaging, CustomEventMessage } from "./custom_event_message"; import type { MessageConnect, RuntimeMessageSender } from "./types"; import { DefinedFlags } from "@App/app/service/service_worker/runtime.consts"; +import { uuidv4 } from "@App/pkg/utils/uuid"; let contentMessage: CustomEventMessage; let injectMessage: CustomEventMessage; @@ -12,10 +13,13 @@ let client: CustomEventMessage; const nextTick = () => Promise.resolve().then(() => {}); const setupGlobal = () => { - const flags = "-test.server"; + const testFlag = uuidv4(); + const testPageMessaging = createPageMessaging(testFlag); // 创建 content 和 inject 之间的消息通道 - contentMessage = new CustomEventMessage(flags, true); // content 端 - injectMessage = new CustomEventMessage(flags, false); // inject 端 + contentMessage = new CustomEventMessage(testPageMessaging, true); // content 端 + injectMessage = new CustomEventMessage(testPageMessaging, false); // inject 端 + contentMessage.bindEmitter(); + injectMessage.bindEmitter(); // 服务端使用 content 消息 server = new Server("api", contentMessage); @@ -33,7 +37,7 @@ const setupGlobal = () => { vi.fn().mockImplementation((event: Event) => { if (event instanceof CustomEvent) { const eventType = event.type; - if (eventType.includes("-test.server")) { + if (eventType.includes(testFlag)) { let targetEventType: string; let messageThis: CustomEventMessage; let messageThat: CustomEventMessage; diff --git a/rspack.config.ts b/rspack.config.ts index f0fe226a7..c7bdd6fe2 100644 --- a/rspack.config.ts +++ b/rspack.config.ts @@ -34,6 +34,7 @@ export default defineConfig({ offscreen: `${src}/offscreen.ts`, sandbox: `${src}/sandbox.ts`, content: `${src}/content.ts`, + scripting: `${src}/scripting.ts`, inject: `${src}/inject.ts`, popup: `${src}/pages/popup/main.tsx`, install: `${src}/pages/install/main.tsx`, diff --git a/src/app/service/content/content.ts b/src/app/service/content/content.ts index ec39006c4..59ed5f04e 100644 --- a/src/app/service/content/content.ts +++ b/src/app/service/content/content.ts @@ -1,4 +1,4 @@ -import { Client, sendMessage } from "@Packages/message/client"; +import { Client } from "@Packages/message/client"; import { type CustomEventMessage } from "@Packages/message/custom_event_message"; import { forwardMessage, type Server } from "@Packages/message/server"; import type { MessageSend } from "@Packages/message/types"; @@ -16,7 +16,7 @@ export default class ContentRuntime { constructor( // 监听来自service_worker的消息 - private readonly extServer: Server, + private readonly extServer: null, // 监听来自inject的消息 private readonly server: Server, // 发送给扩展service_worker的通信接口 @@ -29,16 +29,16 @@ export default class ContentRuntime { ) {} init() { - this.extServer.on("runtime/emitEvent", (data) => { - // 转发给inject和scriptExecutor - this.scriptExecutor.emitEvent(data); - return sendMessage(this.senderToInject, "inject/runtime/emitEvent", data); - }); - this.extServer.on("runtime/valueUpdate", (data) => { - // 转发给inject和scriptExecutor - this.scriptExecutor.valueUpdate(data); - return sendMessage(this.senderToInject, "inject/runtime/valueUpdate", data); - }); + // this.extServer.on("runtime/emitEvent", (data) => { + // // 转发给inject和scriptExecutor + // this.scriptExecutor.emitEvent(data); + // return sendMessage(this.senderToInject, "inject/runtime/emitEvent", data); + // }); + // this.extServer.on("runtime/valueUpdate", (data) => { + // // 转发给inject和scriptExecutor + // this.scriptExecutor.valueUpdate(data); + // return sendMessage(this.senderToInject, "inject/runtime/valueUpdate", data); + // }); this.server.on("logger", (data: Logger) => { LoggerCore.logger().log(data.level, data.message, data.label); }); @@ -127,8 +127,8 @@ export default class ContentRuntime { ); } - pageLoad(messageFlag: string, envInfo: GMInfoEnv) { - this.scriptExecutor.checkEarlyStartScript("content", messageFlag, envInfo); + pageLoad(envInfo: GMInfoEnv) { + this.scriptExecutor.checkEarlyStartScript("content", MessageFlag, envInfo); const client = new RuntimeClient(this.senderToExt); // 向service_worker请求脚本列表及环境信息 client.pageLoad().then((o) => { diff --git a/src/app/service/content/utils.ts b/src/app/service/content/utils.ts index 0c2c1c5c4..54a2e8bed 100644 --- a/src/app/service/content/utils.ts +++ b/src/app/service/content/utils.ts @@ -151,7 +151,8 @@ export function compilePreInjectScript( return `window['${flag}'] = function(){${autoDeleteMountCode}${scriptCode}}; { let o = { cancelable: true, detail: { scriptFlag: '${flag}', scriptInfo: (${scriptInfoJSON}) } }, - f = () => performance.dispatchEvent(new CustomEvent('${evScriptLoad}', o)), + c = typeof cloneInto === "function" ? cloneInto(o, document.defaultView) : o, + f = () => performance.dispatchEvent(new CustomEvent('${evScriptLoad}', c)), needWait = f(); if (needWait) performance.addEventListener('${evEnvLoad}', f, { once: true }); } diff --git a/src/app/service/service_worker/runtime.ts b/src/app/service/service_worker/runtime.ts index c8c2e60f7..46cf18a2d 100644 --- a/src/app/service/service_worker/runtime.ts +++ b/src/app/service/service_worker/runtime.ts @@ -18,11 +18,9 @@ import { } from "./utils"; import { checkUserScriptsAvailable, - randomMessageFlag, getMetadataStr, getUserConfigStr, obtainBlackList, - isFirefox, sourceMapTo, } from "@App/pkg/utils/utils"; import { cacheInstance } from "@App/app/cache"; @@ -52,10 +50,11 @@ import type { CompiledResource, ResourceType } from "@App/app/repo/resource"; import { CompiledResourceDAO } from "@App/app/repo/resource"; import { setOnTabURLChanged } from "./url_monitor"; import { scriptToMenu, type TPopupPageLoadInfo } from "./popup_scriptmenu"; +import { uuidv4 } from "@App/pkg/utils/uuid"; // 避免使用版本号控制导致代码理解混乱 // 用来清除 UserScript API 里的旧缓存 -const USERSCRIPTS_REGISTER_CONTROL = "92292a62-4e81-4dc3-87d0-cb0f0cb9883d"; +const USERSCRIPTS_REGISTER_CONTROL = "92292a62-5e81-3dc3-87d0-cb0f0cb9883e"; const ORIGINAL_URLMATCH_SUFFIX = "{ORIGINAL}"; // 用于标记原始URLPatterns的后缀 @@ -137,7 +136,9 @@ export class RuntimeService { .get("scriptInjectMessageFlag") .then((res) => { runtimeGlobal.messageFlag = res?.value || this.generateMessageFlag(); - return this.localStorageDAO.save({ key: "scriptInjectMessageFlag", value: runtimeGlobal.messageFlag }); + if (runtimeGlobal.messageFlag !== res?.value) { + return this.localStorageDAO.save({ key: "scriptInjectMessageFlag", value: runtimeGlobal.messageFlag }); + } }) .catch(console.error); this.logger = LoggerCore.logger({ component: "runtime" }); @@ -666,13 +667,15 @@ export class RuntimeService { chrome.userScripts?.unregister(), chrome.scripting.unregisterContentScripts(), this.localStorageDAO.save({ key: "scriptInjectMessageFlag", value: runtimeGlobal.messageFlag }), + chrome.storage.session.set({ unregisterUserscriptsFlag: `${Date.now()}.${Math.random()}` }), ]); } } // 生成messageFlag generateMessageFlag(): string { - return randomMessageFlag(); + // return randomMessageFlag(); + return uuidv4(); } getMessageFlag() { @@ -846,34 +849,31 @@ export class RuntimeService { } // Note: Chrome does not support file.js?query // 注意:Chrome 不支持 file.js?query - if (isFirefox()) { - // 使用 URLSearchParams 避免字符编码问题 - retContent = [ - { - id: "scriptcat-content", - js: [`/src/content.js?${new URLSearchParams({ usp_flag: messageFlag })}&usp_end`], - matches: [""], - allFrames: true, - runAt: "document_start", - excludeMatches, - } satisfies chrome.scripting.RegisteredContentScript, - ]; - } else { - const contentJs = await this.getContentJsCode(); - if (contentJs) { - const codeBody = `(function (MessageFlag) {\n${contentJs}\n})('${messageFlag}')`; - const code = `${codeBody}${sourceMapTo("scriptcat-content.js")}\n`; - retInject.push({ - id: "scriptcat-content", - js: [{ code }], - matches: [""], - allFrames: true, - runAt: "document_start", - world: "USER_SCRIPT", - excludeMatches, - excludeGlobs, - } satisfies chrome.userScripts.RegisteredUserScript); - } + retContent = [ + { + id: "scriptcat-content", + js: ["/src/scripting.js"], + matches: [""], + allFrames: true, + runAt: "document_start", + excludeMatches, + } satisfies chrome.scripting.RegisteredContentScript, + ]; + + const contentJs = await this.getContentJsCode(); + if (contentJs) { + const codeBody = `(function (MessageFlag) {\n${contentJs}\n})('${messageFlag}')`; + const code = `${codeBody}${sourceMapTo("scriptcat-content.js")}\n`; + retInject.push({ + id: "scriptcat-content", + js: [{ code }], + matches: [""], + allFrames: true, + runAt: "document_start", + world: "USER_SCRIPT", + excludeMatches, + excludeGlobs, + } satisfies chrome.userScripts.RegisteredUserScript); } return { content: retContent, inject: retInject }; diff --git a/src/app/service/service_worker/value.ts b/src/app/service/service_worker/value.ts index 42f539294..be3403367 100644 --- a/src/app/service/service_worker/value.ts +++ b/src/app/service/service_worker/value.ts @@ -77,31 +77,36 @@ export class ValueService { // 推送值到tab async pushValueToTab(sendData: T) { - const { storageName } = sendData; - chrome.tabs.query({}, (tabs) => { - const lastError = chrome.runtime.lastError; - if (lastError) { - console.error("chrome.runtime.lastError in chrome.tabs.query:", lastError); - // 没有 tabs 资讯,无法发推送到 tabs - return; - } - // 推送到所有加载了本脚本的tab中 - for (const tab of tabs) { - const tabId = tab.id; - if (tab.discarded || !tabId) continue; - this.popup!.getScriptMenu(tabId).then((scriptMenu) => { - if (scriptMenu.find((item) => item.storageName === storageName)) { - this.runtime!.sendMessageToTab( - { - tabId, - }, - "valueUpdate", - sendData - ); - } - }); - } + // const { storageName } = sendData; + chrome.storage.local.set({ + valueUpdateDelivery: { + rId: `${Date.now()}.${Math.random()}`, + sendData, + }, }); + // chrome.tabs.query({}, (tabs) => { + // const lastError = chrome.runtime.lastError; + // if (lastError) { + // console.error("chrome.runtime.lastError in chrome.tabs.query:", lastError); + // // 没有 tabs 资讯,无法发推送到 tabs + // return; + // } + // // 推送到所有加载了本脚本的tab中 + // for (const tab of tabs) { + // const tabId = tab.id!; + // this.popup!.getScriptMenu(tabId).then((scriptMenu) => { + // if (scriptMenu.find((item) => item.storageName === storageName)) { + // this.runtime!.sendMessageToTab( + // { + // tabId, + // }, + // "valueUpdate", + // sendData + // ); + // } + // }); + // } + // }); // 推送到offscreen中 this.runtime!.sendMessageToTab( { diff --git a/src/content.ts b/src/content.ts index 2e4beb5c0..b5aaf86aa 100644 --- a/src/content.ts +++ b/src/content.ts @@ -1,51 +1,126 @@ import LoggerCore from "./app/logger/core"; import MessageWriter from "./app/logger/message_writer"; import { ExtensionMessage } from "@Packages/message/extension_message"; -import { CustomEventMessage } from "@Packages/message/custom_event_message"; +import { + CustomEventMessage, + createPageMessaging, + pageAddEventListener, + pageDispatchCustomEvent, +} from "@Packages/message/custom_event_message"; import { Server } from "@Packages/message/server"; import ContentRuntime from "./app/service/content/content"; import { initEnvInfo, ScriptExecutor } from "./app/service/content/script_executor"; -import { randomMessageFlag, getUspMessageFlag } from "./pkg/utils/utils"; import type { Message } from "@Packages/message/types"; +import { sendMessage } from "@Packages/message/client"; +import type { ValueUpdateDataEncoded } from "./app/service/content/types"; +import { uuidv4, uuidv5 } from "./pkg/utils/uuid"; -// @ts-ignore -const MessageFlag: string | null = (typeof arguments === "object" && arguments?.[0]) || getUspMessageFlag(); - -if (!MessageFlag) { - console.error("MessageFlag is unavailable."); -} else if (typeof chrome?.runtime?.onMessage?.addListener !== "function") { - // Firefox userScripts.RegisteredUserScript does not provide chrome.runtime.onMessage.addListener - // Firefox scripting.RegisteredContentScript does provide chrome.runtime.onMessage.addListener - // Firefox 的 userScripts.RegisteredUserScript 不提供 chrome.runtime.onMessage.addListener - // Firefox 的 scripting.RegisteredContentScript 提供 chrome.runtime.onMessage.addListener - console.error("chrome.runtime.onMessage.addListener is not a function"); -} else { - // 建立与service_worker页面的连接 - const extMsgComm: Message = new ExtensionMessage(false); - // 初始化日志组件 - const loggerCore = new LoggerCore({ - writer: new MessageWriter(extMsgComm, "serviceWorker/logger"), - labels: { env: "content" }, - }); +/* global MessageFlag */ + +const mainKey = uuidv5("scriptcat-listen-inject", MessageFlag); + +const contentRandomId = uuidv4(); + +let scriptingMessagingBind = () => {}; +// ------------ 對象 ------------ +class ImmutableEventTarget extends EventTarget {} +ImmutableEventTarget.prototype.addEventListener = EventTarget.prototype.addEventListener; +ImmutableEventTarget.prototype.dispatchEvent = EventTarget.prototype.dispatchEvent; +ImmutableEventTarget.prototype.removeEventListener = EventTarget.prototype.removeEventListener; + +const pageMessaging = createPageMessaging(""); +const scriptExecutorPageMessaging = createPageMessaging(uuidv4()); + +const scriptingMessaging = createPageMessaging(""); + +const emitters = new Map(); - loggerCore.logger().debug("content start"); +const msgInject = new CustomEventMessage(pageMessaging, true); - const msgInject = new CustomEventMessage(MessageFlag, true); +// ------------ 監聽 ------------ - // 处理scriptExecutor - const scriptExecutorFlag = randomMessageFlag(); - const scriptExecutorMsg = new CustomEventMessage(scriptExecutorFlag, true); - const scriptExecutor = new ScriptExecutor(new CustomEventMessage(scriptExecutorFlag, false)); +performance.addEventListener(mainKey, (ev) => { + // 注:即使外部執行 "scriptcat-listen-inject", 不知道 inject.ts 的亂數 flag 是不可能截取資料 + if (ev instanceof CustomEvent && typeof ev.detail?.injectFlagEvt === "string") { + // 必定由 inject.ts 要求 + ev.preventDefault(); // dispatchEvent 返回 false + // 按 inject.ts 要求返回 emitter + const { injectFlagEvt, scripting } = ev.detail; + let emitter = emitters.get(injectFlagEvt); + if (!emitter) { + emitters.set(injectFlagEvt, (emitter = uuidv5(injectFlagEvt, contentRandomId))); + } + if (scripting) { + scriptingMessaging.et = emitter; + scriptingMessagingBind(); + } else { + pageMessaging.et = emitter; + msgInject.bindEmitter(); + } + // 傳送 emitter 給 inject.ts + pageDispatchCustomEvent(`${injectFlagEvt}`, { + [`emitterKeyFor${injectFlagEvt}`]: emitter, + }); + } +}); - const server = new Server("content", [msgInject, scriptExecutorMsg]); +// ------------ 连接 ------------ + +// 建立与service_worker页面的连接 +const extMsgComm: Message = new ExtensionMessage(false); +// 初始化日志组件 +const loggerCore = new LoggerCore({ + writer: new MessageWriter(extMsgComm, "serviceWorker/logger"), + labels: { env: "content" }, +}); + +loggerCore.logger().debug("content start"); + +// 处理scriptExecutor +const scriptExecutorMsg1 = new CustomEventMessage(scriptExecutorPageMessaging, true); +scriptExecutorMsg1.bindEmitter(); +const scriptExecutorMsg2 = new CustomEventMessage(scriptExecutorPageMessaging, false); +scriptExecutorMsg2.bindEmitter(); +const scriptExecutor = new ScriptExecutor(scriptExecutorMsg2); + +const server = new Server("content", [msgInject, scriptExecutorMsg1]); + +// Opera中没有chrome.runtime.onConnect,并且content也不需要chrome.runtime.onConnect +// 所以不需要处理连接,设置为false +// const extServer = new Server("content", extMsgComm, false); +// scriptExecutor的消息接口 +// 初始化运行环境 +const runtime = new ContentRuntime(null, server, extMsgComm, msgInject, scriptExecutorMsg1, scriptExecutor); +runtime.init(); +// 页面加载,注入脚本 +runtime.pageLoad(initEnvInfo); + +scriptingMessagingBind = () => { + if (!scriptingMessaging.et) throw new Error("scriptingMessaging is not ready or destroyed"); + pageAddEventListener(`evt_${scriptingMessaging.et}_deliveryMessage`, (ev) => { + if (ev instanceof CustomEvent) { + const { tag, value } = ev.detail; + if (tag === "localStorage:scriptInjectMessageFlag") { + // 反注册所有脚本时,同时中断网页信息传递 + pageMessaging.et = ""; + scriptExecutorPageMessaging.et = ""; + scriptingMessaging.et = ""; + } else if (tag === "valueUpdateDelivery") { + // const storageName = sendData.storageName; + // 转发给inject和scriptExecutor + const sendData = value.sendData as ValueUpdateDataEncoded; + scriptExecutor.valueUpdate(sendData); + sendMessage(msgInject, "inject/runtime/valueUpdate", sendData); + } else if (tag === "content/runtime/emitEvent") { + const data = value; + // 转发给inject和scriptExecutor + scriptExecutor.emitEvent(data); + sendMessage(msgInject, "inject/runtime/emitEvent", data); + } + } + }); +}; - // Opera中没有chrome.runtime.onConnect,并且content也不需要chrome.runtime.onConnect - // 所以不需要处理连接,设置为false - const extServer = new Server("content", extMsgComm, false); - // scriptExecutor的消息接口 - // 初始化运行环境 - const runtime = new ContentRuntime(extServer, server, extMsgComm, msgInject, scriptExecutorMsg, scriptExecutor); - runtime.init(); - // 页面加载,注入脚本 - runtime.pageLoad(MessageFlag, initEnvInfo); -} +// ------------ 請求 ------------ +performance.dispatchEvent(new CustomEvent(mainKey)); +// ----------------------------- diff --git a/src/inject.ts b/src/inject.ts index b434858d1..d7ea191a5 100644 --- a/src/inject.ts +++ b/src/inject.ts @@ -1,16 +1,25 @@ import LoggerCore from "./app/logger/core"; import MessageWriter from "./app/logger/message_writer"; -import { CustomEventMessage } from "@Packages/message/custom_event_message"; +import { + CustomEventMessage, + createPageMessaging, + pageDispatchCustomEvent, +} from "@Packages/message/custom_event_message"; import { Server } from "@Packages/message/server"; import type { TScriptInfo } from "./app/repo/scripts"; import type { GMInfoEnv } from "./app/service/content/types"; import { InjectRuntime } from "./app/service/content/inject"; import { initEnvInfo, ScriptExecutor } from "./app/service/content/script_executor"; -import type { Message } from "@Packages/message/types"; +import { randomMessageFlag } from "./pkg/utils/utils"; +import { uuidv5 } from "./pkg/utils/uuid"; /* global MessageFlag */ -const msg: Message = new CustomEventMessage(MessageFlag, false); +const mainKey = uuidv5("scriptcat-listen-inject", MessageFlag); + +const pageMessaging = createPageMessaging(""); + +const msg = new CustomEventMessage(pageMessaging, false); // 加载logger组件 const logger = new LoggerCore({ @@ -33,3 +42,30 @@ server.on("pageLoad", (data: { injectScriptList: TScriptInfo[]; envInfo: GMInfoE runtime.startScripts(data.injectScriptList, data.envInfo); runtime.onInjectPageLoaded(); }); + +const injectFlag = randomMessageFlag(); +const injectFlagEvt = injectFlag; + +// 用來接收 emitter +performance.addEventListener( + `${injectFlagEvt}`, + (ev) => { + if (ev instanceof CustomEvent && ev.detail?.[`emitterKeyFor${injectFlagEvt}`]) { + pageMessaging.et = ev.detail[`emitterKeyFor${injectFlagEvt}`]; + msg.bindEmitter(); + } + }, + { once: true } +); + +const submitTarget = () => { + return pageDispatchCustomEvent(mainKey, { injectFlagEvt }); +}; + +if (submitTarget() === true) { + performance.addEventListener(mainKey, (ev) => { + if (ev instanceof CustomEvent && !ev.detail) { + submitTarget(); + } + }); +} diff --git a/src/scripting.ts b/src/scripting.ts new file mode 100644 index 000000000..e2b467795 --- /dev/null +++ b/src/scripting.ts @@ -0,0 +1,67 @@ +import { randomMessageFlag } from "./pkg/utils/utils"; +import { createPageMessaging, pageDispatchCustomEvent } from "@Packages/message/custom_event_message"; +import { uuidv5 } from "./pkg/utils/uuid"; + +const scriptingMessaging = createPageMessaging(""); + +chrome.storage.local.get(["localStorage:scriptInjectMessageFlag"]).then((m) => { + const MessageFlag = m["localStorage:scriptInjectMessageFlag"].value; + + const mainKey = uuidv5("scriptcat-listen-inject", MessageFlag); + + const dispatchDeliveryMessage = (detail: any) => { + if (!scriptingMessaging.et) throw new Error("scriptingMessaging is not ready or destroyed"); + pageDispatchCustomEvent(`evt_${scriptingMessaging.et}_deliveryMessage`, detail); + }; + + // ------------------------------ + chrome.storage.local.onChanged.addListener((changes) => { + if (changes["localStorage:scriptInjectMessageFlag"]?.newValue) { + dispatchDeliveryMessage({ + tag: "localStorage:scriptInjectMessageFlag", + value: changes["localStorage:scriptInjectMessageFlag"]?.newValue, + }); + } + if (changes["valueUpdateDelivery"]?.newValue) { + dispatchDeliveryMessage({ + tag: "valueUpdateDelivery", + value: changes["valueUpdateDelivery"]?.newValue, + }); + } + }); + + chrome.runtime.onMessage.addListener((message, _sender) => { + if (!message) return; + const { action, data } = message; + dispatchDeliveryMessage({ + tag: action, + value: data, + }); + }); + + const injectFlag = randomMessageFlag(); + const injectFlagEvt = injectFlag; + + // 用來接收 emitter + performance.addEventListener( + `${injectFlagEvt}`, + (ev) => { + if (ev instanceof CustomEvent && ev.detail?.[`emitterKeyFor${injectFlagEvt}`]) { + scriptingMessaging.et = ev.detail[`emitterKeyFor${injectFlagEvt}`]; + } + }, + { once: true } + ); + + const submitTarget = () => { + return pageDispatchCustomEvent(mainKey, { injectFlagEvt, scripting: true }); + }; + + if (submitTarget() === true) { + performance.addEventListener(mainKey, (ev) => { + if (ev instanceof CustomEvent && !ev.detail) { + submitTarget(); + } + }); + } +}); From 531ac109177b4275220305f85c53693ebf0261c8 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 9 Dec 2025 13:01:04 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=E4=BC=98=E5=8C=96=20scripting.ts=20?= =?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=A0=81=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/scripting.ts | 66 +++++++++++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/src/scripting.ts b/src/scripting.ts index e2b467795..1217e923c 100644 --- a/src/scripting.ts +++ b/src/scripting.ts @@ -3,42 +3,48 @@ import { createPageMessaging, pageDispatchCustomEvent } from "@Packages/message/ import { uuidv5 } from "./pkg/utils/uuid"; const scriptingMessaging = createPageMessaging(""); +const messageStack: any[] = []; + +// 在取得 scriptInjectMessageFlag 前,先堆叠一下,避免漏掉 +let dispatchDeliveryMessage = (message: any) => { + messageStack.push(message); +}; + +// ------------------------------ +chrome.storage.local.onChanged.addListener((changes) => { + if (changes["localStorage:scriptInjectMessageFlag"]?.newValue) { + dispatchDeliveryMessage({ + tag: "localStorage:scriptInjectMessageFlag", + value: changes["localStorage:scriptInjectMessageFlag"]?.newValue, + }); + } + if (changes["valueUpdateDelivery"]?.newValue) { + dispatchDeliveryMessage({ + tag: "valueUpdateDelivery", + value: changes["valueUpdateDelivery"]?.newValue, + }); + } +}); + +chrome.runtime.onMessage.addListener((message, _sender) => { + if (!message) return; + const { action, data } = message; + dispatchDeliveryMessage({ + tag: action, + value: data, + }); +}); chrome.storage.local.get(["localStorage:scriptInjectMessageFlag"]).then((m) => { const MessageFlag = m["localStorage:scriptInjectMessageFlag"].value; const mainKey = uuidv5("scriptcat-listen-inject", MessageFlag); - const dispatchDeliveryMessage = (detail: any) => { + const dispatchDeliveryMessageAfterEtSet = (detail: any) => { if (!scriptingMessaging.et) throw new Error("scriptingMessaging is not ready or destroyed"); pageDispatchCustomEvent(`evt_${scriptingMessaging.et}_deliveryMessage`, detail); }; - // ------------------------------ - chrome.storage.local.onChanged.addListener((changes) => { - if (changes["localStorage:scriptInjectMessageFlag"]?.newValue) { - dispatchDeliveryMessage({ - tag: "localStorage:scriptInjectMessageFlag", - value: changes["localStorage:scriptInjectMessageFlag"]?.newValue, - }); - } - if (changes["valueUpdateDelivery"]?.newValue) { - dispatchDeliveryMessage({ - tag: "valueUpdateDelivery", - value: changes["valueUpdateDelivery"]?.newValue, - }); - } - }); - - chrome.runtime.onMessage.addListener((message, _sender) => { - if (!message) return; - const { action, data } = message; - dispatchDeliveryMessage({ - tag: action, - value: data, - }); - }); - const injectFlag = randomMessageFlag(); const injectFlagEvt = injectFlag; @@ -48,6 +54,14 @@ chrome.storage.local.get(["localStorage:scriptInjectMessageFlag"]).then((m) => { (ev) => { if (ev instanceof CustomEvent && ev.detail?.[`emitterKeyFor${injectFlagEvt}`]) { scriptingMessaging.et = ev.detail[`emitterKeyFor${injectFlagEvt}`]; + dispatchDeliveryMessage = dispatchDeliveryMessageAfterEtSet; + if (messageStack.length > 0) { + const messages = messageStack.slice(); + messageStack.length = 0; + for (const message of messages) { + dispatchDeliveryMessage(message); + } + } } }, { once: true } From 57502783c4f0e34775b8eda0eb7727807780a9ac Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 9 Dec 2025 14:35:29 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=E5=85=B1=E9=80=9A=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/message/common.ts | 17 ++++++++++++++ packages/message/custom_event_message.ts | 26 +++++++--------------- src/app/service/content/script_executor.ts | 3 ++- src/content.ts | 12 ++++------ src/inject.ts | 11 ++++----- src/scripting.ts | 7 +++--- 6 files changed, 39 insertions(+), 37 deletions(-) create mode 100644 packages/message/common.ts diff --git a/packages/message/common.ts b/packages/message/common.ts new file mode 100644 index 000000000..b4757ed75 --- /dev/null +++ b/packages/message/common.ts @@ -0,0 +1,17 @@ +// 避免页面载入后改动全域物件导致消息传递失败 +export const MouseEventClone = MouseEvent; +export const CustomEventClone = CustomEvent; + +// 避免页面载入后改动 EventTarget.prototype 的方法导致消息传递失败 +export const pageDispatchEvent = performance.dispatchEvent.bind(performance); +export const pageAddEventListener = performance.addEventListener.bind(performance); +export const pageRemoveEventListener = performance.removeEventListener.bind(performance); +const detailClone = typeof cloneInto === "function" ? cloneInto : null; +export const pageDispatchCustomEvent = (eventType: string, detail: any) => { + if (detailClone && detail) detail = detailClone(detail, document.defaultView); + const ev = new CustomEventClone(eventType, { + detail, + cancelable: true, + }); + return pageDispatchEvent(ev); +}; diff --git a/packages/message/custom_event_message.ts b/packages/message/custom_event_message.ts index dc27d4fcf..933681b29 100644 --- a/packages/message/custom_event_message.ts +++ b/packages/message/custom_event_message.ts @@ -3,24 +3,14 @@ import { v4 as uuidv4 } from "uuid"; import { type PostMessage, type WindowMessageBody, WindowMessageConnect } from "./window_message"; import EventEmitter from "eventemitter3"; import { DefinedFlags } from "@App/app/service/service_worker/runtime.consts"; - -// 避免页面载入后改动 EventTarget.prototype 的方法导致消息传递失败 -export const pageDispatchEvent = performance.dispatchEvent.bind(performance); -export const pageAddEventListener = performance.addEventListener.bind(performance); -export const pageRemoveEventListener = performance.removeEventListener.bind(performance); -const detailClone = typeof cloneInto === "function" ? cloneInto : null; -export const pageDispatchCustomEvent = (eventType: string, detail: any) => { - if (detailClone && detail) detail = detailClone(detail, document.defaultView); - const ev = new CustomEventClone(eventType, { - detail, - cancelable: true, - }); - return pageDispatchEvent(ev); -}; - -// 避免页面载入后改动全域物件导致消息传递失败 -const MouseEventClone = MouseEvent; -const CustomEventClone = CustomEvent; +import { + pageDispatchEvent, + pageAddEventListener, + pageRemoveEventListener, + pageDispatchCustomEvent, + MouseEventClone, + CustomEventClone, +} from "@Packages/message/common"; // 避免页面载入后改动 Map.prototype 导致消息传递失败 const relatedTargetMap = new Map(); diff --git a/src/app/service/content/script_executor.ts b/src/app/service/content/script_executor.ts index 32e499bfb..34fd6dda7 100644 --- a/src/app/service/content/script_executor.ts +++ b/src/app/service/content/script_executor.ts @@ -6,6 +6,7 @@ import type { GMInfoEnv, ScriptFunc, ValueUpdateDataEncoded } from "./types"; import { addStyleSheet, definePropertyListener } from "./utils"; import type { TScriptInfo } from "@App/app/repo/scripts"; import { DefinedFlags } from "../service_worker/runtime.consts"; +import { pageDispatchEvent } from "@Packages/message/common"; export type ExecScriptEntry = { scriptLoadInfo: TScriptInfo; @@ -101,7 +102,7 @@ export class ScriptExecutor { // 通知 环境 加载完成 // 适用于此「通知环境加载完成」代码执行前的脚本加载 const ev = new CustomEvent(envLoadCompleteEvtName); - performance.dispatchEvent(ev); + pageDispatchEvent(ev); } execEarlyScript(flag: string, scriptInfo: TScriptInfo, envInfo: GMInfoEnv) { diff --git a/src/content.ts b/src/content.ts index b5aaf86aa..e34849108 100644 --- a/src/content.ts +++ b/src/content.ts @@ -1,12 +1,8 @@ import LoggerCore from "./app/logger/core"; import MessageWriter from "./app/logger/message_writer"; import { ExtensionMessage } from "@Packages/message/extension_message"; -import { - CustomEventMessage, - createPageMessaging, - pageAddEventListener, - pageDispatchCustomEvent, -} from "@Packages/message/custom_event_message"; +import { CustomEventMessage, createPageMessaging } from "@Packages/message/custom_event_message"; +import { pageAddEventListener, pageDispatchCustomEvent, pageDispatchEvent } from "@Packages/message/common"; import { Server } from "@Packages/message/server"; import ContentRuntime from "./app/service/content/content"; import { initEnvInfo, ScriptExecutor } from "./app/service/content/script_executor"; @@ -39,7 +35,7 @@ const msgInject = new CustomEventMessage(pageMessaging, true); // ------------ 監聽 ------------ -performance.addEventListener(mainKey, (ev) => { +pageAddEventListener(mainKey, (ev) => { // 注:即使外部執行 "scriptcat-listen-inject", 不知道 inject.ts 的亂數 flag 是不可能截取資料 if (ev instanceof CustomEvent && typeof ev.detail?.injectFlagEvt === "string") { // 必定由 inject.ts 要求 @@ -122,5 +118,5 @@ scriptingMessagingBind = () => { }; // ------------ 請求 ------------ -performance.dispatchEvent(new CustomEvent(mainKey)); +pageDispatchEvent(new CustomEvent(mainKey)); // ----------------------------- diff --git a/src/inject.ts b/src/inject.ts index d7ea191a5..8eed4c49e 100644 --- a/src/inject.ts +++ b/src/inject.ts @@ -1,10 +1,7 @@ import LoggerCore from "./app/logger/core"; import MessageWriter from "./app/logger/message_writer"; -import { - CustomEventMessage, - createPageMessaging, - pageDispatchCustomEvent, -} from "@Packages/message/custom_event_message"; +import { CustomEventMessage, createPageMessaging } from "@Packages/message/custom_event_message"; +import { pageAddEventListener, pageDispatchCustomEvent } from "@Packages/message/common"; import { Server } from "@Packages/message/server"; import type { TScriptInfo } from "./app/repo/scripts"; import type { GMInfoEnv } from "./app/service/content/types"; @@ -47,7 +44,7 @@ const injectFlag = randomMessageFlag(); const injectFlagEvt = injectFlag; // 用來接收 emitter -performance.addEventListener( +pageAddEventListener( `${injectFlagEvt}`, (ev) => { if (ev instanceof CustomEvent && ev.detail?.[`emitterKeyFor${injectFlagEvt}`]) { @@ -63,7 +60,7 @@ const submitTarget = () => { }; if (submitTarget() === true) { - performance.addEventListener(mainKey, (ev) => { + pageAddEventListener(mainKey, (ev) => { if (ev instanceof CustomEvent && !ev.detail) { submitTarget(); } diff --git a/src/scripting.ts b/src/scripting.ts index 1217e923c..223bc5258 100644 --- a/src/scripting.ts +++ b/src/scripting.ts @@ -1,5 +1,6 @@ import { randomMessageFlag } from "./pkg/utils/utils"; -import { createPageMessaging, pageDispatchCustomEvent } from "@Packages/message/custom_event_message"; +import { createPageMessaging } from "@Packages/message/custom_event_message"; +import { pageAddEventListener, pageDispatchCustomEvent } from "@Packages/message/common"; import { uuidv5 } from "./pkg/utils/uuid"; const scriptingMessaging = createPageMessaging(""); @@ -49,7 +50,7 @@ chrome.storage.local.get(["localStorage:scriptInjectMessageFlag"]).then((m) => { const injectFlagEvt = injectFlag; // 用來接收 emitter - performance.addEventListener( + pageAddEventListener( `${injectFlagEvt}`, (ev) => { if (ev instanceof CustomEvent && ev.detail?.[`emitterKeyFor${injectFlagEvt}`]) { @@ -72,7 +73,7 @@ chrome.storage.local.get(["localStorage:scriptInjectMessageFlag"]).then((m) => { }; if (submitTarget() === true) { - performance.addEventListener(mainKey, (ev) => { + pageAddEventListener(mainKey, (ev) => { if (ev instanceof CustomEvent && !ev.detail) { submitTarget(); } From 1de8eddc5fe178fd2587b3fb1f76ed631fe3cf65 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 9 Dec 2025 15:11:36 +0900 Subject: [PATCH 4/6] =?UTF-8?q?cloneInto=20=E6=94=B9=E7=94=A8=20=E5=9B=BA?= =?UTF-8?q?=E5=AE=9A=E7=9A=84performance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/message/common.ts | 3 ++- src/app/service/content/utils.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/message/common.ts b/packages/message/common.ts index b4757ed75..222eed3d7 100644 --- a/packages/message/common.ts +++ b/packages/message/common.ts @@ -1,6 +1,7 @@ // 避免页面载入后改动全域物件导致消息传递失败 export const MouseEventClone = MouseEvent; export const CustomEventClone = CustomEvent; +const performanceClone = performance; // 避免页面载入后改动 EventTarget.prototype 的方法导致消息传递失败 export const pageDispatchEvent = performance.dispatchEvent.bind(performance); @@ -8,7 +9,7 @@ export const pageAddEventListener = performance.addEventListener.bind(performanc export const pageRemoveEventListener = performance.removeEventListener.bind(performance); const detailClone = typeof cloneInto === "function" ? cloneInto : null; export const pageDispatchCustomEvent = (eventType: string, detail: any) => { - if (detailClone && detail) detail = detailClone(detail, document.defaultView); + if (detailClone && detail) detail = detailClone(detail, performanceClone); const ev = new CustomEventClone(eventType, { detail, cancelable: true, diff --git a/src/app/service/content/utils.ts b/src/app/service/content/utils.ts index 54a2e8bed..4e9cf3f9e 100644 --- a/src/app/service/content/utils.ts +++ b/src/app/service/content/utils.ts @@ -151,7 +151,7 @@ export function compilePreInjectScript( return `window['${flag}'] = function(){${autoDeleteMountCode}${scriptCode}}; { let o = { cancelable: true, detail: { scriptFlag: '${flag}', scriptInfo: (${scriptInfoJSON}) } }, - c = typeof cloneInto === "function" ? cloneInto(o, document.defaultView) : o, + c = typeof cloneInto === "function" ? cloneInto(o, performance) : o, f = () => performance.dispatchEvent(new CustomEvent('${evScriptLoad}', c)), needWait = f(); if (needWait) performance.addEventListener('${evEnvLoad}', f, { once: true }); From d650fdfb852f40cae877084ad549f6eb2b1ac2dd Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Thu, 11 Dec 2025 19:21:42 +0900 Subject: [PATCH 5/6] =?UTF-8?q?=E5=88=AA=E6=9C=AA=E4=BD=BF=E7=94=A8=20Immu?= =?UTF-8?q?tableEventTarget?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/content.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/content.ts b/src/content.ts index e34849108..d28b314cd 100644 --- a/src/content.ts +++ b/src/content.ts @@ -19,10 +19,6 @@ const contentRandomId = uuidv4(); let scriptingMessagingBind = () => {}; // ------------ 對象 ------------ -class ImmutableEventTarget extends EventTarget {} -ImmutableEventTarget.prototype.addEventListener = EventTarget.prototype.addEventListener; -ImmutableEventTarget.prototype.dispatchEvent = EventTarget.prototype.dispatchEvent; -ImmutableEventTarget.prototype.removeEventListener = EventTarget.prototype.removeEventListener; const pageMessaging = createPageMessaging(""); const scriptExecutorPageMessaging = createPageMessaging(uuidv4()); From 78d56bce6651e1745e08a53e795f5810ff91a671 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Tue, 16 Dec 2025 17:23:52 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=E8=AF=A5=E9=94=99=E8=AF=AF=E4=B8=BA?= =?UTF-8?q?=E9=A2=84=E6=9C=9F=E5=86=85=E6=83=85=E5=86=B5=EF=BC=8C=E6=97=A0?= =?UTF-8?q?=E9=9C=80=E8=AE=B0=E5=BD=95=20debug=20=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/service_worker/runtime.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/service/service_worker/runtime.ts b/src/app/service/service_worker/runtime.ts index 2681cdf13..4efd2057b 100644 --- a/src/app/service/service_worker/runtime.ts +++ b/src/app/service/service_worker/runtime.ts @@ -342,6 +342,8 @@ export class RuntimeService { try { const res = await chrome.userScripts.getScripts({ ids: ["scriptcat-inject"] }); registered = res.length === 1; + } catch { + // 该错误为预期内情况,无需记录 debug 日志 } finally { // 考虑 UserScripts API 不可使用等情况 runtimeGlobal.registered = registered;