diff --git a/package.json b/package.json index 34d865520..ea6d9a83c 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@dnd-kit/modifiers": "^9.0.0", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", + "acorn": "^8.16.0", "chardet": "^2.1.1", "cron": "^4.4.0", "crypto-js": "^4.2.0", @@ -44,6 +45,7 @@ "eventemitter3": "^5.0.1", "fast-xml-parser": "^5.5.8", "i18next": "^23.16.4", + "magic-string": "^0.30.21", "monaco-editor": "^0.52.2", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ca4e846db..1335be835 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: '@dnd-kit/utilities': specifier: ^3.2.2 version: 3.2.2(react@18.3.1) + acorn: + specifier: ^8.16.0 + version: 8.16.0 chardet: specifier: ^2.1.1 version: 2.1.1 @@ -53,6 +56,9 @@ importers: i18next: specifier: ^23.16.4 version: 23.16.4 + magic-string: + specifier: ^0.30.21 + version: 0.30.21 monaco-editor: specifier: ^0.52.2 version: 0.52.2 diff --git a/rspack.config.ts b/rspack.config.ts index 91969281c..691277ecb 100644 --- a/rspack.config.ts +++ b/rspack.config.ts @@ -52,6 +52,7 @@ export default { service_worker: `${src}/service_worker.ts`, offscreen: `${src}/offscreen.ts`, sandbox: `${src}/sandbox.ts`, + persistent_frame: `${src}/persistent_frame.ts`, content: `${src}/content.ts`, scripting: `${src}/scripting.ts`, inject: `${src}/inject.ts`, @@ -233,6 +234,13 @@ export default { minify: true, chunks: ["sandbox"], }), + new rspack.HtmlRspackPlugin({ + filename: `${dist}/ext/src/persistent_frame.html`, + template: `${src}/pages/persistent_frame.html`, + inject: "head", + minify: true, + chunks: ["persistent_frame"], + }), new ZipExecutionPlugin(), ].filter(Boolean), experiments: { diff --git a/src/pages/persistent_frame.html b/src/pages/persistent_frame.html new file mode 100644 index 000000000..bb5973e67 --- /dev/null +++ b/src/pages/persistent_frame.html @@ -0,0 +1,11 @@ + + + + + + persistent_frame + + +
+ + diff --git a/src/persistent_frame.ts b/src/persistent_frame.ts new file mode 100644 index 000000000..c6bfe23de --- /dev/null +++ b/src/persistent_frame.ts @@ -0,0 +1,32 @@ +// persistent_frame.ts +const WAKE_UP_INTERVAL = 2000; +let waitState = 0; +let lastNow = 0; +if (typeof frameElement === "object" && frameElement) { + const cNode = document.createComment("0"); + let cVal = 0; + const runner = (ts: number) => { + waitState = 1; + cVal = cVal > 8 ? 1 : cVal + 1; + cNode.data = `${cVal}`; + const now = ts; + if (now - lastNow > WAKE_UP_INTERVAL) { + lastNow = now; + chrome.storage.session.set({ persistentWakeup: `${now}` }); + document.title = `wakup at ${now}`; // debug + } + }; + window.addEventListener("message", (ev) => { + if (waitState === 2) { + if (typeof ev.data === "object" && ev.data?.myCustomAction === "waked-up") runner(ev.timeStamp); + } + }); + const mutObserver = new MutationObserver(() => { + if (waitState === 1) { + waitState = 2; + window?.postMessage({ myCustomAction: "waked-up" }, "*"); + } + }); + mutObserver.observe(cNode, { characterData: true }); + runner(0); +} diff --git a/src/pkg/utils/persistent.ts b/src/pkg/utils/persistent.ts new file mode 100644 index 000000000..e6066b408 --- /dev/null +++ b/src/pkg/utils/persistent.ts @@ -0,0 +1,13 @@ +export const keepEventPageRunning = () => { + if (typeof frames !== "object") return; + if (typeof document === "undefined") return; + if (typeof document.documentElement === "undefined") return; + if (document.getElementById("persistent_frame")) return; + chrome.storage.session.onChanged.addListener((obj) => { + typeof obj.persistentWakeup !== "undefined"; + }); + const iframe = document.createElement("iframe"); + iframe.id = "persistent_frame"; + iframe.src = chrome.runtime.getURL("/src/persistent_frame.html"); + document.documentElement.appendChild(iframe); +}; diff --git a/src/service_worker.ts b/src/service_worker.ts index 407a27922..3e465b26c 100644 --- a/src/service_worker.ts +++ b/src/service_worker.ts @@ -8,9 +8,11 @@ import { MessageQueue } from "@Packages/message/message_queue"; import { ServiceWorkerMessageSend } from "@Packages/message/window_message"; import migrate, { migrateChromeStorage } from "./app/migrate"; import { cleanInvalidKeys } from "./app/repo/resource"; +import { keepEventPageRunning } from "@App/pkg/utils/persistent"; migrate(); migrateChromeStorage(); +keepEventPageRunning(); const OFFSCREEN_DOCUMENT_PATH = "src/offscreen.html";