erosman / support

Support Location for all my extensions
Mozilla Public License 2.0
174 stars 12 forks source link

[FireMonkey] Userscript Compatibility #429

Closed erosman closed 1 year ago

erosman commented 2 years ago

FireMonkey 2.44 should be compatible with 98% of userscripts. Please read Help for more information.

Please post any userscript issues here for further investigation.

erosman commented 2 years ago

SyntaxError: return not in function

ESLint already displays the parse error for above.

JSHint currently doesn't display the error, as posted to JavaScript: Mark return out of function.

erosman commented 2 years ago

v2.54 Added new function to wrap code in IIFE (Immediately Invoked Function Expression) to help with above.

I will see if it is possible to automate it. :thinking:

Ghost-BD commented 2 years ago

Opera Browser Rocker+Mouse Gestures + Search HighLight still does not work without changes. Same as before.

erosman commented 2 years ago

Opera Browser Rocker+Mouse Gestures + Search HighLight still does not work without changes. Same as before.

re: https://greasyfork.org/en/scripts/419825-opera-browser-rocker-mouse-gestures-search-highlight Right now, I tested standard version 50 of the userscript with above and it was working. Please note that in FM v2.53 fetch/XHR are mapped to the webpage fetch/XHR and might be affected by webpage CSP. GM.fetch is not affected by CSP.

Ghost-BD commented 2 years ago

Checked again, works perfectly now. Sorry for misinformation, but somehow didn't worked first time. Does FM v2.53 run other scripts affected with CORS restriction work without additional fix (like return youtube dislike)?

erosman commented 2 years ago

Does FM v2.53 run other scripts affected with CORS restriction work without additional fix (like return youtube dislike)?

FM 2.53 only mapped fetch & XMLHttpRequest to page window as a workaround for Bug 1715249 until the bug is fixed.

The issue of CSP affects all userscript managers (FM|GM|VM) and all addons, except TM which alters page CSP, despite being against Mozilla Add-on Policies (and may be stopped at anytime).

Add-on Policies "Add-ons must not relax web page security headers, such as the Content Security Policy."

See Also: FireMonkey Help under @inject-into

erosman commented 2 years ago

Also, you said to consider UserCSS custom settings if there is a https://github.com/erosman/support/issues/293, then consider me as one.

v2.56

Ghost-BD commented 2 years ago

After last update, Opera Browser Rocker+Mouse Gestures + Search HighLight is not working at all.

Added experimental @var support for userScript & userCSS

Happy to hear.

erosman commented 2 years ago

After last update, Opera Browser Rocker+Mouse Gestures + Search HighLight is not working at all.

The fetch works fine. It seems the userscript needs to be updated.

TypeError: can't access property "innerText", newDocument.querySelector(...) is null
line 334

Opera Browser Rocker

Ghost-BD commented 2 years ago

Maybe. But, this same script worked just fine before in FM and still works with VM & TM. Also there is a different error in browser console at my side. Error: Return value not accessible to the userScript.

error report 8th may Again, this time the script does not work at all. I have very limited knowledge about this and hope to make the issue clear to you. Thanks.

erosman commented 2 years ago

Error: Return value not accessible to the userScript.

That one ...... I also saw it today and I have already fixed it in v2.56.
Which Firefox are you using? It was strange that it wasn't there before. It is related the GM_getValue and the sync workaround that I did back in v2.43. Above script uses GM_getValue so, that is true.. the script will break. There was no error until now. :man_shrugging:

Please wait for v2.56. I am working on the @var and although it is finished, I am still testing.

Ghost-BD commented 2 years ago

Firefox stable v100.

It is related the GM_getValue and the sync workaround that I did back in v2.43.

That is weird considering relevant time frame of the issue.

Above script uses GM_getValue so, that is true.. the script will break.

In that case, take your time. Thanks.

erosman commented 2 years ago

v2.56 uploaded... let me know

BTW... the text of the error from https://github.com/erosman/support/issues/429#issuecomment-1120445482

Google is blocking their IP 205.185.114.247 s1.allorigins.win

URL: https://api.allorigins.win/get?url=https://www.google.com/search?q=120.37%20GBP%20in%20CAD

About this page

Our systems have detected unusual traffic from your computer network. This page checks to see if it's really you sending the requests, and not a robot. [Why did this happen?]

