web-ext 8.7.1 → 8.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cmd/run.js CHANGED
@@ -27,6 +27,7 @@ export default async function run({
27
27
  noReload = false,
28
28
  preInstall = false,
29
29
  sourceDir,
30
+ verbose = false,
30
31
  watchFile,
31
32
  watchIgnored,
32
33
  startUrl,
@@ -155,6 +156,7 @@ export default async function run({
155
156
  if (target && target.includes('chromium')) {
156
157
  const chromiumRunnerParams = {
157
158
  ...commonRunnerParams,
159
+ verbose,
158
160
  chromiumBinary,
159
161
  chromiumProfile
160
162
  };
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","names":["path","fs","nodeFs","defaultBuildExtension","showDesktopNotification","defaultDesktopNotifications","defaultFirefoxApp","connectWithMaxRetries","defaultFirefoxClient","createLogger","defaultGetValidatedManifest","UsageError","createExtensionRunner","defaultReloadStrategy","MultiExtensionRunner","DefaultMultiExtensionRunner","log","import","meta","url","run","artifactsDir","browserConsole","devtools","pref","firefox","firefoxProfile","profileCreateIfMissing","keepProfileChanges","ignoreFiles","noInput","noReload","preInstall","sourceDir","watchFile","watchIgnored","startUrl","target","args","adbBin","adbHost","adbPort","adbDevice","adbDiscoveryTimeout","adbRemoveOldArtifacts","firefoxApk","firefoxApkComponent","chromiumBinary","chromiumProfile","buildExtension","desktopNotifications","firefoxApp","firefoxClient","reloadStrategy","getValidatedManifest","resolve","info","Array","isArray","every","el","customPrefs","manifestData","profileDir","isDir","existsSync","mkdir","runners","commonRunnerParams","extensions","length","includes","firefoxDesktopRunnerParams","firefoxBinary","profilePath","firefoxDesktopRunner","params","push","firefoxAndroidRunnerParams","buildSourceDir","extensionSourceDir","tmpArtifactsDir","asNeeded","showReadyMessage","firefoxAndroidRunner","chromiumRunnerParams","chromiumRunner","extensionRunner"],"sources":["../../src/cmd/run.js"],"sourcesContent":["import path from 'path';\nimport fs from 'fs/promises';\nimport nodeFs from 'fs';\n\nimport defaultBuildExtension from './build.js';\nimport { showDesktopNotification as defaultDesktopNotifications } from '../util/desktop-notifier.js';\nimport * as defaultFirefoxApp from '../firefox/index.js';\nimport { connectWithMaxRetries as defaultFirefoxClient } from '../firefox/remote.js';\nimport { createLogger } from '../util/logger.js';\nimport defaultGetValidatedManifest from '../util/manifest.js';\nimport { UsageError } from '../errors.js';\nimport {\n createExtensionRunner,\n defaultReloadStrategy,\n MultiExtensionRunner as DefaultMultiExtensionRunner,\n} from '../extension-runners/index.js';\n\nconst log = createLogger(import.meta.url);\n\n// Run command types and implementation.\n\nexport default async function run(\n {\n artifactsDir,\n browserConsole = false,\n devtools = false,\n pref,\n firefox,\n firefoxProfile,\n profileCreateIfMissing,\n keepProfileChanges = false,\n ignoreFiles,\n noInput = false,\n noReload = false,\n preInstall = false,\n sourceDir,\n watchFile,\n watchIgnored,\n startUrl,\n target,\n args,\n // Android CLI options.\n adbBin,\n adbHost,\n adbPort,\n adbDevice,\n adbDiscoveryTimeout,\n adbRemoveOldArtifacts,\n firefoxApk,\n firefoxApkComponent,\n // Chromium CLI options.\n chromiumBinary,\n chromiumProfile,\n },\n {\n buildExtension = defaultBuildExtension,\n desktopNotifications = defaultDesktopNotifications,\n firefoxApp = defaultFirefoxApp,\n firefoxClient = defaultFirefoxClient,\n reloadStrategy = defaultReloadStrategy,\n MultiExtensionRunner = DefaultMultiExtensionRunner,\n getValidatedManifest = defaultGetValidatedManifest,\n } = {},\n) {\n sourceDir = path.resolve(sourceDir);\n log.info(`Running web extension from ${sourceDir}`);\n if (preInstall) {\n log.info(\n \"Disabled auto-reloading because it's not possible with \" +\n '--pre-install',\n );\n noReload = true;\n }\n\n if (\n watchFile != null &&\n (!Array.isArray(watchFile) ||\n !watchFile.every((el) => typeof el === 'string'))\n ) {\n throw new UsageError('Unexpected watchFile type');\n }\n\n // Create an alias for --pref since it has been transformed into an\n // object containing one or more preferences.\n const customPrefs = pref;\n const manifestData = await getValidatedManifest(sourceDir);\n\n const profileDir = firefoxProfile || chromiumProfile;\n\n if (profileCreateIfMissing) {\n if (!profileDir) {\n throw new UsageError(\n '--profile-create-if-missing requires ' +\n '--firefox-profile or --chromium-profile',\n );\n }\n const isDir = nodeFs.existsSync(profileDir);\n if (isDir) {\n log.info(`Profile directory ${profileDir} already exists`);\n } else {\n log.info(`Profile directory not found. Creating directory ${profileDir}`);\n await fs.mkdir(profileDir);\n }\n }\n\n const runners = [];\n\n const commonRunnerParams = {\n // Common options.\n extensions: [{ sourceDir, manifestData }],\n keepProfileChanges,\n startUrl,\n args,\n desktopNotifications,\n };\n\n if (!target || target.length === 0 || target.includes('firefox-desktop')) {\n const firefoxDesktopRunnerParams = {\n ...commonRunnerParams,\n\n // Firefox specific CLI options.\n firefoxBinary: firefox,\n profilePath: firefoxProfile,\n customPrefs,\n browserConsole,\n devtools,\n preInstall,\n\n // Firefox runner injected dependencies.\n firefoxApp,\n firefoxClient,\n };\n\n const firefoxDesktopRunner = await createExtensionRunner({\n target: 'firefox-desktop',\n params: firefoxDesktopRunnerParams,\n });\n runners.push(firefoxDesktopRunner);\n }\n\n if (target && target.includes('firefox-android')) {\n const firefoxAndroidRunnerParams = {\n ...commonRunnerParams,\n\n // Firefox specific CLI options.\n profilePath: firefoxProfile,\n customPrefs,\n browserConsole,\n preInstall,\n firefoxApk,\n firefoxApkComponent,\n adbDevice,\n adbHost,\n adbPort,\n adbBin,\n adbDiscoveryTimeout,\n adbRemoveOldArtifacts,\n\n // Injected dependencies.\n firefoxApp,\n firefoxClient,\n desktopNotifications: defaultDesktopNotifications,\n buildSourceDir: (extensionSourceDir, tmpArtifactsDir) => {\n return buildExtension(\n {\n sourceDir: extensionSourceDir,\n ignoreFiles,\n asNeeded: false,\n // Use a separate temporary directory for building the extension zip file\n // that we are going to upload on the android device.\n artifactsDir: tmpArtifactsDir,\n },\n {\n // Suppress the message usually logged by web-ext build.\n showReadyMessage: false,\n },\n );\n },\n };\n\n const firefoxAndroidRunner = await createExtensionRunner({\n target: 'firefox-android',\n params: firefoxAndroidRunnerParams,\n });\n runners.push(firefoxAndroidRunner);\n }\n\n if (target && target.includes('chromium')) {\n const chromiumRunnerParams = {\n ...commonRunnerParams,\n chromiumBinary,\n chromiumProfile,\n };\n\n const chromiumRunner = await createExtensionRunner({\n target: 'chromium',\n params: chromiumRunnerParams,\n });\n runners.push(chromiumRunner);\n }\n\n const extensionRunner = new MultiExtensionRunner({\n desktopNotifications,\n runners,\n });\n\n await extensionRunner.run();\n\n if (noReload) {\n log.info('Automatic extension reloading has been disabled');\n } else {\n log.info('The extension will reload if any source file changes');\n\n reloadStrategy({\n extensionRunner,\n sourceDir,\n watchFile,\n watchIgnored,\n artifactsDir,\n ignoreFiles,\n noInput,\n });\n }\n\n return extensionRunner;\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"run.js","names":["path","fs","nodeFs","defaultBuildExtension","showDesktopNotification","defaultDesktopNotifications","defaultFirefoxApp","connectWithMaxRetries","defaultFirefoxClient","createLogger","defaultGetValidatedManifest","UsageError","createExtensionRunner","defaultReloadStrategy","MultiExtensionRunner","DefaultMultiExtensionRunner","log","import","meta","url","run","artifactsDir","browserConsole","devtools","pref","firefox","firefoxProfile","profileCreateIfMissing","keepProfileChanges","ignoreFiles","noInput","noReload","preInstall","sourceDir","verbose","watchFile","watchIgnored","startUrl","target","args","adbBin","adbHost","adbPort","adbDevice","adbDiscoveryTimeout","adbRemoveOldArtifacts","firefoxApk","firefoxApkComponent","chromiumBinary","chromiumProfile","buildExtension","desktopNotifications","firefoxApp","firefoxClient","reloadStrategy","getValidatedManifest","resolve","info","Array","isArray","every","el","customPrefs","manifestData","profileDir","isDir","existsSync","mkdir","runners","commonRunnerParams","extensions","length","includes","firefoxDesktopRunnerParams","firefoxBinary","profilePath","firefoxDesktopRunner","params","push","firefoxAndroidRunnerParams","buildSourceDir","extensionSourceDir","tmpArtifactsDir","asNeeded","showReadyMessage","firefoxAndroidRunner","chromiumRunnerParams","chromiumRunner","extensionRunner"],"sources":["../../src/cmd/run.js"],"sourcesContent":["import path from 'path';\nimport fs from 'fs/promises';\nimport nodeFs from 'fs';\n\nimport defaultBuildExtension from './build.js';\nimport { showDesktopNotification as defaultDesktopNotifications } from '../util/desktop-notifier.js';\nimport * as defaultFirefoxApp from '../firefox/index.js';\nimport { connectWithMaxRetries as defaultFirefoxClient } from '../firefox/remote.js';\nimport { createLogger } from '../util/logger.js';\nimport defaultGetValidatedManifest from '../util/manifest.js';\nimport { UsageError } from '../errors.js';\nimport {\n createExtensionRunner,\n defaultReloadStrategy,\n MultiExtensionRunner as DefaultMultiExtensionRunner,\n} from '../extension-runners/index.js';\n\nconst log = createLogger(import.meta.url);\n\n// Run command types and implementation.\n\nexport default async function run(\n {\n artifactsDir,\n browserConsole = false,\n devtools = false,\n pref,\n firefox,\n firefoxProfile,\n profileCreateIfMissing,\n keepProfileChanges = false,\n ignoreFiles,\n noInput = false,\n noReload = false,\n preInstall = false,\n sourceDir,\n verbose = false,\n watchFile,\n watchIgnored,\n startUrl,\n target,\n args,\n // Android CLI options.\n adbBin,\n adbHost,\n adbPort,\n adbDevice,\n adbDiscoveryTimeout,\n adbRemoveOldArtifacts,\n firefoxApk,\n firefoxApkComponent,\n // Chromium CLI options.\n chromiumBinary,\n chromiumProfile,\n },\n {\n buildExtension = defaultBuildExtension,\n desktopNotifications = defaultDesktopNotifications,\n firefoxApp = defaultFirefoxApp,\n firefoxClient = defaultFirefoxClient,\n reloadStrategy = defaultReloadStrategy,\n MultiExtensionRunner = DefaultMultiExtensionRunner,\n getValidatedManifest = defaultGetValidatedManifest,\n } = {},\n) {\n sourceDir = path.resolve(sourceDir);\n log.info(`Running web extension from ${sourceDir}`);\n if (preInstall) {\n log.info(\n \"Disabled auto-reloading because it's not possible with \" +\n '--pre-install',\n );\n noReload = true;\n }\n\n if (\n watchFile != null &&\n (!Array.isArray(watchFile) ||\n !watchFile.every((el) => typeof el === 'string'))\n ) {\n throw new UsageError('Unexpected watchFile type');\n }\n\n // Create an alias for --pref since it has been transformed into an\n // object containing one or more preferences.\n const customPrefs = pref;\n const manifestData = await getValidatedManifest(sourceDir);\n\n const profileDir = firefoxProfile || chromiumProfile;\n\n if (profileCreateIfMissing) {\n if (!profileDir) {\n throw new UsageError(\n '--profile-create-if-missing requires ' +\n '--firefox-profile or --chromium-profile',\n );\n }\n const isDir = nodeFs.existsSync(profileDir);\n if (isDir) {\n log.info(`Profile directory ${profileDir} already exists`);\n } else {\n log.info(`Profile directory not found. Creating directory ${profileDir}`);\n await fs.mkdir(profileDir);\n }\n }\n\n const runners = [];\n\n const commonRunnerParams = {\n // Common options.\n extensions: [{ sourceDir, manifestData }],\n keepProfileChanges,\n startUrl,\n args,\n desktopNotifications,\n };\n\n if (!target || target.length === 0 || target.includes('firefox-desktop')) {\n const firefoxDesktopRunnerParams = {\n ...commonRunnerParams,\n\n // Firefox specific CLI options.\n firefoxBinary: firefox,\n profilePath: firefoxProfile,\n customPrefs,\n browserConsole,\n devtools,\n preInstall,\n\n // Firefox runner injected dependencies.\n firefoxApp,\n firefoxClient,\n };\n\n const firefoxDesktopRunner = await createExtensionRunner({\n target: 'firefox-desktop',\n params: firefoxDesktopRunnerParams,\n });\n runners.push(firefoxDesktopRunner);\n }\n\n if (target && target.includes('firefox-android')) {\n const firefoxAndroidRunnerParams = {\n ...commonRunnerParams,\n\n // Firefox specific CLI options.\n profilePath: firefoxProfile,\n customPrefs,\n browserConsole,\n preInstall,\n firefoxApk,\n firefoxApkComponent,\n adbDevice,\n adbHost,\n adbPort,\n adbBin,\n adbDiscoveryTimeout,\n adbRemoveOldArtifacts,\n\n // Injected dependencies.\n firefoxApp,\n firefoxClient,\n desktopNotifications: defaultDesktopNotifications,\n buildSourceDir: (extensionSourceDir, tmpArtifactsDir) => {\n return buildExtension(\n {\n sourceDir: extensionSourceDir,\n ignoreFiles,\n asNeeded: false,\n // Use a separate temporary directory for building the extension zip file\n // that we are going to upload on the android device.\n artifactsDir: tmpArtifactsDir,\n },\n {\n // Suppress the message usually logged by web-ext build.\n showReadyMessage: false,\n },\n );\n },\n };\n\n const firefoxAndroidRunner = await createExtensionRunner({\n target: 'firefox-android',\n params: firefoxAndroidRunnerParams,\n });\n runners.push(firefoxAndroidRunner);\n }\n\n if (target && target.includes('chromium')) {\n const chromiumRunnerParams = {\n ...commonRunnerParams,\n verbose,\n chromiumBinary,\n chromiumProfile,\n };\n\n const chromiumRunner = await createExtensionRunner({\n target: 'chromium',\n params: chromiumRunnerParams,\n });\n runners.push(chromiumRunner);\n }\n\n const extensionRunner = new MultiExtensionRunner({\n desktopNotifications,\n runners,\n });\n\n await extensionRunner.run();\n\n if (noReload) {\n log.info('Automatic extension reloading has been disabled');\n } else {\n log.info('The extension will reload if any source file changes');\n\n reloadStrategy({\n extensionRunner,\n sourceDir,\n watchFile,\n watchIgnored,\n artifactsDir,\n ignoreFiles,\n noInput,\n });\n }\n\n return extensionRunner;\n}\n"],"mappings":"AAAA,OAAOA,IAAI,MAAM,MAAM;AACvB,OAAOC,EAAE,MAAM,aAAa;AAC5B,OAAOC,MAAM,MAAM,IAAI;AAEvB,OAAOC,qBAAqB,MAAM,YAAY;AAC9C,SAASC,uBAAuB,IAAIC,2BAA2B,QAAQ,6BAA6B;AACpG,OAAO,KAAKC,iBAAiB,MAAM,qBAAqB;AACxD,SAASC,qBAAqB,IAAIC,oBAAoB,QAAQ,sBAAsB;AACpF,SAASC,YAAY,QAAQ,mBAAmB;AAChD,OAAOC,2BAA2B,MAAM,qBAAqB;AAC7D,SAASC,UAAU,QAAQ,cAAc;AACzC,SACEC,qBAAqB,EACrBC,qBAAqB,EACrBC,oBAAoB,IAAIC,2BAA2B,QAC9C,+BAA+B;AAEtC,MAAMC,GAAG,GAAGP,YAAY,CAACQ,MAAM,CAACC,IAAI,CAACC,GAAG,CAAC;;AAEzC;;AAEA,eAAe,eAAeC,GAAGA,CAC/B;EACEC,YAAY;EACZC,cAAc,GAAG,KAAK;EACtBC,QAAQ,GAAG,KAAK;EAChBC,IAAI;EACJC,OAAO;EACPC,cAAc;EACdC,sBAAsB;EACtBC,kBAAkB,GAAG,KAAK;EAC1BC,WAAW;EACXC,OAAO,GAAG,KAAK;EACfC,QAAQ,GAAG,KAAK;EAChBC,UAAU,GAAG,KAAK;EAClBC,SAAS;EACTC,OAAO,GAAG,KAAK;EACfC,SAAS;EACTC,YAAY;EACZC,QAAQ;EACRC,MAAM;EACNC,IAAI;EACJ;EACAC,MAAM;EACNC,OAAO;EACPC,OAAO;EACPC,SAAS;EACTC,mBAAmB;EACnBC,qBAAqB;EACrBC,UAAU;EACVC,mBAAmB;EACnB;EACAC,cAAc;EACdC;AACF,CAAC,EACD;EACEC,cAAc,GAAG/C,qBAAqB;EACtCgD,oBAAoB,GAAG9C,2BAA2B;EAClD+C,UAAU,GAAG9C,iBAAiB;EAC9B+C,aAAa,GAAG7C,oBAAoB;EACpC8C,cAAc,GAAGzC,qBAAqB;EACtCC,oBAAoB,GAAGC,2BAA2B;EAClDwC,oBAAoB,GAAG7C;AACzB,CAAC,GAAG,CAAC,CAAC,EACN;EACAuB,SAAS,GAAGjC,IAAI,CAACwD,OAAO,CAACvB,SAAS,CAAC;EACnCjB,GAAG,CAACyC,IAAI,CAAC,8BAA8BxB,SAAS,EAAE,CAAC;EACnD,IAAID,UAAU,EAAE;IACdhB,GAAG,CAACyC,IAAI,CACN,yDAAyD,GACvD,eACJ,CAAC;IACD1B,QAAQ,GAAG,IAAI;EACjB;EAEA,IACEI,SAAS,IAAI,IAAI,KAChB,CAACuB,KAAK,CAACC,OAAO,CAACxB,SAAS,CAAC,IACxB,CAACA,SAAS,CAACyB,KAAK,CAAEC,EAAE,IAAK,OAAOA,EAAE,KAAK,QAAQ,CAAC,CAAC,EACnD;IACA,MAAM,IAAIlD,UAAU,CAAC,2BAA2B,CAAC;EACnD;;EAEA;EACA;EACA,MAAMmD,WAAW,GAAGtC,IAAI;EACxB,MAAMuC,YAAY,GAAG,MAAMR,oBAAoB,CAACtB,SAAS,CAAC;EAE1D,MAAM+B,UAAU,GAAGtC,cAAc,IAAIuB,eAAe;EAEpD,IAAItB,sBAAsB,EAAE;IAC1B,IAAI,CAACqC,UAAU,EAAE;MACf,MAAM,IAAIrD,UAAU,CAClB,uCAAuC,GACrC,yCACJ,CAAC;IACH;IACA,MAAMsD,KAAK,GAAG/D,MAAM,CAACgE,UAAU,CAACF,UAAU,CAAC;IAC3C,IAAIC,KAAK,EAAE;MACTjD,GAAG,CAACyC,IAAI,CAAC,qBAAqBO,UAAU,iBAAiB,CAAC;IAC5D,CAAC,MAAM;MACLhD,GAAG,CAACyC,IAAI,CAAC,mDAAmDO,UAAU,EAAE,CAAC;MACzE,MAAM/D,EAAE,CAACkE,KAAK,CAACH,UAAU,CAAC;IAC5B;EACF;EAEA,MAAMI,OAAO,GAAG,EAAE;EAElB,MAAMC,kBAAkB,GAAG;IACzB;IACAC,UAAU,EAAE,CAAC;MAAErC,SAAS;MAAE8B;IAAa,CAAC,CAAC;IACzCnC,kBAAkB;IAClBS,QAAQ;IACRE,IAAI;IACJY;EACF,CAAC;EAED,IAAI,CAACb,MAAM,IAAIA,MAAM,CAACiC,MAAM,KAAK,CAAC,IAAIjC,MAAM,CAACkC,QAAQ,CAAC,iBAAiB,CAAC,EAAE;IACxE,MAAMC,0BAA0B,GAAG;MACjC,GAAGJ,kBAAkB;MAErB;MACAK,aAAa,EAAEjD,OAAO;MACtBkD,WAAW,EAAEjD,cAAc;MAC3BoC,WAAW;MACXxC,cAAc;MACdC,QAAQ;MACRS,UAAU;MAEV;MACAoB,UAAU;MACVC;IACF,CAAC;IAED,MAAMuB,oBAAoB,GAAG,MAAMhE,qBAAqB,CAAC;MACvD0B,MAAM,EAAE,iBAAiB;MACzBuC,MAAM,EAAEJ;IACV,CAAC,CAAC;IACFL,OAAO,CAACU,IAAI,CAACF,oBAAoB,CAAC;EACpC;EAEA,IAAItC,MAAM,IAAIA,MAAM,CAACkC,QAAQ,CAAC,iBAAiB,CAAC,EAAE;IAChD,MAAMO,0BAA0B,GAAG;MACjC,GAAGV,kBAAkB;MAErB;MACAM,WAAW,EAAEjD,cAAc;MAC3BoC,WAAW;MACXxC,cAAc;MACdU,UAAU;MACVc,UAAU;MACVC,mBAAmB;MACnBJ,SAAS;MACTF,OAAO;MACPC,OAAO;MACPF,MAAM;MACNI,mBAAmB;MACnBC,qBAAqB;MAErB;MACAO,UAAU;MACVC,aAAa;MACbF,oBAAoB,EAAE9C,2BAA2B;MACjD2E,cAAc,EAAEA,CAACC,kBAAkB,EAAEC,eAAe,KAAK;QACvD,OAAOhC,cAAc,CACnB;UACEjB,SAAS,EAAEgD,kBAAkB;UAC7BpD,WAAW;UACXsD,QAAQ,EAAE,KAAK;UACf;UACA;UACA9D,YAAY,EAAE6D;QAChB,CAAC,EACD;UACE;UACAE,gBAAgB,EAAE;QACpB,CACF,CAAC;MACH;IACF,CAAC;IAED,MAAMC,oBAAoB,GAAG,MAAMzE,qBAAqB,CAAC;MACvD0B,MAAM,EAAE,iBAAiB;MACzBuC,MAAM,EAAEE;IACV,CAAC,CAAC;IACFX,OAAO,CAACU,IAAI,CAACO,oBAAoB,CAAC;EACpC;EAEA,IAAI/C,MAAM,IAAIA,MAAM,CAACkC,QAAQ,CAAC,UAAU,CAAC,EAAE;IACzC,MAAMc,oBAAoB,GAAG;MAC3B,GAAGjB,kBAAkB;MACrBnC,OAAO;MACPc,cAAc;MACdC;IACF,CAAC;IAED,MAAMsC,cAAc,GAAG,MAAM3E,qBAAqB,CAAC;MACjD0B,MAAM,EAAE,UAAU;MAClBuC,MAAM,EAAES;IACV,CAAC,CAAC;IACFlB,OAAO,CAACU,IAAI,CAACS,cAAc,CAAC;EAC9B;EAEA,MAAMC,eAAe,GAAG,IAAI1E,oBAAoB,CAAC;IAC/CqC,oBAAoB;IACpBiB;EACF,CAAC,CAAC;EAEF,MAAMoB,eAAe,CAACpE,GAAG,CAAC,CAAC;EAE3B,IAAIW,QAAQ,EAAE;IACZf,GAAG,CAACyC,IAAI,CAAC,iDAAiD,CAAC;EAC7D,CAAC,MAAM;IACLzC,GAAG,CAACyC,IAAI,CAAC,sDAAsD,CAAC;IAEhEH,cAAc,CAAC;MACbkC,eAAe;MACfvD,SAAS;MACTE,SAAS;MACTC,YAAY;MACZf,YAAY;MACZQ,WAAW;MACXC;IACF,CAAC,CAAC;EACJ;EAEA,OAAO0D,eAAe;AACxB","ignoreList":[]}
@@ -1,3 +1,12 @@
1
+ function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); }
2
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
3
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
4
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
5
+ function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); }
6
+ function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
7
+ function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); }
8
+ function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; }
9
+ function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
1
10
  /**
2
11
  * This module provide an ExtensionRunner subclass that manage an extension executed
3
12
  * in a Chromium-based browser instance.
@@ -6,7 +15,6 @@
6
15
  import fs from 'fs/promises';
7
16
  import path from 'path';
8
17
  import { Launcher as ChromeLauncher, launch as defaultChromiumLaunch } from 'chrome-launcher';
9
- import WebSocket, { WebSocketServer } from 'ws';
10
18
  import { createLogger } from '../util/logger.js';
11
19
  import { TempDir } from '../util/temp-dir.js';
12
20
  import isDirectory from '../util/is-directory.js';
@@ -15,16 +23,148 @@ const log = createLogger(import.meta.url);
15
23
  const EXCLUDED_CHROME_FLAGS = ['--disable-extensions', '--mute-audio', '--disable-component-update'];
16
24
  export const DEFAULT_CHROME_FLAGS = ChromeLauncher.defaultFlags().filter(flag => !EXCLUDED_CHROME_FLAGS.includes(flag));
17
25
 
26
+ // This is a client for the Chrome Devtools protocol. The methods and results
27
+ // are documented at https://chromedevtools.github.io/devtools-protocol/tot/
28
+ var _receivedData = /*#__PURE__*/new WeakMap();
29
+ var _isProcessingMessage = /*#__PURE__*/new WeakMap();
30
+ var _lastId = /*#__PURE__*/new WeakMap();
31
+ var _deferredResponses = /*#__PURE__*/new WeakMap();
32
+ var _disconnected = /*#__PURE__*/new WeakMap();
33
+ var _disconnectedPromise = /*#__PURE__*/new WeakMap();
34
+ var _resolveDisconnectedPromise = /*#__PURE__*/new WeakMap();
35
+ var _ChromeDevtoolsProtocolClient_brand = /*#__PURE__*/new WeakSet();
36
+ class ChromeDevtoolsProtocolClient {
37
+ constructor(chromiumInstance) {
38
+ _classPrivateMethodInitSpec(this, _ChromeDevtoolsProtocolClient_brand);
39
+ _classPrivateFieldInitSpec(this, _receivedData, '');
40
+ _classPrivateFieldInitSpec(this, _isProcessingMessage, false);
41
+ _classPrivateFieldInitSpec(this, _lastId, 0);
42
+ _classPrivateFieldInitSpec(this, _deferredResponses, new Map());
43
+ _classPrivateFieldInitSpec(this, _disconnected, false);
44
+ _classPrivateFieldInitSpec(this, _disconnectedPromise, void 0);
45
+ _classPrivateFieldInitSpec(this, _resolveDisconnectedPromise, void 0);
46
+ // Print all exchanged CDP messages to ease debugging.
47
+ _defineProperty(this, "TEST_LOG_VERBOSE_CDP", process.env.TEST_LOG_VERBOSE_CDP);
48
+ // remoteDebuggingPipes is from chrome-launcher, see
49
+ // https://github.com/GoogleChrome/chrome-launcher/pull/347
50
+ const {
51
+ incoming,
52
+ outgoing
53
+ } = chromiumInstance.remoteDebuggingPipes;
54
+ _classPrivateFieldSet(_disconnectedPromise, this, new Promise(resolve => {
55
+ _classPrivateFieldSet(_resolveDisconnectedPromise, this, resolve);
56
+ }));
57
+ if (incoming.closed) {
58
+ // Strange. Did Chrome fail to start, or exit on startup?
59
+ log.warn('CDP already disconnected at initialization');
60
+ _assertClassBrand(_ChromeDevtoolsProtocolClient_brand, this, _finalizeDisconnect).call(this);
61
+ return;
62
+ }
63
+ incoming.on('data', data => {
64
+ _classPrivateFieldSet(_receivedData, this, _classPrivateFieldGet(_receivedData, this) + data);
65
+ _assertClassBrand(_ChromeDevtoolsProtocolClient_brand, this, _processNextMessage).call(this);
66
+ });
67
+ incoming.on('error', error => {
68
+ log.error(error);
69
+ _assertClassBrand(_ChromeDevtoolsProtocolClient_brand, this, _finalizeDisconnect).call(this);
70
+ });
71
+ incoming.on('close', () => _assertClassBrand(_ChromeDevtoolsProtocolClient_brand, this, _finalizeDisconnect).call(this));
72
+ this.outgoingPipe = outgoing;
73
+ }
74
+ waitUntilDisconnected() {
75
+ return _classPrivateFieldGet(_disconnectedPromise, this);
76
+ }
77
+ async sendCommand(method, params, sessionId = undefined) {
78
+ var _this$lastId;
79
+ if (_classPrivateFieldGet(_disconnected, this)) {
80
+ throw new Error(`CDP disconnected, cannot send: command ${method}`);
81
+ }
82
+ const message = {
83
+ id: _classPrivateFieldSet(_lastId, this, (_this$lastId = _classPrivateFieldGet(_lastId, this), ++_this$lastId)),
84
+ method,
85
+ params,
86
+ sessionId
87
+ };
88
+ const rawMessage = `${JSON.stringify(message)}\x00`;
89
+ if (this.TEST_LOG_VERBOSE_CDP) {
90
+ process.stderr.write(`[CDP] [SEND] ${rawMessage}\n`);
91
+ }
92
+ return new Promise((resolve, reject) => {
93
+ // CDP will always send a response.
94
+ _classPrivateFieldGet(_deferredResponses, this).set(message.id, {
95
+ method,
96
+ resolve,
97
+ reject
98
+ });
99
+ this.outgoingPipe.write(rawMessage);
100
+ });
101
+ }
102
+ }
103
+
18
104
  /**
19
105
  * Implements an IExtensionRunner which manages a Chromium instance.
20
106
  */
