Browse Source

chore: update node handlers browser api

Ahmad Kholid 1 year ago
parent
commit
d6dfbc87ca
38 changed files with 331 additions and 246 deletions
  1. 1 0
      jsconfig.json
  2. 4 45
      src/background/index.js
  3. 2 1
      src/content/commandPalette/App.vue
  4. 2 16
      src/popup/pages/Home.vue
  5. 16 1
      src/service/browser-api/BrowserAPIEventHandler.js
  6. 15 0
      src/service/browser-api/BrowserAPIService.js
  7. 67 3
      src/service/browser-api/browser-api-map.js
  8. 13 7
      src/utils/api.js
  9. 2 1
      src/utils/helper.js
  10. 1 2
      src/utils/message.js
  11. 0 3
      src/workflowEngine/BrowserApi.js
  12. 3 3
      src/workflowEngine/WorkflowEngine.js
  13. 20 16
      src/workflowEngine/WorkflowManager.js
  14. 4 3
      src/workflowEngine/WorkflowState.js
  15. 13 12
      src/workflowEngine/blocksHandler/handlerActiveTab.js
  16. 6 6
      src/workflowEngine/blocksHandler/handlerClipboard.js
  17. 10 6
      src/workflowEngine/blocksHandler/handlerCloseTab.js
  18. 6 6
      src/workflowEngine/blocksHandler/handlerCookie.js
  19. 3 5
      src/workflowEngine/blocksHandler/handlerExecuteWorkflow.js
  20. 10 12
      src/workflowEngine/blocksHandler/handlerExportData.js
  21. 2 2
      src/workflowEngine/blocksHandler/handlerForwardPage.js
  22. 2 2
      src/workflowEngine/blocksHandler/handlerGoBack.js
  23. 5 3
      src/workflowEngine/blocksHandler/handlerGoogleDrive.js
  24. 17 14
      src/workflowEngine/blocksHandler/handlerHandleDownload.js
  25. 2 1
      src/workflowEngine/blocksHandler/handlerHoverElement.js
  26. 6 5
      src/workflowEngine/blocksHandler/handlerInteractionBlock.js
  27. 2 2
      src/workflowEngine/blocksHandler/handlerLink.js
  28. 9 9
      src/workflowEngine/blocksHandler/handlerNewTab.js
  29. 4 2
      src/workflowEngine/blocksHandler/handlerNewWindow.js
  30. 4 4
      src/workflowEngine/blocksHandler/handlerNotification.js
  31. 12 12
      src/workflowEngine/blocksHandler/handlerParameterPrompt.js
  32. 10 9
      src/workflowEngine/blocksHandler/handlerProxy.js
  33. 2 2
      src/workflowEngine/blocksHandler/handlerReloadTab.js
  34. 3 3
      src/workflowEngine/blocksHandler/handlerSaveAssets.js
  35. 9 7
      src/workflowEngine/blocksHandler/handlerSwitchTab.js
  36. 3 3
      src/workflowEngine/blocksHandler/handlerTabUrl.js
  37. 24 12
      src/workflowEngine/blocksHandler/handlerTakeScreenshot.js
  38. 17 6
      src/workflowEngine/helper.js

+ 1 - 0
jsconfig.json

@@ -5,6 +5,7 @@
       "@/*": ["src/*"],
       "@/*": ["src/*"],
       "@business": ["business/dev/*"]
       "@business": ["business/dev/*"]
     },
     },
+    "lib": ["ESNext", "DOM"],
     "module": "ESNext",
     "module": "ESNext",
     "target": "ES2020"
     "target": "ES2020"
   },
   },

+ 4 - 45
src/background/index.js

@@ -5,12 +5,14 @@ import getFile, { readFileAsBase64 } from '@/utils/getFile';
 import automa from '@business';
 import automa from '@business';
 import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import BrowserAPIEventHandler from '@/service/browser-api/BrowserAPIEventHandler';
 import BrowserAPIEventHandler from '@/service/browser-api/BrowserAPIEventHandler';
+import { IS_FIREFOX } from '@/common/utils/constant';
 import { registerWorkflowTrigger } from '../utils/workflowTrigger';
 import { registerWorkflowTrigger } from '../utils/workflowTrigger';
 import BackgroundUtils from './BackgroundUtils';
 import BackgroundUtils from './BackgroundUtils';
 import BackgroundWorkflowUtils from './BackgroundWorkflowUtils';
 import BackgroundWorkflowUtils from './BackgroundWorkflowUtils';
 import BackgroundEventsListeners from './BackgroundEventsListeners';
 import BackgroundEventsListeners from './BackgroundEventsListeners';
+import BackgroundOffscreen from './BackgroundOffscreen';
 
 
-const isFirefox = BROWSER_TYPE === 'firefox';
+BackgroundOffscreen.instance.sendMessage('halo');
 
 
 browser.alarms.onAlarm.addListener(BackgroundEventsListeners.onAlarms);
 browser.alarms.onAlarm.addListener(BackgroundEventsListeners.onAlarms);
 
 
@@ -34,7 +36,7 @@ browser.webNavigation.onHistoryStateUpdated.addListener(
   BackgroundEventsListeners.onHistoryStateUpdated
   BackgroundEventsListeners.onHistoryStateUpdated
 );
 );
 
 