This page appears when Google automatically detects requests coming from your computer network which appear to be in violation of the [Terms of Service]. The block will expire shortly after those requests stop. In the meantime, solving the above CAPTCHA will let you continue to use our services.

This traffic may have been sent by malicious software, a browser plug-in, or a script that sends automated requests. If you share your network connection, ask your administrator for help — a different computer using the same IP address may be responsible. [Learn more]

Sometimes you may be asked to solve the CAPTCHA if you are using advanced terms that robots are known to use, or sending requests very quickly. IP address: 205.185.114.247 Time: 2022-05-09T08:05:22Z URL: https://www.google.com/search?q=120.37%20GBP%20in%20CAD

Ghost-BD commented 2 years ago

Previous issue fixed with v2.56.

Google is blocking their IP 205.185.114.247 s1.allorigins.win

CAPTCHA caught real bot this time😆.

It seems the userscript needs to be updated.

As currency convert functionality now bugged in TM & VM too he might or maybe wait for ban to alleviate.

Thanks for @var support in FM.

r-a-y commented 2 years ago

For this userscript, https://greasyfork.org/en/scripts/374833-yt2invidio, the GM_registerMenuCommand doesn't appear to render the script command options in FM. It works with Violentmonkey though.

Is it due to the script using async for the GM_registerMenuCommand callback?

erosman commented 2 years ago

For this userscript, https://greasyfork.org/en/scripts/374833-yt2invidio, the GM_registerMenuCommand doesn't appear to render the script command options in FM. It works with Violentmonkey though.

Is it due to the script using async for the GM_registerMenuCommand callback?

async should not have a bearing here as it affects the result of the function.

Test

VM by default injects into page context and also provides GM API there (unlike FM|TM). Try setting the injection to content in VM and see if the script works as before. If it doesn't, then that is the issue and a unique behavior of VM.

You can also try it in TM and see how it works as TM would inject it in content context in this case.

Notes

Script declares these but not use it:

// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_openInTab
// @grant       unsafeWindow

The following is ignored in FM as it is not needed:

// @require     https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
r-a-y commented 2 years ago

Try setting the injection to content in VM and see if the script works as before. If it doesn't, then that is the issue and a unique behavior of VM.

You can also try it in TM and see how it works as TM would inject it in content context in this case.

The script commands for the userscript I mentioned works on both Violentmonkey and Tampermonkey, which means that only FireMonkey is exhibiting problems.

Have you tested the script yourself to see if the script commands show up in FireMonkey?

I also tried a couple of other userscripts that use GM.registerMenuCommand just now and the script commands also do not show up in FM. Try with: https://greasyfork.org/en/scripts/20771-stig-s-art-grabr (this one also uses a polyfill) or https://greasyfork.org/en/scripts/394820-mouseover-popup-image-viewer

erosman commented 2 years ago

Have you tested the script yourself to see if the script commands show up in FireMonkey?

They do. 170546232-7c7ced76-78a5-4ea0-ad51-31fbf12a780d2

r-a-y commented 2 years ago

Hmm, I'm wondering why the script commands are not showing up for me. I'm using FM 2.56 , FF 100.0.2.

erosman commented 2 years ago

Hmm, I'm wondering why the script commands are not showing up for me. I'm using FM 2.56 , FF 100.0.2.

I tested it on this page, FF Nightly 102.0a1

cyfung1031 commented 2 years ago

https://greasyfork.org/en/scripts/428651-tabview-youtube The userscript is not working in FireMonkey v2.45.

At first glance, I don't see any issues. The script to too large and has large minified @require to debug properly.

If the developer points out the issue, I will see what can be done.

PS. I posted to Return YouTube Dislike with the code but there is no response so far.

@erosman Hi, I am the author of Tabview Youtube.

I checked the script was stopped when it wants to get the deref from the WeakRef for the page dom. This bug stopped without any error message and not a documented behavior in official document. This should be a bug in FireMonkey.

I tried following to see what happen but in vain. It just stopped.

      const WeakRef = window.WeakRef;
      const mWeakRef = WeakRef ? (o => o ? new WeakRef(o) : null) : (o => o || null);
      const kRef = (wr => (wr && wr.deref) ? wr.deref() : wr);

      console.log(977)
      let mzz={hi:123};
      console.log(978, mzz)
      let nzz=mWeakRef(mzz);
      console.log(988, nzz, kRef(nzz))