107
+ function _processNextMessage() {
108
+ if (_classPrivateFieldGet(_isProcessingMessage, this)) {
109
+ return;
110
+ }
111
+ _classPrivateFieldSet(_isProcessingMessage, this, true);
112
+ let end = _classPrivateFieldGet(_receivedData, this).indexOf('\x00');
113
+ while (end !== -1) {
114
+ const rawMessage = _classPrivateFieldGet(_receivedData, this).slice(0, end);
115
+ _classPrivateFieldSet(_receivedData, this, _classPrivateFieldGet(_receivedData, this).slice(end + 1)); // +1 skips \x00.
116
+ try {
117
+ if (this.TEST_LOG_VERBOSE_CDP) {
118
+ process.stderr.write(`[CDP] [RECV] ${rawMessage}\n`);
119
+ }
120
+ const {
121
+ id,
122
+ error,
123
+ result
124
+ } = JSON.parse(rawMessage);
125
+ const deferredResponse = _classPrivateFieldGet(_deferredResponses, this).get(id);
126
+ if (deferredResponse) {
127
+ _classPrivateFieldGet(_deferredResponses, this).delete(id);
128
+ if (error) {
129
+ const err = new Error(error.message || 'Unexpected CDP response');
130
+ deferredResponse.reject(err);
131
+ } else {
132
+ deferredResponse.resolve(result);
133
+ }
134
+ } else {
135
+ // Dropping events and non-response messages since we don't need it.
136
+ }
137
+ } catch (e) {
138
+ log.error(e);
139
+ }
140
+ end = _classPrivateFieldGet(_receivedData, this).indexOf('\x00');
141
+ }
142
+ _classPrivateFieldSet(_isProcessingMessage, this, false);
143
+ if (_classPrivateFieldGet(_disconnected, this)) {
144
+ for (const {
145
+ method,
146
+ reject
147
+ } of _classPrivateFieldGet(_deferredResponses, this).values()) {
148
+ reject(new Error(`CDP connection closed before response to ${method}`));
149
+ }
150
+ _classPrivateFieldGet(_deferredResponses, this).clear();
151
+ _classPrivateFieldGet(_resolveDisconnectedPromise, this).call(this);
152
+ }
153
+ }
154
+ function _finalizeDisconnect() {
155
+ if (!_classPrivateFieldGet(_disconnected, this)) {
156
+ _classPrivateFieldSet(_disconnected, this, true);
157
+ _assertClassBrand(_ChromeDevtoolsProtocolClient_brand, this, _processNextMessage).call(this);
158
+ }
159
+ }
21
160
  export class ChromiumExtensionRunner {
22
161
  cleanupCallbacks;
23
162
  params;
24
163
  chromiumInstance;
25
164
  chromiumLaunch;
26
- reloadManagerExtension;
27
- wss;
165
+ // --load-extension is deprecated, but only supported in Chrome 126+, see:
166
+ // https://github.com/mozilla/web-ext/issues/3388#issuecomment-2906982117
167
+ forceUseDeprecatedLoadExtension;
28
168
  exiting;
29
169
  _promiseSetupDone;
30
170
  constructor(params) {
@@ -33,6 +173,9 @@ export class ChromiumExtensionRunner {
33
173
  } = params;
34
174
  this.params = params;
35
175
  this.chromiumLaunch = chromiumLaunch;
176
+ // We will try to use Extensions.loadUnpacked first (Chrome 126+), and if
177
+ // that does not work fall back to --load-extension.
178
+ this.forceUseDeprecatedLoadExtension = false;
36
179
  this.cleanupCallbacks = new Set();
37
180
  }
38
181
 
@@ -88,36 +231,16 @@ export class ChromiumExtensionRunner {
88
231
  * Setup the Chromium Profile and run a Chromium instance.
89
232
  */
90
233
  async setupInstance() {
91
- // Start a websocket server on a free localhost TCP port.
92
- this.wss = await new Promise(resolve => {
93
- const server = new WebSocketServer(
94
- // Use a ipv4 host so we don't need to escape ipv6 address
95
- // https://github.com/mozilla/web-ext/issues/2331
96
- {
97
- port: 0,
98
- host: '127.0.0.1',
99
- clientTracking: true
100
- },
101
- // Wait the server to be listening (so that the extension
102
- // runner can successfully retrieve server address and port).
103
- () => resolve(server));
104
- });
105
-
106
- // Prevent unhandled socket error (e.g. when chrome
107
- // is exiting, See https://github.com/websockets/ws/issues/1256).
108
- this.wss.on('connection', function (socket) {
109
- socket.on('error', err => {
110
- log.debug(`websocket connection error: ${err}`);
111
- });
112
- });
113
-
114
- // Create the extension that will manage the addon reloads
115
- this.reloadManagerExtension = await this.createReloadManagerExtension();
234
+ // NOTE: This function may be called twice, if the user is using an old
235
+ // Chrome version (before Chrome 126), because then we have to add a
236
+ // command-line flag (--load-extension) to load the extension. For details,
237
+ // see:
238
+ // https://github.com/mozilla/web-ext/issues/3388#issuecomment-2906982117
116
239
 
117
240
  // Start chrome pointing it to a given profile dir
118
- const extensions = [this.reloadManagerExtension].concat(this.params.extensions.map(({
241
+ const extensions = this.params.extensions.map(({
119
242
  sourceDir
120
- }) => sourceDir)).join(',');
243
+ }) => sourceDir);
121
244
  const {
122
245
  chromiumBinary
123
246
  } = this.params;
@@ -126,7 +249,12 @@ export class ChromiumExtensionRunner {
126
249
  log.debug(`(chromiumBinary: ${chromiumBinary})`);
127
250
  }
128
251
  const chromeFlags = [...DEFAULT_CHROME_FLAGS];
129
- chromeFlags.push(`--load-extension=${extensions}`);
252
+ chromeFlags.push('--remote-debugging-pipe');
253
+ if (!this.forceUseDeprecatedLoadExtension) {
254
+ chromeFlags.push('--enable-unsafe-extension-debugging');
255
+ } else {
256
+ chromeFlags.push(`--load-extension=${extensions.join(',')}`);
257
+ }
130
258
  if (this.params.args) {
131
259
  chromeFlags.push(...this.params.args);
132
260
  }
@@ -169,109 +297,60 @@ export class ChromiumExtensionRunner {
169
297
  chromeFlags.push(...startingUrls);
170
298
  }
171
299
  this.chromiumInstance = await this.chromiumLaunch({
172
- enableExtensions: true,
173
300
  chromePath: chromiumBinary,
174
301
  chromeFlags,
175
302
  startingUrl,
176
303
  userDataDir,
304
+ logLevel: this.params.verbose ? 'verbose' : 'silent',
177
305
  // Ignore default flags to keep the extension enabled.
178
306
  ignoreDefaultFlags: true
179
307
  });
308
+ this.cdp = new ChromeDevtoolsProtocolClient(this.chromiumInstance);
309
+ const initialChromiumInstance = this.chromiumInstance;
180
310
  this.chromiumInstance.process.once('close', () => {
311
+ if (this.chromiumInstance !== initialChromiumInstance) {
312
+ // This happens when we restart Chrome to fall back to --load-extension.
313
+ return;
314
+ }
181
315
  this.chromiumInstance = null;
182
316
  if (!this.exiting) {
183
317
  log.info('Exiting on Chromium instance disconnected.');
184
318
  this.exit();
185
319
  }
186
320
  });
187
- }
188
- async wssBroadcast(data) {
189
- return new Promise(resolve => {
190
- const clients = this.wss ? new Set(this.wss.clients) : new Set();
191
- function cleanWebExtReloadComplete() {
192
- const client = this;
193
- client.removeEventListener('message', webExtReloadComplete);
194
- client.removeEventListener('close', cleanWebExtReloadComplete);
195
- clients.delete(client);
196
- }
197
- const webExtReloadComplete = async message => {
198
- const msg = JSON.parse(message.data);
199
- if (msg.type === 'webExtReloadExtensionComplete') {
200
- for (const client of clients) {
201
- cleanWebExtReloadComplete.call(client);
321
+ if (!this.forceUseDeprecatedLoadExtension) {
322
+ // Assume that the required Extensions.loadUnpacked CDP method is
323
+ // supported. If it is not, we will fall back to --load-extension.
324
+ let cdpSupportsExtensionsLoadUnpacked = true;
325
+ for (const sourceDir of extensions) {
326
+ try {
327
+ await this.cdp.sendCommand('Extensions.loadUnpacked', {
328
+ path: sourceDir
329
+ });
330
+ } catch (e) {
331
+ // Chrome 125- will emit the following message:
332
+ if (e.message === "'Extensions.loadUnpacked' wasn't found") {
333
+ cdpSupportsExtensionsLoadUnpacked = false;
334
+ break;
202
335
  }
203
- resolve();
204
- }
205
- };
206
- for (const client of clients) {
207
- if (client.readyState === WebSocket.OPEN) {
208
- client.addEventListener('message', webExtReloadComplete);
209
- client.addEventListener('close', cleanWebExtReloadComplete);
210
- client.send(JSON.stringify(data));
211
- } else {
212
- clients.delete(client);
336
+ log.error(`Failed to load extension at ${sourceDir}: ${e.message}`);
337
+ // We do not have to throw - the extension can work again when
338
+ // auto-reload is used. But users may like a hard fail, and this is
339
+ // consistent with the firefox runner.
340
+ throw e;
213
341
  }
214
342
  }
215
- if (clients.size === 0) {
216
- resolve();
343
+ if (!cdpSupportsExtensionsLoadUnpacked) {
344
+ // Retry once, now with --load-extension.
345
+ log.warn('Cannot load extension via CDP, falling back to old method');
346
+ this.forceUseDeprecatedLoadExtension = true;
347
+ this.chromiumInstance = null;
348
+ await initialChromiumInstance.kill();
349
+ await this.cdp.waitUntilDisconnected();
350
+ this.cdp = null;
351
+ return this.setupInstance();
217
352
  }
218
- });
219
- }
220
- async createReloadManagerExtension() {
221
- const tmpDir = new TempDir();
222
- await tmpDir.create();
223
- this.registerCleanup(() => tmpDir.remove());
224
- const extPath = path.join(tmpDir.path(), `reload-manager-extension-${Date.now()}`);
225
- log.debug(`Creating reload-manager-extension in ${extPath}`);
226
- await fs.mkdir(extPath, {
227
- recursive: true
228
- });
229
- await fs.writeFile(path.join(extPath, 'manifest.json'), JSON.stringify({
230
- manifest_version: 2,
231
- name: 'web-ext Reload Manager Extension',
232
- version: '1.0',
233
- permissions: ['management', 'tabs'],
234
- background: {
235
- scripts: ['bg.js']
236
- }
237
- }));
238
- const wssInfo = this.wss.address();
239
- const bgPage = `(function bgPage() {
240
- async function getAllDevExtensions() {
241
- const allExtensions = await new Promise(
242
- r => chrome.management.getAll(r));
243
-
244
- return allExtensions.filter((extension) => {
245
- return extension.enabled &&
246
- extension.installType === "development" &&
247
- extension.id !== chrome.runtime.id;
248
- });
249
- }
250
-
251
- const setEnabled = (extensionId, value) =>
252
- chrome.runtime.id == extensionId ?
253
- new Promise.resolve() :
254
- new Promise(r => chrome.management.setEnabled(extensionId, value, r));
255
-
256
- async function reloadExtension(extensionId) {
257
- await setEnabled(extensionId, false);
258
- await setEnabled(extensionId, true);
259
- }
260
-
261
- const ws = new window.WebSocket(
262
- "ws://${wssInfo.address}:${wssInfo.port}");
263
-
264
- ws.onmessage = async (evt) => {
265
- const msg = JSON.parse(evt.data);
266
- if (msg.type === 'webExtReloadAllExtensions') {
267
- const devExtensions = await getAllDevExtensions();
268
- await Promise.all(devExtensions.map(ext => reloadExtension(ext.id)));
269
- ws.send(JSON.stringify({ type: 'webExtReloadExtensionComplete' }));
270
- }
271
- };
272
- })()`;
273
- await fs.writeFile(path.join(extPath, 'bg.js'), bgPage);
274
- return extPath;
353
+ }
275
354
  }
276
355
 
277
356
  /**
@@ -280,15 +359,158 @@ export class ChromiumExtensionRunner {
280
359
  */
281
360
  async reloadAllExtensions() {
282
361
  const runnerName = this.getName();
283
- await this.wssBroadcast({
284
- type: 'webExtReloadAllExtensions'
285
- });
362
+ if (this.forceUseDeprecatedLoadExtension) {
363
+ this.reloadAllExtensionsFallbackForChrome125andEarlier();
364
+ } else {
365
+ for (const {
366
+ sourceDir
367
+ } of this.params.extensions) {
368
+ try {
369
+ await this.cdp.sendCommand('Extensions.loadUnpacked', {
370
+ path: sourceDir
371
+ });
372
+ } catch (e) {
373
+ log.error(`Failed to load extension at ${sourceDir}: ${e.message}`);
374
+ }
375
+ }
376
+ }
286
377
  process.stdout.write(`\rLast extension reload: ${new Date().toTimeString()}`);
287
378
  log.debug('\n');
288
379
  return [{
289
380
  runnerName
290
381
  }];
291
382
  }
383
+ async reloadAllExtensionsFallbackForChrome125andEarlier() {
384
+ // Ideally, we'd like to use the "Extensions.loadUnpacked" CDP command to
385
+ // reload an extension, but that is unsupported in Chrome 125 and earlier.
386
+ //
387
+ // As a fallback, connect to chrome://extensions/ and reload from there.
388
+ // Since we are targeting old Chrome versions, we can safely use the
389
+ // chrome.developerPrivate APIs, because these are never going to change
390
+ // for the old browser versions. Do NOT use this for newer versions!
391
+ //
392
+ // Target.* CDP methods documented at: https://chromedevtools.github.io/devtools-protocol/tot/Target/
393
+ // developerPrivate documented at:
394
+ // https://source.chromium.org/chromium/chromium/src/+/main:chrome/common/extensions/api/developer_private.idl
395
+ //
396
+ // Specific revision that exposed developerPrivate to chrome://extensions/:
397
+ // https://source.chromium.org/chromium/chromium/src/+/main:chrome/common/extensions/api/developer_private.idl;drc=69bf75316e7ae533c0a0dccc1a56ca019aa95a1e
398
+ // https://chromium.googlesource.com/chromium/src.git/+/69bf75316e7ae533c0a0dccc1a56ca019aa95a1e
399
+ //
400
+ // Specific revision that introduced developerPrivate.getExtensionsInfo:
401
+ // https://source.chromium.org/chromium/chromium/src/+/main:chrome/common/extensions/api/developer_private.idl;drc=69bf75316e7ae533c0a0dccc1a56ca019aa95a1e
402
+ //
403
+ // The above changes are from 2015; The --remote-debugging-pipe feature
404
+ // that we rely on for CDP was added in 2018; this is the version of the
405
+ // developerPrivate API at that time:
406
+ // https://source.chromium.org/chromium/chromium/src/+/main:chrome/common/extensions/api/developer_private.idl;drc=c9ae59c8f37d487f1f01c222deb6b7d1f51c99c2
407
+
408
+ // Find an existing chrome://extensions/ tab, if it exists.
409
+ let {
410
+ targetInfos: targets
411
+ } = await this.cdp.sendCommand('Target.getTargets', {
412
+ filter: [{
413
+ type: 'tab'
414
+ }]
415
+ });
416
+ targets = targets.filter(t => t.url.startsWith('chrome://extensions/'));
417
+ let targetId;
418
+ const hasExistingTarget = targets.length > 0;
419
+ if (hasExistingTarget) {
420
+ targetId = targets[0].targetId;
421
+ } else {
422
+ const result = await this.cdp.sendCommand('Target.createTarget', {
423
+ url: 'chrome://extensions/',
424
+ newWindow: true,
425
+ background: true,
426
+ windowState: 'minimized'
427
+ });
428
+ targetId = result.targetId;
429
+ }
430
+ const codeToEvaluateInChrome = async () => {
431
+ // This function is serialized and executed in Chrome. Designed for
432
+ // compatibility with Chrome 69 - 125. Do not use JS syntax of functions
433
+ // that are not supported in these versions!
434
+
435
+ // eslint-disable-next-line no-undef
436
+ const developerPrivate = chrome.developerPrivate;
437
+ if (!developerPrivate || !developerPrivate.getExtensionsInfo) {
438
+ // When chrome://extensions/ is still loading, its document URL may be
439
+ // about:blank and the chrome.developerPrivate API is not exposed.
440
+ return 'NOT_READY_PLEASE_RETRY';
441
+ }
442
+ const extensionIds = [];
443
+ await new Promise(resolve => {
444
+ developerPrivate.getExtensionsInfo(extensions => {
445
+ for (const extension of extensions || []) {
446
+ if (extension.location === 'UNPACKED') {
447
+ // We only care about those loaded via --load-extension.
448
+ extensionIds.push(extension.id);
449
+ }
450
+ }
451
+ resolve();
452
+ });
453
+ });
454
+ const reloadPromises = extensionIds.map(extensionId => {
455
+ return new Promise((resolve, reject) => {
456
+ developerPrivate.reload(extensionId,
457
+ // Suppress alert dialog when load fails.
458
+ {
459
+ failQuietly: true,
460
+ populateErrorForUnpacked: true
461
+ }, loadError => {
462
+ if (loadError) {
463
+ reject(new Error(loadError.error));
464
+ } else {
465
+ resolve();
466
+ }
467
+ });
468
+ });
469
+ });
470
+ await Promise.all(reloadPromises);
471
+ return reloadPromises.length;
472
+ };
473
+ try {
474
+ const targetResult = await this.cdp.sendCommand('Target.attachToTarget', {
475
+ targetId,
476
+ flatten: true
477
+ });
478
+ if (!targetResult.sessionId) {
479
+ throw new Error('Unexpectedly, no sessionId from attachToTarget');
480
+ }
481
+ // In practice, we're going to run the logic only once. But if we are
482
+ // unlucky, chrome://extensions is still loading, so we will then retry.
483
+ for (let i = 0; i < 3; ++i) {
484
+ var _evalResult$result;
485
+ const evalResult = await this.cdp.sendCommand('Runtime.evaluate', {
486
+ expression: `(${codeToEvaluateInChrome})();`,
487
+ awaitPromise: true
488
+ }, targetResult.sessionId);
489
+ const evalResultReturnValue = (_evalResult$result = evalResult.result) === null || _evalResult$result === void 0 ? void 0 : _evalResult$result.value;
490
+ if (evalResultReturnValue === 'NOT_READY_PLEASE_RETRY') {
491
+ await new Promise(r => setTimeout(r, 200 * i));
492
+ continue;
493
+ }
494
+ if (evalResult.exceptionDetails) {
495
+ log.error(`Failed to reload: ${evalResult.exceptionDetails.text}`);
496
+ }
497
+ if (evalResultReturnValue !== this.params.extensions.length) {
498
+ log.warn(`Failed to reload extensions: ${evalResultReturnValue}`);
499
+ }
500
+ break;
501
+ }
502
+ } finally {
503
+ if (!hasExistingTarget && targetId) {
504
+ try {
505
+ await this.cdp.sendCommand('Target.closeTarget', {
506
+ targetId
507
+ });
508
+ } catch (e) {
509
+ log.error(e);
510
+ }
511
+ }
512
+ }
513
+ }
292
514
 
293
515
  /**
294
516
  * Reloads a single extension, collect any reload error and resolves to
@@ -329,18 +551,9 @@ export class ChromiumExtensionRunner {
329
551
  await this.chromiumInstance.kill();
330
552
  this.chromiumInstance = null;
331
553
  }
332
- if (this.wss) {
333
- // Close all websocket clients, closing the WebSocketServer
334
- // does not terminate the existing connection and it wouldn't
335
- // resolve until all of the existing connections are closed.
336
- for (const wssClient of ((_this$wss = this.wss) === null || _this$wss === void 0 ? void 0 : _this$wss.clients) || []) {
337
- var _this$wss;
338
- if (wssClient.readyState === WebSocket.OPEN) {
339
- wssClient.terminate();
340
- }
341
- }
342
- await new Promise(resolve => this.wss ? this.wss.close(resolve) : resolve());
343
- this.wss = null;
554
+ if (this.cdp) {
555
+ await this.cdp.waitUntilDisconnected();
556
+ this.cdp = null;
344
557
  }
345
558
 
346
559
  // Call all the registered cleanup callbacks.
@@ -1 +1 @@
1
- {"version":3,"file":"chromium.js","names":["fs","path","Launcher","ChromeLauncher","launch","defaultChromiumLaunch","WebSocket","WebSocketServer","createLogger","TempDir","isDirectory","fileExists","log","import","meta","url","EXCLUDED_CHROME_FLAGS","DEFAULT_CHROME_FLAGS","defaultFlags","filter","flag","includes","ChromiumExtensionRunner","cleanupCallbacks","params","chromiumInstance","chromiumLaunch","reloadManagerExtension","wss","exiting","_promiseSetupDone","constructor","Set","getName","run","setupInstance","isUserDataDir","dirPath","localStatePath","join","defaultPath","isProfileDir","securePreferencesPath","getProfilePaths","chromiumProfile","userDataDir","profileDirName","isProfileDirAndNotUserData","dir","base","parse","Promise","resolve","server","port","host","clientTracking","on","socket","err","debug","createReloadManagerExtension","extensions","concat","map","sourceDir","chromiumBinary","chromeFlags","push","args","keepProfileChanges","Error","tmpDir","create","tmpDirPath","cp","recursive","startingUrl","startUrl","startingUrls","Array","isArray","shift","enableExtensions","chromePath","ignoreDefaultFlags","process","once","info","exit","wssBroadcast","data","clients","cleanWebExtReloadComplete","client","removeEventListener","webExtReloadComplete","delete","message","msg","JSON","type","call","readyState","OPEN","addEventListener","send","stringify","size","registerCleanup","remove","extPath","Date","now","mkdir","writeFile","manifest_version","name","version","permissions","background","scripts","wssInfo","address","bgPage","reloadAllExtensions","runnerName","stdout","write","toTimeString","reloadExtensionBySourceDir","extensionSourceDir","fn","add","catch","kill","wssClient","_this$wss","terminate","close","error"],"sources":["../../src/extension-runners/chromium.js"],"sourcesContent":["/**\n * This module provide an ExtensionRunner subclass that manage an extension executed\n * in a Chromium-based browser instance.\n */\n\nimport fs from 'fs/promises';\nimport path from 'path';\n\nimport {\n Launcher as ChromeLauncher,\n launch as defaultChromiumLaunch,\n} from 'chrome-launcher';\nimport WebSocket, { WebSocketServer } from 'ws';\n\nimport { createLogger } from '../util/logger.js';\nimport { TempDir } from '../util/temp-dir.js';\nimport isDirectory from '../util/is-directory.js';\nimport fileExists from '../util/file-exists.js';\n\nconst log = createLogger(import.meta.url);\n\nconst EXCLUDED_CHROME_FLAGS = [\n '--disable-extensions',\n '--mute-audio',\n '--disable-component-update',\n];\n\nexport const DEFAULT_CHROME_FLAGS = ChromeLauncher.defaultFlags().filter(\n (flag) => !EXCLUDED_CHROME_FLAGS.includes(flag),\n);\n\n/**\n * Implements an IExtensionRunner which manages a Chromium instance.\n */\nexport class ChromiumExtensionRunner {\n cleanupCallbacks;\n params;\n chromiumInstance;\n chromiumLaunch;\n reloadManagerExtension;\n wss;\n exiting;\n _promiseSetupDone;\n\n constructor(params) {\n const { chromiumLaunch = defaultChromiumLaunch } = params;\n this.params = params;\n this.chromiumLaunch = chromiumLaunch;\n this.cleanupCallbacks = new Set();\n }\n\n // Method exported from the IExtensionRunner interface.\n\n /**\n * Returns the runner name.\n */\n getName() {\n return 'Chromium';\n }\n\n async run() {\n // Run should never be called more than once.\n this._promiseSetupDone = this.setupInstance();\n await this._promiseSetupDone;\n }\n\n static async isUserDataDir(dirPath) {\n const localStatePath = path.join(dirPath, 'Local State');\n const defaultPath = path.join(dirPath, 'Default');\n // Local State and Default are typical for the user-data-dir\n return (\n (await fileExists(localStatePath)) && (await isDirectory(defaultPath))\n );\n }\n\n static async isProfileDir(dirPath) {\n const securePreferencesPath = path.join(dirPath, 'Secure Preferences');\n //Secure Preferences is typical for a profile dir inside a user data dir\n return await fileExists(securePreferencesPath);\n }\n\n static async getProfilePaths(chromiumProfile) {\n if (!chromiumProfile) {\n return {\n userDataDir: null,\n profileDirName: null,\n };\n }\n\n const isProfileDirAndNotUserData =\n (await ChromiumExtensionRunner.isProfileDir(chromiumProfile)) &&\n !(await ChromiumExtensionRunner.isUserDataDir(chromiumProfile));\n\n if (isProfileDirAndNotUserData) {\n const { dir: userDataDir, base: profileDirName } =\n path.parse(chromiumProfile);\n return {\n userDataDir,\n profileDirName,\n };\n }\n\n return {\n userDataDir: chromiumProfile,\n profileDirName: null,\n };\n }\n\n /**\n * Setup the Chromium Profile and run a Chromium instance.\n */\n async setupInstance() {\n // Start a websocket server on a free localhost TCP port.\n this.wss = await new Promise((resolve) => {\n const server = new WebSocketServer(\n // Use a ipv4 host so we don't need to escape ipv6 address\n // https://github.com/mozilla/web-ext/issues/2331\n { port: 0, host: '127.0.0.1', clientTracking: true },\n // Wait the server to be listening (so that the extension\n // runner can successfully retrieve server address and port).\n () => resolve(server),\n );\n });\n\n // Prevent unhandled socket error (e.g. when chrome\n // is exiting, See https://github.com/websockets/ws/issues/1256).\n this.wss.on('connection', function (socket) {\n socket.on('error', (err) => {\n log.debug(`websocket connection error: ${err}`);\n });\n });\n\n // Create the extension that will manage the addon reloads\n this.reloadManagerExtension = await this.createReloadManagerExtension();\n\n // Start chrome pointing it to a given profile dir\n const extensions = [this.reloadManagerExtension]\n .concat(this.params.extensions.map(({ sourceDir }) => sourceDir))\n .join(',');\n\n const { chromiumBinary } = this.params;\n\n log.debug('Starting Chromium instance...');\n\n if (chromiumBinary) {\n log.debug(`(chromiumBinary: ${chromiumBinary})`);\n }\n\n const chromeFlags = [...DEFAULT_CHROME_FLAGS];\n\n chromeFlags.push(`--load-extension=${extensions}`);\n\n if (this.params.args) {\n chromeFlags.push(...this.params.args);\n }\n\n // eslint-disable-next-line prefer-const\n let { userDataDir, profileDirName } =\n await ChromiumExtensionRunner.getProfilePaths(\n this.params.chromiumProfile,\n );\n\n if (userDataDir && this.params.keepProfileChanges) {\n if (\n profileDirName &&\n !(await ChromiumExtensionRunner.isUserDataDir(userDataDir))\n ) {\n throw new Error(\n 'The profile you provided is not in a ' +\n 'user-data-dir. The changes cannot be kept. Please either ' +\n 'remove --keep-profile-changes or use a profile in a ' +\n 'user-data-dir directory',\n );\n }\n } else if (!this.params.keepProfileChanges) {\n // the user provided an existing profile directory but doesn't want\n // the changes to be kept. we copy this directory to a temporary\n // user data dir.\n const tmpDir = new TempDir();\n await tmpDir.create();\n const tmpDirPath = tmpDir.path();\n\n if (userDataDir && profileDirName) {\n // copy profile dir to this temp user data dir.\n await fs.cp(\n path.join(userDataDir, profileDirName),\n path.join(tmpDirPath, profileDirName),\n { recursive: true },\n );\n } else if (userDataDir) {\n await fs.cp(userDataDir, tmpDirPath, { recursive: true });\n }\n userDataDir = tmpDirPath;\n }\n\n if (profileDirName) {\n chromeFlags.push(`--profile-directory=${profileDirName}`);\n }\n\n let startingUrl;\n if (this.params.startUrl) {\n const startingUrls = Array.isArray(this.params.startUrl)\n ? this.params.startUrl\n : [this.params.startUrl];\n startingUrl = startingUrls.shift();\n chromeFlags.push(...startingUrls);\n }\n\n this.chromiumInstance = await this.chromiumLaunch({\n enableExtensions: true,\n chromePath: chromiumBinary,\n chromeFlags,\n startingUrl,\n userDataDir,\n // Ignore default flags to keep the extension enabled.\n ignoreDefaultFlags: true,\n });\n\n this.chromiumInstance.process.once('close', () => {\n this.chromiumInstance = null;\n\n if (!this.exiting) {\n log.info('Exiting on Chromium instance disconnected.');\n this.exit();\n }\n });\n }\n\n async wssBroadcast(data) {\n return new Promise((resolve) => {\n const clients = this.wss ? new Set(this.wss.clients) : new Set();\n\n function cleanWebExtReloadComplete() {\n const client = this;\n client.removeEventListener('message', webExtReloadComplete);\n client.removeEventListener('close', cleanWebExtReloadComplete);\n clients.delete(client);\n }\n\n const webExtReloadComplete = async (message) => {\n const msg = JSON.parse(message.data);\n\n if (msg.type === 'webExtReloadExtensionComplete') {\n for (const client of clients) {\n cleanWebExtReloadComplete.call(client);\n }\n resolve();\n }\n };\n\n for (const client of clients) {\n if (client.readyState === WebSocket.OPEN) {\n client.addEventListener('message', webExtReloadComplete);\n client.addEventListener('close', cleanWebExtReloadComplete);\n\n client.send(JSON.stringify(data));\n } else {\n clients.delete(client);\n }\n }\n\n if (clients.size === 0) {\n resolve();\n }\n });\n }\n\n async createReloadManagerExtension() {\n const tmpDir = new TempDir();\n await tmpDir.create();\n this.registerCleanup(() => tmpDir.remove());\n\n const extPath = path.join(\n tmpDir.path(),\n `reload-manager-extension-${Date.now()}`,\n );\n\n log.debug(`Creating reload-manager-extension in ${extPath}`);\n\n await fs.mkdir(extPath, { recursive: true });\n\n await fs.writeFile(\n path.join(extPath, 'manifest.json'),\n JSON.stringify({\n manifest_version: 2,\n name: 'web-ext Reload Manager Extension',\n version: '1.0',\n permissions: ['management', 'tabs'],\n background: {\n scripts: ['bg.js'],\n },\n }),\n );\n\n const wssInfo = this.wss.address();\n\n const bgPage = `(function bgPage() {\n async function getAllDevExtensions() {\n const allExtensions = await new Promise(\n r => chrome.management.getAll(r));\n\n return allExtensions.filter((extension) => {\n return extension.enabled &&\n extension.installType === \"development\" &&\n extension.id !== chrome.runtime.id;\n });\n }\n\n const setEnabled = (extensionId, value) =>\n chrome.runtime.id == extensionId ?\n new Promise.resolve() :\n new Promise(r => chrome.management.setEnabled(extensionId, value, r));\n\n async function reloadExtension(extensionId) {\n await setEnabled(extensionId, false);\n await setEnabled(extensionId, true);\n }\n\n const ws = new window.WebSocket(\n \"ws://${wssInfo.address}:${wssInfo.port}\");\n\n ws.onmessage = async (evt) => {\n const msg = JSON.parse(evt.data);\n if (msg.type === 'webExtReloadAllExtensions') {\n const devExtensions = await getAllDevExtensions();\n await Promise.all(devExtensions.map(ext => reloadExtension(ext.id)));\n ws.send(JSON.stringify({ type: 'webExtReloadExtensionComplete' }));\n }\n };\n })()`;\n\n await fs.writeFile(path.join(extPath, 'bg.js'), bgPage);\n return extPath;\n }\n\n /**\n * Reloads all the extensions, collect any reload error and resolves to\n * an array composed by a single ExtensionRunnerReloadResult object.\n */\n async reloadAllExtensions() {\n const runnerName = this.getName();\n\n await this.wssBroadcast({\n type: 'webExtReloadAllExtensions',\n });\n\n process.stdout.write(\n `\\rLast extension reload: ${new Date().toTimeString()}`,\n );\n log.debug('\\n');\n\n return [{ runnerName }];\n }\n\n /**\n * Reloads a single extension, collect any reload error and resolves to\n * an array composed by a single ExtensionRunnerReloadResult object.\n */\n async reloadExtensionBySourceDir(\n extensionSourceDir, // eslint-disable-line no-unused-vars\n ) {\n // TODO(rpl): detect the extension ids assigned to the\n // target extensions and map it to the extensions source dir\n // (https://github.com/mozilla/web-ext/issues/1687).\n return this.reloadAllExtensions();\n }\n\n /**\n * Register a callback to be called when the runner has been exited\n * (e.g. the Chromium instance exits or the user has requested web-ext\n * to exit).\n */\n registerCleanup(fn) {\n this.cleanupCallbacks.add(fn);\n }\n\n /**\n * Exits the runner, by closing the managed Chromium instance.\n */\n async exit() {\n this.exiting = true;\n\n // Wait for the setup to complete if the extension runner is already\n // being started.\n if (this._promiseSetupDone) {\n // Ignore initialization errors if any.\n await this._promiseSetupDone.catch((err) => {\n log.debug(`ignored setup error on chromium runner shutdown: ${err}`);\n });\n }\n\n if (this.chromiumInstance) {\n await this.chromiumInstance.kill();\n this.chromiumInstance = null;\n }\n\n if (this.wss) {\n // Close all websocket clients, closing the WebSocketServer\n // does not terminate the existing connection and it wouldn't\n // resolve until all of the existing connections are closed.\n for (const wssClient of this.wss?.clients || []) {\n if (wssClient.readyState === WebSocket.OPEN) {\n wssClient.terminate();\n }\n }\n await new Promise((resolve) =>\n this.wss ? this.wss.close(resolve) : resolve(),\n );\n this.wss = null;\n }\n\n // Call all the registered cleanup callbacks.\n for (const fn of this.cleanupCallbacks) {\n try {\n fn();\n } catch (error) {\n log.error(error);\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"chromium.js","names":["fs","path","Launcher","ChromeLauncher","launch","defaultChromiumLaunch","createLogger","TempDir","isDirectory","fileExists","log","import","meta","url","EXCLUDED_CHROME_FLAGS","DEFAULT_CHROME_FLAGS","defaultFlags","filter","flag","includes","_receivedData","WeakMap","_isProcessingMessage","_lastId","_deferredResponses","_disconnected","_disconnectedPromise","_resolveDisconnectedPromise","_ChromeDevtoolsProtocolClient_brand","WeakSet","ChromeDevtoolsProtocolClient","constructor","chromiumInstance","_classPrivateMethodInitSpec","_classPrivateFieldInitSpec","Map","_defineProperty","process","env","TEST_LOG_VERBOSE_CDP","incoming","outgoing","remoteDebuggingPipes","_classPrivateFieldSet","Promise","resolve","closed","warn","_assertClassBrand","_finalizeDisconnect","call","on","data","_classPrivateFieldGet","_processNextMessage","error","outgoingPipe","waitUntilDisconnected","sendCommand","method","params","sessionId","undefined","_this$lastId","Error","message","id","rawMessage","JSON","stringify","stderr","write","reject","set","end","indexOf","slice","result","parse","deferredResponse","get","delete","err","e","values","clear","ChromiumExtensionRunner","cleanupCallbacks","chromiumLaunch","forceUseDeprecatedLoadExtension","exiting","_promiseSetupDone","Set","getName","run","setupInstance","isUserDataDir","dirPath","localStatePath","join","defaultPath","isProfileDir","securePreferencesPath","getProfilePaths","chromiumProfile","userDataDir","profileDirName","isProfileDirAndNotUserData","dir","base","extensions","map","sourceDir","chromiumBinary","debug","chromeFlags","push","args","keepProfileChanges","tmpDir","create","tmpDirPath","cp","recursive","startingUrl","startUrl","startingUrls","Array","isArray","shift","chromePath","logLevel","verbose","ignoreDefaultFlags","cdp","initialChromiumInstance","once","info","exit","cdpSupportsExtensionsLoadUnpacked","kill","reloadAllExtensions","runnerName","reloadAllExtensionsFallbackForChrome125andEarlier","stdout","Date","toTimeString","targetInfos","targets","type","t","startsWith","targetId","hasExistingTarget","length","newWindow","background","windowState","codeToEvaluateInChrome","developerPrivate","chrome","getExtensionsInfo","extensionIds","extension","location","reloadPromises","extensionId","reload","failQuietly","populateErrorForUnpacked","loadError","all","targetResult","flatten","i","_evalResult$result","evalResult","expression","awaitPromise","evalResultReturnValue","value","r","setTimeout","exceptionDetails","text","reloadExtensionBySourceDir","extensionSourceDir","registerCleanup","fn","add","catch"],"sources":["../../src/extension-runners/chromium.js"],"sourcesContent":["/**\n * This module provide an ExtensionRunner subclass that manage an extension executed\n * in a Chromium-based browser instance.\n */\n\nimport fs from 'fs/promises';\nimport path from 'path';\n\nimport {\n Launcher as ChromeLauncher,\n launch as defaultChromiumLaunch,\n} from 'chrome-launcher';\n\nimport { createLogger } from '../util/logger.js';\nimport { TempDir } from '../util/temp-dir.js';\nimport isDirectory from '../util/is-directory.js';\nimport fileExists from '../util/file-exists.js';\n\nconst log = createLogger(import.meta.url);\n\nconst EXCLUDED_CHROME_FLAGS = [\n '--disable-extensions',\n '--mute-audio',\n '--disable-component-update',\n];\n\nexport const DEFAULT_CHROME_FLAGS = ChromeLauncher.defaultFlags().filter(\n (flag) => !EXCLUDED_CHROME_FLAGS.includes(flag),\n);\n\n// This is a client for the Chrome Devtools protocol. The methods and results\n// are documented at https://chromedevtools.github.io/devtools-protocol/tot/\nclass ChromeDevtoolsProtocolClient {\n #receivedData = '';\n #isProcessingMessage = false;\n #lastId = 0;\n #deferredResponses = new Map();\n #disconnected = false;\n #disconnectedPromise;\n #resolveDisconnectedPromise;\n\n // Print all exchanged CDP messages to ease debugging.\n TEST_LOG_VERBOSE_CDP = process.env.TEST_LOG_VERBOSE_CDP;\n\n constructor(chromiumInstance) {\n // remoteDebuggingPipes is from chrome-launcher, see\n // https://github.com/GoogleChrome/chrome-launcher/pull/347\n const { incoming, outgoing } = chromiumInstance.remoteDebuggingPipes;\n this.#disconnectedPromise = new Promise((resolve) => {\n this.#resolveDisconnectedPromise = resolve;\n });\n if (incoming.closed) {\n // Strange. Did Chrome fail to start, or exit on startup?\n log.warn('CDP already disconnected at initialization');\n this.#finalizeDisconnect();\n return;\n }\n incoming.on('data', (data) => {\n this.#receivedData += data;\n this.#processNextMessage();\n });\n incoming.on('error', (error) => {\n log.error(error);\n this.#finalizeDisconnect();\n });\n incoming.on('close', () => this.#finalizeDisconnect());\n this.outgoingPipe = outgoing;\n }\n\n waitUntilDisconnected() {\n return this.#disconnectedPromise;\n }\n\n async sendCommand(method, params, sessionId = undefined) {\n if (this.#disconnected) {\n throw new Error(`CDP disconnected, cannot send: command ${method}`);\n }\n const message = {\n id: ++this.#lastId,\n method,\n params,\n sessionId,\n };\n const rawMessage = `${JSON.stringify(message)}\\x00`;\n if (this.TEST_LOG_VERBOSE_CDP) {\n process.stderr.write(`[CDP] [SEND] ${rawMessage}\\n`);\n }\n return new Promise((resolve, reject) => {\n // CDP will always send a response.\n this.#deferredResponses.set(message.id, { method, resolve, reject });\n this.outgoingPipe.write(rawMessage);\n });\n }\n\n #processNextMessage() {\n if (this.#isProcessingMessage) {\n return;\n }\n this.#isProcessingMessage = true;\n let end = this.#receivedData.indexOf('\\x00');\n while (end !== -1) {\n const rawMessage = this.#receivedData.slice(0, end);\n this.#receivedData = this.#receivedData.slice(end + 1); // +1 skips \\x00.\n try {\n if (this.TEST_LOG_VERBOSE_CDP) {\n process.stderr.write(`[CDP] [RECV] ${rawMessage}\\n`);\n }\n const { id, error, result } = JSON.parse(rawMessage);\n const deferredResponse = this.#deferredResponses.get(id);\n if (deferredResponse) {\n this.#deferredResponses.delete(id);\n if (error) {\n const err = new Error(error.message || 'Unexpected CDP response');\n deferredResponse.reject(err);\n } else {\n deferredResponse.resolve(result);\n }\n } else {\n // Dropping events and non-response messages since we don't need it.\n }\n } catch (e) {\n log.error(e);\n }\n end = this.#receivedData.indexOf('\\x00');\n }\n this.#isProcessingMessage = false;\n if (this.#disconnected) {\n for (const { method, reject } of this.#deferredResponses.values()) {\n reject(new Error(`CDP connection closed before response to ${method}`));\n }\n this.#deferredResponses.clear();\n this.#resolveDisconnectedPromise();\n }\n }\n\n #finalizeDisconnect() {\n if (!this.#disconnected) {\n this.#disconnected = true;\n this.#processNextMessage();\n }\n }\n}\n\n/**\n * Implements an IExtensionRunner which manages a Chromium instance.\n */\nexport class ChromiumExtensionRunner {\n cleanupCallbacks;\n params;\n chromiumInstance;\n chromiumLaunch;\n // --load-extension is deprecated, but only supported in Chrome 126+, see:\n // https://github.com/mozilla/web-ext/issues/3388#issuecomment-2906982117\n forceUseDeprecatedLoadExtension;\n exiting;\n _promiseSetupDone;\n\n constructor(params) {\n const { chromiumLaunch = defaultChromiumLaunch } = params;\n this.params = params;\n this.chromiumLaunch = chromiumLaunch;\n // We will try to use Extensions.loadUnpacked first (Chrome 126+), and if\n // that does not work fall back to --load-extension.\n this.forceUseDeprecatedLoadExtension = false;\n this.cleanupCallbacks = new Set();\n }\n\n // Method exported from the IExtensionRunner interface.\n\n /**\n * Returns the runner name.\n */\n getName() {\n return 'Chromium';\n }\n\n async run() {\n // Run should never be called more than once.\n this._promiseSetupDone = this.setupInstance();\n await this._promiseSetupDone;\n }\n\n static async isUserDataDir(dirPath) {\n const localStatePath = path.join(dirPath, 'Local State');\n const defaultPath = path.join(dirPath, 'Default');\n // Local State and Default are typical for the user-data-dir\n return (\n (await fileExists(localStatePath)) && (await isDirectory(defaultPath))\n );\n }\n\n static async isProfileDir(dirPath) {\n const securePreferencesPath = path.join(dirPath, 'Secure Preferences');\n //Secure Preferences is typical for a profile dir inside a user data dir\n return await fileExists(securePreferencesPath);\n }\n\n static async getProfilePaths(chromiumProfile) {\n if (!chromiumProfile) {\n return {\n userDataDir: null,\n profileDirName: null,\n };\n }\n\n const isProfileDirAndNotUserData =\n (await ChromiumExtensionRunner.isProfileDir(chromiumProfile)) &&\n !(await ChromiumExtensionRunner.isUserDataDir(chromiumProfile));\n\n if (isProfileDirAndNotUserData) {\n const { dir: userDataDir, base: profileDirName } =\n path.parse(chromiumProfile);\n return {\n userDataDir,\n profileDirName,\n };\n }\n\n return {\n userDataDir: chromiumProfile,\n profileDirName: null,\n };\n }\n\n /**\n * Setup the Chromium Profile and run a Chromium instance.\n */\n async setupInstance() {\n // NOTE: This function may be called twice, if the user is using an old\n // Chrome version (before Chrome 126), because then we have to add a\n // command-line flag (--load-extension) to load the extension. For details,\n // see:\n // https://github.com/mozilla/web-ext/issues/3388#issuecomment-2906982117\n\n // Start chrome pointing it to a given profile dir\n const extensions = this.params.extensions.map(({ sourceDir }) => sourceDir);\n\n const { chromiumBinary } = this.params;\n\n log.debug('Starting Chromium instance...');\n\n if (chromiumBinary) {\n log.debug(`(chromiumBinary: ${chromiumBinary})`);\n }\n\n const chromeFlags = [...DEFAULT_CHROME_FLAGS];\n chromeFlags.push('--remote-debugging-pipe');\n\n if (!this.forceUseDeprecatedLoadExtension) {\n chromeFlags.push('--enable-unsafe-extension-debugging');\n } else {\n chromeFlags.push(`--load-extension=${extensions.join(',')}`);\n }\n\n if (this.params.args) {\n chromeFlags.push(...this.params.args);\n }\n\n // eslint-disable-next-line prefer-const\n let { userDataDir, profileDirName } =\n await ChromiumExtensionRunner.getProfilePaths(\n this.params.chromiumProfile,\n );\n\n if (userDataDir && this.params.keepProfileChanges) {\n if (\n profileDirName &&\n !(await ChromiumExtensionRunner.isUserDataDir(userDataDir))\n ) {\n throw new Error(\n 'The profile you provided is not in a ' +\n 'user-data-dir. The changes cannot be kept. Please either ' +\n 'remove --keep-profile-changes or use a profile in a ' +\n 'user-data-dir directory',\n );\n }\n } else if (!this.params.keepProfileChanges) {\n // the user provided an existing profile directory but doesn't want\n // the changes to be kept. we copy this directory to a temporary\n // user data dir.\n const tmpDir = new TempDir();\n await tmpDir.create();\n const tmpDirPath = tmpDir.path();\n\n if (userDataDir && profileDirName) {\n // copy profile dir to this temp user data dir.\n await fs.cp(\n path.join(userDataDir, profileDirName),\n path.join(tmpDirPath, profileDirName),\n { recursive: true },\n );\n } else if (userDataDir) {\n await fs.cp(userDataDir, tmpDirPath, { recursive: true });\n }\n userDataDir = tmpDirPath;\n }\n\n if (profileDirName) {\n chromeFlags.push(`--profile-directory=${profileDirName}`);\n }\n\n let startingUrl;\n if (this.params.startUrl) {\n const startingUrls = Array.isArray(this.params.startUrl)\n ? this.params.startUrl\n : [this.params.startUrl];\n startingUrl = startingUrls.shift();\n chromeFlags.push(...startingUrls);\n }\n\n this.chromiumInstance = await this.chromiumLaunch({\n chromePath: chromiumBinary,\n chromeFlags,\n startingUrl,\n userDataDir,\n logLevel: this.params.verbose ? 'verbose' : 'silent',\n // Ignore default flags to keep the extension enabled.\n ignoreDefaultFlags: true,\n });\n this.cdp = new ChromeDevtoolsProtocolClient(this.chromiumInstance);\n\n const initialChromiumInstance = this.chromiumInstance;\n this.chromiumInstance.process.once('close', () => {\n if (this.chromiumInstance !== initialChromiumInstance) {\n // This happens when we restart Chrome to fall back to --load-extension.\n return;\n }\n this.chromiumInstance = null;\n\n if (!this.exiting) {\n log.info('Exiting on Chromium instance disconnected.');\n this.exit();\n }\n });\n\n if (!this.forceUseDeprecatedLoadExtension) {\n // Assume that the required Extensions.loadUnpacked CDP method is\n // supported. If it is not, we will fall back to --load-extension.\n let cdpSupportsExtensionsLoadUnpacked = true;\n for (const sourceDir of extensions) {\n try {\n await this.cdp.sendCommand('Extensions.loadUnpacked', {\n path: sourceDir,\n });\n } catch (e) {\n // Chrome 125- will emit the following message:\n if (e.message === \"'Extensions.loadUnpacked' wasn't found\") {\n cdpSupportsExtensionsLoadUnpacked = false;\n break;\n }\n log.error(`Failed to load extension at ${sourceDir}: ${e.message}`);\n // We do not have to throw - the extension can work again when\n // auto-reload is used. But users may like a hard fail, and this is\n // consistent with the firefox runner.\n throw e;\n }\n }\n if (!cdpSupportsExtensionsLoadUnpacked) {\n // Retry once, now with --load-extension.\n log.warn('Cannot load extension via CDP, falling back to old method');\n this.forceUseDeprecatedLoadExtension = true;\n this.chromiumInstance = null;\n await initialChromiumInstance.kill();\n await this.cdp.waitUntilDisconnected();\n this.cdp = null;\n return this.setupInstance();\n }\n }\n }\n\n /**\n * Reloads all the extensions, collect any reload error and resolves to\n * an array composed by a single ExtensionRunnerReloadResult object.\n */\n async reloadAllExtensions() {\n const runnerName = this.getName();\n\n if (this.forceUseDeprecatedLoadExtension) {\n this.reloadAllExtensionsFallbackForChrome125andEarlier();\n } else {\n for (const { sourceDir } of this.params.extensions) {\n try {\n await this.cdp.sendCommand('Extensions.loadUnpacked', {\n path: sourceDir,\n });\n } catch (e) {\n log.error(`Failed to load extension at ${sourceDir}: ${e.message}`);\n }\n }\n }\n\n process.stdout.write(\n `\\rLast extension reload: ${new Date().toTimeString()}`,\n );\n log.debug('\\n');\n\n return [{ runnerName }];\n }\n\n async reloadAllExtensionsFallbackForChrome125andEarlier() {\n // Ideally, we'd like to use the \"Extensions.loadUnpacked\" CDP command to\n // reload an extension, but that is unsupported in Chrome 125 and earlier.\n //\n // As a fallback, connect to chrome://extensions/ and reload from there.\n // Since we are targeting old Chrome versions, we can safely use the\n // chrome.developerPrivate APIs, because these are never going to change\n // for the old browser versions. Do NOT use this for newer versions!\n //\n // Target.* CDP methods documented at: https://chromedevtools.github.io/devtools-protocol/tot/Target/\n // developerPrivate documented at:\n // https://source.chromium.org/chromium/chromium/src/+/main:chrome/common/extensions/api/developer_private.idl\n //\n // Specific revision that exposed developerPrivate to chrome://extensions/:\n // https://source.chromium.org/chromium/chromium/src/+/main:chrome/common/extensions/api/developer_private.idl;drc=69bf75316e7ae533c0a0dccc1a56ca019aa95a1e\n // https://chromium.googlesource.com/chromium/src.git/+/69bf75316e7ae533c0a0dccc1a56ca019aa95a1e\n //\n // Specific revision that introduced developerPrivate.getExtensionsInfo:\n // https://source.chromium.org/chromium/chromium/src/+/main:chrome/common/extensions/api/developer_private.idl;drc=69bf75316e7ae533c0a0dccc1a56ca019aa95a1e\n //\n // The above changes are from 2015; The --remote-debugging-pipe feature\n // that we rely on for CDP was added in 2018; this is the version of the\n // developerPrivate API at that time:\n // https://source.chromium.org/chromium/chromium/src/+/main:chrome/common/extensions/api/developer_private.idl;drc=c9ae59c8f37d487f1f01c222deb6b7d1f51c99c2\n\n // Find an existing chrome://extensions/ tab, if it exists.\n let { targetInfos: targets } = await this.cdp.sendCommand(\n 'Target.getTargets',\n { filter: [{ type: 'tab' }] },\n );\n targets = targets.filter((t) => t.url.startsWith('chrome://extensions/'));\n let targetId;\n const hasExistingTarget = targets.length > 0;\n if (hasExistingTarget) {\n targetId = targets[0].targetId;\n } else {\n const result = await this.cdp.sendCommand('Target.createTarget', {\n url: 'chrome://extensions/',\n newWindow: true,\n background: true,\n windowState: 'minimized',\n });\n targetId = result.targetId;\n }\n const codeToEvaluateInChrome = async () => {\n // This function is serialized and executed in Chrome. Designed for\n // compatibility with Chrome 69 - 125. Do not use JS syntax of functions\n // that are not supported in these versions!\n\n // eslint-disable-next-line no-undef\n const developerPrivate = chrome.developerPrivate;\n if (!developerPrivate || !developerPrivate.getExtensionsInfo) {\n // When chrome://extensions/ is still loading, its document URL may be\n // about:blank and the chrome.developerPrivate API is not exposed.\n return 'NOT_READY_PLEASE_RETRY';\n }\n const extensionIds = [];\n await new Promise((resolve) => {\n developerPrivate.getExtensionsInfo((extensions) => {\n for (const extension of extensions || []) {\n if (extension.location === 'UNPACKED') {\n // We only care about those loaded via --load-extension.\n extensionIds.push(extension.id);\n }\n }\n resolve();\n });\n });\n const reloadPromises = extensionIds.map((extensionId) => {\n return new Promise((resolve, reject) => {\n developerPrivate.reload(\n extensionId,\n // Suppress alert dialog when load fails.\n { failQuietly: true, populateErrorForUnpacked: true },\n (loadError) => {\n if (loadError) {\n reject(new Error(loadError.error));\n } else {\n resolve();\n }\n },\n );\n });\n });\n await Promise.all(reloadPromises);\n return reloadPromises.length;\n };\n try {\n const targetResult = await this.cdp.sendCommand('Target.attachToTarget', {\n targetId,\n flatten: true,\n });\n if (!targetResult.sessionId) {\n throw new Error('Unexpectedly, no sessionId from attachToTarget');\n }\n // In practice, we're going to run the logic only once. But if we are\n // unlucky, chrome://extensions is still loading, so we will then retry.\n for (let i = 0; i < 3; ++i) {\n const evalResult = await this.cdp.sendCommand(\n 'Runtime.evaluate',\n {\n expression: `(${codeToEvaluateInChrome})();`,\n awaitPromise: true,\n },\n targetResult.sessionId,\n );\n const evalResultReturnValue = evalResult.result?.value;\n if (evalResultReturnValue === 'NOT_READY_PLEASE_RETRY') {\n await new Promise((r) => setTimeout(r, 200 * i));\n continue;\n }\n if (evalResult.exceptionDetails) {\n log.error(`Failed to reload: ${evalResult.exceptionDetails.text}`);\n }\n if (evalResultReturnValue !== this.params.extensions.length) {\n log.warn(`Failed to reload extensions: ${evalResultReturnValue}`);\n }\n break;\n }\n } finally {\n if (!hasExistingTarget && targetId) {\n try {\n await this.cdp.sendCommand('Target.closeTarget', { targetId });\n } catch (e) {\n log.error(e);\n }\n }\n }\n }\n\n /**\n * Reloads a single extension, collect any reload error and resolves to\n * an array composed by a single ExtensionRunnerReloadResult object.\n */\n async reloadExtensionBySourceDir(\n extensionSourceDir, // eslint-disable-line no-unused-vars\n ) {\n // TODO(rpl): detect the extension ids assigned to the\n // target extensions and map it to the extensions source dir\n // (https://github.com/mozilla/web-ext/issues/1687).\n return this.reloadAllExtensions();\n }\n\n /**\n * Register a callback to be called when the runner has been exited\n * (e.g. the Chromium instance exits or the user has requested web-ext\n * to exit).\n */\n registerCleanup(fn) {\n this.cleanupCallbacks.add(fn);\n }\n\n /**\n * Exits the runner, by closing the managed Chromium instance.\n */\n async exit() {\n this.exiting = true;\n\n // Wait for the setup to complete if the extension runner is already\n // being started.\n if (this._promiseSetupDone) {\n // Ignore initialization errors if any.\n await this._promiseSetupDone.catch((err) => {\n log.debug(`ignored setup error on chromium runner shutdown: ${err}`);\n });\n }\n\n if (this.chromiumInstance) {\n await this.chromiumInstance.kill();\n this.chromiumInstance = null;\n }\n\n if (this.cdp) {\n await this.cdp.waitUntilDisconnected();\n this.cdp = null;\n }\n\n // Call all the registered cleanup callbacks.\n for (const fn of this.cleanupCallbacks) {\n try {\n fn();\n } catch (error) {\n log.error(error);\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-ext",
3
- "version": "8.7.1",
3
+ "version": "8.8.0",
4
4
  "description": "A command line tool to help build, run, and test web extensions",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -59,9 +59,9 @@
59
59
  "opera"
60
60
  ],
61
61
  "dependencies": {
62
- "@babel/runtime": "7.27.1",
62
+ "@babel/runtime": "7.27.6",
63
63
  "@devicefarmer/adbkit": "3.3.8",
64
- "addons-linter": "7.13.0",
64
+ "addons-linter": "7.15.0",
65
65
  "camelcase": "8.0.0",
66
66
  "chrome-launcher": "1.2.0",
67
67
  "debounce": "1.2.1",
@@ -84,14 +84,13 @@
84
84
  "tmp": "0.2.3",
85
85
  "update-notifier": "7.3.1",
86
86
  "watchpack": "2.4.4",
87
- "ws": "8.18.2",
88
87
  "yargs": "17.7.2",
89
88
  "zip-dir": "2.0.0"
90
89
  },
91
90
  "devDependencies": {
92
91
  "@babel/cli": "7.27.2",
93
- "@babel/core": "7.27.1",
94
- "@babel/eslint-parser": "7.27.1",
92
+ "@babel/core": "7.27.4",
93
+ "@babel/eslint-parser": "7.27.5",
95
94
  "@babel/preset-env": "7.27.2",
96
95
  "@babel/register": "7.27.1",
97
96
  "@commitlint/cli": "19.8.1",
@@ -110,10 +109,10 @@
110
109
  "fs-extra": "11.3.0",
111
110
  "git-rev-sync": "3.0.2",
112
111
  "html-entities": "2.6.0",
113
- "mocha": "11.4.0",
112
+ "mocha": "11.7.0",
114
113
  "nyc": "17.1.0",
115
114
  "prettier": "3.5.3",
116
- "pretty-quick": "4.1.1",
115
+ "pretty-quick": "4.2.2",
117
116
  "prettyjson": "1.2.5",
118
117
  "shelljs": "0.8.5",
119
118
  "sinon": "20.0.0",