From 4772efdd83c1bfa7b243a8e50b091abc74f8f2b7 Mon Sep 17 00:00:00 2001 From: TrinityHades <11bailess11@gmail.com> Date: Fri, 22 Aug 2025 14:57:38 -0700 Subject: [PATCH] fix: lint check --- SAFARI.md | 8 +- src/background.ts | 51 ++++----- src/background/messages/makeRequest.ts | 130 ++++++++++------------- src/background/messages/openPage.ts | 22 ++-- src/components/SafariPermissionGuide.tsx | 36 +++---- src/contents/movie-web.ts | 43 ++++---- src/hooks/useDomainWhitelist.ts | 4 +- src/hooks/usePermission.ts | 78 +++++++------- src/utils/declarativeNetRequest.ts | 99 ++++++++--------- src/utils/extension.ts | 24 ++--- src/utils/tabs.ts | 35 +++--- 11 files changed, 240 insertions(+), 290 deletions(-) diff --git a/SAFARI.md b/SAFARI.md index 0ccc48d..8444b1a 100644 --- a/SAFARI.md +++ b/SAFARI.md @@ -38,16 +38,21 @@ Safari requires manual permission setup: ### 3. Common Safari Issues & Fixes #### Issue: "Invalid call to runtime.connect()" + **Fix**: This occurs when the background script isn't ready. The extension now includes: + - Delayed messaging setup for Safari - Retry logic for failed connections - Better error handling #### Issue: WebSocket Connection Blocked + **Fix**: Use `pnpm dev:safari` which disables hot-reload WebSockets that Safari blocks. #### Issue: Permissions Not Working -**Fix**: + +**Fix**: + - Ensure both `host_permissions` and `optional_host_permissions` are in manifest - Guide users through Safari's manual permission setup - Check permissions through Safari Preferences, not runtime API @@ -71,6 +76,7 @@ Safari requires manual permission setup: ### 6. Production Deployment For Safari App Store distribution: + 1. You'll need to create a native macOS app wrapper 2. Use Xcode to create the Safari extension project 3. Follow Apple's Safari extension guidelines diff --git a/src/background.ts b/src/background.ts index 8893fee..a62a75b 100644 --- a/src/background.ts +++ b/src/background.ts @@ -1,56 +1,47 @@ -import '@plasmohq/messaging/background' +import '@plasmohq/messaging/background'; +import { getBrowserAPI, isChrome, isFirefox, isSafari } from '~utils/extension'; -import { getBrowserAPI, isChrome, isFirefox, isSafari } from '~utils/extension' +const browserAPI = getBrowserAPI(); -// Initialize Plasmo messaging system -// This ensures that the messaging handlers are properly set up -console.log('Background script loaded') - -const browserAPI = getBrowserAPI() - -// Safari has different startup behavior, so we need to handle it differently if (isSafari()) { // Safari doesn't need the reload behavior that Chrome/Firefox require - console.log('Running on Safari') + console.log('Running on Safari'); // Ensure messaging is ready for Safari browserAPI.runtime.onInstalled.addListener(() => { - console.log('Safari extension installed/updated') + console.log('Safari extension installed/updated'); // Give Safari time to initialize messaging setTimeout(() => { - console.log('Safari messaging should be ready') - }, 1000) - }) + console.log('Safari messaging should be ready'); + }, 1000); + }); // Handle Safari runtime errors more gracefully - browserAPI.runtime.onConnect.addListener(port => { - console.log('Safari port connected:', port.name) + browserAPI.runtime.onConnect.addListener((port) => { + console.log('Safari port connected:', port.name); port.onDisconnect.addListener(() => { if (browserAPI.runtime.lastError) { - console.log( - 'Safari port disconnected with error:', - browserAPI.runtime.lastError.message - ) + console.log('Safari port disconnected with error:', browserAPI.runtime.lastError.message); } - }) - }) + }); + }); } else if (isChrome()) { // Both brave and chrome for some reason need this extension reload, // If this isn't done, they will never load properly and will fail updateDynamicRules() chrome.runtime.onStartup.addListener(() => { - chrome.runtime.reload() - }) + chrome.runtime.reload(); + }); chrome.runtime.onInstalled.addListener(() => { - console.log('Chrome extension installed/updated') - }) + console.log('Chrome extension installed/updated'); + }); } else if (isFirefox()) { // Firefox behavior browser.runtime.onStartup.addListener(() => { - browser.runtime.reload() - }) + browser.runtime.reload(); + }); browser.runtime.onInstalled.addListener(() => { - console.log('Firefox extension installed/updated') - }) + console.log('Firefox extension installed/updated'); + }); } diff --git a/src/background/messages/makeRequest.ts b/src/background/messages/makeRequest.ts index 7c1845a..2e1fd9a 100644 --- a/src/background/messages/makeRequest.ts +++ b/src/background/messages/makeRequest.ts @@ -1,70 +1,60 @@ -import type { PlasmoMessaging } from '@plasmohq/messaging' +import type { PlasmoMessaging } from '@plasmohq/messaging'; -import type { BaseRequest } from '~types/request' -import type { BaseResponse } from '~types/response' -import { - removeDynamicRules, - setDynamicRules -} from '~utils/declarativeNetRequest' -import { getBrowserAPI, isFirefox, isSafari } from '~utils/extension' -import { makeFullUrl } from '~utils/fetcher' -import { assertDomainWhitelist, canAccessCookies } from '~utils/storage' +import type { BaseRequest } from '~types/request'; +import type { BaseResponse } from '~types/response'; +import { removeDynamicRules, setDynamicRules } from '~utils/declarativeNetRequest'; +import { isFirefox } from '~utils/extension'; +import { makeFullUrl } from '~utils/fetcher'; +import { assertDomainWhitelist, canAccessCookies } from '~utils/storage'; -const MAKE_REQUEST_DYNAMIC_RULE = 23498 +const MAKE_REQUEST_DYNAMIC_RULE = 23498; export interface Request extends BaseRequest { - baseUrl?: string - headers?: Record - method?: string - query?: Record - readHeaders?: Record - url: string - body?: any - bodyType?: 'string' | 'FormData' | 'URLSearchParams' | 'object' + baseUrl?: string; + headers?: Record; + method?: string; + query?: Record; + readHeaders?: Record; + url: string; + body?: any; + bodyType?: 'string' | 'FormData' | 'URLSearchParams' | 'object'; } type Response = BaseResponse<{ response: { - statusCode: number - headers: Record - finalUrl: string - body: T - } -}> + statusCode: number; + headers: Record; + finalUrl: string; + body: T; + }; +}>; -const mapBodyToFetchBody = ( - body: Request['body'], - bodyType: Request['bodyType'] -): BodyInit => { +const mapBodyToFetchBody = (body: Request['body'], bodyType: Request['bodyType']): BodyInit => { if (bodyType === 'FormData') { - const formData = new FormData() + const formData = new FormData(); body.forEach(([key, value]: [any, any]) => { - formData.append(key, value.toString()) - }) + formData.append(key, value.toString()); + }); } if (bodyType === 'URLSearchParams') { - return new URLSearchParams(body) + return new URLSearchParams(body); } if (bodyType === 'object') { - return JSON.stringify(body) + return JSON.stringify(body); } if (bodyType === 'string') { - return body + return body; } - return body -} + return body; +}; -const handler: PlasmoMessaging.MessageHandler> = async ( - req, - res -) => { +const handler: PlasmoMessaging.MessageHandler> = async (req, res) => { try { - if (!req.sender?.tab?.url) - throw new Error('No tab URL found in the request.') - if (!req.body) throw new Error('No request body found in the request.') + if (!req.sender?.tab?.url) throw new Error('No tab URL found in the request.'); + if (!req.body) throw new Error('No request body found in the request.'); - const url = makeFullUrl(req.body.url, req.body) - await assertDomainWhitelist(req.sender.tab.url) + const url = makeFullUrl(req.body.url, req.body); + await assertDomainWhitelist(req.sender.tab.url); await setDynamicRules({ ruleId: MAKE_REQUEST_DYNAMIC_RULE, @@ -73,28 +63,26 @@ const handler: PlasmoMessaging.MessageHandler> = async ( // set Access-Control-Allow-Credentials if the reqested host has access to cookies responseHeaders: { ...(canAccessCookies(new URL(url).hostname) && { - 'Access-Control-Allow-Credentials': 'true' - }) - } - }) + 'Access-Control-Allow-Credentials': 'true', + }), + }, + }); const response = await fetch(url, { method: req.body.method, headers: req.body.headers, - body: mapBodyToFetchBody(req.body.body, req.body.bodyType) - }) - await removeDynamicRules([MAKE_REQUEST_DYNAMIC_RULE]) - const contentType = response.headers.get('content-type') - const body = contentType?.includes('application/json') - ? await response.json() - : await response.text() + body: mapBodyToFetchBody(req.body.body, req.body.bodyType), + }); + await removeDynamicRules([MAKE_REQUEST_DYNAMIC_RULE]); + const contentType = response.headers.get('content-type'); + const body = contentType?.includes('application/json') ? await response.json() : await response.text(); const cookies = await (chrome || browser).cookies.getAll({ url: response.url, ...(isFirefox() && { - firstPartyDomain: new URL(response.url).hostname - }) - }) + firstPartyDomain: new URL(response.url).hostname, + }), + }); res.send({ success: true, @@ -104,22 +92,20 @@ const handler: PlasmoMessaging.MessageHandler> = async ( ...Object.fromEntries(response.headers.entries()), // include cookies if allowed for the reqested host ...(canAccessCookies(new URL(url).hostname) && { - 'Set-Cookie': cookies - .map(cookie => `${cookie.name}=${cookie.value}`) - .join(', ') - }) + 'Set-Cookie': cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join(', '), + }), }, body, - finalUrl: response.url - } - }) + finalUrl: response.url, + }, + }); } catch (err) { - console.error('failed request', err) + console.error('failed request', err); res.send({ success: false, - error: err instanceof Error ? err.message : String(err) - }) + error: err instanceof Error ? err.message : String(err), + }); } -} +}; -export default handler +export default handler; diff --git a/src/background/messages/openPage.ts b/src/background/messages/openPage.ts index 31bf1a1..fe83ada 100644 --- a/src/background/messages/openPage.ts +++ b/src/background/messages/openPage.ts @@ -1,8 +1,8 @@ -import type { PlasmoMessaging } from '@plasmohq/messaging' +import type { PlasmoMessaging } from '@plasmohq/messaging'; -import type { BaseRequest } from '~types/request' -import type { BaseResponse } from '~types/response' -import { getBrowserAPI } from '~utils/extension' +import type { BaseRequest } from '~types/request'; +import type { BaseResponse } from '~types/response'; +import { getBrowserAPI } from '~utils/extension'; type Request = BaseRequest & { page: string; @@ -14,15 +14,13 @@ const handler: PlasmoMessaging.MessageHandler = async (re if (!req.sender?.tab?.id) throw new Error('No tab ID found in the request.'); if (!req.body) throw new Error('No body found in the request.'); - const searchParams = new URLSearchParams() - searchParams.set('redirectUrl', req.body.redirectUrl) + const searchParams = new URLSearchParams(); + searchParams.set('redirectUrl', req.body.redirectUrl); - const browserAPI = getBrowserAPI() - const url = browserAPI.runtime.getURL( - `/tabs/${req.body.page}.html?${searchParams.toString()}` - ) + const browserAPI = getBrowserAPI(); + const url = browserAPI.runtime.getURL(`/tabs/${req.body.page}.html?${searchParams.toString()}`); await (browserAPI.tabs as any).update(req.sender.tab.id, { - url + url, }); res.send({ @@ -34,6 +32,6 @@ const handler: PlasmoMessaging.MessageHandler = async (re error: err instanceof Error ? err.message : String(err), }); } -} +}; export default handler; diff --git a/src/components/SafariPermissionGuide.tsx b/src/components/SafariPermissionGuide.tsx index d0fd0dd..51ee0a6 100644 --- a/src/components/SafariPermissionGuide.tsx +++ b/src/components/SafariPermissionGuide.tsx @@ -2,8 +2,8 @@ import { useCallback } from 'react'; import { Button } from '~components/Button'; import { Icon } from '~components/Icon'; -import { isSafari } from '~utils/extension'; import { usePermission } from '~hooks/usePermission'; +import { isSafari } from '~utils/extension'; import '../tabs/PermissionRequest.css'; @@ -40,59 +40,47 @@ export default function SafariPermissionGuide() { return (
-