I use Firefox 91 ESR. After showing "977" and "978", the script stopped and no display of "988".

Update: After using try catch, "Error: Permission denied to access object" is shown.

image

// ==UserScript==
// @name test01
// @version          1.0
// @include     https://github.com/erosman/support/issues/429
// ==/UserScript==

try{

      const WeakRef = window.WeakRef;
      const mWeakRef = WeakRef ? (o => o ? new WeakRef(o) : null) : (o => o || null);
      const kRef = (wr => (wr && wr.deref) ? wr.deref() : wr);

      console.log(977)
      let mzz={hi:123};
      console.log(978, mzz)
      let nzz=mWeakRef(mzz);
      console.log(988, nzz, kRef(nzz))

}catch(e){
  console.log(e)
}
cyfung1031 commented 2 years ago

another userscript with Compatibility Issue https://greasyfork.org/en/scripts/427575

The following error is shown TypeError: 'getComputedStyle' called on an object that does not implement interface Window.

This script runs normally in other userscript managers.

=====================================

another userscript with Compatibility Issue https://greasyfork.org/en/scripts/433908

GM_registerMenuCommand is not working

update in 2022/07/31

getComputedStyle can be solved be const getComputedStyle = window.getComputedStyle.bind(window)

erosman commented 2 years ago

@cyfung1031 Thank you for testing the issue.

I am traveling and not at my usual set-up. Looking at your post, it appears to be the issue of X-ray Vision & contexts. It is possible that the new in new WeakRef(o) is breaking the sample code but requires verification.

FireMonkey injects into an isolated userScripts context which is not the same as contentScript context, which is meant for extension's privileged code, but used by GM|TM|VM to inject userscripts.

window in this context is NOT the window of the webpage.

Userscript can use unsafeWindow or window.wrappedJSObject to access page context window.

There are other considerations:

There is also CSP issue. TM is the only userscript manager that alters webpage CSP which can play a part in userscript compatibility.

How is the script working with other userscript managers?

AFA Tabview Youtube, there is also the sync GM_getResourceText which in FireMonkey is supported for CSS but not JS, JSON, etc.

erosman commented 2 years ago

another userscript with Compatibility Issue https://greasyfork.org/en/scripts/427575

The following error is shown TypeError: 'getComputedStyle' called on an object that does not implement interface Window.

My guess would be a similar issue of window in userScript context.

another userscript with Compatibility Issue https://greasyfork.org/en/scripts/433908

GM_registerMenuCommand is not working

The menus show. Do you mean it doesn't function? Are there any errors?

cyfung1031 commented 2 years ago

I understand the difference between unsafeWindow and window. even for the DOM element, if the data is set by property, userscript cannot access them.

but for getComputedStyle, WeakRef, these functions/classes shall be accessible from the window object in general userscript. using window.WeakRef is because WeakRef might be not defined in old browser, and window.WeakRef will be either a class function or undefined. for getComputedStyle, it can be called in ViolentMonkey and TamperMonkey but not in FireMonkey. This is weird.

Why FireMonkey does not support GM_getResourceText for JS or other filetypes? GM_getResourceText should be just getting the content text of the plain text file instead of trying to see whether it is JS/CSS/other file.

erosman commented 2 years ago

for getComputedStyle, it can be called in ViolentMonkey and TamperMonkey but not in FireMonkey. This is weird.

getComputedStyle is actually Window.getComputedStyle(). userScripts context is isolated & window is not the same as webpage window. GM|TM|VM do not use the secure & isolated 'userScriptscontext and use the common 'contentScripts context which has the same window as the webpage window. (please read FM help under @ inject-into & Xray Vision & Sharing objects with page scripts for more information)

Why FireMonkey does not support GM_getResourceText for JS or other filetypes? GM_getResourceText should be just getting the content text of the plain text file instead of trying to see whether it is JS/CSS/other file.

Since Firefox 57, all fetch|XHR and many other operations are asynchronous. FireMonkey & GM support async GM.getResourceText. The sync GM_getResourceText as well as many other sync GM API in TM|VM are workarounds. There is no true method to get storage or remote data synchronously.

They fetch GM_getResourceText asynchronously and store it at the cost of increased storage and read/write operation (CPU & RAM usage). Many userscripts use many @resource that are many MBs of data, some of which are not even used or used conditionally.

Userscripts have been advised to use async GM. API but due to TM|VM workarounds, they continue to use the pre-Firefox 57 GM_ API. (please also read FM Help under Preamble)

Arias800 commented 2 years ago

Hello, The userscript ppixiv doesn't work with FireMonkey. It doesn't work on greasamonkey, but work on violentmonkey.

The error Uncaught Error: Permission denied to access object seem to be related to @connect. But I don't know what trigger the error Error freezing [object HTMLDocument]: TypeError: can't prevent extensions on this proxy object.

erosman commented 2 years ago

@Arias800 I don't think it is related to @connect which is not supported by Violentmonkey. @connect is supported by Tampermonkey.

VM injects userscripts into page by default and also provides GM API. That changes the behavior of the userscript.

To test...

Arias800 commented 2 years ago

I tested with content and the userscript stopped working. So you were right.

I have continued to doing some debugging and I find two issue :



The error `Error freezing [object HTMLDocument]: TypeError: can't prevent extensions on this proxy object` appear with violentmonkey too, and it doesn't seem to be an issue.
erosman commented 2 years ago

I also had a quick look but the script is too large for a quick check.

Add a console.log to test

    encodeHashParams(params)
    {
        console.log(params);
        let values = [];
        for(let key of params.keys())
        {
            let key_values = params.getAll(key);
            for(let value of key_values)
            {
                key = helpers.encodeHashParam(key);
                value = helpers.encodeHashParam(value);
                values.push(key + "=" + value);
            }
        }

        return values.join("&");
    },
Arias800 commented 2 years ago

I replaced for(let key of params.keys()) with for(let key of Object.keys(params)) and the menu appear.

params is empty, as it is used when loading the artwork. But currently, all json requests fail with Firemonkey. This is probably the only problem left, but I have no idea why this happens.

erosman commented 2 years ago

Are they XHR requests?

Arias800 commented 2 years ago

From what I see, no it's not (I don't have a lot of knowledge in JavaScript).

    send_request: async function(options)
    {
        if(options == null)
            options = {};

        // Usually we'll use helpers.fetch, but fall back on window.fetch in case we haven't
        // called block_network_requests yet.  This happens if main_controller.setup needs
        // to fetch the page.
        let fetch = helpers.fetch || window.fetch;

        let data = { };

        // For Firefox, we need to clone data into the page context.  In Chrome this does nothing.
        if(window.cloneInto)
            data = cloneInto(data, window);

        data.method = options.method || "GET";
        data.signal = options.signal;
        data.cache = options.cache;
        if(options.data)
            data.body = cloneInto(options.data, window); 

        // Convert options.headers to a Headers object.  For Firefox, this has to be
        // unsafeWindow.Headers.
        if(options.headers)
        {
            let headers = new unsafeWindow.Headers();
            for(let key in options.headers)
                headers.append(key, options.headers[key]);
            data.headers = headers;
        }

        try {
            return await fetch(options.url, data);
        } catch(e) {
            // Don't log an error if we were intentionally aborted.
            if(data.signal && data.signal.aborted)
                return null;

            console.error("Error loading %s", options.url, e);
            if(options.data)
                console.error("Data:", options.data);
            return null;
        }
    },
erosman commented 2 years ago

It uses fetch but I dont which context it runs it in. Was there an error? Is there CORS error?

Script developer should be able to answer these.

Arias800 commented 2 years ago

I finally manage to make the requests with GM.xmlHttpRequest. But I think it's possible to be something better.

I will ask the script developer directly. Thank you for your time, I will come back if I ever need more information.

Arias800 commented 2 years ago

Hello, I have talk with the developer of ppixiv. The issue was the injection mode use by Firemonkey. The developer of ppixiv have force the userscript to be injected into page.

So, It's probably something that you can fix on the addon side.

erosman commented 2 years ago

Does the whole script have to be injected into the page? That is not a problem but it wont have any GM API access in FM|TM|GM.

The behavior of VM in this regard does not match other userscript managers as per FireMonkey Help: inject-into.

Arias800 commented 2 years ago

Yes, I think the whole script need to be injected into the page.

I'm currently using the script with // @inject-into page, and I don't have any issue.

The only GM function use on the script, as far as I know, are GM.xmlHttpRequest and GM_xmlhttpRequest, and they seem to work correctly.

