diff --git a/src/background.ts b/src/background.ts index 90aa589..56a7f0a 100644 --- a/src/background.ts +++ b/src/background.ts @@ -1,10 +1,10 @@ -import { runtime, scripting, tabs, webNavigation } from 'webextension-polyfill'; +import { runtime, scripting, storage, tabs, webNavigation } from 'webextension-polyfill'; import { fetchUser } from './gkApi'; import { injectionScope as inject_azureDevops } from './hosts/azureDevops'; import { injectionScope as inject_bitbucket } from './hosts/bitbucket'; import { injectionScope as inject_github } from './hosts/github'; import { injectionScope as inject_gitlab } from './hosts/gitlab'; -import { domainToMatchPattern, refreshPermissions } from './permissions-helper'; +import { refreshPermissions } from './permissions-helper'; import { getEnterpriseConnections, GKDotDevUrl, PermissionsGrantedMessage, PopupInitMessage } from './shared'; import type { CacheContext } from './types'; @@ -22,6 +22,24 @@ const DefaultInjectionDomains: InjectionDomains = { azureDevops: ['dev.azure.com'], }; +webNavigation.onDOMContentLoaded.addListener(async details => { + const { injectionDomains } = (await storage.session.get('injectionDomains')) as { + injectionDomains?: InjectionDomains; + }; + if (!injectionDomains) { + return; + } + + const injectionFn = getInjectionFn(details.url, injectionDomains); + if (injectionFn) { + void scripting.executeScript({ + target: { tabId: details.tabId }, + func: injectionFn, + args: [details.url, GKDotDevUrl], + }); + } +}); + webNavigation.onHistoryStateUpdated.addListener(details => { // used to detect when the user navigates to a different page in the same tab const url = new URL(details.url); @@ -62,39 +80,6 @@ async function computeInjectionDomains(context: CacheContext) { return injectionDomains; } -async function addInjectionListener(context: CacheContext) { - const injectionDomains = await computeInjectionDomains(context); - const allDomains = Object.values(injectionDomains as any).flat(); - - // note: This is a closure over injectionDomains - const injectScript = (tabId: number, tabUrl: string) => { - void scripting.executeScript({ - target: { tabId: tabId }, - // injectImmediately: true, - func: getInjectionFn(tabUrl, injectionDomains), - args: [tabUrl, GKDotDevUrl], - }); - }; - - webNavigation.onDOMContentLoaded.addListener(details => injectScript(details.tabId, details.url), { - url: allDomains.map(domain => ({ hostContains: domain })), - }); - - // Immediately inject into the currently open compatible tabs. This is needed because when the background - // script is idle, its event listeners are not active. Opening a compatible tab will cause the background - // script to awaken and setup the event listeners again, but the tab will load before that happens. - const currentTabs = await tabs.query({ - url: allDomains.map(domainToMatchPattern), - status: 'complete', // only query tabs that have finished loading - discarded: false, // discarded tabs will reload when focused so we don't need to inject into them now - }); - currentTabs.forEach(tab => { - if (tab.id && tab.url) { - injectScript(tab.id, tab.url); - } - }); -} - function urlHostHasDomain(url: URL, domains: string[]): boolean { return domains.some(domain => url.hostname.endsWith(domain)); } @@ -102,7 +87,7 @@ function urlHostHasDomain(url: URL, domains: string[]): boolean { function getInjectionFn( rawUrl: string, injectionDomains: InjectionDomains, -): (url: string, gkDotDevUrl: string) => void { +): ((url: string, gkDotDevUrl: string) => void) | null { const url = new URL(rawUrl); if (urlHostHasDomain(url, injectionDomains.github)) { return inject_github; @@ -120,8 +105,7 @@ function getInjectionFn( return inject_azureDevops; } - console.error('Unsupported host'); - throw new Error('Unsupported host'); + return null; } async function main() { @@ -131,9 +115,9 @@ async function main() { const context: CacheContext = {}; // This removes unneded permissions await refreshPermissions(context); - // NOTE: This may request hosts that we may not have permissions for, which will log errors for the extension - // This does not cause any issues, and eliminating the errors requires more logic - await addInjectionListener(context); + + const injectionDomains = await computeInjectionDomains(context); + void storage.session.set({ injectionDomains: injectionDomains }); } void main(); diff --git a/src/permissions-helper.ts b/src/permissions-helper.ts index c7ec795..38b73b6 100644 --- a/src/permissions-helper.ts +++ b/src/permissions-helper.ts @@ -3,7 +3,7 @@ import { permissions } from 'webextension-polyfill'; import { arrayDifference, CloudProviders, getEnterpriseConnections } from './shared'; import type { CacheContext } from './types'; -export function domainToMatchPattern(domain: string): string { +function domainToMatchPattern(domain: string): string { return `*://*.${domain}/*`; }