web-ext 6.7.0 → 7.1.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/README.md +17 -8
- package/bin/web-ext.js +13 -0
- package/index.js +12 -0
- package/lib/cmd/build.js +226 -0
- package/lib/cmd/build.js.map +1 -0
- package/lib/cmd/docs.js +16 -0
- package/lib/cmd/docs.js.map +1 -0
- package/lib/cmd/index.js +47 -0
- package/lib/cmd/index.js.map +1 -0
- package/lib/cmd/lint.js +50 -0
- package/lib/cmd/lint.js.map +1 -0
- package/lib/cmd/run.js +199 -0
- package/lib/cmd/run.js.map +1 -0
- package/lib/cmd/sign.js +140 -0
- package/lib/cmd/sign.js.map +1 -0
- package/lib/config.js +144 -0
- package/lib/config.js.map +1 -0
- package/{src → lib}/errors.js +26 -35
- package/lib/errors.js.map +1 -0
- package/lib/extension-runners/base.js +2 -0
- package/lib/extension-runners/base.js.map +1 -0
- package/{src → lib}/extension-runners/chromium.js +121 -178
- package/lib/extension-runners/chromium.js.map +1 -0
- package/{src → lib}/extension-runners/firefox-android.js +168 -326
- package/lib/extension-runners/firefox-android.js.map +1 -0
- package/{src → lib}/extension-runners/firefox-desktop.js +73 -114
- package/lib/extension-runners/firefox-desktop.js.map +1 -0
- package/lib/extension-runners/index.js +311 -0
- package/lib/extension-runners/index.js.map +1 -0
- package/lib/firefox/index.js +362 -0
- package/lib/firefox/index.js.map +1 -0
- package/lib/firefox/package-identifiers.js +5 -0
- package/lib/firefox/package-identifiers.js.map +1 -0
- package/{src → lib}/firefox/preferences.js +27 -70
- package/lib/firefox/preferences.js.map +1 -0
- package/{src → lib}/firefox/rdp-client.js +98 -105
- package/lib/firefox/rdp-client.js.map +1 -0
- package/{src → lib}/firefox/remote.js +55 -129
- package/lib/firefox/remote.js.map +1 -0
- package/lib/main.js +9 -0
- package/lib/main.js.map +1 -0
- package/lib/program.js +663 -0
- package/lib/program.js.map +1 -0
- package/lib/util/adb.js +322 -0
- package/lib/util/adb.js.map +1 -0
- package/lib/util/artifacts.js +52 -0
- package/lib/util/artifacts.js.map +1 -0
- package/lib/util/desktop-notifier.js +27 -0
- package/lib/util/desktop-notifier.js.map +1 -0
- package/{src → lib}/util/file-exists.js +7 -14
- package/lib/util/file-exists.js.map +1 -0
- package/{src → lib}/util/file-filter.js +31 -59
- package/lib/util/file-filter.js.map +1 -0
- package/lib/util/is-directory.js +20 -0
- package/lib/util/is-directory.js.map +1 -0
- package/lib/util/logger.js +79 -0
- package/lib/util/logger.js.map +1 -0
- package/{src → lib}/util/manifest.js +18 -50
- package/lib/util/manifest.js.map +1 -0
- package/{src → lib}/util/promisify.js +6 -9
- package/lib/util/promisify.js.map +1 -0
- package/{src → lib}/util/stdin.js +3 -7
- package/lib/util/stdin.js.map +1 -0
- package/{src → lib}/util/temp-dir.js +47 -52
- package/lib/util/temp-dir.js.map +1 -0
- package/lib/util/updates.js +16 -0
- package/lib/util/updates.js.map +1 -0
- package/lib/watcher.js +78 -0
- package/lib/watcher.js.map +1 -0
- package/package.json +50 -52
- package/CODE_OF_CONDUCT.md +0 -10
- package/bin/web-ext +0 -7
- package/dist/web-ext.js +0 -2
- package/index.mjs +0 -13
- package/src/cmd/build.js +0 -319
- package/src/cmd/docs.js +0 -33
- package/src/cmd/index.js +0 -57
- package/src/cmd/lint.js +0 -102
- package/src/cmd/run.js +0 -266
- package/src/cmd/sign.js +0 -198
- package/src/config.js +0 -187
- package/src/extension-runners/base.js +0 -40
- package/src/extension-runners/index.js +0 -381
- package/src/firefox/index.js +0 -541
- package/src/firefox/package-identifiers.js +0 -14
- package/src/main.js +0 -19
- package/src/program.js +0 -765
- package/src/util/adb.js +0 -433
- package/src/util/artifacts.js +0 -69
- package/src/util/desktop-notifier.js +0 -41
- package/src/util/is-directory.js +0 -23
- package/src/util/logger.js +0 -131
- package/src/util/updates.js +0 -21
- package/src/watcher.js +0 -114
package/{src → lib}/errors.js
RENAMED
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
/* @flow */
|
|
2
1
|
import ExtendableError from 'es6-error';
|
|
3
|
-
|
|
4
|
-
|
|
5
2
|
/*
|
|
6
3
|
* Base error for all custom web-ext errors.
|
|
7
4
|
*/
|
|
5
|
+
|
|
8
6
|
export class WebExtError extends ExtendableError {
|
|
9
|
-
constructor(message
|
|
7
|
+
constructor(message) {
|
|
10
8
|
super(message);
|
|
11
9
|
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
10
|
|
|
11
|
+
}
|
|
15
12
|
/*
|
|
16
13
|
* The class for errors that can be fixed by the developer.
|
|
17
14
|
*/
|
|
15
|
+
|
|
18
16
|
export class UsageError extends WebExtError {
|
|
19
|
-
constructor(message
|
|
17
|
+
constructor(message) {
|
|
20
18
|
super(message);
|
|
21
19
|
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
20
|
|
|
21
|
+
}
|
|
25
22
|
/*
|
|
26
23
|
* The manifest for the extension is invalid (or missing).
|
|
27
24
|
*/
|
|
25
|
+
|
|
28
26
|
export class InvalidManifest extends UsageError {
|
|
29
|
-
constructor(message
|
|
27
|
+
constructor(message) {
|
|
30
28
|
super(message);
|
|
31
29
|
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
30
|
|
|
31
|
+
}
|
|
35
32
|
/*
|
|
36
33
|
* The remote Firefox does not support temporary add-on installation.
|
|
37
34
|
*/
|
|
35
|
+
|
|
38
36
|
export class RemoteTempInstallNotSupported extends WebExtError {
|
|
39
|
-
constructor(message
|
|
37
|
+
constructor(message) {
|
|
40
38
|
super(message);
|
|
41
39
|
}
|
|
42
|
-
}
|
|
43
40
|
|
|
41
|
+
}
|
|
44
42
|
/*
|
|
45
43
|
* The errors collected when reloading all extensions at once
|
|
46
44
|
* (initialized from a map of errors by extensionSourceDir string).
|
|
47
45
|
*/
|
|
46
|
+
|
|
48
47
|
export class MultiExtensionsReloadError extends WebExtError {
|
|
49
|
-
constructor(errorsMap
|
|
48
|
+
constructor(errorsMap) {
|
|
50
49
|
let errors = '';
|
|
50
|
+
|
|
51
51
|
for (const [sourceDir, error] of errorsMap) {
|
|
52
52
|
const msg = String(error);
|
|
53
53
|
errors += `\nError on extension loaded from ${sourceDir}: ${msg}\n`;
|
|
54
54
|
}
|
|
55
|
-
const message = `Reload errors: ${errors}`;
|
|
56
55
|
|
|
56
|
+
const message = `Reload errors: ${errors}`;
|
|
57
57
|
super(message);
|
|
58
58
|
this.errorsBySourceDir = errorsMap;
|
|
59
59
|
}
|
|
60
|
-
}
|
|
61
60
|
|
|
61
|
+
}
|
|
62
62
|
/*
|
|
63
63
|
* Sugar-y way to catch only instances of a certain error.
|
|
64
64
|
*
|
|
@@ -72,10 +72,9 @@ export class MultiExtensionsReloadError extends WebExtError {
|
|
|
72
72
|
* All other errors will be re-thrown.
|
|
73
73
|
*
|
|
74
74
|
*/
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return (error) => {
|
|
75
|
+
|
|
76
|
+
export function onlyInstancesOf(predicate, errorHandler) {
|
|
77
|
+
return error => {
|
|
79
78
|
if (error instanceof predicate) {
|
|
80
79
|
return errorHandler(error);
|
|
81
80
|
} else {
|
|
@@ -83,8 +82,6 @@ export function onlyInstancesOf(
|
|
|
83
82
|
}
|
|
84
83
|
};
|
|
85
84
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
85
|
/*
|
|
89
86
|
* Sugar-y way to catch only errors having certain code(s).
|
|
90
87
|
*
|
|
@@ -105,16 +102,13 @@ export function onlyInstancesOf(
|
|
|
105
102
|
* All other errors will be re-thrown.
|
|
106
103
|
*
|
|
107
104
|
*/
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
): Function {
|
|
112
|
-
return (error) => {
|
|
105
|
+
|
|
106
|
+
export function onlyErrorsWithCode(codeWanted, errorHandler) {
|
|
107
|
+
return error => {
|
|
113
108
|
let throwError = true;
|
|
114
109
|
|
|
115
110
|
if (Array.isArray(codeWanted)) {
|
|
116
|
-
if (codeWanted.indexOf(error.code) !== -1 ||
|
|
117
|
-
codeWanted.indexOf(error.errno) !== -1) {
|
|
111
|
+
if (codeWanted.indexOf(error.code) !== -1 || codeWanted.indexOf(error.errno) !== -1) {
|
|
118
112
|
throwError = false;
|
|
119
113
|
}
|
|
120
114
|
} else if (error.code === codeWanted || error.errno === codeWanted) {
|
|
@@ -128,11 +122,7 @@ export function onlyErrorsWithCode(
|
|
|
128
122
|
return errorHandler(error);
|
|
129
123
|
};
|
|
130
124
|
}
|
|
131
|
-
|
|
132
|
-
export function isErrorWithCode(
|
|
133
|
-
codeWanted: string | Array<string>,
|
|
134
|
-
error: Object,
|
|
135
|
-
): boolean {
|
|
125
|
+
export function isErrorWithCode(codeWanted, error) {
|
|
136
126
|
if (Array.isArray(codeWanted) && codeWanted.indexOf(error.code) !== -1) {
|
|
137
127
|
return true;
|
|
138
128
|
} else if (error.code === codeWanted) {
|
|
@@ -141,3 +131,4 @@ export function isErrorWithCode(
|
|
|
141
131
|
|
|
142
132
|
return false;
|
|
143
133
|
}
|
|
134
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","names":["ExtendableError","WebExtError","constructor","message","UsageError","InvalidManifest","RemoteTempInstallNotSupported","MultiExtensionsReloadError","errorsMap","errors","sourceDir","error","msg","String","errorsBySourceDir","onlyInstancesOf","predicate","errorHandler","onlyErrorsWithCode","codeWanted","throwError","Array","isArray","indexOf","code","errno","isErrorWithCode"],"sources":["../src/errors.js"],"sourcesContent":["/* @flow */\nimport ExtendableError from 'es6-error';\n\n\n/*\n * Base error for all custom web-ext errors.\n */\nexport class WebExtError extends ExtendableError {\n constructor(message: string) {\n super(message);\n }\n}\n\n\n/*\n * The class for errors that can be fixed by the developer.\n */\nexport class UsageError extends WebExtError {\n constructor(message: string) {\n super(message);\n }\n}\n\n\n/*\n * The manifest for the extension is invalid (or missing).\n */\nexport class InvalidManifest extends UsageError {\n constructor(message: string) {\n super(message);\n }\n}\n\n\n/*\n * The remote Firefox does not support temporary add-on installation.\n */\nexport class RemoteTempInstallNotSupported extends WebExtError {\n constructor(message: string) {\n super(message);\n }\n}\n\n/*\n * The errors collected when reloading all extensions at once\n * (initialized from a map of errors by extensionSourceDir string).\n */\nexport class MultiExtensionsReloadError extends WebExtError {\n constructor(errorsMap: Map<string, Error>) {\n let errors = '';\n for (const [sourceDir, error] of errorsMap) {\n const msg = String(error);\n errors += `\\nError on extension loaded from ${sourceDir}: ${msg}\\n`;\n }\n const message = `Reload errors: ${errors}`;\n\n super(message);\n this.errorsBySourceDir = errorsMap;\n }\n}\n\n/*\n * Sugar-y way to catch only instances of a certain error.\n *\n * Usage:\n *\n * Promise.reject(SyntaxError)\n * .catch(onlyInstancesOf(SyntaxError, (error) => {\n * // error is guaranteed to be an instance of SyntaxError\n * }))\n *\n * All other errors will be re-thrown.\n *\n */\nexport function onlyInstancesOf(\n predicate: Function, errorHandler: Function\n): Function {\n return (error) => {\n if (error instanceof predicate) {\n return errorHandler(error);\n } else {\n throw error;\n }\n };\n}\n\n\n/*\n * Sugar-y way to catch only errors having certain code(s).\n *\n * Usage:\n *\n * Promise.resolve()\n * .catch(onlyErrorsWithCode('ENOENT', (error) => {\n * // error.code is guaranteed to be ENOENT\n * }))\n *\n * or:\n *\n * Promise.resolve()\n * .catch(onlyErrorsWithCode(['ENOENT', 'ENOTDIR'], (error) => {\n * // ...\n * }))\n *\n * All other errors will be re-thrown.\n *\n */\nexport function onlyErrorsWithCode(\n codeWanted: (string | number) | Array<string | number>,\n errorHandler: Function\n): Function {\n return (error) => {\n let throwError = true;\n\n if (Array.isArray(codeWanted)) {\n if (codeWanted.indexOf(error.code) !== -1 ||\n codeWanted.indexOf(error.errno) !== -1) {\n throwError = false;\n }\n } else if (error.code === codeWanted || error.errno === codeWanted) {\n throwError = false;\n }\n\n if (throwError) {\n throw error;\n }\n\n return errorHandler(error);\n };\n}\n\nexport function isErrorWithCode(\n codeWanted: string | Array<string>,\n error: Object,\n): boolean {\n if (Array.isArray(codeWanted) && codeWanted.indexOf(error.code) !== -1) {\n return true;\n } else if (error.code === codeWanted) {\n return true;\n }\n\n return false;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","names":["showDesktopNotification","defaultDesktopNotifications"],"sources":["../../src/extension-runners/base.js"],"sourcesContent":["/* @flow */\n\nimport {\n showDesktopNotification as defaultDesktopNotifications,\n} from '../util/desktop-notifier';\nimport type {ExtensionManifest} from '../util/manifest';\n\nexport type Extension = {|\n sourceDir: string,\n manifestData: ExtensionManifest,\n|};\n\nexport type ExtensionRunnerParams = {|\n // Common cli params.\n extensions: Array<Extension>,\n profilePath?: string,\n keepProfileChanges: boolean,\n startUrl: ?string | ?Array<string>,\n args?: Array<string>,\n\n // Common injected dependencies.\n desktopNotifications: typeof defaultDesktopNotifications,\n|};\n\nexport type ExtensionRunnerReloadResult = {|\n runnerName: string,\n reloadError?: Error,\n sourceDir?: string,\n|};\n\nexport interface IExtensionRunner {\n getName(): string,\n run(): Promise<void>,\n reloadAllExtensions(): Promise<Array<ExtensionRunnerReloadResult>>,\n reloadExtensionBySourceDir(\n extensionSourceDir: string\n ): Promise<Array<ExtensionRunnerReloadResult>>,\n registerCleanup(fn: Function): void,\n exit(): Promise<void>,\n}\n"],"mappings":"AAEA,SACEA,uBAAuB,IAAIC,2BAD7B,QAEO,0BAFP"}
|
|
@@ -1,167 +1,121 @@
|
|
|
1
|
-
/* @flow */
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* This module provide an ExtensionRunner subclass that manage an extension executed
|
|
5
3
|
* in a Chromium-based browser instance.
|
|
6
4
|
*/
|
|
7
|
-
|
|
8
5
|
import path from 'path';
|
|
9
|
-
|
|
10
6
|
import fs from 'fs-extra';
|
|
11
7
|
import asyncMkdirp from 'mkdirp';
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from '
|
|
16
|
-
import
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
ExtensionRunnerParams,
|
|
22
|
-
ExtensionRunnerReloadResult,
|
|
23
|
-
} from './base';
|
|
24
|
-
import isDirectory from '../util/is-directory';
|
|
25
|
-
import fileExists from '../util/file-exists';
|
|
26
|
-
|
|
27
|
-
type ChromiumSpecificRunnerParams = {|
|
|
28
|
-
chromiumBinary?: string,
|
|
29
|
-
chromiumProfile?: string,
|
|
30
|
-
chromiumLaunch?: typeof defaultChromiumLaunch,
|
|
31
|
-
|};
|
|
32
|
-
|
|
33
|
-
export type ChromiumExtensionRunnerParams = {|
|
|
34
|
-
...ExtensionRunnerParams,
|
|
35
|
-
// Chromium desktop CLI params.
|
|
36
|
-
...ChromiumSpecificRunnerParams,
|
|
37
|
-
|};
|
|
38
|
-
|
|
39
|
-
const log = createLogger(__filename);
|
|
40
|
-
|
|
41
|
-
const EXCLUDED_CHROME_FLAGS = [
|
|
42
|
-
'--disable-extensions',
|
|
43
|
-
'--mute-audio',
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
export const DEFAULT_CHROME_FLAGS: Array<string> = ChromeLauncher.defaultFlags()
|
|
47
|
-
.filter((flag) => !EXCLUDED_CHROME_FLAGS.includes(flag));
|
|
48
|
-
|
|
8
|
+
import { Launcher as ChromeLauncher, launch as defaultChromiumLaunch } from 'chrome-launcher';
|
|
9
|
+
import WebSocket, { WebSocketServer } from 'ws';
|
|
10
|
+
import { createLogger } from '../util/logger.js';
|
|
11
|
+
import { TempDir } from '../util/temp-dir.js';
|
|
12
|
+
import isDirectory from '../util/is-directory.js';
|
|
13
|
+
import fileExists from '../util/file-exists.js';
|
|
14
|
+
const log = createLogger(import.meta.url);
|
|
15
|
+
const EXCLUDED_CHROME_FLAGS = ['--disable-extensions', '--mute-audio'];
|
|
16
|
+
export const DEFAULT_CHROME_FLAGS = ChromeLauncher.defaultFlags().filter(flag => !EXCLUDED_CHROME_FLAGS.includes(flag));
|
|
49
17
|
/**
|
|
50
18
|
* Implements an IExtensionRunner which manages a Chromium instance.
|
|
51
19
|
*/
|
|
20
|
+
|
|
52
21
|
export class ChromiumExtensionRunner {
|
|
53
|
-
|
|
54
|
-
params: ChromiumExtensionRunnerParams;
|
|
55
|
-
chromiumInstance: ?ChromeLauncher;
|
|
56
|
-
chromiumLaunch: typeof defaultChromiumLaunch;
|
|
57
|
-
reloadManagerExtension: string;
|
|
58
|
-
wss: ?WebSocket.Server;
|
|
59
|
-
exiting: boolean;
|
|
60
|
-
_promiseSetupDone: ?Promise<void>;
|
|
61
|
-
|
|
62
|
-
constructor(params: ChromiumExtensionRunnerParams) {
|
|
22
|
+
constructor(params) {
|
|
63
23
|
const {
|
|
64
|
-
chromiumLaunch = defaultChromiumLaunch
|
|
24
|
+
chromiumLaunch = defaultChromiumLaunch
|
|
65
25
|
} = params;
|
|
66
26
|
this.params = params;
|
|
67
27
|
this.chromiumLaunch = chromiumLaunch;
|
|
68
28
|
this.cleanupCallbacks = new Set();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Method exported from the IExtensionRunner interface.
|
|
29
|
+
} // Method exported from the IExtensionRunner interface.
|
|
72
30
|
|
|
73
31
|
/**
|
|
74
32
|
* Returns the runner name.
|
|
75
33
|
*/
|
|
76
|
-
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
getName() {
|
|
77
37
|
return 'Chromium';
|
|
78
38
|
}
|
|
79
39
|
|
|
80
|
-
async run()
|
|
40
|
+
async run() {
|
|
81
41
|
// Run should never be called more than once.
|
|
82
42
|
this._promiseSetupDone = this.setupInstance();
|
|
83
43
|
await this._promiseSetupDone;
|
|
84
44
|
}
|
|
85
45
|
|
|
86
|
-
static async isUserDataDir(dirPath
|
|
46
|
+
static async isUserDataDir(dirPath) {
|
|
87
47
|
const localStatePath = path.join(dirPath, 'Local State');
|
|
88
|
-
const defaultPath = path.join(dirPath, 'Default');
|
|
89
|
-
|
|
90
|
-
return await fileExists(localStatePath)
|
|
91
|
-
&& await isDirectory(defaultPath);
|
|
48
|
+
const defaultPath = path.join(dirPath, 'Default'); // Local State and Default are typical for the user-data-dir
|
|
49
|
+
|
|
50
|
+
return (await fileExists(localStatePath)) && (await isDirectory(defaultPath));
|
|
92
51
|
}
|
|
93
52
|
|
|
94
|
-
static async isProfileDir(dirPath
|
|
95
|
-
const securePreferencesPath = path.join(
|
|
96
|
-
|
|
97
|
-
//Secure Preferences is typical for a profile dir inside a user data dir
|
|
53
|
+
static async isProfileDir(dirPath) {
|
|
54
|
+
const securePreferencesPath = path.join(dirPath, 'Secure Preferences'); //Secure Preferences is typical for a profile dir inside a user data dir
|
|
55
|
+
|
|
98
56
|
return await fileExists(securePreferencesPath);
|
|
99
57
|
}
|
|
100
58
|
|
|
101
|
-
static async getProfilePaths(chromiumProfile
|
|
102
|
-
userDataDir: ?string,
|
|
103
|
-
profileDirName: ?string
|
|
104
|
-
}> {
|
|
59
|
+
static async getProfilePaths(chromiumProfile) {
|
|
105
60
|
if (!chromiumProfile) {
|
|
106
61
|
return {
|
|
107
62
|
userDataDir: null,
|
|
108
|
-
profileDirName: null
|
|
63
|
+
profileDirName: null
|
|
109
64
|
};
|
|
110
65
|
}
|
|
111
66
|
|
|
112
|
-
const isProfileDirAndNotUserData =
|
|
113
|
-
await ChromiumExtensionRunner.isProfileDir(chromiumProfile)
|
|
114
|
-
&& !await ChromiumExtensionRunner.isUserDataDir(chromiumProfile);
|
|
67
|
+
const isProfileDirAndNotUserData = (await ChromiumExtensionRunner.isProfileDir(chromiumProfile)) && !(await ChromiumExtensionRunner.isUserDataDir(chromiumProfile));
|
|
115
68
|
|
|
116
69
|
if (isProfileDirAndNotUserData) {
|
|
117
|
-
const {
|
|
118
|
-
|
|
70
|
+
const {
|
|
71
|
+
dir: userDataDir,
|
|
72
|
+
base: profileDirName
|
|
73
|
+
} = path.parse(chromiumProfile);
|
|
119
74
|
return {
|
|
120
75
|
userDataDir,
|
|
121
|
-
profileDirName
|
|
76
|
+
profileDirName
|
|
122
77
|
};
|
|
123
78
|
}
|
|
124
79
|
|
|
125
80
|
return {
|
|
126
81
|
userDataDir: chromiumProfile,
|
|
127
|
-
profileDirName: null
|
|
82
|
+
profileDirName: null
|
|
128
83
|
};
|
|
129
|
-
|
|
130
84
|
}
|
|
131
|
-
|
|
132
85
|
/**
|
|
133
86
|
* Setup the Chromium Profile and run a Chromium instance.
|
|
134
87
|
*/
|
|
135
|
-
async setupInstance(): Promise<void> {
|
|
136
|
-
// Start a websocket server on a free localhost TCP port.
|
|
137
|
-
this.wss = await new Promise((resolve) => {
|
|
138
|
-
const server = new WebSocket.Server(
|
|
139
|
-
// Use a ipv4 host so we don't need to escape ipv6 address
|
|
140
|
-
// https://github.com/mozilla/web-ext/issues/2331
|
|
141
|
-
{port: 0, host: '127.0.0.1'},
|
|
142
|
-
// Wait the server to be listening (so that the extension
|
|
143
|
-
// runner can successfully retrieve server address and port).
|
|
144
|
-
() => resolve(server));
|
|
145
|
-
});
|
|
146
88
|
|
|
147
|
-
|
|
89
|
+
|
|
90
|
+
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( // Use a ipv4 host so we don't need to escape ipv6 address
|
|
94
|
+
// https://github.com/mozilla/web-ext/issues/2331
|
|
95
|
+
{
|
|
96
|
+
port: 0,
|
|
97
|
+
host: '127.0.0.1',
|
|
98
|
+
clientTracking: true
|
|
99
|
+
}, // Wait the server to be listening (so that the extension
|
|
100
|
+
// runner can successfully retrieve server address and port).
|
|
101
|
+
() => resolve(server));
|
|
102
|
+
}); // Prevent unhandled socket error (e.g. when chrome
|
|
148
103
|
// is exiting, See https://github.com/websockets/ws/issues/1256).
|
|
149
|
-
|
|
150
|
-
|
|
104
|
+
|
|
105
|
+
this.wss.on('connection', function (socket) {
|
|
106
|
+
socket.on('error', err => {
|
|
151
107
|
log.debug(`websocket connection error: ${err}`);
|
|
152
108
|
});
|
|
153
|
-
});
|
|
109
|
+
}); // Create the extension that will manage the addon reloads
|
|
154
110
|
|
|
155
|
-
//
|
|
156
|
-
this.reloadManagerExtension = await this.createReloadManagerExtension();
|
|
157
|
-
|
|
158
|
-
// Start chrome pointing it to a given profile dir
|
|
159
|
-
const extensions = [this.reloadManagerExtension].concat(
|
|
160
|
-
this.params.extensions.map(({sourceDir}) => sourceDir)
|
|
161
|
-
).join(',');
|
|
162
|
-
|
|
163
|
-
const {chromiumBinary} = this.params;
|
|
111
|
+
this.reloadManagerExtension = await this.createReloadManagerExtension(); // Start chrome pointing it to a given profile dir
|
|
164
112
|
|
|
113
|
+
const extensions = [this.reloadManagerExtension].concat(this.params.extensions.map(({
|
|
114
|
+
sourceDir
|
|
115
|
+
}) => sourceDir)).join(',');
|
|
116
|
+
const {
|
|
117
|
+
chromiumBinary
|
|
118
|
+
} = this.params;
|
|
165
119
|
log.debug('Starting Chromium instance...');
|
|
166
120
|
|
|
167
121
|
if (chromiumBinary) {
|
|
@@ -169,25 +123,21 @@ export class ChromiumExtensionRunner {
|
|
|
169
123
|
}
|
|
170
124
|
|
|
171
125
|
const chromeFlags = [...DEFAULT_CHROME_FLAGS];
|
|
172
|
-
|
|
173
126
|
chromeFlags.push(`--load-extension=${extensions}`);
|
|
174
127
|
|
|
175
128
|
if (this.params.args) {
|
|
176
129
|
chromeFlags.push(...this.params.args);
|
|
177
|
-
}
|
|
130
|
+
} // eslint-disable-next-line prefer-const
|
|
178
131
|
|
|
179
|
-
|
|
180
|
-
let {
|
|
181
|
-
|
|
182
|
-
|
|
132
|
+
|
|
133
|
+
let {
|
|
134
|
+
userDataDir,
|
|
135
|
+
profileDirName
|
|
136
|
+
} = await ChromiumExtensionRunner.getProfilePaths(this.params.chromiumProfile);
|
|
183
137
|
|
|
184
138
|
if (userDataDir && this.params.keepProfileChanges) {
|
|
185
|
-
if (profileDirName
|
|
186
|
-
|
|
187
|
-
throw new Error('The profile you provided is not in a ' +
|
|
188
|
-
'user-data-dir. The changes cannot be kept. Please either ' +
|
|
189
|
-
'remove --keep-profile-changes or use a profile in a ' +
|
|
190
|
-
'user-data-dir directory');
|
|
139
|
+
if (profileDirName && !(await ChromiumExtensionRunner.isUserDataDir(userDataDir))) {
|
|
140
|
+
throw new Error('The profile you provided is not in a ' + 'user-data-dir. The changes cannot be kept. Please either ' + 'remove --keep-profile-changes or use a profile in a ' + 'user-data-dir directory');
|
|
191
141
|
}
|
|
192
142
|
} else if (!this.params.keepProfileChanges) {
|
|
193
143
|
// the user provided an existing profile directory but doesn't want
|
|
@@ -199,15 +149,11 @@ export class ChromiumExtensionRunner {
|
|
|
199
149
|
|
|
200
150
|
if (userDataDir && profileDirName) {
|
|
201
151
|
// copy profile dir to this temp user data dir.
|
|
202
|
-
await fs.copy(path.join(
|
|
203
|
-
userDataDir,
|
|
204
|
-
profileDirName), path.join(
|
|
205
|
-
tmpDirPath,
|
|
206
|
-
profileDirName),
|
|
207
|
-
);
|
|
152
|
+
await fs.copy(path.join(userDataDir, profileDirName), path.join(tmpDirPath, profileDirName));
|
|
208
153
|
} else if (userDataDir) {
|
|
209
154
|
await fs.copy(userDataDir, tmpDirPath);
|
|
210
155
|
}
|
|
156
|
+
|
|
211
157
|
userDataDir = tmpDirPath;
|
|
212
158
|
}
|
|
213
159
|
|
|
@@ -216,9 +162,9 @@ export class ChromiumExtensionRunner {
|
|
|
216
162
|
}
|
|
217
163
|
|
|
218
164
|
let startingUrl;
|
|
165
|
+
|
|
219
166
|
if (this.params.startUrl) {
|
|
220
|
-
const startingUrls = Array.isArray(this.params.startUrl) ?
|
|
221
|
-
this.params.startUrl : [this.params.startUrl];
|
|
167
|
+
const startingUrls = Array.isArray(this.params.startUrl) ? this.params.startUrl : [this.params.startUrl];
|
|
222
168
|
startingUrl = startingUrls.shift();
|
|
223
169
|
chromeFlags.push(...startingUrls);
|
|
224
170
|
}
|
|
@@ -230,9 +176,8 @@ export class ChromiumExtensionRunner {
|
|
|
230
176
|
startingUrl,
|
|
231
177
|
userDataDir,
|
|
232
178
|
// Ignore default flags to keep the extension enabled.
|
|
233
|
-
ignoreDefaultFlags: true
|
|
179
|
+
ignoreDefaultFlags: true
|
|
234
180
|
});
|
|
235
|
-
|
|
236
181
|
this.chromiumInstance.process.once('close', () => {
|
|
237
182
|
this.chromiumInstance = null;
|
|
238
183
|
|
|
@@ -243,8 +188,8 @@ export class ChromiumExtensionRunner {
|
|
|
243
188
|
});
|
|
244
189
|
}
|
|
245
190
|
|
|
246
|
-
async wssBroadcast(data
|
|
247
|
-
return new Promise(
|
|
191
|
+
async wssBroadcast(data) {
|
|
192
|
+
return new Promise(resolve => {
|
|
248
193
|
const clients = this.wss ? new Set(this.wss.clients) : new Set();
|
|
249
194
|
|
|
250
195
|
function cleanWebExtReloadComplete() {
|
|
@@ -254,13 +199,14 @@ export class ChromiumExtensionRunner {
|
|
|
254
199
|
clients.delete(client);
|
|
255
200
|
}
|
|
256
201
|
|
|
257
|
-
const webExtReloadComplete = async
|
|
202
|
+
const webExtReloadComplete = async message => {
|
|
258
203
|
const msg = JSON.parse(message.data);
|
|
259
204
|
|
|
260
205
|
if (msg.type === 'webExtReloadExtensionComplete') {
|
|
261
206
|
for (const client of clients) {
|
|
262
207
|
cleanWebExtReloadComplete.call(client);
|
|
263
208
|
}
|
|
209
|
+
|
|
264
210
|
resolve();
|
|
265
211
|
}
|
|
266
212
|
};
|
|
@@ -269,7 +215,6 @@ export class ChromiumExtensionRunner {
|
|
|
269
215
|
if (client.readyState === WebSocket.OPEN) {
|
|
270
216
|
client.addEventListener('message', webExtReloadComplete);
|
|
271
217
|
client.addEventListener('close', cleanWebExtReloadComplete);
|
|
272
|
-
|
|
273
218
|
client.send(JSON.stringify(data));
|
|
274
219
|
} else {
|
|
275
220
|
clients.delete(client);
|
|
@@ -282,36 +227,24 @@ export class ChromiumExtensionRunner {
|
|
|
282
227
|
});
|
|
283
228
|
}
|
|
284
229
|
|
|
285
|
-
async createReloadManagerExtension()
|
|
230
|
+
async createReloadManagerExtension() {
|
|
286
231
|
const tmpDir = new TempDir();
|
|
287
232
|
await tmpDir.create();
|
|
288
233
|
this.registerCleanup(() => tmpDir.remove());
|
|
289
|
-
|
|
290
|
-
const extPath = path.join(
|
|
291
|
-
tmpDir.path(),
|
|
292
|
-
`reload-manager-extension-${Date.now()}`
|
|
293
|
-
);
|
|
294
|
-
|
|
234
|
+
const extPath = path.join(tmpDir.path(), `reload-manager-extension-${Date.now()}`);
|
|
295
235
|
log.debug(`Creating reload-manager-extension in ${extPath}`);
|
|
296
|
-
|
|
297
236
|
await asyncMkdirp(extPath);
|
|
237
|
+
await fs.writeFile(path.join(extPath, 'manifest.json'), JSON.stringify({
|
|
238
|
+
manifest_version: 2,
|
|
239
|
+
name: 'web-ext Reload Manager Extension',
|
|
240
|
+
version: '1.0',
|
|
241
|
+
permissions: ['management', 'tabs'],
|
|
242
|
+
background: {
|
|
243
|
+
scripts: ['bg.js']
|
|
244
|
+
}
|
|
245
|
+
})); // $FlowIgnore: this method is only called right after creating the server and so wss should be defined.
|
|
298
246
|
|
|
299
|
-
await fs.writeFile(
|
|
300
|
-
path.join(extPath, 'manifest.json'),
|
|
301
|
-
JSON.stringify({
|
|
302
|
-
manifest_version: 2,
|
|
303
|
-
name: 'web-ext Reload Manager Extension',
|
|
304
|
-
version: '1.0',
|
|
305
|
-
permissions: ['management', 'tabs'],
|
|
306
|
-
background: {
|
|
307
|
-
scripts: ['bg.js'],
|
|
308
|
-
},
|
|
309
|
-
})
|
|
310
|
-
);
|
|
311
|
-
|
|
312
|
-
// $FlowIgnore: this method is only called right after creating the server and so wss should be defined.
|
|
313
247
|
const wssInfo = this.wss.address();
|
|
314
|
-
|
|
315
248
|
const bgPage = `(function bgPage() {
|
|
316
249
|
async function getAllDevExtensions() {
|
|
317
250
|
const allExtensions = await new Promise(
|
|
@@ -346,62 +279,60 @@ export class ChromiumExtensionRunner {
|
|
|
346
279
|
}
|
|
347
280
|
};
|
|
348
281
|
})()`;
|
|
349
|
-
|
|
350
282
|
await fs.writeFile(path.join(extPath, 'bg.js'), bgPage);
|
|
351
283
|
return extPath;
|
|
352
284
|
}
|
|
353
|
-
|
|
354
285
|
/**
|
|
355
286
|
* Reloads all the extensions, collect any reload error and resolves to
|
|
356
287
|
* an array composed by a single ExtensionRunnerReloadResult object.
|
|
357
288
|
*/
|
|
358
|
-
async reloadAllExtensions(): Promise<Array<ExtensionRunnerReloadResult>> {
|
|
359
|
-
const runnerName = this.getName();
|
|
360
289
|
|
|
290
|
+
|
|
291
|
+
async reloadAllExtensions() {
|
|
292
|
+
const runnerName = this.getName();
|
|
361
293
|
await this.wssBroadcast({
|
|
362
|
-
type: 'webExtReloadAllExtensions'
|
|
294
|
+
type: 'webExtReloadAllExtensions'
|
|
363
295
|
});
|
|
364
|
-
|
|
365
|
-
process.stdout.write(
|
|
366
|
-
`\rLast extension reload: ${(new Date()).toTimeString()}`);
|
|
296
|
+
process.stdout.write(`\rLast extension reload: ${new Date().toTimeString()}`);
|
|
367
297
|
log.debug('\n');
|
|
368
|
-
|
|
369
|
-
|
|
298
|
+
return [{
|
|
299
|
+
runnerName
|
|
300
|
+
}];
|
|
370
301
|
}
|
|
371
|
-
|
|
372
302
|
/**
|
|
373
303
|
* Reloads a single extension, collect any reload error and resolves to
|
|
374
304
|
* an array composed by a single ExtensionRunnerReloadResult object.
|
|
375
305
|
*/
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
)
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
async reloadExtensionBySourceDir(extensionSourceDir) {
|
|
379
309
|
// TODO(rpl): detect the extension ids assigned to the
|
|
380
310
|
// target extensions and map it to the extensions source dir
|
|
381
311
|
// (https://github.com/mozilla/web-ext/issues/1687).
|
|
382
312
|
return this.reloadAllExtensions();
|
|
383
313
|
}
|
|
384
|
-
|
|
385
314
|
/**
|
|
386
315
|
* Register a callback to be called when the runner has been exited
|
|
387
316
|
* (e.g. the Chromium instance exits or the user has requested web-ext
|
|
388
317
|
* to exit).
|
|
389
318
|
*/
|
|
390
|
-
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
registerCleanup(fn) {
|
|
391
322
|
this.cleanupCallbacks.add(fn);
|
|
392
323
|
}
|
|
393
|
-
|
|
394
324
|
/**
|
|
395
325
|
* Exits the runner, by closing the managed Chromium instance.
|
|
396
326
|
*/
|
|
397
|
-
async exit(): Promise<void> {
|
|
398
|
-
this.exiting = true;
|
|
399
327
|
|
|
400
|
-
|
|
328
|
+
|
|
329
|
+
async exit() {
|
|
330
|
+
this.exiting = true; // Wait for the setup to complete if the extension runner is already
|
|
401
331
|
// being started.
|
|
332
|
+
|
|
402
333
|
if (this._promiseSetupDone) {
|
|
403
334
|
// Ignore initialization errors if any.
|
|
404
|
-
await this._promiseSetupDone.catch(
|
|
335
|
+
await this._promiseSetupDone.catch(err => {
|
|
405
336
|
log.debug(`ignored setup error on chromium runner shutdown: ${err}`);
|
|
406
337
|
});
|
|
407
338
|
}
|
|
@@ -412,12 +343,22 @@ export class ChromiumExtensionRunner {
|
|
|
412
343
|
}
|
|
413
344
|
|
|
414
345
|
if (this.wss) {
|
|
415
|
-
|
|
416
|
-
|
|
346
|
+
// Close all websocket clients, closing the WebSocketServer
|
|
347
|
+
// does not terminate the existing connection and it wouldn't
|
|
348
|
+
// resolve until all of the existing connections are closed.
|
|
349
|
+
for (const wssClient of ((_this$wss = this.wss) === null || _this$wss === void 0 ? void 0 : _this$wss.clients) || []) {
|
|
350
|
+
var _this$wss;
|
|
351
|
+
|
|
352
|
+
if (wssClient.readyState === WebSocket.OPEN) {
|
|
353
|
+
wssClient.terminate();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
await new Promise(resolve => this.wss ? this.wss.close(resolve) : resolve());
|
|
417
358
|
this.wss = null;
|
|
418
|
-
}
|
|
359
|
+
} // Call all the registered cleanup callbacks.
|
|
360
|
+
|
|
419
361
|
|
|
420
|
-
// Call all the registered cleanup callbacks.
|
|
421
362
|
for (const fn of this.cleanupCallbacks) {
|
|
422
363
|
try {
|
|
423
364
|
fn();
|
|
@@ -426,4 +367,6 @@ export class ChromiumExtensionRunner {
|
|
|
426
367
|
}
|
|
427
368
|
}
|
|
428
369
|
}
|
|
370
|
+
|
|
429
371
|
}
|
|
372
|
+
//# sourceMappingURL=chromium.js.map
|