// @grant       GM.xmlHttpRequest
// @grant       GM_xmlhttpRequest

EDIT : I have an error with the function name cloneInto. The error is : ReferenceError: cloneInto is not defined I'm currently searching what this function is.

erosman commented 2 years ago

I think that whole script doesn't need to be injected into the page.

cloneInto is not standard JavaScript and only works in the context of an extension (not in a web page).

Script grants GM_getValue & GM_setValue but never uses it.

ppixiv.resources are strings of JS/HTML and they appear to be executed in the page context using eval() (line 38,483) (The code starts from line 38,462-38,562). As per Xray Vision & Sharing objects with page scripts, you can try window.eval instead.

cyfung1031 commented 2 years ago

@cyfung1031 Thank you for testing the issue.

I am traveling and not at my usual set-up. Looking at your post, it appears to be the issue of X-ray Vision & contexts. It is possible that the new in new WeakRef(o) is breaking the sample code but requires verification.

FireMonkey injects into an isolated userScripts context which is not the same as contentScript context, which is meant for extension's privileged code, but used by GM|TM|VM to inject userscripts.

window in this context is NOT the window of the webpage.

Userscript can use unsafeWindow or window.wrappedJSObject to access page context window.

There are other considerations:

  • GM will inject the script in content context
  • VM by default injects the script into page context so the window will be the same as webpage window
  • TM will inject the script in content context (unless @grant none)

There is also CSP issue. TM is the only userscript manager that alters webpage CSP which can play a part in userscript compatibility.

How is the script working with other userscript managers?

AFA Tabview Youtube, there is also the sync GM_getResourceText which in FireMonkey is supported for CSS but not JS, JSON, etc.

I am trying to do something to let my script to run in FireMonkey but in vain. Please help P.S. I found that getComputedStyle can be still using with window.getComputedStyle.bind(window)

Q1

the WeakRef problem is still there.


// ==UserScript==
// @name         test01
// @version     0.1
// @match     https://*/*
// @run-at      document-start
// ==/UserScript==

/* jshint esversion:8 */
try {

    const WeakRef = window.WeakRef;
    const mWeakRef = WeakRef ? (o => o ? new WeakRef(o) : null) : (o => o || null);

    let mzz = {
        hi: 123
    };

    console.log(101, mzz);
    let nzz = mWeakRef(mzz);
    console.log(102, nzz);

} catch (e) {
    console.log(108, e);
}
console.log(103);

cannot execute new WeakRef(o)

image

// ==UserScript==
// @name         test02
// @version     0.1
// @match     https://*/*
// @run-at      document-start
// ==/UserScript==

/* jshint esversion:8 */
try {

    // const WeakRef = window.WeakRef;
    const mWeakRef = WeakRef ? (o => o ? new WeakRef(o) : null) : (o => o || null);

    let mzz = {
        hi: 123
    };

    console.log(101, mzz);
    let nzz = mWeakRef(mzz);
    console.log(102, nzz);

} catch (e) {
    console.log(108, e);
}
console.log(103);

but this can execute new WeakRef(o)

image

I think window.WeakRef shall be same as WeakRef. need backward compatibility so cannot directly call WeakRef. need to check undefined or not using window.WeakRef.

Q2

// ==UserScript==
// @name         test03
// @version     0.1
// @match     https://*/*
// @run-at      document-start
// @grant       GM.getResourceText
// @resource     resource1 https://www.w3schools.com/browserref.css
// ==/UserScript==

/* jshint esversion:8 */

(async function() {

    console.log(101);
    try {
        await GM.getResourceText("resource1");
        console.log(102);
    } catch (e) {
        console.log(108, e);
    }
    console.log(103);

})();

image

the result is this. I don't know why.

for GM_getResourceText with CSS file,

// ==UserScript==
// @name         test04
// @version     0.1
// @match     https://*/*
// @run-at      document-start
// @grant       GM_getResourceText
// @resource     resource1 https://www.w3schools.com/browserref.css
// ==/UserScript==

/* jshint esversion:8 */

(async function() {

    console.log(101);
    try {
        let res = GM_getResourceText("resource1");
        console.log(102, res.length);
    } catch (e) {
        console.log(108, e);
    }
    console.log(103);

})();

the result is wrong

image

==================================