-const contextMenu = isFirefox ? browser.menus : browser.contextMenus;
+const contextMenu = IS_FIREFOX ? browser.menus : browser.contextMenus;
 if (contextMenu && contextMenu.onClicked) {
 if (contextMenu && contextMenu.onClicked) {
   contextMenu.onClicked.addListener(
   contextMenu.onClicked.addListener(
     BackgroundEventsListeners.onContextMenuClicked
     BackgroundEventsListeners.onContextMenuClicked
@@ -204,46 +206,3 @@ message.on('workflow:breakpoint', (id) => {
 automa('background', message);
 automa('background', message);
 
 
 browser.runtime.onMessage.addListener(message.listener);
 browser.runtime.onMessage.addListener(message.listener);
-
-// if (!isFirefox) {
-//   const sandboxIframe = document.createElement('iframe');
-//   sandboxIframe.src = '/sandbox.html';
-//   sandboxIframe.id = 'sandbox';
-
-//   document.body.appendChild(sandboxIframe);
-
-//   window.addEventListener('message', async ({ data }) => {
-//     if (data?.type !== 'automa-fetch') return;
-
-//     const sendResponse = (result) => {
-//       sandboxIframe.contentWindow.postMessage(
-//         {
-//           type: 'fetchResponse',
-//           data: result,
-//           id: data.data.id,
-//         },
-//         '*'
-//       );
-//     };
-
-//     const { type, resource } = data.data;
-//     try {
-//       const response = await fetch(resource.url, resource);
-//       if (!response.ok) throw new Error(response.statusText);
-
-//       let result = null;
-
-//       if (type === 'base64') {
-//         const blob = await response.blob();
-//         const base64 = await readFileAsBase64(blob);
-
-//         result = base64;
-//       } else {
-//         result = await response[type]();
-//       }
-//       sendResponse({ isError: false, result });
-//     } catch (error) {
-//       sendResponse({ isError: true, result: error.message });
-//     }
-//   });
-// }

+ 2 - 1
src/content/commandPalette/App.vue

@@ -190,6 +190,7 @@ import { sendMessage } from '@/utils/message';
 import { debounce, parseJSON } from '@/utils/helper';
 import { debounce, parseJSON } from '@/utils/helper';
 import ParameterInputValue from '@/components/newtab/workflow/edit/Parameter/ParameterInputValue.vue';
 import ParameterInputValue from '@/components/newtab/workflow/edit/Parameter/ParameterInputValue.vue';
 import ParameterJsonValue from '@/components/newtab/workflow/edit/Parameter/ParameterJsonValue.vue';
 import ParameterJsonValue from '@/components/newtab/workflow/edit/Parameter/ParameterJsonValue.vue';
+import RendererWorkflowService from '@/service/renderer/RendererWorkflowService';
 
 
 const paramsList = {
 const paramsList = {
   string: {
   string: {
@@ -265,8 +266,8 @@ function sendExecuteCommand(workflow, options = {}) {
     includeTabId: true,
     includeTabId: true,
     options: { ...options, checkParams: false },
     options: { ...options, checkParams: false },
   };
   };
+  RendererWorkflowService.executeWorkflow(workflowData);
 
 
-  sendMessage('workflow:execute', workflowData, 'background');
   state.active = false;
   state.active = false;
 }
 }
 function executeWorkflow(workflow) {
 function executeWorkflow(workflow) {

+ 2 - 16
src/popup/pages/Home.vue

@@ -187,7 +187,6 @@ import browser from 'webextension-polyfill';
 import { useUserStore } from '@/stores/user';
 import { useUserStore } from '@/stores/user';
 import { useFolderStore } from '@/stores/folder';
 import { useFolderStore } from '@/stores/folder';
 import { useDialog } from '@/composable/dialog';
 import { useDialog } from '@/composable/dialog';
-import { sendMessage } from '@/utils/message';
 import { useWorkflowStore } from '@/stores/workflow';
 import { useWorkflowStore } from '@/stores/workflow';
 import { useGroupTooltip } from '@/composable/groupTooltip';
 import { useGroupTooltip } from '@/composable/groupTooltip';
 import { useTeamWorkflowStore } from '@/stores/teamWorkflow';
 import { useTeamWorkflowStore } from '@/stores/teamWorkflow';
@@ -198,6 +197,7 @@ import automa from '@business';
 import HomeWorkflowCard from '@/components/popup/home/HomeWorkflowCard.vue';
 import HomeWorkflowCard from '@/components/popup/home/HomeWorkflowCard.vue';
 import HomeTeamWorkflows from '@/components/popup/home/HomeTeamWorkflows.vue';
 import HomeTeamWorkflows from '@/components/popup/home/HomeTeamWorkflows.vue';
 import BackgroundUtils from '@/background/BackgroundUtils';
 import BackgroundUtils from '@/background/BackgroundUtils';
+import RendererWorkflowService from '@/service/renderer/RendererWorkflowService';
 
 
 const isMV2 = browser.runtime.getManifest().manifest_version === 2;
 const isMV2 = browser.runtime.getManifest().manifest_version === 2;
 
 
@@ -315,21 +315,7 @@ function togglePinWorkflow(workflow) {
 }
 }
 async function executeWorkflow(workflow) {
 async function executeWorkflow(workflow) {
   try {
   try {
-    const [tab] = await browser.tabs.query({
-      url: browser.runtime.getURL('/newtab.html'),
-    });
-    if (tab && !isMV2) {
-      await browser.tabs.sendMessage(tab.id, {
-        type: 'workflow:execute',
-        data: {
-          data: workflow,
-          options: workflow?.options,
-        },
-      });
-    } else {
-      await sendMessage('workflow:execute', workflow, 'background');
-    }
-
+    await RendererWorkflowService.executeWorkflow(workflow, workflow.options);
     window.close();
     window.close();
   } catch (error) {
   } catch (error) {
     console.error(error);
     console.error(error);

+ 16 - 1
src/service/browser-api/BrowserAPIEventHandler.js

@@ -86,7 +86,9 @@ class BrowserAPIEventHandler {
           type: 'add',
           type: 'add',
         },
         },
         'background'
         'background'
-      );
+      ).then(() => {
+        this.#isEventAdded.add(name);
+      });
     };
     };
 
 
     /**
     /**
@@ -111,8 +113,21 @@ class BrowserAPIEventHandler {
       delete this.#eventsHandler[name];
       delete this.#eventsHandler[name];
     };
     };
 
 
+    const hasListeners = () => {
+      return this.#events[name].length > 0;
+    };
+
+    /**
+     * @param {eventListenerCallback} callback
+     */
+    const hasListener = (callback) => {
+      return this.#events[name].includes(callback);
+    };
+
     this.#eventsHandler[name] = {
     this.#eventsHandler[name] = {
       addListener,
       addListener,
+      hasListener,
+      hasListeners,
       removeListener,
       removeListener,
     };
     };
 
 

+ 15 - 0
src/service/browser-api/BrowserAPIService.js

@@ -157,6 +157,21 @@ class BrowserAPIService {
   /** @type {typeof Browser.webNavigation} */
   /** @type {typeof Browser.webNavigation} */
   static webNavigation;
   static webNavigation;
 
 
+  /** @type {typeof Browser.permissions} */
+  static permissions;
+
+  /** @type {typeof Browser.downloads} */
+  static downloads;
+
+  /** @type {typeof Browser.notifications} */
+  static notifications;
+
+  /** @type {typeof Browser.browserAction} */
+  static browserAction;
+
+  /** @type {typeof Browser.extension} */
+  static extension;
+
   static contentScript = BrowserConentScript;
   static contentScript = BrowserConentScript;
 }
 }
 
 

+ 67 - 3
src/service/browser-api/browser-api-map.js

@@ -1,28 +1,92 @@
 import Browser from 'webextension-polyfill';
 import Browser from 'webextension-polyfill';
 
 
-/** @type {{api: unknown, path: string; isEvent?: true}[]} */
+/** @type {{api: () => unknown, path: string; isEvent?: true}[]} */
 export const browserAPIMap = [
 export const browserAPIMap = [
   { api: () => Browser.tabs.get, path: 'tabs.get' },
   { api: () => Browser.tabs.get, path: 'tabs.get' },
+  { api: () => chrome.tabs.group, path: 'tabs.group' },
   { api: () => Browser.tabs.query, path: 'tabs.query' },
   { api: () => Browser.tabs.query, path: 'tabs.query' },
+  { api: () => Browser.tabs.update, path: 'tabs.update' },
+  { api: () => Browser.tabs.create, path: 'tabs.create' },
+  { api: () => Browser.tabs.remove, path: 'tabs.remove' },
+  { api: () => Browser.tabs.reload, path: 'tabs.reload' },
+  { api: () => Browser.tabs.goBack, path: 'tabs.goBack' },
+  { api: () => Browser.tabs.setZoom, path: 'tabs.setZoom' },
+  { api: () => Browser.tabs.goForward, path: 'tabs.goForward' },
+  { api: () => Browser.tabs.captureTab, path: 'tabs.captureTab' },
+  { api: () => Browser.tabs.captureVisibleTab, path: 'tabs.captureVisibleTab' },
   { isEvent: true, api: () => Browser.tabs.onRemoved, path: 'tabs.onRemoved' },
   { isEvent: true, api: () => Browser.tabs.onRemoved, path: 'tabs.onRemoved' },
   {
   {
     isEvent: true,
     isEvent: true,
     path: 'webNavigation.onCreatedNavigationTarget',
     path: 'webNavigation.onCreatedNavigationTarget',
     api: () => Browser.webNavigation.onCreatedNavigationTarget,
     api: () => Browser.webNavigation.onCreatedNavigationTarget,
   },
   },
+  {
+    isEvent: true,
+    path: 'webNavigation.onErrorOccurred',
+    api: () => Browser.webNavigation.onErrorOccurred,
+  },
+  {
+    path: 'webNavigation.getAllFrames',
+    api: () => Browser.webNavigation.getAllFrames,
+  },
+  { api: () => Browser.windows.get, path: 'windows.get' },
   { api: () => Browser.windows.update, path: 'windows.update' },
   { api: () => Browser.windows.update, path: 'windows.update' },
   { api: () => Browser.windows.create, path: 'windows.create' },
   { api: () => Browser.windows.create, path: 'windows.create' },
+  { api: () => Browser.windows.getAll, path: 'windows.getAll' },
+  { api: () => Browser.windows.remove, path: 'windows.remove' },
+  { api: () => Browser.windows.getCurrent, path: 'windows.getCurrent' },
   {
   {
     isEvent: true,
     isEvent: true,
     path: 'windows.onRemoved',
     path: 'windows.onRemoved',
     api: () => Browser.windows.onRemoved,
     api: () => Browser.windows.onRemoved,
   },
   },
+  {
+    isEvent: true,
+    path: 'storage.onChanged',
+    api: () => Browser.storage.onChanged,
+  },
   { api: () => Browser.storage.local.get, path: 'storage.local.get' },
   { api: () => Browser.storage.local.get, path: 'storage.local.get' },
   { api: () => Browser.storage.local.set, path: 'storage.local.set' },
   { api: () => Browser.storage.local.set, path: 'storage.local.set' },
   { api: () => Browser.storage.local.remove, path: 'storage.local.remove' },
   { api: () => Browser.storage.local.remove, path: 'storage.local.remove' },
   { api: () => Browser.proxy.settings.clear, path: 'proxy.settings.clear' },
   { api: () => Browser.proxy.settings.clear, path: 'proxy.settings.clear' },
+  { api: () => Browser.proxy.settings.set, path: 'proxy.settings.set' },
+  {
+    isEvent: true,
+    path: 'debugger.onEvent',
+    api: () => chrome.debugger.onEvent,
+  },
+  { path: 'debugger.detach', api: () => chrome.debugger.detach },
+  { path: 'permissions.contains', api: () => Browser.permissions.contains },
+  { path: 'cookies.get', api: () => Browser.cookies?.get },
+  { path: 'cookies.getAll', api: () => Browser.cookies?.getAll },
+  { path: 'cookies.remove', api: () => Browser.cookies?.remove },
+  { path: 'downloads.search', api: () => Browser.downloads?.search },
+  { path: 'downloads.download', api: () => Browser.downloads?.download },
+  {
+    isEvent: true,
+    path: 'downloads.onCreated',
+    api: () => Browser.downloads?.onCreated,
+  },
+  {
+    isEvent: true,
+    path: 'downloads.onDeterminingFilename',
+    api: () => chrome.downloads?.onDeterminingFilename,
+  },
+  {
+    isEvent: true,
+    path: 'downloads.onChanged',
+    api: () => Browser.downloads?.onChanged,
+  },
+  {
+    path: 'browserAction.setBadgeText',
+    api: () => (Browser.action || Browser.browserAction).setBadgeText,
+  },
+  {
+    path: 'notifications.create',
+    api: () => Browser.notifications?.create,
+  },
   {
   {
-    api: () => chrome.debugger.onEvent.addListener,
-    path: 'debugger.onEvent.addListener',
+    path: 'extension.isAllowedFileSchemeAccess',
+    api: () => Browser.extension.isAllowedFileSchemeAccess,
   },
   },
 ];
 ];

+ 13 - 7
src/utils/api.js

@@ -1,5 +1,5 @@
 import secrets from 'secrets';
 import secrets from 'secrets';
-import browser from 'webextension-polyfill';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import { parseJSON, isObject } from './helper';
 import { parseJSON, isObject } from './helper';
 
 
 export async function fetchApi(path, options = {}) {
 export async function fetchApi(path, options = {}) {
@@ -9,7 +9,7 @@ export async function fetchApi(path, options = {}) {
     ...(options?.headers || {}),
     ...(options?.headers || {}),
   };
   };
 
 
-  const { session } = await browser.storage.local.get('session');
+  const { session } = await BrowserAPIService.storage.local.get('session');
   if (session && options?.auth) {
   if (session && options?.auth) {
     delete options.auth;
     delete options.auth;
 
 
@@ -24,7 +24,7 @@ export async function fetchApi(path, options = {}) {
         throw new Error(result.message);
         throw new Error(result.message);
       }
       }
 
 
-      await browser.storage.local.set({ session: result });
+      await BrowserAPIService.storage.local.set({ session: result });
       token = result.access_token;
       token = result.access_token;
     }
     }
 
 
@@ -108,7 +108,9 @@ export async function getUserWorkflows(useCache = true) {
     'user-workflows',
     'user-workflows',
     async () => {
     async () => {
       try {
       try {
-        const { lastBackup } = await browser.storage.local.get('lastBackup');
+        const { lastBackup } = await BrowserAPIService.storage.local.get(
+          'lastBackup'
+        );
         const response = await fetchApi(
         const response = await fetchApi(
           `/me/workflows?lastBackup=${(useCache && lastBackup) || null}`,
           `/me/workflows?lastBackup=${(useCache && lastBackup) || null}`,
           { auth: true }
           { auth: true }
@@ -154,7 +156,9 @@ export function validateOauthToken() {
 
 
   const startFetch = async () => {
   const startFetch = async () => {
     try {
     try {
-      const { sessionToken } = await browser.storage.local.get('sessionToken');
+      const { sessionToken } = await BrowserAPIService.storage.local.get(
+        'sessionToken'
+      );
       if (!sessionToken) return null;
       if (!sessionToken) return null;
 
 
       const response = await fetch(
       const response = await fetch(
@@ -189,7 +193,9 @@ export function validateOauthToken() {
 }
 }
 
 
 export async function fetchGapi(url, resource = {}, options = {}) {
 export async function fetchGapi(url, resource = {}, options = {}) {
-  const { sessionToken } = await browser.storage.local.get('sessionToken');
+  const { sessionToken } = await BrowserAPIService.storage.local.get(
+    'sessionToken'
+  );
   if (!sessionToken) throw new Error('unauthorized');
   if (!sessionToken) throw new Error('unauthorized');
 
 
   const { search, origin, pathname } = new URL(url);
   const { search, origin, pathname } = new URL(url);
@@ -226,7 +232,7 @@ export async function fetchGapi(url, resource = {}, options = {}) {
       searchParams.set('access_token', refreshResult.token);
       searchParams.set('access_token', refreshResult.token);
       sessionToken.access = refreshResult.token;
       sessionToken.access = refreshResult.token;
 
 
-      await browser.storage.local.set({ sessionToken });
+      await BrowserAPIService.storage.local.set({ sessionToken });
 
 
       if (tryCount < maxTry) {
       if (tryCount < maxTry) {
         tryCount += 1;
         tryCount += 1;

+ 2 - 1
src/utils/helper.js

@@ -1,3 +1,4 @@
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import browser from 'webextension-polyfill';
 import browser from 'webextension-polyfill';
 
 
 export async function getActiveTab() {
 export async function getActiveTab() {
@@ -249,7 +250,7 @@ export function debounce(callback, time = 200) {
 
 
 export async function clearCache(workflow) {
 export async function clearCache(workflow) {
   try {
   try {
-    await browser.storage.local.remove(`state:${workflow.id}`);
+    await BrowserAPIService.storage.local.remove(`state:${workflow.id}`);
 
 
     const flows = parseJSON(workflow.drawflow, null);
     const flows = parseJSON(workflow.drawflow, null);
     const blocks = flows && flows.drawflow.Home.data;
     const blocks = flows && flows.drawflow.Home.data;

+ 1 - 2
src/utils/message.js

@@ -1,5 +1,4 @@
 import browser from 'webextension-polyfill';
 import browser from 'webextension-polyfill';
-import { objectHasKey } from './helper';
 
 
 const nameBuilder = (prefix, name) => (prefix ? `${prefix}--${name}` : name);
 const nameBuilder = (prefix, name) => (prefix ? `${prefix}--${name}` : name);
 const isFirefox = BROWSER_TYPE === 'firefox';
 const isFirefox = BROWSER_TYPE === 'firefox';
@@ -36,7 +35,7 @@ export class MessageListener {
   }
   }
 
 
   on(name, listener) {
   on(name, listener) {
-    if (objectHasKey(this.listeners, name)) {
+    if (Object.hasOwn(this.listeners, name)) {
       console.error(`You already added ${name}`);
       console.error(`You already added ${name}`);
       return this.on;
       return this.on;
     }
     }

+ 0 - 3
src/workflowEngine/BrowserApi.js

@@ -1,3 +0,0 @@
-class BrowserAPI {}
-
-export default BrowserAPI;

+ 3 - 3
src/workflowEngine/WorkflowEngine.js

@@ -263,7 +263,7 @@ class WorkflowEngine {
         !this.workflow.connectedTable
         !this.workflow.connectedTable
       ) {
       ) {
         const lastStateKey = `state:${this.workflow.id}`;
         const lastStateKey = `state:${this.workflow.id}`;
-        const value = await BrowserAPIService.storage.localGet(lastStateKey);
+        const value = await BrowserAPIService.storage.local.get(lastStateKey);
         const lastState = value[lastStateKey];
         const lastState = value[lastStateKey];
 
 
         if (lastState) {
         if (lastState) {
@@ -273,7 +273,7 @@ class WorkflowEngine {
       }
       }
 
 
       const { settings: userSettings } =
       const { settings: userSettings } =
-        await BrowserAPIService.storage.localGet('settings');
+        await BrowserAPIService.storage.local.get('settings');
       this.logsLimit = userSettings?.logsLimit || 1001;
       this.logsLimit = userSettings?.logsLimit || 1001;
 
 
       this.workflow.table = columns;
       this.workflow.table = columns;
@@ -375,7 +375,7 @@ class WorkflowEngine {
   }
   }
 
 
   async executeQueue() {
   async executeQueue() {
-    const { workflowQueue } = await BrowserAPIService.storage.localGet(
+    const { workflowQueue } = await BrowserAPIService.storage.local.get(
       'workflowQueue'
       'workflowQueue'
     );
     );
     const queueIndex = (workflowQueue || []).indexOf(this.workflow?.id);
     const queueIndex = (workflowQueue || []).indexOf(this.workflow?.id);

+ 20 - 16
src/workflowEngine/WorkflowManager.js

@@ -1,8 +1,8 @@
-import browser from 'webextension-polyfill';
 import { fetchApi } from '@/utils/api';
 import { fetchApi } from '@/utils/api';
 import getBlockMessage from '@/utils/getBlockMessage';
 import getBlockMessage from '@/utils/getBlockMessage';
 import convertWorkflowData from '@/utils/convertWorkflowData';
 import convertWorkflowData from '@/utils/convertWorkflowData';
 import dayjs from '@/lib/dayjs';
 import dayjs from '@/lib/dayjs';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import WorkflowEvent from './WorkflowEvent';
 import WorkflowEvent from './WorkflowEvent';
 import WorkflowState from './WorkflowState';
 import WorkflowState from './WorkflowState';
 import WorkflowLogger from './WorkflowLogger';
 import WorkflowLogger from './WorkflowLogger';
@@ -11,14 +11,14 @@ import blocksHandler from './blocksHandler';
 
 
 const workflowStateStorage = {
 const workflowStateStorage = {
   get() {
   get() {
-    return browser.storage.local
+    return BrowserAPIService.storage.local
       .get('workflowStates')
       .get('workflowStates')
       .then(({ workflowStates }) => workflowStates || []);
       .then(({ workflowStates }) => workflowStates || []);
   },
   },
   set(key, value) {
   set(key, value) {
     const states = Object.values(value);
     const states = Object.values(value);
 
 
-    return browser.storage.local.set({ workflowStates: states });
+    return BrowserAPIService.storage.local.set({ workflowStates: states });
   },
   },
 };
 };
 
 
@@ -65,16 +65,16 @@ class WorkflowManager {
     engine.init();
     engine.init();
     engine.on('destroyed', ({ id, status, history, blockDetail, ...rest }) => {
     engine.on('destroyed', ({ id, status, history, blockDetail, ...rest }) => {
       if (status !== 'stopped') {
       if (status !== 'stopped') {
-        browser.permissions
+        BrowserAPIService.permissions
           .contains({ permissions: ['notifications'] })
           .contains({ permissions: ['notifications'] })
           .then((hasPermission) => {
           .then((hasPermission) => {
             if (!hasPermission || !workflowData.settings.notification) return;
             if (!hasPermission || !workflowData.settings.notification) return;
 
 
             const name = workflowData.name.slice(0, 32);
             const name = workflowData.name.slice(0, 32);
 
 
-            browser.notifications.create(`logs:${id}`, {
+            BrowserAPIService.notifications.create(`logs:${id}`, {
               type: 'basic',
               type: 'basic',
-              iconUrl: browser.runtime.getURL('icon-128.png'),
+              iconUrl: BrowserAPIService.runtime.getURL('icon-128.png'),
               title: status === 'success' ? 'Success' : 'Error',
               title: status === 'success' ? 'Success' : 'Error',
               message: `${
               message: `${
                 status === 'success' ? 'Successfully' : 'Failed'
                 status === 'success' ? 'Successfully' : 'Failed'
@@ -119,16 +119,20 @@ class WorkflowManager {
       }
       }
     });
     });
 
 
-    browser.storage.local.get('checkStatus').then(({ checkStatus }) => {
-      const isSameDay = dayjs().isSame(checkStatus, 'day');
-      if (!isSameDay || !checkStatus) {
-        fetchApi('/status')
-          .then((response) => response.json())
-          .then(() => {
-            browser.storage.local.set({ checkStatus: new Date().toString() });
-          });
-      }
-    });
+    BrowserAPIService.storage.local
+      .get('checkStatus')
+      .then(({ checkStatus }) => {
+        const isSameDay = dayjs().isSame(checkStatus, 'day');
+        if (!isSameDay || !checkStatus) {
+          fetchApi('/status')
+            .then((response) => response.json())
+            .then(() => {
+              BrowserAPIService.storage.local.set({
+                checkStatus: new Date().toString(),
+              });
+            });
+        }
+      });
 
 
     return engine;
     return engine;
   }
   }

+ 4 - 3
src/workflowEngine/WorkflowState.js

@@ -1,5 +1,5 @@
 /* eslint-disable  no-param-reassign */
 /* eslint-disable  no-param-reassign */
-import browser from 'webextension-polyfill';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 
 
 class WorkflowState {
 class WorkflowState {
   constructor({ storage, key = 'workflowState' }) {
   constructor({ storage, key = 'workflowState' }) {
@@ -13,8 +13,9 @@ class WorkflowState {
   }
   }
 
 
   _updateBadge() {
   _updateBadge() {
-    const browserAction = browser.action || browser.browserAction;
-    browserAction.setBadgeText({ text: (this.states.size || '').toString() });
+    BrowserAPIService.browserAction.setBadgeText({
+      text: (this.states.size || '').toString(),
+    });
   }
   }
 
 
   _saveToStorage() {
   _saveToStorage() {

+ 13 - 12
src/workflowEngine/blocksHandler/handlerActiveTab.js

@@ -1,5 +1,5 @@
-import browser from 'webextension-polyfill';
 import { sleep } from '@/utils/helper';
 import { sleep } from '@/utils/helper';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import { attachDebugger, injectPreloadScript } from '../helper';
 import { attachDebugger, injectPreloadScript } from '../helper';
 
 
 async function activeTab(block) {
 async function activeTab(block) {
@@ -10,8 +10,7 @@ async function activeTab(block) {
     };
     };
 
 
     if (this.activeTab.id) {
     if (this.activeTab.id) {
-      await browser.tabs.update(this.activeTab.id, { active: true });
-
+      await BrowserAPIService.tabs.update(this.activeTab.id, { active: true });
       return data;
       return data;
     }
     }
 
 
@@ -24,15 +23,17 @@ async function activeTab(block) {
       tabsQuery.currentWindow = true;
       tabsQuery.currentWindow = true;
     } else if (this.engine.isPopup) {
     } else if (this.engine.isPopup) {
       let windowId = null;
       let windowId = null;
-      const extURL = browser.runtime.getURL('');
-      const windows = await browser.windows.getAll({ populate: true });
+      const extURL = BrowserAPIService.runtime.getURL('');
+      const windows = await BrowserAPIService.windows.getAll({
+        populate: true,
+      });
       for (const browserWindow of windows) {
       for (const browserWindow of windows) {
         const [tab] = browserWindow.tabs;
         const [tab] = browserWindow.tabs;
         const isDashboard =
         const isDashboard =
           browserWindow.tabs.length === 1 && tab.url?.includes(extURL);
           browserWindow.tabs.length === 1 && tab.url?.includes(extURL);
 
 
         if (isDashboard) {
         if (isDashboard) {
-          await browser.windows.update(browserWindow.id, {
+          await BrowserAPIService.windows.update(browserWindow.id, {
             focused: false,
             focused: false,
           });
           });
         } else if (browserWindow.focused) {
         } else if (browserWindow.focused) {
@@ -43,12 +44,12 @@ async function activeTab(block) {
       if (windowId) tabsQuery.windowId = windowId;
       if (windowId) tabsQuery.windowId = windowId;
       else if (windows.length > 2) tabsQuery.lastFocusedWindow = true;
       else if (windows.length > 2) tabsQuery.lastFocusedWindow = true;
     } else {
     } else {
-      const dashboardTabs = await browser.tabs.query({
-        url: browser.runtime.getURL('/newtab.html'),
+      const dashboardTabs = await BrowserAPIService.tabs.query({
+        url: BrowserAPIService.runtime.getURL('/newtab.html'),
       });
       });
       await Promise.all(
       await Promise.all(
         dashboardTabs.map((item) =>
         dashboardTabs.map((item) =>
-          browser.windows.update(item.windowId, {
+          BrowserAPIService.windows.update(item.windowId, {
             focused: false,
             focused: false,
           })
           })
         )
         )
@@ -57,7 +58,7 @@ async function activeTab(block) {
       tabsQuery.currentWindow = true;
       tabsQuery.currentWindow = true;
     }
     }
 
 
-    const [tab] = await browser.tabs.query(tabsQuery);
+    const [tab] = await BrowserAPIService.tabs.query(tabsQuery);
     if (!tab) {
     if (!tab) {
       throw new Error("Can't find active tab");
       throw new Error("Can't find active tab");
     }
     }
@@ -100,8 +101,8 @@ async function activeTab(block) {
       }
       }
     }
     }
 
 
-    await browser.tabs.update(tab.id, { active: true });
-    await browser.windows.update(tab.windowId, { focused: true });
+    await BrowserAPIService.tabs.update(tab.id, { active: true });
+    await BrowserAPIService.windows.update(tab.windowId, { focused: true });
 
 
     await sleep(200);
     await sleep(200);
 
 

+ 6 - 6
src/workflowEngine/blocksHandler/handlerClipboard.js

@@ -1,4 +1,5 @@
-import browser from 'webextension-polyfill';
+import { IS_FIREFOX } from '@/common/utils/constant';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import { copyTextToClipboard } from '../helper';
 import { copyTextToClipboard } from '../helper';
 
 
 function doCommand(command, value) {
 function doCommand(command, value) {
@@ -22,16 +23,15 @@ function doCommand(command, value) {
 }
 }
 
 
 export default async function ({ data, id, label }) {
 export default async function ({ data, id, label }) {
-  const isFirefox = BROWSER_TYPE === 'firefox';
-  if (!isFirefox && !this.engine?.isPopup && !this.engine?.isMV2)
+  if (!IS_FIREFOX && !this.engine?.isPopup && !this.engine?.isMV2)
     throw new Error('Clipboard block is not supported in background execution');
     throw new Error('Clipboard block is not supported in background execution');
 
 
   const permissions = ['clipboardRead'];
   const permissions = ['clipboardRead'];
-  if (isFirefox) {
+  if (IS_FIREFOX) {
     permissions.push('clipboardWrite');
     permissions.push('clipboardWrite');
   }
   }
 
 
-  const hasPermission = await browser.permissions.contains({
+  const hasPermission = await BrowserAPIService.permissions.contains({
     permissions,
     permissions,
   });
   });
 
 
@@ -67,7 +67,7 @@ export default async function ({ data, id, label }) {
 
 
     valueToReturn = text;
     valueToReturn = text;
 
 
-    if (isFirefox) {
+    if (IS_FIREFOX) {
       await copyTextToClipboard(text);
       await copyTextToClipboard(text);
     } else {
     } else {
       doCommand('copy', text);
       doCommand('copy', text);

+ 10 - 6
src/workflowEngine/blocksHandler/handlerCloseTab.js

@@ -1,10 +1,10 @@
-import browser from 'webextension-polyfill';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 
 
 async function closeWindow(data, windowId) {
 async function closeWindow(data, windowId) {
   const windowIds = [];
   const windowIds = [];
 
 
   if (data.allWindows) {
   if (data.allWindows) {
-    const windows = await browser.windows.getAll();
+    const windows = await BrowserAPIService.windows.getAll();
 
 
     windows.forEach(({ id }) => {
     windows.forEach(({ id }) => {
       windowIds.push(id);
       windowIds.push(id);
@@ -15,13 +15,15 @@ async function closeWindow(data, windowId) {
     if (windowId && typeof windowId === 'number') {
     if (windowId && typeof windowId === 'number') {
       currentWindowId = windowId;
       currentWindowId = windowId;
     } else {
     } else {
-      currentWindowId = (await browser.windows.getCurrent()).id;
+      currentWindowId = (await BrowserAPIService.windows.getCurrent()).id;
     }
     }
 
 
     windowIds.push(currentWindowId);
     windowIds.push(currentWindowId);
   }
   }
 
 
-  await Promise.allSettled(windowIds.map((id) => browser.windows.remove(id)));
+  await Promise.allSettled(
+    windowIds.map((id) => BrowserAPIService.windows.remove(id))
+  );
 }
 }
 
 
 async function closeTab(data, tabId) {
 async function closeTab(data, tabId) {
@@ -30,10 +32,12 @@ async function closeTab(data, tabId) {
   if (data.activeTab && tabId) {
   if (data.activeTab && tabId) {
     tabIds = tabId;
     tabIds = tabId;
   } else if (data.url) {
   } else if (data.url) {
-    tabIds = (await browser.tabs.query({ url: data.url })).map((tab) => tab.id);
+    tabIds = (await BrowserAPIService.tabs.query({ url: data.url })).map(
+      (tab) => tab.id
+    );
   }
   }
 
 
-  if (tabIds) await browser.tabs.remove(tabIds);
+  if (tabIds) await BrowserAPIService.tabs.remove(tabIds);
 }
 }
 
 
 export default async function ({ data, id }) {
 export default async function ({ data, id }) {

+ 6 - 6
src/workflowEngine/blocksHandler/handlerCookie.js

@@ -1,4 +1,4 @@
-import browser from 'webextension-polyfill';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import { parseJSON } from '@/utils/helper';
 import { parseJSON } from '@/utils/helper';
 
 
 function getValues(data, keys) {
 function getValues(data, keys) {
@@ -33,7 +33,7 @@ const keys = {
 };
 };
 
 
 async function cookie({ data, id }) {
 async function cookie({ data, id }) {
-  const hasPermission = await browser.permissions.contains({
+  const hasPermission = await BrowserAPIService.permissions.contains({
     permissions: ['cookies'],
     permissions: ['cookies'],
   });
   });
 
 
@@ -53,7 +53,7 @@ async function cookie({ data, id }) {
     const obj = parseJSON(data.jsonCode, null);
     const obj = parseJSON(data.jsonCode, null);
     if (!obj) throw new Error('Invalid JSON format');
     if (!obj) throw new Error('Invalid JSON format');
 
 
-    result = await browser.cookies[key](obj);
+    result = await BrowserAPIService.cookies[key](obj);
   } else {
   } else {
     const values = getValues(data, keys[key]);
     const values = getValues(data, keys[key]);
     if (values.expirationDate) {
     if (values.expirationDate) {
@@ -61,15 +61,15 @@ async function cookie({ data, id }) {
     }
     }
 
 
     if (data.type === 'remove' && !data.name) {
     if (data.type === 'remove' && !data.name) {
-      const cookies = await browser.cookies.getAll({ url: data.url });
+      const cookies = await BrowserAPIService.cookies.getAll({ url: data.url });
       const removePromise = cookies.map(({ name }) =>
       const removePromise = cookies.map(({ name }) =>
-        browser.cookies.remove({ name, url: data.url })
+        BrowserAPIService.cookies.remove({ name, url: data.url })
       );
       );
       await Promise.allSettled(removePromise);
       await Promise.allSettled(removePromise);
 
 
       result = cookies;
       result = cookies;
     } else {
     } else {
-      result = await browser.cookies[key](values);
+      result = await BrowserAPIService.cookies[key](values);
     }
     }
   }
   }
 
 

+ 3 - 5
src/workflowEngine/blocksHandler/handlerExecuteWorkflow.js

@@ -1,8 +1,8 @@
-import browser from 'webextension-polyfill';
 import { isWhitespace, parseJSON } from '@/utils/helper';
 import { isWhitespace, parseJSON } from '@/utils/helper';
 import decryptFlow, { getWorkflowPass } from '@/utils/decryptFlow';
 import decryptFlow, { getWorkflowPass } from '@/utils/decryptFlow';
 import convertWorkflowData from '@/utils/convertWorkflowData';
 import convertWorkflowData from '@/utils/convertWorkflowData';
 import { nanoid } from 'nanoid';
 import { nanoid } from 'nanoid';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import WorkflowEngine from '../WorkflowEngine';
 import WorkflowEngine from '../WorkflowEngine';
 
 
 function workflowListener(workflow, options) {
 function workflowListener(workflow, options) {
@@ -48,10 +48,8 @@ function findWorkflow(workflows, workflowId) {
 async function executeWorkflow({ id: blockId, data }, { refData }) {
 async function executeWorkflow({ id: blockId, data }, { refData }) {
   if (data.workflowId === '') throw new Error('empty-workflow');
   if (data.workflowId === '') throw new Error('empty-workflow');
 
 
-  const { workflows, teamWorkflows } = await browser.storage.local.get([
-    'workflows',
-    'teamWorkflows',
-  ]);
+  const { workflows, teamWorkflows } =
+    await BrowserAPIService.storage.local.get(['workflows', 'teamWorkflows']);
   let workflow = null;
   let workflow = null;
 
 
   if (data.workflowId.startsWith('team')) {
   if (data.workflowId.startsWith('team')) {

+ 10 - 12
src/workflowEngine/blocksHandler/handlerExportData.js

@@ -1,5 +1,5 @@
-import browser from 'webextension-polyfill';
 import { default as dataExporter, files } from '@/utils/dataExporter';
 import { default as dataExporter, files } from '@/utils/dataExporter';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 
 
 function blobToBase64(blob) {
 function blobToBase64(blob) {
   return new Promise((resolve) => {
   return new Promise((resolve) => {
@@ -26,32 +26,30 @@ async function exportData({ data, id }, { refData }) {
     }
     }
   }
   }
 
 
-  const hasDownloadAccess = await browser.permissions.contains({
-    permissions: ['downloads'],
-  });
+  const isDOMAvailable = typeof document !== 'undefined';
   let blobUrl = dataExporter(payload, {
   let blobUrl = dataExporter(payload, {
     ...data,
     ...data,
     csvOptions: {
     csvOptions: {
       delimiter: data.csvDelimiter || ',',
       delimiter: data.csvDelimiter || ',',
     },
     },
-    returnUrl: hasDownloadAccess,
-    returnBlob: !this.engine.isPopup && !this.engine.isMV2,
+    returnUrl: !isDOMAvailable,
   });
   });
 
 
-  if (!this.engine.isPopup && !hasDownloadAccess) {
-    throw new Error("Don't have download permission");
-  } else if (!this.engine.isPopup && !this.engine.isMV2) {
+  const hasDownloadAccess =
+    !isDOMAvailable &&
+    (await BrowserAPIService.permissions.contains({
+      permissions: ['downloads'],
+    }));
+  if (hasDownloadAccess) {
     blobUrl = await blobToBase64(blobUrl);
     blobUrl = await blobToBase64(blobUrl);
-  }
 
 
-  if (hasDownloadAccess) {
     const filename = `${data.name || 'unnamed'}${files[data.type].ext}`;
     const filename = `${data.name || 'unnamed'}${files[data.type].ext}`;
     const options = {
     const options = {
       filename,
       filename,
       conflictAction: data.onConflict || 'uniquify',
       conflictAction: data.onConflict || 'uniquify',
     };
     };
 
 
-    await browser.downloads.download({
+    await BrowserAPIService.downloads.download({
       ...options,
       ...options,
       url: blobUrl,
       url: blobUrl,
     });
     });

+ 2 - 2
src/workflowEngine/blocksHandler/handlerForwardPage.js

@@ -1,9 +1,9 @@
-import browser from 'webextension-polyfill';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 
 
 export async function goBack({ id }) {
 export async function goBack({ id }) {
   if (!this.activeTab.id) throw new Error('no-tab');
   if (!this.activeTab.id) throw new Error('no-tab');
 
 
-  await browser.tabs.goForward(this.activeTab.id);
+  await BrowserAPIService.tabs.goForward(this.activeTab.id);
 
 
   return {
   return {
     data: '',
     data: '',

+ 2 - 2
src/workflowEngine/blocksHandler/handlerGoBack.js

@@ -1,9 +1,9 @@
-import browser from 'webextension-polyfill';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 
 
 export async function goBack({ id }) {
 export async function goBack({ id }) {
   if (!this.activeTab.id) throw new Error('no-tab');
   if (!this.activeTab.id) throw new Error('no-tab');
 
 
-  await browser.tabs.goBack(this.activeTab.id);
+  await BrowserAPIService.tabs.goBack(this.activeTab.id);
 
 
   return {
   return {
     data: '',
     data: '',

+ 5 - 3
src/workflowEngine/blocksHandler/handlerGoogleDrive.js

@@ -1,6 +1,6 @@
-import browser from 'webextension-polyfill';
 import { fetchGapi, validateOauthToken } from '@/utils/api';
 import { fetchGapi, validateOauthToken } from '@/utils/api';
 import getFile from '@/utils/getFile';
 import getFile from '@/utils/getFile';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import renderString from '../templating/renderString';
 import renderString from '../templating/renderString';
 
 
 function getFilename(url) {
 function getFilename(url) {
@@ -17,7 +17,9 @@ function getFilename(url) {
 }
 }
 
 
 export async function googleDrive({ id, data }, { refData }) {
 export async function googleDrive({ id, data }, { refData }) {
-  const { sessionToken } = await browser.storage.local.get('sessionToken');
+  const { sessionToken } = await BrowserAPIService.storage.local.get(
+    'sessionToken'
+  );
   if (!sessionToken) throw new Error("You haven't connect Google Drive");
   if (!sessionToken) throw new Error("You haven't connect Google Drive");
 
 
   await validateOauthToken();
   await validateOauthToken();
@@ -26,7 +28,7 @@ export async function googleDrive({ id, data }, { refData }) {
     let path = (await renderString(item.path, refData, this.engine.isPopup))
     let path = (await renderString(item.path, refData, this.engine.isPopup))
       .value;
       .value;
     if (item.type === 'downloadId') {
     if (item.type === 'downloadId') {
-      const [downloadItem] = await browser.downloads.search({
+      const [downloadItem] = await BrowserAPIService.downloads.search({
         id: +path,
         id: +path,
         exists: true,
         exists: true,
         state: 'complete',
         state: 'complete',

+ 17 - 14
src/workflowEngine/blocksHandler/handlerHandleDownload.js

@@ -1,4 +1,5 @@
-import browser from 'webextension-polyfill';
+import { IS_FIREFOX } from '@/common/utils/constant';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 
 
 const getFileExtension = (str) => /(?:\.([^.]+))?$/.exec(str)[1];
 const getFileExtension = (str) => /(?:\.([^.]+))?$/.exec(str)[1];
 function determineFilenameListener(item, suggest) {
 function determineFilenameListener(item, suggest) {
@@ -37,7 +38,7 @@ async function handleDownload({ data, id: blockId }) {
     if (Number.isNaN(+data.downloadId))
     if (Number.isNaN(+data.downloadId))
       throw new Error('Download id is not a number');
       throw new Error('Download id is not a number');
 
 
-    const [downloadItem] = await browser.downloads.search({
+    const [downloadItem] = await BrowserAPIService.downloads.search({
       id: +data.downloadId,
       id: +data.downloadId,
     });
     });
     if (!downloadItem)
     if (!downloadItem)
@@ -64,10 +65,10 @@ async function handleDownload({ data, id: blockId }) {
     if (!this.activeTab.id) throw new Error('no-tab');
     if (!this.activeTab.id) throw new Error('no-tab');
 
 
     const hasListener =
     const hasListener =
-      BROWSER_TYPE === 'chrome' &&
-      chrome.downloads.onDeterminingFilename.hasListeners(() => {});
+      !IS_FIREFOX &&
+      BrowserAPIService.downloads.onDeterminingFilename.hasListeners(() => {});
     if (!hasListener) {
     if (!hasListener) {
-      chrome.downloads.onDeterminingFilename.addListener(
+      BrowserAPIService.downloads.onDeterminingFilename.addListener(
         determineFilenameListener
         determineFilenameListener
       );
       );
     }
     }
@@ -81,10 +82,10 @@ async function handleDownload({ data, id: blockId }) {
       names[id] = data;
       names[id] = data;
       sessionStorage.setItem('rename-downloaded-files', JSON.stringify(names));
       sessionStorage.setItem('rename-downloaded-files', JSON.stringify(names));
 
 
-      browser.downloads.onCreated.removeListener(handleCreated);
+      BrowserAPIService.downloads.onCreated.removeListener(handleCreated);
     };
     };
     if (!downloadId) {
     if (!downloadId) {
-      browser.downloads.onCreated.addListener(handleCreated);
+      BrowserAPIService.downloads.onCreated.addListener(handleCreated);
     }
     }
 
 
     if (!data.waitForDownload) {
     if (!data.waitForDownload) {
@@ -128,7 +129,7 @@ async function handleDownload({ data, id: blockId }) {
         JSON.stringify(filesname)
         JSON.stringify(filesname)
       );
       );
 
 
-      chrome.downloads.onDeterminingFilename.removeListener(
+      BrowserAPIService.downloads.onDeterminingFilename.removeListener(
         determineFilenameListener
         determineFilenameListener
       );
       );
 
 
@@ -140,7 +141,7 @@ async function handleDownload({ data, id: blockId }) {
 
 
     const handleChanged = ({ state, id, filename }) => {
     const handleChanged = ({ state, id, filename }) => {
       if (this.engine.isDestroyed || isResolved) {
       if (this.engine.isDestroyed || isResolved) {
-        browser.downloads.onChanged.removeListener(handleChanged);
+        BrowserAPIService.downloads.onChanged.removeListener(handleChanged);
         return;
         return;
       }
       }
 
 
@@ -152,15 +153,17 @@ async function handleDownload({ data, id: blockId }) {
       if (DOWNLOAD_STATE.includes(state.current)) {
       if (DOWNLOAD_STATE.includes(state.current)) {
         resolvePromise(id);
         resolvePromise(id);
       } else {
       } else {
-        browser.downloads.search({ id: downloadId }).then(([download]) => {
-          if (!download || !DOWNLOAD_STATE.includes(download.state)) return;
+        BrowserAPIService.downloads
+          .search({ id: downloadId })
+          .then(([download]) => {
+            if (!download || !DOWNLOAD_STATE.includes(download.state)) return;
 
 
-          resolvePromise(id);
-        });
+            resolvePromise(id);
+          });
       }
       }
     };
     };
 
 
-    browser.downloads.onChanged.addListener(handleChanged);
+    BrowserAPIService.downloads.onChanged.addListener(handleChanged);
   });
   });
 
 
   return result;
   return result;

+ 2 - 1
src/workflowEngine/blocksHandler/handlerHoverElement.js

@@ -1,3 +1,4 @@
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import { attachDebugger } from '../helper';
 import { attachDebugger } from '../helper';
 
 
 export async function hoverElement(block) {
 export async function hoverElement(block) {
@@ -24,7 +25,7 @@ export async function hoverElement(block) {
   });
   });
 
 
   if (!debugMode) {
   if (!debugMode) {
-    chrome.debugger.detach({ tabId: this.activeTab.id });
+    BrowserAPIService.debugger.detach({ tabId: this.activeTab.id });
   }
   }
 
 
   return {
   return {

+ 6 - 5
src/workflowEngine/blocksHandler/handlerInteractionBlock.js

@@ -1,16 +1,17 @@
-import browser from 'webextension-polyfill';
 import { objectHasKey } from '@/utils/helper';
 import { objectHasKey } from '@/utils/helper';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import { attachDebugger } from '../helper';
 import { attachDebugger } from '../helper';
 
 
 async function checkAccess(blockName) {
 async function checkAccess(blockName) {
   if (blockName === 'upload-file') {
   if (blockName === 'upload-file') {
-    const hasFileAccess = await browser.extension.isAllowedFileSchemeAccess();
+    const hasFileAccess =
+      await BrowserAPIService.extension.isAllowedFileSchemeAccess();
 
 
     if (hasFileAccess) return true;
     if (hasFileAccess) return true;
 
 
     throw new Error('no-file-access');
     throw new Error('no-file-access');
   } else if (blockName === 'clipboard') {
   } else if (blockName === 'clipboard') {
-    const hasPermission = await browser.permissions.contains({
+    const hasPermission = await BrowserAPIService.permissions.contains({
       permissions: ['clipboardRead'],
       permissions: ['clipboardRead'],
     });
     });
 
 
@@ -73,7 +74,7 @@ async function interactionHandler(block) {
     }
     }
 
 
     if (debugMode && isChrome) {
     if (debugMode && isChrome) {
-      chrome.debugger.detach({ tabId: this.activeTab.id });
+      BrowserAPIService.debugger.detach({ tabId: this.activeTab.id });
     }
     }
 
 
     return {
     return {
@@ -82,7 +83,7 @@ async function interactionHandler(block) {
     };
     };
   } catch (error) {
   } catch (error) {
     if (debugMode && isChrome) {
     if (debugMode && isChrome) {
-      chrome.debugger.detach({ tabId: this.activeTab.id });
+      BrowserAPIService.debugger.detach({ tabId: this.activeTab.id });
     }
     }
 
 
     error.data = {
     error.data = {

+ 2 - 2
src/workflowEngine/blocksHandler/handlerLink.js

@@ -1,4 +1,4 @@
-import browser from 'webextension-polyfill';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 
 
 export default async function ({ data, id, label }) {
 export default async function ({ data, id, label }) {
   const url = await this._sendMessageToTab({
   const url = await this._sendMessageToTab({
@@ -8,7 +8,7 @@ export default async function ({ data, id, label }) {
   });
   });
 
 
   if (data.openInNewTab) {
   if (data.openInNewTab) {
-    const tab = await browser.tabs.create({
+    const tab = await BrowserAPIService.tabs.create({
       url,
       url,
       windowId: this.activeTab.windowId,
       windowId: this.activeTab.windowId,
     });
     });

+ 9 - 9
src/workflowEngine/blocksHandler/handlerNewTab.js

@@ -1,5 +1,5 @@
-import browser from 'webextension-polyfill';
 import { isWhitespace, sleep } from '@/utils/helper';
 import { isWhitespace, sleep } from '@/utils/helper';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import {
 import {
   waitTabLoaded,
   waitTabLoaded,
   attachDebugger,
   attachDebugger,
@@ -20,7 +20,7 @@ function isValidURL(url) {
 async function newTab({ id, data }) {
 async function newTab({ id, data }) {
   if (this.windowId) {
   if (this.windowId) {
     try {
     try {
-      await browser.windows.get(this.windowId);
+      await BrowserAPIService.windows.get(this.windowId);
     } catch (error) {
     } catch (error) {
       this.windowId = null;
       this.windowId = null;
     }
     }
@@ -39,12 +39,12 @@ async function newTab({ id, data }) {
   const isChrome = BROWSER_TYPE === 'chrome';
   const isChrome = BROWSER_TYPE === 'chrome';
 
 
   if (data.updatePrevTab && this.activeTab.id) {
   if (data.updatePrevTab && this.activeTab.id) {
-    tab = await browser.tabs.update(this.activeTab.id, {
+    tab = await BrowserAPIService.tabs.update(this.activeTab.id, {
       url: data.url,
       url: data.url,
       active: data.active,
       active: data.active,
     });
     });
   } else {
   } else {
-    tab = await browser.tabs.create({
+    tab = await BrowserAPIService.tabs.create({
       url: data.url,
       url: data.url,
       active: data.active,
       active: data.active,
       windowId: this.windowId,
       windowId: this.windowId,
@@ -61,14 +61,14 @@ async function newTab({ id, data }) {
         await sendDebugCommand(tab.id, 'Network.setUserAgentOverride', {
         await sendDebugCommand(tab.id, 'Network.setUserAgentOverride', {
           userAgent: data.userAgent,
           userAgent: data.userAgent,
         });
         });
-        await browser.tabs.reload(tab.id);
+        await BrowserAPIService.tabs.reload(tab.id);
         await sleep(1000);
         await sleep(1000);
       }
       }
     }
     }
 
 
     if (data.tabZoom && data.tabZoom !== 1) {
     if (data.tabZoom && data.tabZoom !== 1) {
       await sleep(1000);
       await sleep(1000);
-      await browser.tabs.setZoom(tab.id, data.tabZoom);
+      await BrowserAPIService.tabs.setZoom(tab.id, data.tabZoom);
     }
     }
 
 
     this.activeTab.id = tab.id;
     this.activeTab.id = tab.id;
@@ -88,7 +88,7 @@ async function newTab({ id, data }) {
     }
     }
 
 
     if (isChrome) {
     if (isChrome) {
-      chrome.tabs.group(options, (tabGroupId) => {
+      BrowserAPIService.tabs.group(options, (tabGroupId) => {
         this.activeTab.groupId = tabGroupId;
         this.activeTab.groupId = tabGroupId;
       });
       });
     }
     }
@@ -97,7 +97,7 @@ async function newTab({ id, data }) {
   this.activeTab.frameId = 0;
   this.activeTab.frameId = 0;
 
 
   if (isChrome && !this.settings.debugMode && data.customUserAgent) {
   if (isChrome && !this.settings.debugMode && data.customUserAgent) {
-    chrome.debugger.detach({ tabId: tab.id });
+    BrowserAPIService.debugger.detach({ tabId: tab.id });
   }
   }
 
 
   if (this.preloadScripts.length > 0) {
   if (this.preloadScripts.length > 0) {
@@ -127,7 +127,7 @@ async function newTab({ id, data }) {
     });
     });
   }
   }
 
 
-  await browser.windows.update(tab.windowId, { focused: true });
+  await BrowserAPIService.windows.update(tab.windowId, { focused: true });
 
 
   return {
   return {
     data: data.url,
     data: data.url,

+ 4 - 2
src/workflowEngine/blocksHandler/handlerNewWindow.js

@@ -1,4 +1,4 @@
-import browser from 'webextension-polyfill';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import { attachDebugger } from '../helper';
 import { attachDebugger } from '../helper';
 
 
 export async function newWindow({ data, id }) {
 export async function newWindow({ data, id }) {
@@ -17,7 +17,9 @@ export async function newWindow({ data, id }) {
   }
   }
   if (data.url) windowOptions.url = data.url;
   if (data.url) windowOptions.url = data.url;
 
 
-  const newWindowInstance = await browser.windows.create(windowOptions);
+  const newWindowInstance = await BrowserAPIService.windows.create(
+    windowOptions
+  );
   this.windowId = newWindowInstance.id;
   this.windowId = newWindowInstance.id;
 
 
   if (data.url) {
   if (data.url) {

+ 4 - 4
src/workflowEngine/blocksHandler/handlerNotification.js

@@ -1,8 +1,8 @@
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import { nanoid } from 'nanoid';
 import { nanoid } from 'nanoid';
-import browser from 'webextension-polyfill';
 
 
 export default async function ({ data, id }) {
 export default async function ({ data, id }) {
-  const hasPermission = await browser.permissions.contains({
+  const hasPermission = await BrowserAPIService.permissions.contains({
     permissions: ['notifications'],
     permissions: ['notifications'],
   });
   });
 
 
@@ -16,7 +16,7 @@ export default async function ({ data, id }) {
   const options = {
   const options = {
     title: data.title,
     title: data.title,
     message: data.message,
     message: data.message,
-    iconUrl: browser.runtime.getURL('icon-128.png'),
+    iconUrl: BrowserAPIService.runtime.getURL('icon-128.png'),
   };
   };
 
 
   ['iconUrl', 'imageUrl'].forEach((key) => {
   ['iconUrl', 'imageUrl'].forEach((key) => {
@@ -26,7 +26,7 @@ export default async function ({ data, id }) {
     options[key] = url;
     options[key] = url;
   });
   });
 
 
-  await browser.notifications.create(nanoid(), {
+  await BrowserAPIService.notifications.create(nanoid(), {
     ...options,
     ...options,
     type: options.imageUrl ? 'image' : 'basic',
     type: options.imageUrl ? 'image' : 'basic',
   });
   });

+ 12 - 12
src/workflowEngine/blocksHandler/handlerParameterPrompt.js

@@ -1,6 +1,6 @@
 import { nanoid } from 'nanoid/non-secure';
 import { nanoid } from 'nanoid/non-secure';
-import browser from 'webextension-polyfill';
 import { sleep } from '@/utils/helper';
 import { sleep } from '@/utils/helper';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import renderString from '../templating/renderString';
 import renderString from '../templating/renderString';
 
 
 function getInputtedParams(promptId, ms = 10000) {
 function getInputtedParams(promptId, ms = 10000) {
@@ -11,8 +11,8 @@ function getInputtedParams(promptId, ms = 10000) {
       if (!event[promptId]) return;
       if (!event[promptId]) return;
 
 
       clearTimeout(timeout);
       clearTimeout(timeout);
-      browser.storage.onChanged.removeListener(storageListener);
-      browser.storage.local.remove(promptId);
+      BrowserAPIService.storage.onChanged.removeListener(storageListener);
+      BrowserAPIService.storage.local.remove(promptId);
 
 
       const { newValue } = event[promptId];
       const { newValue } = event[promptId];
       if (newValue.$isError) {
       if (newValue.$isError) {
@@ -25,12 +25,12 @@ function getInputtedParams(promptId, ms = 10000) {
 
 
     if (ms > 0) {
     if (ms > 0) {
       setTimeout(() => {
       setTimeout(() => {
-        browser.storage.onChanged.removeListener(storageListener);
+        BrowserAPIService.storage.onChanged.removeListener(storageListener);
         resolve({});
         resolve({});
       }, ms);
       }, ms);
     }
     }
 
 
-    browser.storage.onChanged.addListener(storageListener);
+    BrowserAPIService.storage.onChanged.addListener(storageListener);
   });
   });
 }
 }
 
 
@@ -51,25 +51,25 @@ async function renderParamValue(param, refData, isPopup) {
 }
 }
 
 
 export default async function ({ data, id }, { refData }) {
 export default async function ({ data, id }, { refData }) {
-  const paramURL = browser.runtime.getURL('/params.html');
-  let tab = (await browser.tabs.query({})).find((item) =>
+  const paramURL = BrowserAPIService.runtime.getURL('/params.html');
+  let tab = (await BrowserAPIService.tabs.query({})).find((item) =>
     item.url.includes(paramURL)
     item.url.includes(paramURL)
   );
   );
 
 
   if (!tab) {
   if (!tab) {
-    const { tabs } = await browser.windows.create({
+    const { tabs } = await BrowserAPIService.windows.create({
       type: 'popup',
       type: 'popup',
       width: 480,
       width: 480,
       height: 600,
       height: 600,
-      url: browser.runtime.getURL('/params.html'),
+      url: BrowserAPIService.runtime.getURL('/params.html'),
     });
     });
     [tab] = tabs;
     [tab] = tabs;
     await sleep(1000);
     await sleep(1000);
   } else {
   } else {
-    await browser.tabs.update(tab.id, {
+    await BrowserAPIService.tabs.update(tab.id, {
       active: true,
       active: true,
     });
     });
-    await browser.windows.update(tab.windowId, { focused: true });
+    await BrowserAPIService.windows.update(tab.windowId, { focused: true });
   }
   }
 
 
   const promptId = `params-prompt:${nanoid(4)}__${id}`;
   const promptId = `params-prompt:${nanoid(4)}__${id}`;
@@ -81,7 +81,7 @@ export default async function ({ data, id }, { refData }) {
     )
     )
   );
   );
 
 
-  await browser.tabs.sendMessage(tab.id, {
+  await BrowserAPIService.tabs.sendMessage(tab.id, {
     name: 'workflow:params-block',
     name: 'workflow:params-block',
     data: {
     data: {
       params,
       params,

+ 10 - 9
src/workflowEngine/blocksHandler/handlerProxy.js

@@ -1,12 +1,12 @@
-import browser from 'webextension-polyfill';
 import { isWhitespace } from '@/utils/helper';
 import { isWhitespace } from '@/utils/helper';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 
 
 function setProxy({ data, id }) {
 function setProxy({ data, id }) {
   const nextBlockId = this.getBlockConnections(id);
   const nextBlockId = this.getBlockConnections(id);
 
 
   return new Promise((resolve, reject) => {
   return new Promise((resolve, reject) => {
     if (data.clearProxy) {
     if (data.clearProxy) {
-      browser.proxy.settings.clear({});
+      BrowserAPIService.proxy.settings.clear({});
     }
     }
 
 
     const config = {
     const config = {
@@ -62,15 +62,16 @@ function setProxy({ data, id }) {
     if (proxyPort && !Number.isNaN(+proxyPort)) {
     if (proxyPort && !Number.isNaN(+proxyPort)) {
       config.rules.singleProxy.port = +proxyPort;
       config.rules.singleProxy.port = +proxyPort;
     }
     }
+    BrowserAPIService.proxy.settings
+      .set({ value: config, scope: 'regular' })
+      .then(() => {
+        this.engine.isUsingProxy = true;
 
 
-    chrome.proxy.settings.set({ value: config, scope: 'regular' }, () => {
-      this.engine.isUsingProxy = true;
-
-      resolve({
-        data: data.host,
-        nextBlockId,
+        resolve({
+          data: data.host,
+          nextBlockId,
+        });
       });
       });
-    });
   });
   });
 }
 }
 
 

+ 2 - 2
src/workflowEngine/blocksHandler/handlerReloadTab.js

@@ -1,9 +1,9 @@
-import browser from 'webextension-polyfill';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 
 
 export async function reloadTab({ id }) {
 export async function reloadTab({ id }) {
   if (!this.activeTab.id) throw new Error('no-tab');
   if (!this.activeTab.id) throw new Error('no-tab');
 
 
-  await browser.tabs.reload(this.activeTab.id);
+  await BrowserAPIService.tabs.reload(this.activeTab.id);
 
 
   return {
   return {
     data: '',
     data: '',

+ 3 - 3
src/workflowEngine/blocksHandler/handlerSaveAssets.js

@@ -1,4 +1,4 @@
-import browser from 'webextension-polyfill';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 
 
 function getFilename(url) {
 function getFilename(url) {
   try {
   try {
@@ -14,7 +14,7 @@ function getFilename(url) {
 }
 }
 
 
 export default async function ({ data, id, label }) {
 export default async function ({ data, id, label }) {
-  const hasPermission = await browser.permissions.contains({
+  const hasPermission = await BrowserAPIService.permissions.contains({
     permissions: ['downloads'],
     permissions: ['downloads'],
   });
   });
 
 
@@ -40,7 +40,7 @@ export default async function ({ data, id, label }) {
       index += 1;
       index += 1;
     }
     }
 
 
-    return browser.downloads.download(options);
+    return BrowserAPIService.downloads.download(options);
   };
   };
 
 
   let downloadIds = null;
   let downloadIds = null;

+ 9 - 7
src/workflowEngine/blocksHandler/handlerSwitchTab.js

@@ -1,4 +1,4 @@
-import browser from 'webextension-polyfill';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 import { attachDebugger, injectPreloadScript } from '../helper';
 import { attachDebugger, injectPreloadScript } from '../helper';
 
 
 export default async function ({ data, id }) {
 export default async function ({ data, id }) {
@@ -24,7 +24,9 @@ export default async function ({ data, id }) {
 
 
   const isTabsQuery = ['match-patterns', 'tab-title'];
   const isTabsQuery = ['match-patterns', 'tab-title'];
   const tabs =
   const tabs =
-    findTabBy !== 'match-patterns' ? await browser.tabs.query({}) : [];
+    findTabBy !== 'match-patterns'
+      ? await BrowserAPIService.tabs.query({})
+      : [];
 
 
   if (isTabsQuery.includes(findTabBy)) {
   if (isTabsQuery.includes(findTabBy)) {
     const query = {};
     const query = {};
@@ -32,7 +34,7 @@ export default async function ({ data, id }) {
     if (data.findTabBy === 'match-patterns') query.url = data.matchPattern;
     if (data.findTabBy === 'match-patterns') query.url = data.matchPattern;
     else if (data.findTabBy === 'tab-title') query.title = data.tabTitle;
     else if (data.findTabBy === 'tab-title') query.title = data.tabTitle;
 
 
-    [tab] = await browser.tabs.query(query);
+    [tab] = await BrowserAPIService.tabs.query(query);
 
 
     if (!tab) {
     if (!tab) {
       if (data.createIfNoMatch) {
       if (data.createIfNoMatch) {
@@ -40,9 +42,9 @@ export default async function ({ data, id }) {
           throw generateError('invalid-active-tab', { url: data.url });
           throw generateError('invalid-active-tab', { url: data.url });
         }
         }
 
 
-        tab = await browser.tabs.create({
-          active: activeTab,
+        tab = await BrowserAPIService.tabs.create({
           url: data.url,
           url: data.url,
+          active: activeTab,
           windowId: this.windowId,
           windowId: this.windowId,
         });
         });
       } else {
       } else {
@@ -66,7 +68,7 @@ export default async function ({ data, id }) {
       throw generateError(`Can't find a tab with ${data.tabIndex} index`);
       throw generateError(`Can't find a tab with ${data.tabIndex} index`);
   }
   }
 
 
-  await browser.tabs.update(tab.id, { active: activeTab });
+  await BrowserAPIService.tabs.update(tab.id, { active: activeTab });
 
 
   this.activeTab.id = tab.id;
   this.activeTab.id = tab.id;
   this.activeTab.frameId = 0;
   this.activeTab.frameId = 0;
@@ -98,7 +100,7 @@ export default async function ({ data, id }) {
   }
   }
 
 
   if (activeTab) {
   if (activeTab) {
-    await browser.windows.update(tab.windowId, { focused: true });
+    await BrowserAPIService.windows.update(tab.windowId, { focused: true });
   }
   }
 
 
   return {
   return {

+ 3 - 3
src/workflowEngine/blocksHandler/handlerTabUrl.js

@@ -1,4 +1,4 @@
-import browser from 'webextension-polyfill';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 
 
 export async function logData({ id, data }) {
 export async function logData({ id, data }) {
   let urls = [];
   let urls = [];
@@ -6,7 +6,7 @@ export async function logData({ id, data }) {
   if (data.type === 'active-tab') {
   if (data.type === 'active-tab') {
     if (!this.activeTab.id) throw new Error('no-tab');
     if (!this.activeTab.id) throw new Error('no-tab');
 
 
-    const tab = await browser.tabs.get(this.activeTab.id);
+    const tab = await BrowserAPIService.tabs.get(this.activeTab.id);
     urls = tab.url || tab.pendingUrl || '';
     urls = tab.url || tab.pendingUrl || '';
   } else {
   } else {
     const query = {};
     const query = {};
@@ -18,7 +18,7 @@ export async function logData({ id, data }) {
       query.title = data.qTitle;
       query.title = data.qTitle;
     }
     }
 
 
-    const tabs = await browser.tabs.query(query);
+    const tabs = await BrowserAPIService.tabs.query(query);
     urls = tabs.map((tab) => tab.url);
     urls = tabs.map((tab) => tab.url);
   }
   }
 
 

+ 24 - 12
src/workflowEngine/blocksHandler/handlerTakeScreenshot.js

@@ -1,15 +1,16 @@
-import browser from 'webextension-polyfill';
 import { fileSaver } from '@/utils/helper';
 import { fileSaver } from '@/utils/helper';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
+import { IS_FIREFOX } from '@/common/utils/constant';
 import { waitTabLoaded } from '../helper';
 import { waitTabLoaded } from '../helper';
 
 
 async function saveImage({ filename, uri, ext }) {
 async function saveImage({ filename, uri, ext }) {
-  const hasDownloadAccess = await browser.permissions.contains({
+  const hasDownloadAccess = await BrowserAPIService.permissions.contains({
     permissions: ['downloads'],
     permissions: ['downloads'],
   });
   });
   const name = `${filename || 'Screenshot'}.${ext || 'png'}`;
   const name = `${filename || 'Screenshot'}.${ext || 'png'}`;
 
 
   if (hasDownloadAccess) {
   if (hasDownloadAccess) {
-    await browser.downloads.download({
+    await BrowserAPIService.downloads.download({
       url: uri,
       url: uri,
       filename: name,
       filename: name,
     });
     });
@@ -61,31 +62,42 @@ async function takeScreenshot({ data, id, label }) {
       }
       }
 
 
       let tab = null;
       let tab = null;
-      const isChrome = BROWSER_TYPE === 'chrome';
+      const isChrome = !IS_FIREFOX;
       const captureTab = async () => {
       const captureTab = async () => {
         let result = null;
         let result = null;
 
 
         if (isChrome) {
         if (isChrome) {
-          result = await browser.tabs.captureVisibleTab(tab.windowId, options);
+          const currentTab = await BrowserAPIService.tabs.get(
+            this.activeTab.id
+          );
+          result = await BrowserAPIService.tabs.captureVisibleTab(
+            currentTab.windowId,
+            options
+          );
         } else {
         } else {
-          result = await browser.tabs.captureTab(this.activeTab.id, options);
+          result = await BrowserAPIService.tabs.captureTab(
+            this.activeTab.id,
+            options
+          );
         }
         }
 
 
         return result;
         return result;
       };
       };
 
 
       if (isChrome) {
       if (isChrome) {
-        [tab] = await browser.tabs.query({
+        [tab] = await BrowserAPIService.tabs.query({
           active: true,
           active: true,
           url: '*://*/*',
           url: '*://*/*',
         });
         });
 
 
         if (this.windowId) {
         if (this.windowId) {
-          await browser.windows.update(this.windowId, { focused: true });
+          await BrowserAPIService.windows.update(this.windowId, {
+            focused: true,
+          });
         }
         }
       }
       }
 
 
-      await browser.tabs.update(this.activeTab.id, { active: true });
+      await BrowserAPIService.tabs.update(this.activeTab.id, { active: true });
       await waitTabLoaded({ tabId: this.activeTab.id, listenError: true });
       await waitTabLoaded({ tabId: this.activeTab.id, listenError: true });
 
 
       screenshot = await (data.fullPage ||
       screenshot = await (data.fullPage ||
@@ -102,13 +114,13 @@ async function takeScreenshot({ data, id, label }) {
         : captureTab());
         : captureTab());
 
 
       if (tab) {
       if (tab) {
-        await browser.windows.update(tab.windowId, { focused: true });
-        await browser.tabs.update(tab.id, { active: true });
+        await BrowserAPIService.windows.update(tab.windowId, { focused: true });
+        await BrowserAPIService.tabs.update(tab.id, { active: true });
       }
       }
 
 
       await saveScreenshot(screenshot);
       await saveScreenshot(screenshot);
     } else {
     } else {
-      screenshot = await browser.tabs.captureVisibleTab(options);
+      screenshot = await BrowserAPIService.tabs.captureVisibleTab(options);
 
 
       await saveScreenshot(screenshot);
       await saveScreenshot(screenshot);
     }
     }

+ 17 - 6
src/workflowEngine/helper.js

@@ -1,5 +1,6 @@
 import browser from 'webextension-polyfill';
 import browser from 'webextension-polyfill';
 import { customAlphabet } from 'nanoid/non-secure';
 import { customAlphabet } from 'nanoid/non-secure';
+import BrowserAPIService from '@/service/browser-api/BrowserAPIService';
 
 
 export function escapeElementPolicy(script) {
 export function escapeElementPolicy(script) {
   if (window?.trustedTypes?.createPolicy) {
   if (window?.trustedTypes?.createPolicy) {
@@ -38,7 +39,9 @@ export function messageSandbox(type, data = {}) {
 
 
 export async function getFrames(tabId) {
 export async function getFrames(tabId) {
   try {
   try {
-    const frames = await browser.webNavigation.getAllFrames({ tabId });
+    const frames = await BrowserAPIService.webNavigation.getAllFrames({
+      tabId,
+    });
     const framesObj = frames.reduce((acc, { frameId, url }) => {
     const framesObj = frames.reduce((acc, { frameId, url }) => {
       const key = url === 'about:blank' ? '' : url;
       const key = url === 'about:blank' ? '' : url;
 
 
@@ -85,21 +88,27 @@ export function waitTabLoaded({ tabId, listenError = false, ms = 10000 }) {
         return;
         return;
 
 
       clearTimeout(timeout);
       clearTimeout(timeout);
-      browser.webNavigation.onErrorOccurred.removeListener(onErrorOccurred);
+      BrowserAPIService.webNavigation.onErrorOccurred.removeListener(
+        onErrorOccurred
+      );
       reject(new Error(details.error));
       reject(new Error(details.error));
     };
     };
 
 
     if (ms > 0) {
     if (ms > 0) {
       timeout = setTimeout(() => {
       timeout = setTimeout(() => {
-        browser.webNavigation.onErrorOccurred.removeListener(onErrorOccurred);
+        BrowserAPIService.webNavigation.onErrorOccurred.removeListener(
+          onErrorOccurred
+        );
         reject(new Error('Timeout'));
         reject(new Error('Timeout'));
       }, ms);
       }, ms);
     }
     }
     if (listenError && BROWSER_TYPE === 'chrome')
     if (listenError && BROWSER_TYPE === 'chrome')
-      browser.webNavigation.onErrorOccurred.addListener(onErrorOccurred);
+      BrowserAPIService.webNavigation.onErrorOccurred.addListener(
+        onErrorOccurred
+      );
 
 
     const activeTabStatus = () => {
     const activeTabStatus = () => {
-      browser.tabs.get(tabId).then((tab) => {
+      BrowserAPIService.tabs.get(tabId).then((tab) => {
         if (!tab) {
         if (!tab) {
           reject(new Error('no-tab'));
           reject(new Error('no-tab'));
           return;
           return;
@@ -114,7 +123,9 @@ export function waitTabLoaded({ tabId, listenError = false, ms = 10000 }) {
 
 
         clearTimeout(timeout);
         clearTimeout(timeout);
 
 
-        browser.webNavigation.onErrorOccurred.removeListener(onErrorOccurred);
+        BrowserAPIService.webNavigation.onErrorOccurred.removeListener(
+          onErrorOccurred
+        );
         resolve();
         resolve();
       });
       });
     };
     };