- Safari Setup Required -

+

Safari Setup Required

Safari extensions require manual setup. Please follow these steps to enable the P-Stream extension:

- } - purple - > + } purple>

Step 1: Enable Extension

- Open Safari → Preferences → Extensions, then enable "P-Stream extension" + Open Safari → Preferences → Extensions, then enable "P-Stream extension"

- } - > + }>

Step 2: Grant Website Access

- Go to Safari → Preferences → Websites → P-Stream extension → Set to "Allow on all websites" or add specific sites + Go to Safari → Preferences → Websites → P-Stream extension → Set to "Allow on all websites" or + add specific sites

- } - > + }>

Step 3: Reload Pages

-

- Reload any streaming website pages where you want to use the extension -

+

Reload any streaming website pages where you want to use the extension

- +

- Note: Safari handles extension permissions differently than Chrome. - These steps are required for the extension to work properly with streaming websites. + Note: Safari handles extension permissions differently than Chrome. These steps are + required for the extension to work properly with streaming websites.

diff --git a/src/contents/movie-web.ts b/src/contents/movie-web.ts index f5addc9..5abf063 100644 --- a/src/contents/movie-web.ts +++ b/src/contents/movie-web.ts @@ -1,49 +1,48 @@ -import { relayMessage } from '@plasmohq/messaging' -import type { PlasmoCSConfig } from 'plasmo' +import { relayMessage } from '@plasmohq/messaging'; +import type { PlasmoCSConfig } from 'plasmo'; export const config: PlasmoCSConfig = { - matches: [''] -} + matches: [''], +}; // Safari requires a delay before setting up messaging const isSafari = () => { try { return ( chrome.runtime.getURL('').startsWith('safari-web-extension://') || - (typeof browser !== 'undefined' && - browser.runtime.getURL('').startsWith('safari-web-extension://')) - ) + (typeof browser !== 'undefined' && browser.runtime.getURL('').startsWith('safari-web-extension://')) + ); } catch { - return false + return false; } -} +}; const setupMessaging = () => { try { relayMessage({ - name: 'hello' - }) + name: 'hello', + }); relayMessage({ - name: 'makeRequest' - }) + name: 'makeRequest', + }); relayMessage({ - name: 'prepareStream' - }) + name: 'prepareStream', + }); relayMessage({ - name: 'openPage' - }) + name: 'openPage', + }); } catch (error) { - console.log('Failed to setup messaging, retrying...', error) - setTimeout(setupMessaging, 1000) + console.log('Failed to setup messaging, retrying...', error); + setTimeout(setupMessaging, 1000); } -} +}; // Safari needs a delay to ensure background script is ready if (isSafari()) { - setTimeout(setupMessaging, 500) + setTimeout(setupMessaging, 500); } else { - setupMessaging() + setupMessaging(); } diff --git a/src/hooks/useDomainWhitelist.ts b/src/hooks/useDomainWhitelist.ts index 9bf332c..a45e711 100644 --- a/src/hooks/useDomainWhitelist.ts +++ b/src/hooks/useDomainWhitelist.ts @@ -27,9 +27,7 @@ export function useToggleWhitelistDomain(domain: string | null) { const { domainWhitelist, addDomain, removeDomain } = useDomainWhitelist(); const isWhitelisted = domainWhitelist.includes(domain ?? ''); const { grantPermission } = usePermission(); - const iconPath = (chrome || browser).runtime.getURL( - isWhitelisted ? 'assets/active.png' : 'assets/inactive.png', - ); + const iconPath = (chrome || browser).runtime.getURL(isWhitelisted ? 'assets/active.png' : 'assets/inactive.png'); (chrome || browser).action.setIcon({ path: iconPath, diff --git a/src/hooks/usePermission.ts b/src/hooks/usePermission.ts index 8a0426d..9207d91 100644 --- a/src/hooks/usePermission.ts +++ b/src/hooks/usePermission.ts @@ -1,81 +1,83 @@ -import { useCallback, useEffect, useState } from 'react' +import { useCallback, useEffect, useState } from 'react'; -import { getBrowserAPI, isSafari } from '~utils/extension' -import { useDomainWhitelist } from './useDomainWhitelist' +import { getBrowserAPI, isSafari } from '~utils/extension'; -export async function hasPermission () { - const browserAPI = getBrowserAPI() +import { useDomainWhitelist } from './useDomainWhitelist'; + +export async function hasPermission() { + const browserAPI = getBrowserAPI(); if (isSafari()) { try { const tabs = await (browserAPI.tabs as any).query({ active: true, - currentWindow: true - }) - return tabs && tabs.length > 0 + currentWindow: true, + }); + return tabs && tabs.length > 0; } catch (error) { - console.log('Safari permission check failed:', error) - return false + console.log('Safari permission check failed:', error); + return false; } } try { return await (browserAPI.permissions as any).contains({ - origins: [''] - }) + origins: [''], + }); } catch (error) { - console.log('Permission check failed:', error) - return false + console.log('Permission check failed:', error); + return false; } } -export function usePermission () { - const { addDomain } = useDomainWhitelist() - const [permission, setPermission] = useState(false) +export function usePermission() { + const { addDomain } = useDomainWhitelist(); + const [permission, setPermission] = useState(false); const grantPermission = useCallback( async (domain?: string) => { - const browserAPI = getBrowserAPI() + const browserAPI = getBrowserAPI(); if (isSafari()) { - const hasPerms = await hasPermission() + const hasPerms = await hasPermission(); if (!hasPerms) { + // eslint-disable-next-line no-alert alert( 'To use this extension, please:\n\n' + '1. Open Safari Preferences\n' + '2. Go to the Websites tab\n' + '3. Find "P-Stream extension" in the left sidebar\n' + '4. Set it to "Allow" for the websites you want to use\n\n' + - 'You may also need to enable the extension in Safari > Preferences > Extensions' - ) - return false + 'You may also need to enable the extension in Safari > Preferences > Extensions', + ); + return false; } - setPermission(true) - if (domain) addDomain(domain) - return true + setPermission(true); + if (domain) addDomain(domain); + return true; } try { const granted = await (browserAPI.permissions as any).request({ - origins: [''] - }) - setPermission(granted) - if (granted && domain) addDomain(domain) - return granted + origins: [''], + }); + setPermission(granted); + if (granted && domain) addDomain(domain); + return granted; } catch (error) { - console.log('Permission request failed:', error) - return false + console.log('Permission request failed:', error); + return false; } }, - [addDomain] - ) + [addDomain], + ); useEffect(() => { - hasPermission().then(has => setPermission(has)) - }, []) + hasPermission().then((has) => setPermission(has)); + }, []); return { hasPermission: permission, - grantPermission - } + grantPermission, + }; } diff --git a/src/utils/declarativeNetRequest.ts b/src/utils/declarativeNetRequest.ts index fbb2503..1b3c5ba 100644 --- a/src/utils/declarativeNetRequest.ts +++ b/src/utils/declarativeNetRequest.ts @@ -1,27 +1,26 @@ -import { getBrowserAPI, isChrome, isSafari } from './extension' -import { modifiableResponseHeaders } from './storage' +import { getBrowserAPI, isChrome, isSafari } from './extension'; interface DynamicRule { - ruleId: number - targetDomains?: [string, ...string[]] - targetRegex?: string - requestHeaders?: Record - responseHeaders?: Record + ruleId: number; + targetDomains?: [string, ...string[]]; + targetRegex?: string; + requestHeaders?: Record; + responseHeaders?: Record; } const mapHeadersToDeclarativeNetRequestHeaders = ( headers: Record, - op: string + op: string, ): { header: string; operation: any; value: string }[] => { return Object.entries(headers).map(([name, value]) => ({ header: name, operation: op, - value - })) -} + value, + })); +}; export const setDynamicRules = async (body: DynamicRule) => { - const browserAPI = getBrowserAPI() + const browserAPI = getBrowserAPI(); if (isChrome() || isSafari()) { await (browserAPI.declarativeNetRequest as any).updateDynamicRules({ @@ -31,44 +30,37 @@ export const setDynamicRules = async (body: DynamicRule) => { id: body.ruleId, condition: { ...(body.targetDomains && { requestDomains: body.targetDomains }), - ...(body.targetRegex && { regexFilter: body.targetRegex }) + ...(body.targetRegex && { regexFilter: body.targetRegex }), }, action: { type: 'modifyHeaders', - ...(body.requestHeaders && - Object.keys(body.requestHeaders).length > 0 + ...(body.requestHeaders && Object.keys(body.requestHeaders).length > 0 ? { - requestHeaders: mapHeadersToDeclarativeNetRequestHeaders( - body.requestHeaders, - 'set' - ) + requestHeaders: mapHeadersToDeclarativeNetRequestHeaders(body.requestHeaders, 'set'), } : {}), responseHeaders: [ { header: 'Access-Control-Allow-Origin', operation: 'set', - value: '*' + value: '*', }, { header: 'Access-Control-Allow-Methods', operation: 'set', - value: 'GET, POST, PUT, DELETE, PATCH, OPTIONS' + value: 'GET, POST, PUT, DELETE, PATCH, OPTIONS', }, { header: 'Access-Control-Allow-Headers', operation: 'set', - value: '*' + value: '*', }, - ...mapHeadersToDeclarativeNetRequestHeaders( - body.responseHeaders ?? {}, - 'set' - ) - ] - } - } - ] - }) + ...mapHeadersToDeclarativeNetRequestHeaders(body.responseHeaders ?? {}, 'set'), + ], + }, + }, + ], + }); } else { // Firefox await (browserAPI.declarativeNetRequest as any).updateDynamicRules({ @@ -78,57 +70,50 @@ export const setDynamicRules = async (body: DynamicRule) => { id: body.ruleId, condition: { ...(body.targetDomains && { requestDomains: body.targetDomains }), - ...(body.targetRegex && { regexFilter: body.targetRegex }) + ...(body.targetRegex && { regexFilter: body.targetRegex }), }, action: { type: 'modifyHeaders', - ...(body.requestHeaders && - Object.keys(body.requestHeaders).length > 0 + ...(body.requestHeaders && Object.keys(body.requestHeaders).length > 0 ? { - requestHeaders: mapHeadersToDeclarativeNetRequestHeaders( - body.requestHeaders, - 'set' - ) + requestHeaders: mapHeadersToDeclarativeNetRequestHeaders(body.requestHeaders, 'set'), } : {}), responseHeaders: [ { header: 'Access-Control-Allow-Origin', operation: 'set', - value: '*' + value: '*', }, { header: 'Access-Control-Allow-Methods', operation: 'set', - value: 'GET, POST, PUT, DELETE, PATCH, OPTIONS' + value: 'GET, POST, PUT, DELETE, PATCH, OPTIONS', }, { header: 'Access-Control-Allow-Headers', operation: 'set', - value: '*' + value: '*', }, - ...mapHeadersToDeclarativeNetRequestHeaders( - body.responseHeaders ?? {}, - 'set' - ) - ] - } - } - ] - }) + ...mapHeadersToDeclarativeNetRequestHeaders(body.responseHeaders ?? {}, 'set'), + ], + }, + }, + ], + }); } if (browserAPI.runtime.lastError?.message) { - throw new Error(browserAPI.runtime.lastError.message) + throw new Error(browserAPI.runtime.lastError.message); } -} +}; export const removeDynamicRules = async (ruleIds: number[]) => { - const browserAPI = getBrowserAPI() + const browserAPI = getBrowserAPI(); await (browserAPI.declarativeNetRequest as any).updateDynamicRules({ - removeRuleIds: ruleIds - }) + removeRuleIds: ruleIds, + }); if (browserAPI.runtime.lastError?.message) { - throw new Error(browserAPI.runtime.lastError?.message ?? 'Unknown error') + throw new Error(browserAPI.runtime.lastError?.message ?? 'Unknown error'); } -} +}; diff --git a/src/utils/extension.ts b/src/utils/extension.ts index 80342bf..2dc244e 100644 --- a/src/utils/extension.ts +++ b/src/utils/extension.ts @@ -1,32 +1,32 @@ export const isChrome = () => { - return chrome.runtime.getURL('').startsWith('chrome-extension://') -} + return chrome.runtime.getURL('').startsWith('chrome-extension://'); +}; export const isFirefox = () => { try { - return browser.runtime.getURL('').startsWith('moz-extension://') + return browser.runtime.getURL('').startsWith('moz-extension://'); } catch { - return false + return false; } -} +}; export const isSafari = () => { try { return ( chrome.runtime.getURL('').startsWith('safari-web-extension://') || browser.runtime.getURL('').startsWith('safari-web-extension://') - ) + ); } catch { - return false + return false; } -} +}; export const getBrowserAPI = () => { if (isSafari()) { - return typeof browser !== 'undefined' ? browser : chrome + return typeof browser !== 'undefined' ? browser : chrome; } if (isFirefox()) { - return browser + return browser; } - return chrome -} + return chrome; +}; diff --git a/src/utils/tabs.ts b/src/utils/tabs.ts index 831f55e..73dd21a 100644 --- a/src/utils/tabs.ts +++ b/src/utils/tabs.ts @@ -1,26 +1,23 @@ -import { getBrowserAPI, isChrome, isSafari } from './extension' +import { getBrowserAPI } from './extension'; -export function queryCurrentDomain (cb: (domain: string | null) => void) { +export function queryCurrentDomain(cb: (domain: string | null) => void) { const handle = (tabUrl: string | undefined) => { - if (!tabUrl) cb(null) - else cb(tabUrl) - } - const ops = { active: true, currentWindow: true } as const - const browserAPI = getBrowserAPI() - - ;(browserAPI.tabs as any) - .query(ops) - .then((tabs: any[]) => handle(tabs[0]?.url)) + if (!tabUrl) cb(null); + else cb(tabUrl); + }; + const ops = { active: true, currentWindow: true } as const; + const browserAPI = getBrowserAPI(); + (browserAPI.tabs as any).query(ops).then((tabs: any[]) => handle(tabs[0]?.url)); } -export function listenToTabChanges (cb: () => void) { - const browserAPI = getBrowserAPI() - ;(browserAPI.tabs as any).onActivated.addListener(cb) - ;(browserAPI.tabs as any).onUpdated.addListener(cb) +export function listenToTabChanges(cb: () => void) { + const browserAPI = getBrowserAPI(); + (browserAPI.tabs as any).onActivated.addListener(cb); + (browserAPI.tabs as any).onUpdated.addListener(cb); } -export function stopListenToTabChanges (cb: () => void) { - const browserAPI = getBrowserAPI() - ;(browserAPI.tabs as any).onActivated.removeListener(cb) - ;(browserAPI.tabs as any).onUpdated.removeListener(cb) +export function stopListenToTabChanges(cb: () => void) { + const browserAPI = getBrowserAPI(); + (browserAPI.tabs as any).onActivated.removeListener(cb); + (browserAPI.tabs as any).onUpdated.removeListener(cb); }