"use strict"; this.runtime = class extends ExtensionAPI { getAPI(context) { let { extension } = context; return { runtime: { onConnect: context.messenger.onConnect("runtime.onConnect"), onMessage: context.messenger.onMessage("runtime.onMessage"), onConnectExternal: context.messenger.onConnectExternal( "runtime.onConnectExternal" ), onMessageExternal: context.messenger.onMessageExternal( "runtime.onMessageExternal" ), connect: function(extensionId, connectInfo) { let name = (connectInfo !== null && connectInfo.name) || ""; extensionId = extensionId || extension.id; let recipient = { extensionId }; return context.messenger.connect( context.messageManager, name, recipient ); }, sendMessage(...args) { let extensionId, message, options, responseCallback; if (typeof args[args.length - 1] === "function") { responseCallback = args.pop(); } function checkOptions(options) { if (typeof options !== "object") { return [ false, "runtime.sendMessage's options argument is invalid", ]; } for (let key of Object.keys(options)) { return [false, `Unexpected property ${key}`]; } return [true, {}]; } if (!args.length) { return Promise.reject({ message: "runtime.sendMessage's message argument is missing", }); } else if (args.length === 1) { message = args[0]; } else if (args.length === 2) { // With two optional arguments, this is the ambiguous case, // particularly sendMessage("string", {} or null) // Given that sending a message within the extension is generally // more common than sending the empty object to another extension, // we prefer that conclusion, as long as the second argument looks // like valid options object, or is null/undefined. let [validOpts] = checkOptions(args[1]); if (validOpts || args[1] == null) { [message, options] = args; } else { [extensionId, message] = args; } } else if ( args.length === 3 || (args.length === 4 && args[3] == null) ) { [extensionId, message, options] = args; } else if (args.length === 4 && !responseCallback) { return Promise.reject({ message: "runtime.sendMessage's last argument is not a function", }); } else { return Promise.reject({ message: "runtime.sendMessage received too many arguments", }); } if (extensionId != null && typeof extensionId !== "string") { return Promise.reject({ message: "runtime.sendMessage's extensionId argument is invalid", }); } extensionId = extensionId || extension.id; let recipient = { extensionId }; if (options != null) { let [valid, arg] = checkOptions(options); if (!valid) { return Promise.reject({ message: arg }); } Object.assign(recipient, arg); } return context.messenger.sendMessage( context.messageManager, message, recipient, responseCallback ); }, connectNative(application) { let recipient = { childId: context.childManager.id, toNativeApp: application, }; return context.messenger.connectNative( context.messageManager, "", recipient ); }, sendNativeMessage(application, message) { let recipient = { childId: context.childManager.id, toNativeApp: application, }; return context.messenger.sendNativeMessage( context.messageManager, message, recipient ); }, get lastError() { return context.lastError; }, getManifest() { return Cu.cloneInto(extension.manifest, context.cloneScope); }, id: extension.id, getURL: function(url) { return extension.baseURI.resolve(url); }, }, }; } };