( Firefox 91.12.0esr (64bit), FireMonkey 2.59 )

erosman commented 2 years ago

the WeakRef problem is still there.

window in userScripts context is a limited and different window than the content context. Try unsafeWindow or window.wrappedJSObject to access page context window.

the result is this. I don't know why.

That is bug. When fetch process was updated in FM for container support, I forgot to update GM.getResourceText. :man_facepalming: :pushpin: Fixed for v2.60

for GM_getResourceText with CSS file,

Implementation of GM_getResourceText is different in FireMonkey. CSS will be directly injected into the page.

Read FireMonkey Help ➜ getResourceText

malis2007 commented 2 years ago

https://greasyfork.org/en/scripts/438131-invidious-yewtu-be-embed/code, DDG embedded videos bug was fixed by adding "@allFrames true"

Ghost-BD commented 2 years ago

https://adsbypasser.github.io/ ,https://greasyfork.org/en/scripts/431691-bypass-all-shortlinks can you take a look at those 2 userscripts? A global FM on/off button on toolbar would be helpful.

erosman commented 2 years ago

https://adsbypasser.github.io/ ,https://greasyfork.org/en/scripts/431691-bypass-all-shortlinks can you take a look at those 2 userscripts?

They are very large scripts for having a quick look.

A global FM on/off button on toolbar would be helpful.

Do you mean for all scripts? That would mean many asynchronous operations to unregister one by one and then re-register one by one.

Ghost-BD commented 2 years ago

They are very large scripts for having a quick look.

Take your time. Both are popular useful script work on TM|VM.

Do you mean for all scripts?

Yep. Now have to disable FM from add-ons menu to achieve that.

erosman commented 2 years ago

Yep. Now have to disable FM from add-ons menu to achieve that.

GM|TM|VM work differently in mv2 (mv3 is another story). On/Off can be affected at the time of injection as they manually inject scripts. Lets see if there is a popular demand for it.

Ghost-BD commented 2 years ago

Lets see if there is a popular demand for it.

Don't think this has. As a basic task, if not so basic to implement then just wait for mv3 (not much time left to enforce) would be good. Now if that means that ON/OFF switch would be also difficult for GM|TM|VM then they might have to figure this out. Thanks.

pintassilgo commented 2 years ago

This script doesn't work: https://greasyfork.org/en/scripts/29420-google-dwimages

chocolateboy is a popular UserScripts author (132 stars in GitHub repo), their scripts @require GMCompat which doesn't work with FM:

ReferenceError: unsafeWindow is not defined

https://github.com/chocolateboy/gm-compat

pintassilgo commented 2 years ago

Following last comment, I manually copied the required script (index.iife.min.js), pasted it directly into UserScript code and now it's working. So the issue is probably in FM's @require implementation.

Maybe FM doesn't expose unsafeWindow to @require, but it should...

erosman commented 2 years ago

Maybe FM doesn't expose unsafeWindow to @require, but it should...

You can always check the @require result in Dev Tool. It should show if it is included.

eferenceError: unsafeWindow is not defined

GMCompat.unsafeWindow...... that is not the same as unsafeWindow of GM API.

re: https://unpkg.com/gm-compat@1.1.0/dist/index.iife.min.js

const GMCompat=function(){"use strict";let t=unsafeWindow;const{assign:n,freeze:e}=Object,{wrappedJSObject:o}=t,{slice:c}=[],r={unsafeWindow:o?t=o:t},s={cloneFunctions:!0,target:t,wrapReflectors:!0},i={target:t},p="function"==typeof cloneInto?cloneInto:t=>t,u="function"==typeof exportFunction?exportFunction:(n,{defineAs:e,target:o=t}={})=>e?o[e]=n:n;n(r,{apply(t,n,e){const o=c.call(e);return n.apply(t,this.cloneInto(o))},call(t,n,...e){const o=this.cloneInto(e);return n.call(t,...o)},cloneInto(t,e){const o=e?n({},s,e):s;return p(t,o.target,o)},export(t,n){return"function"==typeof t?this.exportFunction(t,n):this.cloneInto(t,n)},exportFunction(t,e){const o=e?n({},i,e):i;return u(t,o.target,o)},unwrap:t=>t&&t.wrappedJSObject||t});return e(r)}();

GMCompat is defined as function but used as object in the userscript.