TBD
-
-
Save mixedpuppy/0a256a6a17238f0bb3b7ffa6fbb564d1 to your computer and use it in GitHub Desktop.
A fiction example webextension (used to design a new userScripts WE API)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const userScriptAPIs = { | |
// GM_something -> name of the API method injected in the sandbox | |
// args -> arguments of the API call | |
// userScriptSandboxAPI -> an API object which provides the metadata of the userScript caller | |
// and expose other helper methods. | |
async GM_something([param1, cb], userScript) { | |
if (!validateGMSomethingArgs([param1, cb])) { | |
// Throws an error (converted by a wrapper implemented internally | |
// into an valid rejection Error instance for the caller sandbox). | |
throw new Error("..."); | |
} | |
const result = await userScript.parent.GM_something(param1); | |
cb(result); | |
}, | |
async GM_something_else(args, userScriptName) { | |
const data = await browser.storage.local.get(userScriptName); | |
return doSomethingElseWith(data, args) | |
}, | |
... | |
}; | |
// This method (only available into the content scripts if the userScripts permission | |
// has been asked by the extension) is called when a userScript is going to | |
// be executed in its newly created sandbox and allows the extension to register a set of | |
// custom API methods into it. | |
browser.userScripts.onUserScript((userScript) => { | |
if (!userScript.metadata.grants) { | |
// no userScript API to grant to this userScript. | |
return; | |
} | |
for (const grant of userScript.metadata.grants) { | |
userScript.registerAPI(GM_something); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Map<name: string -> {source: string, apiOptions: object, metadata: object, script: RegisteredUserScript}> | |
const userScrips: new Map(); | |
// RegisteredContentScript | |
let apiContentScript; | |
// This would be a custom function implemented by the extension, | |
// which would parse the user script source and extract its | |
// metadata (e.g. name, grants etc.) | |
// and the apiOptions (url pattern to match, when it should run ext.) | |
function parseUserScript(source) { | |
... // parse source header for userScript name and options | |
return {metadata, apiOptions}; | |
} | |
const parentAPI = { | |
async GM_something([param1], userScript) { | |
// May check userScript.metadata to affect the result. | |
const result = // ... | |
const result = await somethingAsync(args); | |
return result; | |
} | |
}; | |
async fuction registerUserScript(userScriptSource) { | |
if (!apiContentScript) { | |
// Lazily register the content script which will provide the | |
// custom APIs to the userScript sandboxes. | |
apiContentScript = await browser.contentScripts.register({ | |
file: "apiContentScript.js", | |
matches: ["<all_urls>"], | |
runAt: "document_start", | |
}); | |
} | |
// parse the script source and return the userScript | |
// name (used as the key in the map) and its options | |
// (e.g. matches url pattern, include/exclude pattern, runAt | |
// etc.) | |
const {metadata, apiOptions} = parseUserScript(userScriptSource); | |
userScripts.set(metadata.name, {source: userScriptSource, apiOptions, metadata}); | |
const userScript = await browser.userScripts.register({ | |
...apiOptions, // Used by the API to know which urls to match etc. | |
code: source, // Used by the API to know which source to execute in the userScript sandbox | |
metadata: metadata, // A serializable metadata object which is received by the userScripts API method | |
// implementation (provided by the extension from the registered content script). | |
parentAPI: parentAPI // An optional parameter which can be used to specify a set of userScripts API method | |
// that have to be executed in a regular extension page (vs. being executed in the | |
// contentScript context as the apiContentScript) | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"manifest_version": 2, | |
"name": "example-userscript-manager", | |
"version": "2.0", | |
"background": { | |
"scripts": ["background.js"] | |
}, | |
"permissions": ["userScripts", "<all_urls>", "..."] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment