"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const ipc_renderer_internal_1 = require("@electron/internal/renderer/ipc-renderer-internal"); const ipcRendererUtils = require("@electron/internal/renderer/ipc-renderer-internal-utils"); const url = require("url"); // Todo: Import once extensions have been turned into TypeScript const Event = require('@electron/internal/renderer/extensions/event'); class Tab { constructor(tabId) { this.id = tabId; } } class MessageSender { constructor(tabId, extensionId) { this.tab = tabId ? new Tab(tabId) : null; this.id = extensionId; this.url = `chrome-extension://${extensionId}`; } } class Port { constructor(tabId, portId, extensionId, name) { this.tabId = tabId; this.portId = portId; this.name = name; this.disconnected = false; this.onDisconnect = new Event(); this.onMessage = new Event(); this.onDisconnect = new Event(); this.onMessage = new Event(); this.sender = new MessageSender(tabId, extensionId); ipc_renderer_internal_1.ipcRendererInternal.once(`CHROME_PORT_DISCONNECT_${portId}`, () => { this._onDisconnect(); }); ipc_renderer_internal_1.ipcRendererInternal.on(`CHROME_PORT_POSTMESSAGE_${portId}`, (_event, message) => { const sendResponse = function () { console.error('sendResponse is not implemented'); }; this.onMessage.emit(JSON.parse(message), this.sender, sendResponse); }); } disconnect() { if (this.disconnected) return; ipc_renderer_internal_1.ipcRendererInternal.sendToAll(this.tabId, `CHROME_PORT_DISCONNECT_${this.portId}`); this._onDisconnect(); } postMessage(message) { ipc_renderer_internal_1.ipcRendererInternal.sendToAll(this.tabId, `CHROME_PORT_POSTMESSAGE_${this.portId}`, JSON.stringify(message)); } _onDisconnect() { this.disconnected = true; ipc_renderer_internal_1.ipcRendererInternal.removeAllListeners(`CHROME_PORT_POSTMESSAGE_${this.portId}`); this.onDisconnect.emit(); } } // Inject chrome API to the |context| function injectTo(extensionId, context) { const chrome = context.chrome = context.chrome || {}; ipc_renderer_internal_1.ipcRendererInternal.on(`CHROME_RUNTIME_ONCONNECT_${extensionId}`, (_event, tabId, portId, connectInfo) => { chrome.runtime.onConnect.emit(new Port(tabId, portId, extensionId, connectInfo.name)); }); ipcRendererUtils.handle(`CHROME_RUNTIME_ONMESSAGE_${extensionId}`, (_event, tabId, message) => { return new Promise(resolve => { chrome.runtime.onMessage.emit(message, new MessageSender(tabId, extensionId), resolve); }); }); ipc_renderer_internal_1.ipcRendererInternal.on('CHROME_TABS_ONCREATED', (_event, tabId) => { chrome.tabs.onCreated.emit(new Tab(tabId)); }); ipc_renderer_internal_1.ipcRendererInternal.on('CHROME_TABS_ONREMOVED', (_event, tabId) => { chrome.tabs.onRemoved.emit(tabId); }); chrome.runtime = { id: extensionId, // https://developer.chrome.com/extensions/runtime#method-getURL getURL: function (path) { return url.format({ protocol: 'chrome-extension', slashes: true, hostname: extensionId, pathname: path }); }, // https://developer.chrome.com/extensions/runtime#method-getManifest getManifest: function () { const manifest = ipcRendererUtils.invokeSync('CHROME_EXTENSION_MANIFEST', extensionId); return manifest; }, // https://developer.chrome.com/extensions/runtime#method-connect connect(...args) { // Parse the optional args. let targetExtensionId = extensionId; let connectInfo = { name: '' }; if (args.length === 1) { connectInfo = args[0]; } else if (args.length === 2) { [targetExtensionId, connectInfo] = args; } const { tabId, portId } = ipcRendererUtils.invokeSync('CHROME_RUNTIME_CONNECT', targetExtensionId, connectInfo); return new Port(tabId, portId, extensionId, connectInfo.name); }, // https://developer.chrome.com/extensions/runtime#method-sendMessage sendMessage(...args) { // Parse the optional args. const targetExtensionId = extensionId; let message; let options; let responseCallback = () => { }; if (typeof args[args.length - 1] === 'function') { responseCallback = args.pop(); } if (args.length === 1) { [message] = args; } else if (args.length === 2) { if (typeof args[0] === 'string') { [extensionId, message] = args; } else { [message, options] = args; } } else { [extensionId, message, options] = args; } if (options) { console.error('options are not supported'); } ipcRendererUtils.invoke('CHROME_RUNTIME_SEND_MESSAGE', targetExtensionId, message).then(responseCallback); }, onConnect: new Event(), onMessage: new Event(), onInstalled: new Event() }; chrome.tabs = { // https://developer.chrome.com/extensions/tabs#method-executeScript executeScript(tabId, details, resultCallback = () => { }) { ipcRendererUtils.invoke('CHROME_TABS_EXECUTE_SCRIPT', tabId, extensionId, details) .then((result) => resultCallback([result])); }, // https://developer.chrome.com/extensions/tabs#method-sendMessage sendMessage(tabId, message, _options, responseCallback = () => { }) { ipcRendererUtils.invoke('CHROME_TABS_SEND_MESSAGE', tabId, extensionId, message).then(responseCallback); }, onUpdated: new Event(), onCreated: new Event(), onRemoved: new Event() }; chrome.extension = { getURL: chrome.runtime.getURL, connect: chrome.runtime.connect, onConnect: chrome.runtime.onConnect, sendMessage: chrome.runtime.sendMessage, onMessage: chrome.runtime.onMessage }; chrome.storage = require('@electron/internal/renderer/extensions/storage').setup(extensionId); chrome.pageAction = { show() { }, hide() { }, setTitle() { }, getTitle() { }, setIcon() { }, setPopup() { }, getPopup() { } }; chrome.i18n = require('@electron/internal/renderer/extensions/i18n').setup(extensionId); chrome.webNavigation = require('@electron/internal/renderer/extensions/web-navigation').setup(); // Electron has no concept of a browserAction but we should stub these APIs for compatibility chrome.browserAction = { setIcon() { }, setPopup() { } }; } exports.injectTo = injectTo;