From a2e0a74be172b09998abf1ceec0a66b67d46bfb1 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Sun, 4 Jan 2026 14:29:30 +0900 Subject: [PATCH] =?UTF-8?q?GM=20API=20=E5=AE=9A=E4=B9=89=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/content/content.ts | 6 +- src/app/service/content/gm_api/gm_api.test.ts | 54 ++-- src/app/service/content/gm_api/gm_api.ts | 257 ++++++++++++------ .../service/service_worker/gm_api/gm_api.ts | 8 +- 4 files changed, 214 insertions(+), 111 deletions(-) diff --git a/src/app/service/content/content.ts b/src/app/service/content/content.ts index da0445cfd..8bf14f3f3 100644 --- a/src/app/service/content/content.ts +++ b/src/app/service/content/content.ts @@ -76,7 +76,7 @@ export default class ContentRuntime { case "GM_addElement": { const [parentNodeId, tagName, tmpAttr] = data.params; let attr = { ...tmpAttr }; - let parentNode: EventTarget | undefined; + let parentNode: Node | undefined; // 判断是不是content脚本发过来的 let msg: CustomEventMessage; if (this.contentScriptSet.has(data.uuid) || this.scriptExecutor.execMap.has(data.uuid)) { @@ -85,7 +85,7 @@ export default class ContentRuntime { msg = this.senderToInject; } if (parentNodeId) { - parentNode = msg.getAndDelRelatedTarget(parentNodeId); + parentNode = msg.getAndDelRelatedTarget(parentNodeId) as Node | undefined; } const el = document.createElement(tagName); @@ -104,7 +104,7 @@ export default class ContentRuntime { if (textContent) { el.textContent = textContent; } - (parentNode || document.head || document.body || document.querySelector("*")).appendChild(el); + (parentNode || document.head || document.body || document.querySelector("*")).appendChild(el); const nodeId = msg.sendRelatedTarget(el); return nodeId; } diff --git a/src/app/service/content/gm_api/gm_api.test.ts b/src/app/service/content/gm_api/gm_api.test.ts index 64c1a26f4..75b03d678 100644 --- a/src/app/service/content/gm_api/gm_api.test.ts +++ b/src/app/service/content/gm_api/gm_api.test.ts @@ -33,15 +33,17 @@ const envInfo: GMInfoEnv = { describe.concurrent("@grant GM", () => { it.concurrent("GM_", async () => { const script = Object.assign({}, scriptRes) as ScriptLoadInfo; - script.metadata.grant = ["GM_getValue", "GM_getTab", "GM_saveTab", "GM_cookie"]; + script.metadata.grant = ["GM_getValue", "GM_getTab", "GM_getTabs", "GM_saveTab", "GM_cookie"]; // @ts-ignore const exec = new ExecScript(script, undefined, undefined, nilFn, envInfo); script.code = `return { ["GM.getValue"]: GM.getValue, ["GM.getTab"]: GM.getTab, - ["GM.setTab"]: GM.setTab, + ["GM.getTabs"]: GM.getTabs, + ["GM.saveTab"]: GM.saveTab, GM_getValue: this.GM_getValue, GM_getTab: this.GM_getTab, + GM_getTabs: this.GM_getTabs, GM_saveTab: this.GM_saveTab, GM_cookie: this.GM_cookie, ["GM_cookie.list"]: this.GM_cookie.list, @@ -49,15 +51,20 @@ describe.concurrent("@grant GM", () => { }`; exec.scriptFunc = compileScript(compileScriptCode(script)); const ret = await exec.exec(); - expect(ret["GM.getValue"]).toBeUndefined(); - expect(ret["GM.getTab"]).toBeUndefined(); - expect(ret["GM.setTab"]).toBeUndefined(); - expect(ret.GM_getValue.name).toEqual("bound GM_getValue"); - expect(ret.GM_getTab.name).toEqual("bound GM_getTab"); - expect(ret.GM_saveTab.name).toEqual("bound GM_saveTab"); - expect(ret.GM_cookie.name).toEqual("bound GM_cookie"); - expect(ret["GM_cookie.list"].name).toEqual("bound GM_cookie.list"); - expect(ret["GM.cookie"]).toBeUndefined(); + // getValue + expect(ret.GM_getValue?.name).toEqual("bound GM_getValue"); + expect(ret["GM.getValue"]?.name).toBeUndefined(); + // getTab / getTabs / saveTab + expect(ret.GM_getTab?.name).toEqual("bound GM_getTab"); + expect(ret.GM_getTabs?.name).toEqual("bound GM_getTabs"); + expect(ret.GM_saveTab?.name).toEqual("bound GM_saveTab"); + expect(ret["GM.getTab"]?.name).toBeUndefined(); + expect(ret["GM.getTabs"]?.name).toBeUndefined(); + expect(ret["GM.saveTab"]?.name).toBeUndefined(); + // cookie + expect(ret.GM_cookie?.name).toEqual("bound GM_cookie"); + expect(ret["GM_cookie.list"]?.name).toEqual("bound GM_cookie.list"); + expect(ret["GM.cookie"]?.name).toBeUndefined(); }); it.concurrent("GM.*", async () => { @@ -79,17 +86,20 @@ describe.concurrent("@grant GM", () => { }`; exec.scriptFunc = compileScript(compileScriptCode(script)); const ret = await exec.exec(); - expect(ret["GM.getValue"].name).toEqual("bound GM.getValue"); - expect(ret["GM.getTab"].name).toEqual("bound GM.getTab"); - expect(ret["GM.getTabs"].name).toEqual("bound GM.getTabs"); - expect(ret["GM.saveTab"].name).toEqual("bound GM_saveTab"); - expect(ret.GM_getValue).toBeUndefined(); - expect(ret.GM_getTab.name).toEqual("bound GM_getTab"); - expect(ret.GM_getTabs.name).toEqual("bound GM_getTabs"); - expect(ret.GM_saveTab).toBeUndefined(); - expect(ret.GM_cookie).toBeUndefined(); - expect(ret["GM.cookie"].name).toEqual("bound GM.cookie"); - expect(ret["GM.cookie"].list.name).toEqual("bound GM.cookie.list"); + // getValue + expect(ret["GM.getValue"]?.name).toEqual("bound GM.getValue"); + expect(ret.GM_getValue?.name).toBeUndefined(); + // getTab / getTabs / saveTab + // expect(ret.GM_getTab?.name).toBeUndefined(); + // expect(ret.GM_getTabs?.name).toBeUndefined(); + // expect(ret.GM_saveTab?.name).toBeUndefined(); + expect(ret["GM.getTab"]?.name).toEqual("bound GM.getTab"); + expect(ret["GM.getTabs"]?.name).toEqual("bound GM.getTabs"); + expect(ret["GM.saveTab"]?.name).toEqual("bound GM.saveTab"); + // cookie + expect(ret.GM_cookie?.name).toBeUndefined(); + expect(ret["GM.cookie"]?.name).toEqual("bound GM.cookie"); + expect(ret["GM.cookie"]?.list?.name).toEqual("bound GM.cookie.list"); }); }); diff --git a/src/app/service/content/gm_api/gm_api.ts b/src/app/service/content/gm_api/gm_api.ts index aa109b38e..a2b9b24bc 100644 --- a/src/app/service/content/gm_api/gm_api.ts +++ b/src/app/service/content/gm_api/gm_api.ts @@ -247,7 +247,7 @@ export default class GMApi extends GM_Base { } @GMContext.API() - public ["GM.getValue"](key: string, defaultValue?: any): Promise { + public "GM.getValue"(key: string, defaultValue?: any): Promise { // 兼容GM.getValue return new Promise((resolve) => { const ret = _GM_getValue(this, key, defaultValue); @@ -316,7 +316,7 @@ export default class GMApi extends GM_Base { } @GMContext.API() - public ["GM.setValue"](key: string, value: any): Promise { + public "GM.setValue"(key: string, value: any): Promise { // Asynchronous wrapper for GM_setValue to support GM.setValue return new Promise((resolve) => { _GM_setValue(this, resolve, key, value); @@ -329,7 +329,7 @@ export default class GMApi extends GM_Base { } @GMContext.API() - public ["GM.deleteValue"](key: string): Promise { + public "GM.deleteValue"(key: string): Promise { // Asynchronous wrapper for GM_deleteValue to support GM.deleteValue return new Promise((resolve) => { _GM_setValue(this, resolve, key, undefined); @@ -344,7 +344,7 @@ export default class GMApi extends GM_Base { } @GMContext.API() - public ["GM.listValues"](): Promise { + public "GM.listValues"(): Promise { // Asynchronous wrapper for GM_listValues to support GM.listValues return new Promise((resolve) => { if (!this.scriptRes) return resolve([]); @@ -391,7 +391,7 @@ export default class GMApi extends GM_Base { // Asynchronous wrapper for GM.getValues @GMContext.API({ depend: ["GM_getValues"] }) - public ["GM.getValues"](keysOrDefaults: TGMKeyValue | string[] | null | undefined): Promise { + public "GM.getValues"(keysOrDefaults: TGMKeyValue | string[] | null | undefined): Promise { if (!this.scriptRes) return new Promise(() => {}); return new Promise((resolve) => { const ret = this.GM_getValues(keysOrDefaults); @@ -399,8 +399,8 @@ export default class GMApi extends GM_Base { }); } - @GMContext.API({ depend: ["GM_setValues"] }) - public ["GM.setValues"](values: { [key: string]: any }): Promise { + @GMContext.API() + public "GM.setValues"(values: { [key: string]: any }): Promise { if (!this.scriptRes) return new Promise(() => {}); return new Promise((resolve) => { if (!values || typeof values !== "object") { @@ -425,8 +425,8 @@ export default class GMApi extends GM_Base { } // Asynchronous wrapper for GM.deleteValues - @GMContext.API({ depend: ["GM_deleteValues"] }) - public ["GM.deleteValues"](keys: string[]): Promise { + @GMContext.API() + public "GM.deleteValues"(keys: string[]): Promise { if (!this.scriptRes) return new Promise(() => {}); return new Promise((resolve) => { if (!Array.isArray(keys)) { @@ -441,20 +441,36 @@ export default class GMApi extends GM_Base { }); } - @GMContext.API({ alias: "GM.addValueChangeListener" }) + @GMContext.API() public GM_addValueChangeListener(name: string, listener: GMTypes.ValueChangeListener): number { if (!this.valueChangeListener) return 0; return this.valueChangeListener.add(name, listener); } - @GMContext.API({ alias: "GM.removeValueChangeListener" }) + @GMContext.API({ depend: ["GM_addValueChangeListener"] }) + public "GM.addValueChangeListener"(name: string, listener: GMTypes.ValueChangeListener): Promise { + return new Promise((resolve) => { + const ret = this.GM_addValueChangeListener(name, listener); + resolve(ret); + }); + } + + @GMContext.API() public GM_removeValueChangeListener(listenerId: number): void { if (!this.valueChangeListener) return; this.valueChangeListener.remove(listenerId); } - @GMContext.API({ alias: "GM.log" }) - GM_log(message: string, level: GMTypes.LoggerLevel = "info", ...labels: GMTypes.LoggerLabel[]) { + @GMContext.API({ depend: ["GM_removeValueChangeListener"] }) + public "GM.removeValueChangeListener"(listenerId: number): Promise { + return new Promise((resolve) => { + this.GM_removeValueChangeListener(listenerId); + resolve(); + }); + } + + @GMContext.API() + public GM_log(message: string, level: GMTypes.LoggerLevel = "info", ...labels: GMTypes.LoggerLabel[]): void { if (this.isInvalidContext()) return; if (typeof message !== "string") { message = JSON.stringify(message); @@ -462,6 +478,18 @@ export default class GMApi extends GM_Base { this.sendMessage("GM_log", [message, level, labels]); } + @GMContext.API({ depend: ["GM_log"] }) + public "GM.log"( + message: string, + level: GMTypes.LoggerLevel = "info", + ...labels: GMTypes.LoggerLabel[] + ): Promise { + return new Promise((resolve) => { + this.GM_log(message, level, ...labels); + resolve(); + }); + } + @GMContext.API() public CAT_createBlobUrl(blob: Blob): Promise { return Promise.resolve(toBlobURL(this, blob)); @@ -503,8 +531,8 @@ export default class GMApi extends GM_Base { }); } - @GMContext.API({ follow: "GM.cookie" }) - ["GM.cookie"](action: string, details: GMTypes.CookieDetails) { + @GMContext.API() + public "GM.cookie"(action: string, details: GMTypes.CookieDetails) { return new Promise((resolve, reject) => { _GM_cookie(this, action, details, (cookie, error) => { error ? reject(error) : resolve(cookie); @@ -513,7 +541,7 @@ export default class GMApi extends GM_Base { } @GMContext.API({ follow: "GM.cookie" }) - ["GM.cookie.set"](details: GMTypes.CookieDetails) { + public "GM.cookie.set"(details: GMTypes.CookieDetails) { return new Promise((resolve, reject) => { _GM_cookie(this, "set", details, (cookie, error) => { error ? reject(error) : resolve(cookie); @@ -522,7 +550,7 @@ export default class GMApi extends GM_Base { } @GMContext.API({ follow: "GM.cookie" }) - ["GM.cookie.list"](details: GMTypes.CookieDetails) { + public "GM.cookie.list"(details: GMTypes.CookieDetails) { return new Promise((resolve, reject) => { _GM_cookie(this, "list", details, (cookie, error) => { error ? reject(error) : resolve(cookie); @@ -531,7 +559,7 @@ export default class GMApi extends GM_Base { } @GMContext.API({ follow: "GM.cookie" }) - ["GM.cookie.delete"](details: GMTypes.CookieDetails) { + public "GM.cookie.delete"(details: GMTypes.CookieDetails) { return new Promise((resolve, reject) => { _GM_cookie(this, "delete", details, (cookie, error) => { error ? reject(error) : resolve(cookie); @@ -540,7 +568,7 @@ export default class GMApi extends GM_Base { } @GMContext.API({ follow: "GM_cookie" }) - ["GM_cookie.set"]( + public "GM_cookie.set"( details: GMTypes.CookieDetails, done: (cookie: GMTypes.Cookie[] | any, error: any | undefined) => void ) { @@ -548,7 +576,7 @@ export default class GMApi extends GM_Base { } @GMContext.API({ follow: "GM_cookie" }) - ["GM_cookie.list"]( + public "GM_cookie.list"( details: GMTypes.CookieDetails, done: (cookie: GMTypes.Cookie[] | any, error: any | undefined) => void ) { @@ -556,7 +584,7 @@ export default class GMApi extends GM_Base { } @GMContext.API({ follow: "GM_cookie" }) - ["GM_cookie.delete"]( + public "GM_cookie.delete"( details: GMTypes.CookieDetails, done: (cookie: GMTypes.Cookie[] | any, error: any | undefined) => void ) { @@ -564,7 +592,7 @@ export default class GMApi extends GM_Base { } @GMContext.API() - GM_cookie( + public GM_cookie( action: string, details: GMTypes.CookieDetails, done: (cookie: GMTypes.Cookie[] | any, error: any | undefined) => void @@ -589,8 +617,8 @@ export default class GMApi extends GM_Base { // (同一环境跨脚本也不一样) contentEnvKey: string | undefined; - @GMContext.API({ alias: "GM.registerMenuCommand" }) - GM_registerMenuCommand( + @GMContext.API() + public GM_registerMenuCommand( name: string, listener?: (inputValue?: any) => void, options_or_accessKey?: ScriptMenuItemOption | string @@ -655,15 +683,25 @@ export default class GMApi extends GM_Base { return ret; } - @GMContext.API({ - depend: ["GM_registerMenuCommand"], - }) - CAT_registerMenuInput(...args: Parameters): TScriptMenuItemID { + @GMContext.API({ depend: ["GM_registerMenuCommand"] }) + public "GM.registerMenuCommand"( + name: string, + listener?: (inputValue?: any) => void, + options_or_accessKey?: ScriptMenuItemOption | string + ): Promise { + return new Promise((resolve) => { + const ret = this.GM_registerMenuCommand(name, listener, options_or_accessKey); + resolve(ret); + }); + } + + @GMContext.API({ depend: ["GM_registerMenuCommand"] }) + public CAT_registerMenuInput(...args: Parameters): TScriptMenuItemID { return this.GM_registerMenuCommand(...args); } - @GMContext.API({ alias: "GM.addStyle" }) - GM_addStyle(css: string) { + @GMContext.API() + public GM_addStyle(css: string): Element | undefined { if (!this.message || !this.scriptRes) return; if (typeof css !== "string") throw new Error("The parameter 'css' of GM_addStyle shall be a string."); // 与content页的消息通讯实际是同步,此方法不需要经过background @@ -685,15 +723,23 @@ export default class GMApi extends GM_Base { if (resp.code) { throw new Error(resp.message); } - return (this.message).getAndDelRelatedTarget(resp.data); + return (this.message).getAndDelRelatedTarget(resp.data) as Element; } - @GMContext.API({ alias: "GM.addElement" }) - GM_addElement( - parentNode: EventTarget | string, + @GMContext.API({ depend: ["GM_addStyle"] }) + public "GM.addStyle"(css: string): Promise { + return new Promise((resolve) => { + const ret = this.GM_addStyle(css); + resolve(ret); + }); + } + + @GMContext.API() + public GM_addElement( + parentNode: Node | string, tagName: string | Record, attrs: Record = {} - ) { + ): Element | undefined { if (!this.message || !this.scriptRes) return; // 与content页的消息通讯实际是同步,此方法不需要经过background // 这里直接使用同步的方式去处理, 不要有promise @@ -719,11 +765,23 @@ export default class GMApi extends GM_Base { if (resp.code) { throw new Error(resp.message); } - return (this.message).getAndDelRelatedTarget(resp.data); + return (this.message).getAndDelRelatedTarget(resp.data) as Element; } - @GMContext.API({ alias: "GM.unregisterMenuCommand" }) - GM_unregisterMenuCommand(menuId: TScriptMenuItemID): void { + @GMContext.API({ depend: ["GM_addElement"] }) + public "GM.addElement"( + parentNode: Node | string, + tagName: string | Record, + attrs: Record = {} + ): Promise { + return new Promise((resolve) => { + const ret = this.GM_addElement(parentNode, tagName, attrs); + resolve(ret); + }); + } + + @GMContext.API() + public GM_unregisterMenuCommand(menuId: TScriptMenuItemID): void { if (!this.EE) return; if (!this.contentEnvKey) { return; @@ -736,22 +794,30 @@ export default class GMApi extends GM_Base { this.sendMessage("GM_unregisterMenuCommand", [menuKey] as GMUnRegisterMenuCommandParam); } + @GMContext.API({ depend: ["GM_unregisterMenuCommand"] }) + public "GM.unregisterMenuCommand"(menuId: TScriptMenuItemID): Promise { + return new Promise((resolve) => { + this.GM_unregisterMenuCommand(menuId); + resolve(); + }); + } + @GMContext.API({ depend: ["GM_unregisterMenuCommand"], }) - CAT_unregisterMenuInput(...args: Parameters): void { + public CAT_unregisterMenuInput(...args: Parameters): void { this.GM_unregisterMenuCommand(...args); } @GMContext.API() - CAT_userConfig() { + public CAT_userConfig() { return this.sendMessage("CAT_userConfig", []); } @GMContext.API({ - depend: ["CAT_fetchBlob", "CAT_createBlobUrl"], + depend: ["CAT_fetchBlob"], }) - async CAT_fileStorage(action: "list" | "download" | "upload" | "delete" | "config", details: any) { + public async CAT_fileStorage(action: "list" | "download" | "upload" | "delete" | "config", details: any) { if (action === "config") { this.sendMessage("CAT_fileStorage", ["config"]); return; @@ -790,16 +856,14 @@ export default class GMApi extends GM_Base { } // 用于脚本跨域请求,需要@connect domain指定允许的域名 - @GMContext.API({ - depend: ["CAT_fetchBlob", "CAT_createBlobUrl", "CAT_fetchDocument"], - }) + @GMContext.API() public GM_xmlhttpRequest(details: GMTypes.XHRDetails) { const { abort } = GM_xmlhttpRequest(this, details, false); return { abort }; } - @GMContext.API({ depend: ["CAT_fetchBlob", "CAT_createBlobUrl", "CAT_fetchDocument"] }) - public ["GM.xmlHttpRequest"](details: GMTypes.XHRDetails): Promise & GMRequestHandle { + @GMContext.API() + public "GM.xmlHttpRequest"(details: GMTypes.XHRDetails): Promise & GMRequestHandle { const { retPromise, abort } = GM_xmlhttpRequest(this, details, true); const ret = retPromise as Promise & GMRequestHandle; ret.abort = abort; @@ -813,7 +877,6 @@ export default class GMApi extends GM_Base { * native: 后台xhr下载 -> 后台chrome.download API,disabled: 禁止下载,browser: 后台chrome.download API * */ - @GMContext.API({ alias: "GM.download" }) static _GM_download(a: GMApi, details: GMTypes.DownloadDetails, requirePromise: boolean) { if (a.isInvalidContext()) { return { @@ -1019,7 +1082,7 @@ export default class GMApi extends GM_Base { } @GMContext.API() - public ["GM.download"](arg1: GMTypes.DownloadDetails | string, arg2?: string) { + public "GM.download"(arg1: GMTypes.DownloadDetails | string, arg2?: string) { const details = typeof arg1 === "string" ? { url: arg1, name: arg2 } : { ...arg1 }; const { retPromise, abort } = _GM_download(this, details as GMTypes.DownloadDetails, true); const ret = retPromise as Promise & GMRequestHandle; @@ -1027,16 +1090,13 @@ export default class GMApi extends GM_Base { return ret; } - @GMContext.API({ - depend: ["GM_closeNotification", "GM_updateNotification"], - alias: "GM.notification", - }) - public async GM_notification( + @GMContext.API() + public async "GM.notification"( detail: GMTypes.NotificationDetails | string, ondone?: GMTypes.NotificationOnDone | string, image?: string, onclick?: GMTypes.NotificationOnClick - ) { + ): Promise { if (this.isInvalidContext()) return; const notificationTagMap: Map = this.notificationTagMap || (this.notificationTagMap = new Map()); this.eventId += 1; @@ -1149,17 +1209,31 @@ export default class GMApi extends GM_Base { }); } + @GMContext.API({ + depend: ["GM.notification"], + }) + public GM_notification( + detail: GMTypes.NotificationDetails | string, + ondone?: GMTypes.NotificationOnDone | string, + image?: string, + onclick?: GMTypes.NotificationOnClick + ): void { + this["GM.notification"](detail, ondone, image, onclick); + } + + // ScriptCat 額外API @GMContext.API({ alias: "GM.closeNotification" }) public GM_closeNotification(id: string): void { this.sendMessage("GM_closeNotification", [id]); } + // ScriptCat 額外API @GMContext.API({ alias: "GM.updateNotification" }) public GM_updateNotification(id: string, details: GMTypes.NotificationDetails): void { this.sendMessage("GM_updateNotification", [id, details]); } - @GMContext.API({ depend: ["GM_closeInTab"], alias: "GM.openInTab" }) + @GMContext.API({ depend: ["GM_closeInTab"] }) public GM_openInTab(url: string, param?: GMTypes.OpenTabOptions | boolean): GMTypes.Tab | undefined { if (this.isInvalidContext()) return undefined; let option = {} as GMTypes.OpenTabOptions; @@ -1223,6 +1297,15 @@ export default class GMApi extends GM_Base { return ret; } + @GMContext.API({ depend: ["GM_openInTab", "GM_closeInTab"] }) + public "GM.openInTab"(url: string, param?: GMTypes.OpenTabOptions | boolean): Promise { + return new Promise((resolve) => { + const ret = this.GM_openInTab(url, param); + resolve(ret); + }); + } + + // ScriptCat 額外API @GMContext.API({ alias: "GM.closeInTab" }) public GM_closeInTab(tabid: string) { if (this.isInvalidContext()) return; @@ -1230,50 +1313,58 @@ export default class GMApi extends GM_Base { } @GMContext.API() - GM_getTab(callback: (data: any) => void) { + public GM_getTab(callback: (tabData: object) => void) { if (this.isInvalidContext()) return; - this.sendMessage("GM_getTab", []).then((data) => { - callback(data ?? {}); + this.sendMessage("GM_getTab", []).then((tabData) => { + callback(tabData ?? {}); }); } @GMContext.API({ depend: ["GM_getTab"] }) - public ["GM.getTab"](): Promise { - return new Promise((resolve) => { + public "GM.getTab"(): Promise { + return new Promise((resolve) => { this.GM_getTab((data) => { resolve(data); }); }); } - @GMContext.API({ alias: "GM.saveTab" }) - GM_saveTab(obj: object) { + @GMContext.API() + public GM_saveTab(tabData: object): void { if (this.isInvalidContext()) return; - if (typeof obj === "object") { - obj = JSON.parse(JSON.stringify(obj)); + if (typeof tabData === "object") { + tabData = JSON.parse(JSON.stringify(tabData)); } - this.sendMessage("GM_saveTab", [obj]); + this.sendMessage("GM_saveTab", [tabData]); + } + + @GMContext.API({ depend: ["GM_saveTab"] }) + public "GM.saveTab"(tabData: object): Promise { + return new Promise((resolve) => { + this.GM_saveTab(tabData); + resolve(); + }); } @GMContext.API() - GM_getTabs(callback: (objs: { [key: string | number]: object }) => any) { + public GM_getTabs(callback: (tabsData: { [key: number]: object }) => any) { if (this.isInvalidContext()) return; - this.sendMessage("GM_getTabs", []).then((resp) => { - callback(resp); + this.sendMessage("GM_getTabs", []).then((tabsData) => { + callback(tabsData); }); } @GMContext.API({ depend: ["GM_getTabs"] }) - public ["GM.getTabs"](): Promise<{ [key: string | number]: object }> { - return new Promise<{ [key: string | number]: object }>((resolve) => { - this.GM_getTabs((data) => { - resolve(data); + public "GM.getTabs"(): Promise<{ [key: number]: object }> { + return new Promise<{ [key: number]: object }>((resolve) => { + this.GM_getTabs((tabsData) => { + resolve(tabsData); }); }); } - @GMContext.API({}) - GM_setClipboard(data: string, info?: GMTypes.GMClipboardInfo, cb?: () => void) { + @GMContext.API() + public GM_setClipboard(data: string, info?: GMTypes.GMClipboardInfo, cb?: () => void) { if (this.isInvalidContext()) return; this.sendMessage("GM_setClipboard", [data, info]) .then(() => { @@ -1289,13 +1380,13 @@ export default class GMApi extends GM_Base { } @GMContext.API({ depend: ["GM_setClipboard"] }) - ["GM.setClipboard"](data: string, info?: string | { type?: string; mimetype?: string }): Promise { + public "GM.setClipboard"(data: string, info?: string | { type?: string; mimetype?: string }): Promise { if (this.isInvalidContext()) return new Promise(() => {}); return this.sendMessage("GM_setClipboard", [data, info]); } @GMContext.API() - GM_getResourceText(name: string): string | undefined { + public GM_getResourceText(name: string): string | undefined { const r = this.scriptRes?.resource?.[name]; if (r) { return r.content; @@ -1304,7 +1395,7 @@ export default class GMApi extends GM_Base { } @GMContext.API({ depend: ["GM_getResourceText"] }) - public ["GM.getResourceText"](name: string): Promise { + public "GM.getResourceText"(name: string): Promise { // Asynchronous wrapper for GM_getResourceText to support GM.getResourceText return new Promise((resolve) => { const ret = this.GM_getResourceText(name); @@ -1313,7 +1404,7 @@ export default class GMApi extends GM_Base { } @GMContext.API() - GM_getResourceURL(name: string, isBlobUrl?: boolean): string | undefined { + public GM_getResourceURL(name: string, isBlobUrl?: boolean): string | undefined { const r = this.scriptRes?.resource?.[name]; if (r) { let base64 = r.base64; @@ -1331,7 +1422,7 @@ export default class GMApi extends GM_Base { // GM_getResourceURL的异步版本,用来兼容GM.getResourceUrl @GMContext.API({ depend: ["GM_getResourceURL"] }) - public ["GM.getResourceUrl"](name: string, isBlobUrl?: boolean): Promise { + public "GM.getResourceUrl"(name: string, isBlobUrl?: boolean): Promise { // Asynchronous wrapper for GM_getResourceURL to support GM.getResourceURL return new Promise((resolve) => { const ret = this.GM_getResourceURL(name, isBlobUrl); @@ -1340,12 +1431,12 @@ export default class GMApi extends GM_Base { } @GMContext.API() - ["window.close"]() { + public "window.close"() { return this.sendMessage("window.close", []); } @GMContext.API() - ["window.focus"]() { + public "window.focus"() { return this.sendMessage("window.focus", []); } @@ -1353,7 +1444,7 @@ export default class GMApi extends GM_Base { apiLoadPromise: Promise | undefined; @GMContext.API() - CAT_scriptLoaded() { + public CAT_scriptLoaded() { return this.loadScriptPromise; } } diff --git a/src/app/service/service_worker/gm_api/gm_api.ts b/src/app/service/service_worker/gm_api/gm_api.ts index 2c89c0927..f0c861815 100644 --- a/src/app/service/service_worker/gm_api/gm_api.ts +++ b/src/app/service/service_worker/gm_api/gm_api.ts @@ -1034,7 +1034,9 @@ export default class GMApi { }); } - @PermissionVerify.API({}) + @PermissionVerify.API({ + link: ["GM_closeNotification", "GM_updateNotification"], + }) async GM_notification(request: GMApiRequest<[GMTypes.NotificationDetails, string | undefined]>, sender: IGetSender) { const details: GMTypes.NotificationDetails = request.params[0]; const notificationId: string | undefined = request.params[1]; @@ -1120,7 +1122,7 @@ export default class GMApi { } @PermissionVerify.API({ - link: ["GM_notification"], + link: ["GM_notification", "GM_updateNotification"], }) GM_closeNotification(request: GMApiRequest<[string]>, _sender: IGetSender) { const notificationId = request.params[0]; @@ -1132,7 +1134,7 @@ export default class GMApi { } @PermissionVerify.API({ - link: ["GM_notification"], + link: ["GM_notification", "GM_closeNotification"], }) GM_updateNotification(request: GMApiRequest<[string, GMTypes.NotificationDetails]>, _sender: IGetSender) { if (typeof chrome.notifications?.update !== "function") {