web-ext 5.2.0 → 5.5.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 +3 -2
- package/dist/web-ext.js +1 -1
- package/package.json +25 -25
- package/src/cmd/build.js +6 -2
- package/src/cmd/docs.js +2 -2
- package/src/cmd/run.js +26 -0
- package/src/cmd/sign.js +2 -1
- package/src/extension-runners/chromium.js +9 -7
- package/src/extension-runners/firefox-android.js +3 -11
- package/src/extension-runners/firefox-desktop.js +1 -1
- package/src/extension-runners/index.js +15 -4
- package/src/firefox/index.js +4 -3
- package/src/firefox/package-identifiers.js +4 -0
- package/src/program.js +31 -1
- package/src/util/adb.js +12 -1
- package/src/util/artifacts.js +1 -1
- package/src/util/logger.js +1 -1
- package/src/util/temp-dir.js +1 -1
- package/src/util/zip-dir.js +4 -1
- package/src/watcher.js +8 -2
package/README.md
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
This is a command line tool to help build, run, and test
|
|
4
4
|
[WebExtensions](https://wiki.mozilla.org/WebExtensions).
|
|
5
5
|
|
|
6
|
-
[](https://circleci.com/gh/mozilla/web-ext)
|
|
7
|
+
[](https://codecov.io/gh/mozilla/web-ext)
|
|
8
8
|
[](https://david-dm.org/mozilla/web-ext)
|
|
9
9
|
[](https://david-dm.org/mozilla/web-ext#info=devDependencies)
|
|
10
|
+
[](https://badge.fury.io/js/web-ext)
|
|
10
11
|
|
|
11
12
|
Ultimately, it aims to support browser extensions in a standard, portable,
|
|
12
13
|
cross-platform way. Initially, it will provide a streamlined experience for developing
|
package/dist/web-ext.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
require("source-map-support").install(),module.exports=function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=61)}([function(e,t,n){"use strict";n.d(t,"e",(function(){return o})),n.d(t,"d",(function(){return s})),n.d(t,"a",(function(){return a})),n.d(t,"c",(function(){return c})),n.d(t,"b",(function(){return d})),n.d(t,"g",(function(){return l})),n.d(t,"f",(function(){return u}));var r=n(45),i=n.n(r);class o extends i.a{constructor(e){super(e)}}class s extends o{constructor(e){super(e)}}class a extends s{constructor(e){super(e)}}class c extends o{constructor(e){super(e)}}class d extends o{constructor(e){let t="";for(const[n,r]of e){t+=`\nError on extension loaded from ${n}: ${String(r)}\n`}super("Reload errors: "+t),this.errorsBySourceDir=e}}function l(e,t){return n=>{let r=!0;if(Array.isArray(e)?-1===e.indexOf(n.code)&&-1===e.indexOf(n.errno)||(r=!1):n.code!==e&&n.errno!==e||(r=!1),r)throw n;return t(n)}}function u(e,t){return!(!Array.isArray(e)||-1===e.indexOf(t.code))||t.code===e}},function(e,t){e.exports=require("@babel/runtime/helpers/defineProperty")},function(e,t){e.exports=require("path")},function(e,t,n){"use strict";n.r(t),n.d(t,"ConsoleStream",(function(){return a})),n.d(t,"consoleStream",(function(){return c})),n.d(t,"createLogger",(function(){return d}));var r=n(1),i=n.n(r),o=n(16),s=n.n(o);class a{constructor({verbose:e=!1}={}){i()(this,"verbose",void 0),i()(this,"isCapturing",void 0),i()(this,"capturedMessages",void 0),this.verbose=e,this.isCapturing=!1,this.capturedMessages=[]}format({name:e,msg:t,level:n}){return`${this.verbose?`[${e}][${o.nameFromLevel[n]}] `:""}${t}\n`}makeVerbose(){this.verbose=!0}write(e,{localProcess:t=process}={}){const n=this.verbose?s.a.TRACE:s.a.INFO;if(e.level>=n){const n=this.format(e);this.isCapturing?this.capturedMessages.push(n):t.stdout.write(n)}}startCapturing(){this.isCapturing=!0}stopCapturing(){this.isCapturing=!1,this.capturedMessages=[]}flushCapturedLogs({localProcess:e=process}={}){for(const t of this.capturedMessages)e.stdout.write(t);this.capturedMessages=[]}}const c=new a;function d(e,{createBunyanLog:t=o.createLogger}={}){return t({name:e.replace(/^src\//,""),level:s.a.TRACE,streams:[{type:"raw",stream:c}]})}},function(e,t){e.exports=require("mz")},function(e,t){e.exports=require("util")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return g})),n.d(t,"b",(function(){return m}));var r=n(2),i=n.n(r),o=n(4),s=n(26),a=n.n(s),c=n(27),d=n.n(c),l=n(28),u=n.n(l),f=n(0),h=n(3);const p=Object(h.createLogger)(e);async function g(e){const t=i.a.join(e,"manifest.json");let n,r;p.debug("Validating manifest at "+t);try{n=await o.fs.readFile(t,{encoding:"utf-8"})}catch(e){throw new f.a(`Could not read manifest.json file at ${t}: ${e}`)}n=d()(n);try{r=a()(u()(n))}catch(e){throw new f.a(`Error parsing manifest.json file at ${t}: ${e}`)}const s=[];if(r.name||s.push('missing "name" property'),r.version||s.push('missing "version" property'),r.applications&&!r.applications.gecko&&s.push('missing "applications.gecko" property'),s.length)throw new f.a(`Manifest at ${t} is invalid: ${s.join("; ")}`);return r}function m(e){const t=[e.browser_specific_settings,e.applications];for(const e of t)if(null==e?void 0:e.gecko)return e.gecko.id}}).call(this,"src/util/manifest.js")},function(e,t){e.exports=require("fs")},function(e,t,n){"use strict";function r(e){return e.isTTY}function i(e,t){e.setRawMode(t)}n.d(t,"a",(function(){return r})),n.d(t,"b",(function(){return i}))},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return p})),n.d(t,"b",(function(){return g}));var r=n(1),i=n.n(r),o=n(52),s=n.n(o),a=n(53),c=n.n(a),d=n(3),l=n(0);const u=Object(d.createLogger)(e);class f{constructor(e){i()(this,"client",void 0),i()(this,"checkedForAddonReloading",void 0),this.client=e,this.checkedForAddonReloading=!1,e.client.on("disconnect",()=>{u.debug('Received "disconnect" from Firefox client')}),e.client.on("end",()=>{u.debug('Received "end" from Firefox client')}),e.client.on("message",e=>{u.debug("Received message from client: "+JSON.stringify(e))})}disconnect(){this.client.disconnect()}addonRequest(e,t){return new Promise((n,r)=>{this.client.client.makeRequest({to:e.actor,type:t},e=>{if(e.error){const n=`${e.error}: ${e.message}`;u.debug(`Client responded to '${t}' request with error:`,n),r(new l.e(n))}else n(e)})})}getAddonsActor(){return new Promise((e,t)=>{this.client.request("getRoot",(n,r)=>{n?(u.debug("Falling back to listTabs because getRoot failed: "+n),this.client.request("listTabs",(n,r)=>n?t(new l.e("Remote Firefox: listTabs() error: "+n)):r.addonsActor?void e(r.addonsActor):(u.debug("listTabs returned a falsey addonsActor: "+r.addonsActor),t(new l.c("This is an older version of Firefox that does not provide an add-ons actor for remote installation. Try Firefox 49 or higher."))))):r.addonsActor?e(r.addonsActor):t(new l.c("This version of Firefox does not provide an add-ons actor for remote installation."))})})}installTemporaryAddon(e){return new Promise((t,n)=>{this.getAddonsActor().then(r=>{this.client.client.makeRequest({to:r,type:"installTemporaryAddon",addonPath:e},r=>{if(r.error)return n(new l.e(`installTemporaryAddon: Error: ${r.error}: ${r.message}`));u.debug("installTemporaryAddon: "+JSON.stringify(r)),u.info(`Installed ${e} as a temporary add-on`),t(r)})}).catch(n)})}getInstalledAddon(e){return new Promise((e,t)=>{this.client.request("listAddons",(n,r)=>{n?t(new l.e("Remote Firefox: listAddons() error: "+n)):e(r.addons)})}).then(t=>{for(const n of t)if(n.id===e)return n;throw u.debug("Remote Firefox has these addons: "+t.map(e=>e.id)),new l.e("The remote Firefox does not have your extension installed")})}async checkForAddonReloading(e){if(this.checkedForAddonReloading)return e;{const t=await this.addonRequest(e,"requestTypes");if(-1===t.requestTypes.indexOf("reload")){const e=JSON.stringify(t.requestTypes);throw u.debug("Remote Firefox only supports: "+e),new l.d("This Firefox version does not support add-on reloading. Re-run with --no-reload")}return this.checkedForAddonReloading=!0,e}}async reloadAddon(e){const t=await this.getInstalledAddon(e);await this.checkForAddonReloading(t),await this.addonRequest(t,"reload"),process.stdout.write("\rLast extension reload: "+(new Date).toTimeString()),u.debug("\n")}}async function h(e,{connectToFirefox:t=c.a}={}){u.debug("Connecting to Firefox on port "+e);const n=await t(e);return u.debug("Connected to the remote Firefox debugger on port "+e),new f(n)}async function p({maxRetries:e=250,retryInterval:t=120,port:n},{connectToFirefox:r=h}={}){return u.debug("Connecting to the remote Firefox debugger"),async function(){var i;for(let o=0;o<=e;o++)try{return await r(n)}catch(e){if(!Object(l.f)("ECONNREFUSED",e))throw u.error(e.stack),e;await new Promise(e=>{setTimeout(e,t)}),i=e,u.debug(`Retrying Firefox (${o}); connection error: ${e}`)}throw u.debug("Connect to Firefox debugger: too many retries"),i}()}function g(){return new Promise(e=>{const t=s.a.createServer();t.listen(0,"127.0.0.1",()=>{const n=t.address().port;t.close(()=>e(n))})})}}).call(this,"src/firefox/remote.js")},function(e,t,n){"use strict";(function(e){n.d(t,"b",(function(){return f})),n.d(t,"a",(function(){return h}));var r=n(1),i=n.n(r),o=n(5),s=n(34),a=n.n(s),c=n(3),d=n(36);const l=Object(c.createLogger)(e);a.a.dir[d.b]=Object(d.a)(a.a.dir);const u=Object(o.promisify)(a.a.dir);function f(e){const t=new h;return t.create().then(()=>e(t)).catch(t.errorHandler()).then(t.successHandler())}class h{constructor(){i()(this,"_path",void 0),i()(this,"_removeTempDir",void 0),this._path=void 0,this._removeTempDir=void 0}create(){return u({prefix:"tmp-web-ext-",unsafeCleanup:!0}).then(([e,t])=>(this._path=e,this._removeTempDir=()=>new Promise((e,n)=>{t(t=>t?n(t):e())}),l.debug("Created temporary directory: "+this.path()),this))}path(){if(!this._path)throw new Error("You cannot access path() before calling create()");return this._path}errorHandler(){return async e=>{throw await this.remove(),e}}successHandler(){return async e=>(await this.remove(),e)}remove(){if(this._removeTempDir)return l.debug("Removing temporary directory: "+this.path()),this._removeTempDir&&this._removeTempDir()}}}).call(this,"src/util/temp-dir.js")},function(e,t){e.exports=require("firefox-profile")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return f}));var r=n(1),i=n.n(r),o=n(2),s=n.n(o),a=n(48),c=n.n(a),d=n(3);const l=Object(d.createLogger)(e);class u{constructor({baseIgnoredPatterns:e=["**/*.xpi","**/*.zip","**/.*","**/.*/**/*","**/node_modules","**/node_modules/**/*"],ignoreFiles:t=[],sourceDir:n,artifactsDir:r}={}){i()(this,"filesToIgnore",void 0),i()(this,"sourceDir",void 0),n=s.a.resolve(n),this.filesToIgnore=[],this.sourceDir=n,this.addToIgnoreList(e),t&&this.addToIgnoreList(t),r&&((e,t)=>{const n=s.a.relative(e,t);return!!n&&(".."!==n&&!n.startsWith(".."+s.a.sep))})(n,r)&&(r=s.a.resolve(r),l.debug(`Ignoring artifacts directory "${r}" and all its subdirectories`),this.addToIgnoreList([r,s.a.join(r,"**","*")]))}resolveWithSourceDir(e){const t=s.a.resolve(this.sourceDir,e);return l.debug(`Resolved path ${e} with sourceDir ${this.sourceDir} to `+t),t}addToIgnoreList(e){for(const t of e)if("!"===t.charAt(0)){const e=this.resolveWithSourceDir(t.substr(1));this.filesToIgnore.push("!"+e)}else this.filesToIgnore.push(this.resolveWithSourceDir(t))}wantFile(e){const t=this.resolveWithSourceDir(e);return!(c()(t,this.filesToIgnore).length>0)||(l.debug("FileFilter: ignoring file "+t),!1)}}const f=e=>new u(e)}).call(this,"src/util/file-filter.js")},function(e,t){e.exports=require("camelcase")},function(e,t){e.exports=require("event-to-promise")},function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var r=n(4),i=n(0);function o(e){return r.fs.stat(e).then(e=>e.isDirectory()).catch(Object(i.g)(["ENOENT","ENOTDIR"],()=>!1))}},function(e,t){e.exports=require("bunyan")},function(e,t,n){"use strict";(function(e){n.d(t,"b",(function(){return h})),n.d(t,"a",(function(){return p})),n.d(t,"c",(function(){return m}));var r=n(1),i=n.n(r),o=n(33),s=n.n(o),a=n(0),c=(n(19),n(3)),d=n(12),l=n(8),u=n(29);const f=Object(c.createLogger)(e);async function h(e){switch(e.target){case"firefox-desktop":{const{FirefoxDesktopExtensionRunner:t}=n(64);return new t(e.params)}case"firefox-android":{const{FirefoxAndroidExtensionRunner:t}=n(65);return new t(e.params)}case"chromium":{const{ChromiumExtensionRunner:t}=n(66);return new t(e.params)}default:throw new a.e(`Unknown target: "${e.target}"`)}}class p{constructor(e){i()(this,"extensionRunners",void 0),i()(this,"desktopNotifications",void 0),this.extensionRunners=e.runners,this.desktopNotifications=e.desktopNotifications}getName(){return"Multi Extension Runner"}async run(){const e=[];for(const t of this.extensionRunners)e.push(t.run());await Promise.all(e)}async reloadAllExtensions(){f.debug("Reloading all reloadable add-ons");const e=[];for(const t of this.extensionRunners){const n=t.reloadAllExtensions().then(()=>({runnerName:t.getName()}),e=>({runnerName:t.getName(),reloadError:e}));e.push(n)}return await Promise.all(e).then(e=>(this.handleReloadResults(e),e))}async reloadExtensionBySourceDir(e){f.debug("Reloading add-on at "+e);const t=[];for(const n of this.extensionRunners){const r=n.reloadExtensionBySourceDir(e).then(()=>({runnerName:n.getName(),sourceDir:e}),t=>({runnerName:n.getName(),reloadError:t,sourceDir:e}));t.push(r)}return await Promise.all(t).then(e=>(this.handleReloadResults(e),e))}registerCleanup(e){const t=[];for(const e of this.extensionRunners)t.push(new Promise(t=>{e.registerCleanup(t)}));Promise.all(t).then(e,e)}async exit(){const e=[];for(const t of this.extensionRunners)e.push(t.exit());await Promise.all(e)}handleReloadResults(e){for(const{runnerName:t,reloadError:n,sourceDir:r}of e)if(n instanceof Error){let e="Error occurred while reloading";r&&(e+=` "${r}" `),e+=`on "${t}" - ${n.message}`,f.error("\n"+e),f.debug(n.stack),this.desktopNotifications({title:"web-ext run: extension reload error",message:e})}}}function g({reloadExtension:e,sourceDir:t,watchFile:n,artifactsDir:r,ignoreFiles:i,onSourceChange:o=u.a,createFileFilter:s=d.a}){const a=s({sourceDir:t,artifactsDir:r,ignoreFiles:i});return o({sourceDir:t,watchFile:n,artifactsDir:r,onChange:()=>e(t),shouldWatchFile:e=>a.wantFile(e)})}function m({artifactsDir:e,extensionRunner:t,ignoreFiles:n,noInput:r=!1,sourceDir:i,watchFile:o},{createWatcher:a=g,stdin:c=process.stdin,kill:d=process.kill}={}){const u=!r;u||f.debug("Input has been disabled because of noInput==true");const h=a({reloadExtension:e=>{t.reloadExtensionBySourceDir(e)},sourceDir:i,watchFile:o,artifactsDir:e,ignoreFiles:n});if(t.registerCleanup(()=>{h.close(),u&&c.pause()}),u&&Object(l.a)(c)){s.a.emitKeypressEvents(c),Object(l.b)(c,!0);const e="Press R to reload (and Ctrl-C to quit)";Promise.resolve().then((async function(){f.info(e);let n=!1;for(;!n;){const r=await new Promise(e=>{c.once("keypress",(t,n)=>e(n))});r.ctrl&&"c"===r.name?n=!0:"z"===r.name?(Object(l.b)(c,!1),f.info("\nweb-ext has been suspended on user request"),d(process.pid,"SIGTSTP"),f.info("\nweb-ext has been resumed. "+e),Object(l.b)(c,!0)):"r"===r.name&&(f.debug("Reloading installed extensions on user request"),t.reloadAllExtensions())}f.info("\nExiting web-ext on user request"),t.exit()}))}}}).call(this,"src/extension-runners/index.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"safeFileName",(function(){return P})),n.d(t,"getDefaultLocalizedName",(function(){return A})),n.d(t,"getStringPropertyValue",(function(){return E})),n.d(t,"defaultPackageCreator",(function(){return F})),n.d(t,"default",(function(){return k}));var r=n(2),i=n.n(r),o=n(7),s=n(4),a=n(26),c=n.n(a),d=n(27),l=n.n(d),u=n(28),f=n.n(u),h=n(14),p=n.n(h),g=n(29),m=n(46),b=n(6),w=n(30),x=n(3),y=n(0),v=n(12);const D=Object(x.createLogger)(e);function P(e){return e.toLowerCase().replace(/[^a-z0-9.-]+/g,"_")}async function A({messageFile:e,manifestData:t}){let n,r,i=t.name;try{r=await s.fs.readFile(e,{encoding:"utf-8"})}catch(t){throw new y.d(`Error reading messages.json file at ${e}: ${t}`)}r=l()(r);try{n=c()(f()(r))}catch(t){throw new y.d(`Error parsing messages.json file at ${e}: ${t}`)}return i=t.name.replace(/__MSG_([A-Za-z0-9@_]+?)__/g,(t,r)=>{if(n[r]&&n[r].message)return n[r].message;throw new y.d(`The locale file ${e} is missing key: `+r)}),Promise.resolve(i)}function E(e,t){const n=e.split(".").reduce((e,t)=>e&&e[t],t);if(!["string","number"].includes(typeof n))throw new y.d(`Manifest key "${e}" is missing or has an invalid type: ${n}`);const r=""+n;if(!r.length)throw new y.d(`Manifest key "${e}" value is an empty string`);return r}async function F({manifestData:e,sourceDir:t,fileFilter:n,artifactsDir:r,overwriteDest:s,showReadyMessage:a,filename:c="{name}-{version}.zip"},{eventToPromise:d=p.a}={}){let l;e?(l=Object(b.b)(e),D.debug("Using manifest id="+(l||"[not specified]"))):e=await Object(b.a)(t);const u=await Object(m.a)(t,{filter:(...e)=>n.wantFile(...e)});let f=c,{default_locale:h}=e;if(h){h=h.replace(/-/g,"_");const n=i.a.join(t,"_locales",h,"messages.json");D.debug("Manifest declared default_locale, localizing extension name");const r=await A({messageFile:n,manifestData:e});f=f.replace(/{name}/g,r)}const g=P(function(e,t){const n=e.replace(/{([A-Za-z0-9._]+?)}/g,(e,n)=>E(n,t)),r=i.a.parse(n);if(r.dir)throw new y.d(`Invalid filename template "${e}". Filename "${n}" should not contain a path`);if(![".zip",".xpi"].includes(r.ext))throw new y.d(`Invalid filename template "${e}". Filename "${n}" should have a zip or xpi extension`);return n}(f,e)),w=i.a.join(r,g),x=Object(o.createWriteStream)(w,{flags:"wx"});x.write(u,()=>x.end());try{await d(x,"close")}catch(e){if(!Object(y.f)("EEXIST",e))throw e;if(!s)throw new y.d(`Extension exists at the destination path: ${w}\nUse --overwrite-dest to enable overwriting.`);D.info("Destination exists, overwriting: "+w);const t=Object(o.createWriteStream)(w);t.write(u,()=>t.end()),await d(t,"close")}return a&&D.info("Your web extension is ready: "+w),{extensionPath:w}}async function k({sourceDir:e,artifactsDir:t,asNeeded:n=!1,overwriteDest:r=!1,ignoreFiles:i=[],filename:o="{name}-{version}.zip"},{manifestData:s,createFileFilter:a=v.a,fileFilter:c=a({sourceDir:e,artifactsDir:t,ignoreFiles:i}),onSourceChange:d=g.a,packageCreator:l=F,showReadyMessage:u=!0}={}){const f=n;D.info("Building web extension from "+e);const h=()=>l({manifestData:s,sourceDir:e,fileFilter:c,artifactsDir:t,overwriteDest:r,showReadyMessage:u,filename:o});await Object(w.a)(t);const p=await h();return f&&(D.info("Rebuilding when files change..."),d({sourceDir:e,artifactsDir:t,onChange:()=>h().catch(e=>{throw D.error(e.stack),e}),shouldWatchFile:(...e)=>c.wantFile(...e)})),p}}.call(this,"src/cmd/build.js")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return a}));var r=n(50),i=n.n(r),o=n(3);const s=Object(o.createLogger)(e);function a({title:e,message:t,icon:n},{notifier:r=i.a,log:o=s}={}){return new Promise((i,s)=>{r.notify({title:e,message:t,icon:n},(e,t)=>{e?(o.debug(`Desktop notifier error: ${e.message}, response: `+t),s(e)):i()})})}}).call(this,"src/util/desktop-notifier.js")},function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var r=n(4),i=n(0);async function o(e,{fileIsReadable:t=(e=>r.fs.access(e,r.fs.constants.R_OK))}={}){try{await t(e);return(await r.fs.stat(e)).isFile()}catch(e){if(Object(i.f)(["EACCES","ENOENT"],e))return!1;throw e}}},function(e,t){e.exports=require("fs-extra")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"defaultFirefoxEnv",(function(){return P})),n.d(t,"run",(function(){return A})),n.d(t,"isDefaultProfile",(function(){return F})),n.d(t,"configureProfile",(function(){return k})),n.d(t,"defaultCreateProfileFinder",(function(){return O})),n.d(t,"useProfile",(function(){return S})),n.d(t,"createProfile",(function(){return j})),n.d(t,"copyProfile",(function(){return C})),n.d(t,"installExtension",(function(){return R}));var r=n(7),i=n.n(r),o=n(2),s=n.n(o),a=n(5),c=n(51),d=n.n(c),l=n(11),u=n.n(l),f=n(4),h=n(14),p=n.n(h),g=n(15),m=n(0),b=n(32),w=n(6),x=n(9),y=n(3);const v=Object(y.createLogger)(e),D=f.fs.stat.bind(f.fs),P={XPCOM_DEBUG_BREAK:"stack",NS_TRACE_MALLOC_DISABLE_STACKS:"1"};async function A(e,{fxRunner:t=d.a,findRemotePort:n=x.b,firefoxBinary:r,binaryArgs:i}={}){v.debug("Running Firefox with profile at "+e.path());const o=await n(),s=await t({binary:r,"binary-args":i,"no-remote":!0,listen:o,foreground:!0,profile:e.path(),env:{...process.env,...P},verbose:!0}),a=s.process;return v.debug("Executing Firefox binary: "+s.binary),v.debug("Firefox args: "+s.args.join(" ")),a.on("error",e=>{throw v.error("Firefox error: "+e),e}),v.info("Use --verbose or open Tools > Web Developer > Browser Console to see logging"),a.stderr.on("data",e=>{v.debug("Firefox stderr: "+e.toString().trim())}),a.stdout.on("data",e=>{v.debug("Firefox stdout: "+e.toString().trim())}),a.on("close",()=>{v.debug("Firefox closed")}),{firefox:a,debuggerPort:o}}const E=["default","dev-edition-default"];async function F(e,t=u.a.Finder,n=f.fs.stat){if(E.includes(e))return!0;const r=t.locateUserDirectory(),i=s.a.join(r,"profiles.ini");try{await n(i)}catch(e){if(Object(m.f)("ENOENT",e))return v.debug("profiles.ini not found: "+e),!1;throw e}const o=new t(r),c=Object(a.promisify)(o.readProfiles.bind(o));await c();const d=s.a.normalize(s.a.join(s.a.resolve(e),s.a.sep));for(const t of o.profiles)if(E.includes(t.Name)||"1"===t.Default){let n;if(t.Name===e)return!0;if(n="1"===t.IsRelative?s.a.join(r,t.Path,s.a.sep):s.a.join(t.Path,s.a.sep),s.a.normalize(n)===d)return!0}return!1}function k(e,{app:t="firefox",getPrefs:n=b.b,customPrefs:r={}}={}){const i=n(t);if(Object.keys(i).forEach(t=>{e.setPreference(t,i[t])}),Object.keys(r).length>0){const t=JSON.stringify(r,null,2);v.info("Setting custom Firefox preferences: "+t),Object.keys(r).forEach(t=>{e.setPreference(t,r[t])})}return e.updatePreferences(),Promise.resolve(e)}function O({userDirectoryPath:e,FxProfile:t=u.a}={}){const n=new t.Finder(e),r=Object(a.promisify)(n.readProfiles.bind(n)),i=Object(a.promisify)(n.getPath.bind(n));return async e=>{try{await r();if(0!==n.profiles.filter(t=>t.Name===e).length)return await i(e)}catch(e){if(!Object(m.f)("ENOENT",e))throw e;v.warn("Unable to find Firefox profiles.ini")}}}async function S(e,{app:t,configureThisProfile:n=k,isFirefoxDefaultProfile:r=F,customPrefs:i={},createProfileFinder:o=O}={}){if(await r(e))throw new m.d(`Cannot use --keep-profile-changes on a default profile ("${e}") because web-ext will make it insecure and unsuitable for daily use.\nSee https://github.com/mozilla/web-ext/issues/1005`);let s;const a=o();if(await Object(g.a)(e))v.debug(`Using profile directory "${e}"`),s=e;else if(v.debug(`Assuming ${e} is a named profile`),s=await a(e),!s)throw new m.d(`The request "${e}" profile name cannot be resolved to a profile path`);const c=new u.a({destinationDirectory:s});return await n(c,{app:t,customPrefs:i})}async function j({app:e,configureThisProfile:t=k,customPrefs:n={}}={}){const r=new u.a;return await t(r,{app:e,customPrefs:n})}async function C(e,{app:t,configureThisProfile:n=k,copyFromUserProfile:r=l.copyFromUserProfile,customPrefs:i={}}={}){const o=Object(a.promisify)(u.a.copy),s=Object(a.promisify)(r);try{let r;return await Object(g.a)(e)?(v.debug(`Copying profile directory from "${e}"`),r=await o({profileDirectory:e})):(v.debug(`Assuming ${e} is a named profile`),r=await s({name:e})),n(r,{app:t,customPrefs:i})}catch(t){throw new m.e(`Could not copy Firefox profile from ${e}: ${t}`)}}async function R({asProxy:e=!1,manifestData:t,profile:n,extensionPath:r,asyncFsStat:o=D}){if(!n.extensionsDir)throw new m.e("profile.extensionsDir was unexpectedly empty");try{await o(n.extensionsDir)}catch(e){if(!Object(m.f)("ENOENT",e))throw e;v.debug("Creating extensions directory: "+n.extensionsDir),await f.fs.mkdir(n.extensionsDir)}const a=Object(w.b)(t);if(!a)throw new m.d("An explicit extension ID is required when installing to a profile (applications.gecko.id not found in manifest.json)");if(e){v.debug("Installing as an extension proxy; source: "+r);if(!await Object(g.a)(r))throw new m.e("proxy install: extensionPath must be the extension source directory; got: "+r);const e=s.a.join(n.extensionsDir,""+a),t=i.a.createWriteStream(e);return t.write(r),t.end(),await p()(t,"close")}{const e=i.a.createReadStream(r),t=s.a.join(n.extensionsDir,a+".xpi"),o=i.a.createWriteStream(t);return v.debug(`Installing extension from ${r} to ${t}`),e.pipe(o),await Promise.all([p()(e,"close"),p()(o,"close")])}}}.call(this,"src/firefox/index.js")},function(e,t){e.exports=require("os")},function(e,t){e.exports=require("decamelize")},function(e,t,n){"use strict";t.a={build:async function(e,t){const{default:r}=n(18);return r(e,t)},lint:async function(e,t){const{default:r}=n(62);return r(e,t)},run:async function(e,t){const{default:r}=n(63);return r(e,t)},sign:async function(e,t){const{default:r}=n(67);return r(e,t)},docs:async function(e,t){const{default:r}=n(68);return r(e,t)}}},function(e,t){e.exports=require("parse-json")},function(e,t){e.exports=require("strip-bom")},function(e,t){e.exports=require("strip-json-comments")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return u}));var r=n(4),i=n(43),o=n.n(i),s=n(44),a=n.n(s),c=n(0),d=n(3);const l=Object(d.createLogger)(e);function u({sourceDir:e,watchFile:t,artifactsDir:n,onChange:i,shouldWatchFile:s}){const d=new o.a;i=a()(i,1e3,!0),d.on("change",e=>{!function({artifactsDir:e,onChange:t,filePath:n,shouldWatchFile:r}){0!==n.indexOf(e)&&r(n)?(l.debug("Changed: "+n),l.debug("Last change detection: "+(new Date).toTimeString()),t()):l.debug("Ignoring change to: "+n)}({artifactsDir:n,onChange:i,filePath:e,shouldWatchFile:s})}),l.debug("Watching for file changes in "+(t||e));const u=[],f=[];if(t){if(r.fs.existsSync(t)&&!r.fs.lstatSync(t).isFile())throw new c.d(`Invalid --watch-file value: "${t}" is not a file.`);f.push(t)}else u.push(e);return d.watch(f,u,Date.now()),process.on("SIGINT",()=>d.close()),d}}).call(this,"src/watcher.js")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return l}));var r=n(4),i=n(31),o=n.n(i),s=n(0),a=n(3);const c=Object(a.createLogger)(e),d=r.fs.access.bind(r.fs);async function l(e,{asyncMkdirp:t=o.a,asyncFsAccess:n=d}={}){try{if(!(await r.fs.stat(e)).isDirectory())throw new s.d(`--artifacts-dir="${e}" exists but it is not a directory.`);try{await n(e,r.fs.W_OK)}catch(t){throw Object(s.f)("EACCES",t)?new s.d(`--artifacts-dir="${e}" exists but the user lacks permissions on it.`):t}}catch(n){if(Object(s.f)("EACCES",n))throw new s.d(`Cannot access --artifacts-dir="${e}" because the user lacks permissions: `+n);if(!Object(s.f)("ENOENT",n))throw n;try{c.debug("Creating artifacts directory: "+e),await t(e)}catch(t){throw Object(s.f)("EACCES",t)?new s.d(`Cannot create --artifacts-dir="${e}" because the user lacks permissions: `+t):t}}return e}}).call(this,"src/util/artifacts.js")},function(e,t){e.exports=require("mkdirp")},function(e,t,n){"use strict";(function(e){n.d(t,"b",(function(){return d})),n.d(t,"a",(function(){return l}));var r=n(0),i=n(3);const o=Object(i.createLogger)(e),s=["devtools.debugger.remote-enabled","devtools.debugger.prompt-connection","xpinstall.signatures.required"],a={"browser.dom.window.dump.enabled":!0,"datareporting.policy.dataSubmissionEnabled":!1,"devtools.debugger.remote-enabled":!0,"devtools.debugger.prompt-connection":!1,"devtools.browserconsole.contentMessages":!0,"extensions.logging.enabled":!1,"extensions.checkCompatibility.nightly":!1,"extensions.update.enabled":!1,"extensions.update.notifyUser":!1,"extensions.enabledScopes":5,"extensions.getAddons.cache.enabled":!1,"extensions.installDistroAddons":!1,"extensions.autoDisableScopes":10,"app.update.enabled":!1,"xpinstall.signatures.required":!1,"browser.link.open_newwindow":3},c={common:a,fennec:{"browser.console.showInPanel":!0,"browser.firstrun.show.uidiscovery":!1,"devtools.remote.usb.enabled":!0},firefox:{"browser.startup.homepage":"about:blank","startup.homepage_welcome_url":"about:blank","startup.homepage_welcome_url.additional":"","devtools.errorconsole.enabled":!0,"devtools.chrome.enabled":!0,"urlclassifier.updateinterval":172800,"browser.safebrowsing.provider.0.gethashURL":"http://localhost/safebrowsing-dummy/gethash","browser.safebrowsing.provider.0.keyURL":"http://localhost/safebrowsing-dummy/newkey","browser.safebrowsing.provider.0.updateURL":"http://localhost/safebrowsing-dummy/update","browser.selfsupport.url":"https://localhost/selfrepair","browser.reader.detectedFirstArticle":!0,"datareporting.policy.firstRunURL":""}};function d(e="firefox"){const t=c[e];if(!t)throw new r.e("Unsupported application: "+e);return{...a,...t}}function l(e){const t={};for(const n of e){const e=n.split("=");if(e.length<2)throw new r.d(`Incomplete custom preference: "${n}". Syntax expected: "prefname=prefvalue".`);const i=e[0];let a=e.slice(1).join("=");if(/[^\w{@}.-]/.test(i))throw new r.d("Invalid custom preference name: "+i);a===""+parseInt(a)?a=parseInt(a,10):"true"!==a&&"false"!==a||(a="true"===a),s.includes(i)?o.warn(`'${i}' preference cannot be customized.`):t[""+i]=a}return t}}).call(this,"src/firefox/preferences.js")},function(e,t){e.exports=require("readline")},function(e,t){e.exports=require("tmp")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return b})),n.d(t,"c",(function(){return w})),n.d(t,"b",(function(){return x}));var r=n(23),i=n.n(r),o=n(2),s=n.n(o),a=n(60),c=n.n(a),d=n(13),l=n.n(d),u=n(24),f=n.n(u),h=n(20),p=n(3),g=n(0);const m=Object(p.createLogger)(e);function b({argv:e,argvFromCLI:t,configObject:n,options:r,configFileName:i}){let o={...e};for(const e of Object.keys(n)){if(l()(e)!==e)throw new g.d(`The config option "${e}" must be specified in camel case: "${l()(e)}"`);if(!Array.isArray(n[e])&&"object"==typeof r[e]&&"object"==typeof n[e]){o=b({argv:o,argvFromCLI:t,configObject:n[e],options:r[e],configFileName:i});continue}const s=f()(e,"-");if("object"!=typeof r[s])throw new g.d(`The config file at ${i} specified an unknown option: "${e}"`);if(void 0===r[s].type)throw new g.e(`Option: ${e} was defined without a type.`);const a="count"===r[s].type?"number":r[s].type,c=Array.isArray(n[e])?"array":typeof n[e];if(c!==a)throw new g.d(`The config file at ${i} specified the type of "${e}" incorrectly as "${c}" (expected type "${a}")`);let d;r[s]&&(void 0!==r[s].default?d=r[s].default:"boolean"===a&&(d=!1));if(void 0!==t[e]&&t[e]!==d){m.debug(`Favoring CLI: ${e}=${t[e]} over configuration: ${e}=${n[e]}`),o[e]=t[e];continue}o[e]=n[e];const u=r[s].coerce;u&&(m.debug("Calling coerce() on configured value for "+e),o[e]=u(o[e])),o[s]=o[e]}return o}function w(e){const t=s.a.resolve(e);let n;m.debug(`Loading JS config file: "${e}" (resolved to "${t}")`);try{n=c()(t)}catch(e){throw m.debug("Handling error:",e),new g.d(`Cannot read config file: ${t}\nError: `+e.message)}return e.endsWith("package.json")&&(m.debug("Looking for webExt key inside package.json file"),n=n.webExt||{}),0===Object.keys(n).length&&m.debug(`Config file ${t} did not define any options. Did you set module.exports = {...}?`),n}async function x({getHomeDir:e=i.a.homedir}={}){const t=[s.a.join(e(),".web-ext-config.js"),s.a.join(process.cwd(),"package.json"),s.a.join(process.cwd(),"web-ext-config.js")],n=await Promise.all(t.map(async e=>{const t=s.a.resolve(e);return await Object(h.a)(t)?t:void m.debug(`Discovered config "${t}" does not exist or is not readable`)})),r=[];return n.forEach(e=>{"string"==typeof e&&r.push(e)}),r}}).call(this,"src/config.js")},function(e,t,n){"use strict";n.d(t,"b",(function(){return i})),n.d(t,"a",(function(){return o}));var r=n(5);const i=r.promisify.custom;function o(e){return(...t)=>new Promise((n,r)=>{e(...t,(e,...t)=>{e?r(e):n(t)})})}},function(e,t,n){"use strict";t.a=["org.mozilla.fennec","org.mozilla.fenix","org.mozilla.geckoview_example","org.mozilla.geckoview","org.mozilla.firefox","org.mozilla.reference.browser"]},function(e,t){e.exports=require("chrome-launcher")},function(e,t){e.exports=require("ws")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return F}));var r=n(1),i=n.n(r),o=n(23),s=n.n(o),a=n(2),c=n.n(a),d=n(7),l=n(13),u=n.n(l),f=n(24),h=n.n(f),p=n(41),g=n.n(p),m=n(42),b=n(25),w=n(0),x=n(3),y=n(32),v=n(58),D=n(35);const P=Object(x.createLogger)(e);class A{constructor(e,{absolutePackageDir:t=process.cwd()}={}){i()(this,"absolutePackageDir",void 0),i()(this,"yargs",void 0),i()(this,"commands",void 0),i()(this,"shouldExitProgram",void 0),i()(this,"verboseEnabled",void 0),i()(this,"options",void 0),i()(this,"programArgv",void 0),e=e||process.argv.slice(2),this.programArgv=e;const n=g()(e,t);this.absolutePackageDir=t,this.verboseEnabled=!1,this.shouldExitProgram=!0,this.yargs=n,this.yargs.parserConfiguration({"boolean-negation":!0}),this.yargs.strict(),this.commands={},this.options={}}command(e,t,n,r={}){return this.options[u()(e)]=r,this.yargs.command(e,t,e=>{if(r)return e.demandCommand(0,0,void 0,"This command does not take any arguments").strict().exitProcess(this.shouldExitProgram).env("WEB_EXT").options(r)}),this.commands[e]=n,this}setGlobalOptions(e){return this.options={...this.options,...e},Object.keys(e).forEach(t=>{e[t].global=!0,void 0===e[t].demandOption&&(e[t].demandOption=!0)}),this.yargs.options(e),this}enableVerboseMode(e,t){this.verboseEnabled||(e.makeVerbose(),P.info("Version:",t),this.verboseEnabled=!0)}getArguments(){const e=this.yargs.getValidationInstance(),{requiredArguments:t}=e;e.requiredArguments=()=>{};const n=this.yargs.argv;if(e.requiredArguments=t,null!=n.configDiscovery&&(n.noConfigDiscovery=!n.configDiscovery),null!=n.reload&&(n.noReload=!n.reload),n.ignoreFiles&&!n.ignoreFiles.length)throw new w.d("Not enough arguments following: ignore-files");if(n.startUrl&&!n.startUrl.length)throw new w.d("Not enough arguments following: start-url");return n}checkRequiredArguments(e){this.yargs.getValidationInstance().requiredArguments(e)}cleanupProcessEnvConfigs(e){const t=Object(m.Parser)(this.programArgv)._[0],n=e.env||{};t&&Object.keys(n).filter(e=>e.startsWith("WEB_EXT")).forEach(e=>{const r=(e=>h()(u()(e.replace("WEB_EXT","")),"-"))(e),i=this.options[r],o=this.options[t]&&this.options[t][r];i||o||(P.debug(`Environment ${e} not supported by web-ext ${t}`),delete n[e])})}async execute({checkForUpdates:e=v.a,systemProcess:t=process,logStream:n=x.consoleStream,getVersion:r=E,applyConfigToArgv:i=D.a,discoverConfigFiles:o=D.b,loadJSConfigFile:a=D.c,shouldExitProgram:d=!0,globalEnv:l="production"}={}){this.shouldExitProgram=d,this.yargs.exitProcess(this.shouldExitProgram),this.cleanupProcessEnvConfigs(t);const u=this.getArguments(),f=u._[0],h=r(this.absolutePackageDir),p=this.commands[f];u.verbose&&this.enableVerboseMode(n,h);let g={...u};try{if(void 0===f)throw new w.d("No sub-command was specified in the args");if(!p)throw new w.d("Unknown command: "+f);"production"===l&&e({version:h});const t=[];if(u.configDiscovery){P.debug("Discovering config files. Set --no-config-discovery to disable");const e=await o();t.push(...e)}else P.debug("Not discovering config files");if(u.config&&t.push(c.a.resolve(u.config)),t.length){const e=t.map(e=>e.replace(process.cwd(),".")).map(e=>e.replace(s.a.homedir(),"~")).join(", ");P.info("Applying config file"+(1!==t.length?"s":"")+": "+e)}t.forEach(e=>{const t=a(e);g=i({argv:g,argvFromCLI:u,configFileName:e,configObject:t,options:this.options})}),g.verbose&&this.enableVerboseMode(n,h),this.checkRequiredArguments(g),await p(g,{shouldExitProgram:d})}catch(e){if(e instanceof w.d&&!g.verbose?P.error(`\n${e}\n`):P.error(`\n${e.stack}\n`),e.code&&P.error(`Error code: ${e.code}\n`),P.debug("Command executed: "+f),!this.shouldExitProgram)throw e;t.exit(1)}}}function E(e,{globalEnv:t="production"}={}){if("production"===t){P.debug("Getting the version from package.json");const t=Object(d.readFileSync)(c.a.join(e,"package.json"));return JSON.parse(t).version}{P.debug("Getting version from the git revision");const t=n(69);return`${t.branch(e)}-${t.long(e)}`}}function F(e,{getVersion:t=E,commands:n=b.a,argv:r,runOptions:i={}}={}){const o=new A(r,{absolutePackageDir:e}),s=t(e);var a;return o.yargs.usage("Usage: $0 [options] command\n\nOption values can also be set by declaring an environment variable prefixed\nwith $WEB_EXT_. For example: $WEB_EXT_SOURCE_DIR=/path is the same as\n--source-dir=/path.\n\nTo view specific help for any given command, add the command name.\nExample: $0 --help run.\n").help("help").alias("h","help").env("WEB_EXT").version(s).demandCommand(1,"You must specify a command").strict().recommendCommands(),o.setGlobalOptions({"source-dir":{alias:"s",describe:"Web extension source directory.",default:process.cwd(),requiresArg:!0,type:"string",coerce:c.a.resolve},"artifacts-dir":{alias:"a",describe:"Directory where artifacts will be saved.",default:c.a.join(process.cwd(),"web-ext-artifacts"),normalize:!0,requiresArg:!0,type:"string"},verbose:{alias:"v",describe:"Show verbose output",type:"boolean",demandOption:!1},"ignore-files":{alias:"i",describe:'A list of glob patterns to define which files should be ignored. (Example: --ignore-files=path/to/first.js path/to/second.js "**/*.log")',demandOption:!1,type:"array"},"no-input":{describe:"Disable all features that require standard input",type:"boolean",demandOption:!1},config:{alias:"c",describe:"Path to a CommonJS config file to set option defaults",default:void 0,demandOption:!1,requiresArg:!0,type:"string"},"config-discovery":{describe:"Discover config files in home directory and working directory. Disable with --no-config-discovery.",demandOption:!1,default:!0,type:"boolean"},filename:{alias:"n",describe:"Name of the created extension package file.",default:void 0,normalize:!1,demandOption:!1,requiresArg:!0,type:"string",coerce:(a="Multiple --filename/-n option are not allowed",e=>{if(Array.isArray(e))throw new w.d(a);return e})}}),o.command("build","Create an extension package from source",n.build,{"as-needed":{describe:"Watch for file changes and re-build as needed",type:"boolean"},"overwrite-dest":{alias:"o",describe:"Overwrite destination package if it exists.",type:"boolean"}}).command("sign","Sign the extension so it can be installed in Firefox",n.sign,{"api-key":{describe:"API key (JWT issuer) from addons.mozilla.org",demandOption:!0,type:"string"},"api-secret":{describe:"API secret (JWT secret) from addons.mozilla.org",demandOption:!0,type:"string"},"api-url-prefix":{describe:"Signing API URL prefix",default:"https://addons.mozilla.org/api/v3",demandOption:!0,type:"string"},"api-proxy":{describe:"Use a proxy to access the signing API. Example: https://yourproxy:6000 ",demandOption:!1,type:"string"},id:{describe:"A custom ID for the extension. This has no effect if the extension already declares an explicit ID in its manifest.",demandOption:!1,type:"string"},timeout:{describe:"Number of milliseconds to wait before giving up",type:"number"},channel:{describe:"The channel for which to sign the addon. Either 'listed' or 'unlisted'",type:"string"}}).command("run","Run the extension",n.run,{target:{alias:"t",describe:"The extensions runners to enable. Specify this option multiple times to run against multiple targets.",default:"firefox-desktop",demandOption:!1,type:"array",choices:["firefox-desktop","firefox-android","chromium"]},firefox:{alias:["f","firefox-binary"],describe:"Path or alias to a Firefox executable such as firefox-bin or firefox.exe. If not specified, the default Firefox will be used. You can specify the following aliases in lieu of a path: firefox, beta, nightly, firefoxdeveloperedition.",demandOption:!1,type:"string"},"firefox-profile":{alias:"p",describe:"Run Firefox using a copy of this profile. The profile can be specified as a directory or a name, such as one you would see in the Profile Manager. If not specified, a new temporary profile will be created.",demandOption:!1,type:"string"},"chromium-binary":{describe:"Path or alias to a Chromium executable such as google-chrome, google-chrome.exe or opera.exe etc. If not specified, the default Google Chrome will be used.",demandOption:!1,type:"string"},"chromium-profile":{describe:"Path to a custom Chromium profile",demandOption:!1,type:"string"},"keep-profile-changes":{describe:"Run Firefox directly in custom profile. Any changes to the profile will be saved.",demandOption:!1,type:"boolean"},reload:{describe:"Reload the extension when source files change.Disable with --no-reload.",demandOption:!1,default:!0,type:"boolean"},"watch-file":{describe:"Reload the extension only when the contents of thisfile changes. This is useful if you use a custom build process for your extension",demandOption:!1,type:"string"},"pre-install":{describe:"Pre-install the extension into the profile before startup. This is only needed to support older versions of Firefox.",demandOption:!1,type:"boolean"},pref:{describe:"Launch firefox with a custom preference (example: --pref=general.useragent.locale=fr-FR). You can repeat this option to set more than one preference.",demandOption:!1,requiresArg:!0,type:"array",coerce:y.a},"start-url":{alias:["u","url"],describe:"Launch firefox at specified page",demandOption:!1,type:"array"},"browser-console":{alias:["bc"],describe:"Open the DevTools Browser Console.",demandOption:!1,type:"boolean"},args:{alias:["arg"],describe:"Additional CLI options passed to the Browser binary",demandOption:!1,type:"array"},"adb-bin":{describe:"Specify a custom path to the adb binary",demandOption:!1,type:"string",requiresArg:!0},"adb-host":{describe:"Connect to adb on the specified host",demandOption:!1,type:"string",requiresArg:!0},"adb-port":{describe:"Connect to adb on the specified port",demandOption:!1,type:"string",requiresArg:!0},"adb-device":{alias:["android-device"],describe:"Connect to the specified adb device name",demandOption:!1,type:"string",requiresArg:!0},"adb-discovery-timeout":{describe:"Number of milliseconds to wait before giving up",demandOption:!1,type:"number",requiresArg:!0},"adb-remove-old-artifacts":{describe:"Remove old artifacts directories from the adb device",demandOption:!1,type:"boolean"},"firefox-apk":{describe:"Run a specific Firefox for Android APK. Example: org.mozilla.fennec_aurora",demandOption:!1,type:"string",requiresArg:!0},"firefox-apk-component":{describe:"Run a specific Android Component (defaults to <firefox-apk>/.App)",demandOption:!1,type:"string",requiresArg:!0}}).command("lint","Validate the extension source",n.lint,{output:{alias:"o",describe:"The type of output to generate",type:"string",default:"text",choices:["json","text"]},metadata:{describe:"Output only metadata as JSON",type:"boolean",default:!1},"warnings-as-errors":{describe:"Treat warnings as errors by exiting non-zero for warnings",alias:"w",type:"boolean",default:!1},pretty:{describe:"Prettify JSON output",type:"boolean",default:!1},"self-hosted":{describe:"Your extension will be self-hosted. This disables messages related to hosting on addons.mozilla.org.",type:"boolean",default:!1},boring:{describe:"Disables colorful shell output",type:"boolean",default:!1}}).command("docs","Open the web-ext documentation in a browser",n.docs,{}),o.execute({getVersion:t,...i})}}).call(this,"src/program.js")},function(e,t){e.exports=require("yargs")},function(e,t){e.exports=require("yargs/yargs")},function(e,t){e.exports=require("watchpack")},function(e,t){e.exports=require("debounce")},function(e,t){e.exports=require("es6-error")},function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var r=n(5),i=n(47),o=n.n(i);const s=Object(r.promisify)(o.a)},function(e,t){e.exports=require("zip-dir")},function(e,t){e.exports=require("multimatch")},function(e,t){e.exports=require("addons-linter")},function(e,t){e.exports=require("node-notifier")},function(e,t){e.exports=require("fx-runner")},function(e,t){e.exports=require("net")},function(e,t){e.exports=require("@cliqz-oss/node-firefox-connect")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return f}));var r=n(1),i=n.n(r),o=n(55),s=n.n(o),a=n(0),c=n(3),d=n(37);const l=Object(c.createLogger)(e);async function u(e){try{return await e()}catch(e){if(Object(a.f)("ENOENT",e)&&e.message.includes("spawn adb"))throw new a.d("No adb executable has been found. You can Use --adb-bin, --adb-host/--adb-port to configure it manually if needed.");throw e}}class f{constructor(e){i()(this,"params",void 0),i()(this,"adb",void 0),i()(this,"adbClient",void 0),i()(this,"artifactsDirMap",void 0),i()(this,"userAbortDiscovery",void 0),this.params=e;const{adb:t,adbBin:n,adbHost:r,adbPort:o}=e;this.adb=t||s.a,this.adbClient=this.adb.createClient({bin:n,host:r,port:o}),this.artifactsDirMap=new Map,this.userAbortDiscovery=!1}runShellCommand(e,t){const{adb:n,adbClient:r}=this;return l.debug(`Run adb shell command on ${e}: ${JSON.stringify(t)}`),u(async()=>await r.shell(e,t).then(n.util.readAll)).then(e=>e.toString())}async discoverDevices(){const{adbClient:e}=this;let t=[];return l.debug("Listing android devices"),t=await u(async()=>e.listDevices()),t.map(e=>e.id)}async discoverInstalledFirefoxAPKs(e,t){l.debug("Listing installed Firefox APKs on "+e);return(await this.runShellCommand(e,["pm","list","packages"])).split("\n").map(e=>e.replace("package:","").trim()).filter(e=>{if(t)return e===t;for(const t of d.a)if(e.startsWith(t))return!0;return!1})}async getAndroidVersionNumber(e){const t=(await this.runShellCommand(e,["getprop","ro.build.version.sdk"])).trim(),n=parseInt(t);if(isNaN(n))throw new a.e(`Unable to discovery android version on ${e}: ${t}`);return n}async ensureRequiredAPKRuntimePermissions(e,t,n){const r={};for(const e of n)r[e]=!1;const i=(await this.runShellCommand(e,["pm","dump",t])).split("\n");for(const e of i)for(const t of n)(e.includes(t+": granted=true")||e.includes(t+", granted=true"))&&(r[t]=!0);for(const e of n)if(!r[e])throw new a.d(`Required ${e} has not be granted for ${t}. Please grant them using the Android Settings or using the following adb command:\n\t adb shell pm grant ${t} ${e}\n`)}async amForceStopAPK(e,t){await this.runShellCommand(e,["am","force-stop",t])}async getOrCreateArtifactsDir(e){let t=this.artifactsDirMap.get(e);if(t)return t;t="/sdcard/web-ext-artifacts-"+Date.now();if("1"!==(await this.runShellCommand(e,`test -d ${t} ; echo $?`)).trim())throw new a.e(`Cannot create artifacts directory ${t} because it exists on ${e}.`);return await this.runShellCommand(e,["mkdir","-p",t]),this.artifactsDirMap.set(e,t),t}async detectOrRemoveOldArtifacts(e,t=!1){const{adbClient:n}=this;return l.debug("Checking adb device for existing web-ext artifacts dirs"),u(async()=>{const r=await n.readdir(e,"/sdcard/");let i=!1;for(const n of r){if(!n.isDirectory()||!n.name.startsWith("web-ext-artifacts-"))continue;if(!t)return!0;i=!0;const r="/sdcard/"+n.name;l.debug(`Removing artifacts directory ${r} from device ${e}`),await this.runShellCommand(e,["rm","-rf",r])}return i})}async clearArtifactsDir(e){const t=this.artifactsDirMap.get(e);t&&(this.artifactsDirMap.delete(e),l.debug(`Removing ${t} artifacts directory on ${e} device`),await this.runShellCommand(e,["rm","-rf",t]))}async pushFile(e,t,n){const{adbClient:r}=this;l.debug(`Pushing ${t} to ${n} on ${e}`),await u(async()=>{await r.push(e,t,n).then((function(e){return new Promise(t=>{e.on("end",t)})}))})}async startFirefoxAPK(e,t,n,r){const{adbClient:i}=this;l.debug(`Starting ${t} on ${e}`);const o=[{key:"args",value:"-profile "+r}];if(n?n.includes(".")||(n="."+n):n=".App",n.startsWith("."))for(const e of d.a)(t===e||t.startsWith(e+"."))&&(n=e+n);const s=`${t}/${n}`;await u(async()=>{await i.startActivity(e,{wait:!0,action:"android.activity.MAIN",component:s,extras:o})})}setUserAbortDiscovery(e){this.userAbortDiscovery=e}async discoverRDPUnixSocket(e,t,{maxDiscoveryTime:n,retryInterval:r}={}){let i=[];const o=Date.now();for(;0===i.length;){if(this.userAbortDiscovery)throw new a.d("Exiting Firefox Remote Debugging socket discovery on user request");if(Date.now()-o>n)throw new a.e("Timeout while waiting for the Android Firefox Debugger Socket");i=(await this.runShellCommand(e,["cat","/proc/net/unix"])).split("\n").filter(e=>e.trim().endsWith(t+"/firefox-debugger-socket")),0===i.length&&await new Promise(e=>setTimeout(e,r))}if(i=i.map(e=>e.trim().split(/\s/).pop()),i.length>1)throw new a.e("Unexpected multiple RDP sockets: "+JSON.stringify(i));return i[0]}async setupForward(e,t,n){const{adbClient:r}=this;l.debug(`Configuring ADB forward for ${e}: ${t} -> ${n}`),await u(async()=>{await r.forward(e,n,t)})}}}).call(this,"src/util/adb.js")},function(e,t){e.exports=require("@devicefarmer/adbkit")},function(e,t){e.exports=require("sign-addon")},function(e,t){e.exports=require("open")},function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var r=n(59),i=n.n(r);function o({version:e,updateNotifier:t=i.a}){t({pkg:{name:"web-ext",version:e},updateCheckInterval:2592e5}).notify()}},function(e,t){e.exports=require("update-notifier")},function(e,t){e.exports=require("import-fresh")},function(e,t,n){"use strict";n.r(t);var r=n(40),i=n(25);const o={logger:n(3)};t.default={main:r.a,cmd:i.a,util:o}},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"default",(function(){return a}));var r=n(49),i=n(3),o=n(12);const s=Object(i.createLogger)(e);function a({artifactsDir:e,boring:t,ignoreFiles:n,metadata:i,output:a,pretty:c,sourceDir:d,selfHosted:l,verbose:u,warningsAsErrors:f},{createLinter:h=r.createInstance,createFileFilter:p=o.a,shouldExitProgram:g=!0}={}){const m=p({sourceDir:d,ignoreFiles:n,artifactsDir:e});s.debug("Running addons-linter on "+d);return h({config:{logLevel:u?"debug":"fatal",stack:Boolean(u),pretty:c,warningsAsErrors:f,metadata:i,output:a,boring:t,selfHosted:l,shouldScanFile:e=>m.wantFile(e),_:[d]},runAsBinary:g}).run()}}.call(this,"src/cmd/lint.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"default",(function(){return u}));var r=n(18),i=n(19),o=n(22),s=n(9),a=n(3),c=n(6),d=n(17);const l=Object(a.createLogger)(e);async function u({artifactsDir:e,browserConsole:t=!1,pref:n,firefox:a,firefoxProfile:u,keepProfileChanges:f=!1,ignoreFiles:h,noInput:p=!1,noReload:g=!1,preInstall:m=!1,sourceDir:b,watchFile:w,startUrl:x,target:y,args:v,adbBin:D,adbHost:P,adbPort:A,adbDevice:E,adbDiscoveryTimeout:F,adbRemoveOldArtifacts:k,firefoxApk:O,firefoxApkComponent:S,chromiumBinary:j,chromiumProfile:C},{buildExtension:R=r.default,desktopNotifications:$=i.a,firefoxApp:I=o,firefoxClient:T=s.a,reloadStrategy:N=d.c,MultiExtensionRunner:q=d.a,getValidatedManifest:U=c.a}={}){l.info("Running web extension from "+b),m&&(l.info("Disabled auto-reloading because it's not possible with --pre-install"),g=!0);const _=n,L=[],M={extensions:[{sourceDir:b,manifestData:await U(b)}],keepProfileChanges:f,startUrl:x,args:v,desktopNotifications:$};if(!y||0===y.length||y.includes("firefox-desktop")){const e={...M,firefoxBinary:a,profilePath:u,customPrefs:_,browserConsole:t,preInstall:m,firefoxApp:I,firefoxClient:T},n=await Object(d.b)({target:"firefox-desktop",params:e});L.push(n)}if(y&&y.includes("firefox-android")){const e={...M,profilePath:u,customPrefs:_,browserConsole:t,preInstall:m,firefoxApk:O,firefoxApkComponent:S,adbDevice:E,adbHost:P,adbPort:A,adbBin:D,adbDiscoveryTimeout:F,adbRemoveOldArtifacts:k,firefoxApp:I,firefoxClient:T,desktopNotifications:i.a,buildSourceDir:(e,t)=>R({sourceDir:e,ignoreFiles:h,asNeeded:!1,artifactsDir:t},{showReadyMessage:!1})},n=await Object(d.b)({target:"firefox-android",params:e});L.push(n)}if(y&&y.includes("chromium")){const e={...M,chromiumBinary:j,chromiumProfile:C},t=await Object(d.b)({target:"chromium",params:e});L.push(t)}const B=new q({desktopNotifications:$,runners:L});return await B.run(),g?l.info("Automatic extension reloading has been disabled"):(l.info("The extension will reload if any source file changes"),N({extensionRunner:B,sourceDir:b,watchFile:w,artifactsDir:e,ignoreFiles:h,noInput:p})),B}}.call(this,"src/cmd/run.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"FirefoxDesktopExtensionRunner",(function(){return c}));var r=n(1),i=n.n(r),o=n(0),s=(n(22),n(9),n(3));const a=Object(s.createLogger)(e);class c{constructor(e){i()(this,"cleanupCallbacks",void 0),i()(this,"params",void 0),i()(this,"profile",void 0),i()(this,"reloadableExtensions",void 0),i()(this,"remoteFirefox",void 0),i()(this,"runningInfo",void 0),this.params=e,this.reloadableExtensions=new Map,this.cleanupCallbacks=new Set}getName(){return"Firefox Desktop"}async run(){await this.setupProfileDir(),await this.startFirefoxInstance()}async reloadAllExtensions(){const e=this.getName(),t=new Map;for(const{sourceDir:e}of this.params.extensions){const[n]=await this.reloadExtensionBySourceDir(e);n.reloadError instanceof Error&&t.set(e,n.reloadError)}return t.size>0?[{runnerName:e,reloadError:new o.b(t)}]:[{runnerName:e}]}async reloadExtensionBySourceDir(e){const t=this.getName(),n=this.reloadableExtensions.get(e);if(!n)return[{sourceDir:e,reloadError:new o.e(`Extension not reloadable: no addonId has been mapped to "${e}"`),runnerName:t}];try{await this.remoteFirefox.reloadAddon(n)}catch(n){return[{sourceDir:e,reloadError:n,runnerName:t}]}return[{runnerName:t,sourceDir:e}]}registerCleanup(e){this.cleanupCallbacks.add(e)}async exit(){if(!this.runningInfo||!this.runningInfo.firefox)throw new o.e("No firefox instance is currently running");this.runningInfo.firefox.kill()}async setupProfileDir(){const{customPrefs:e,extensions:t,keepProfileChanges:n,preInstall:r,profilePath:i,firefoxApp:o}=this.params;if(i?n?(a.debug("Using Firefox profile from "+i),this.profile=await o.useProfile(i,{customPrefs:e})):(a.debug("Copying Firefox profile from "+i),this.profile=await o.copyProfile(i,{customPrefs:e})):(a.debug("Creating new Firefox profile"),this.profile=await o.createProfile({customPrefs:e})),r)for(const e of t)await o.installExtension({asProxy:!0,extensionPath:e.sourceDir,manifestData:e.manifestData,profile:this.profile})}async startFirefoxInstance(){const{browserConsole:e,extensions:t,firefoxBinary:n,preInstall:r,startUrl:i,firefoxApp:s,firefoxClient:c,args:d}=this.params,l=[];if(e&&l.push("-jsconsole"),i){const e=Array.isArray(i)?i:[i];for(const t of e)l.push("--url",t)}if(d&&l.push(...d),this.runningInfo=await s.run(this.profile,{firefoxBinary:n,binaryArgs:l}),this.runningInfo.firefox.on("close",()=>{for(const e of this.cleanupCallbacks)try{e()}catch(e){a.error("Exception on executing cleanup callback: "+e)}}),!r){const e=this.remoteFirefox=await c({port:this.runningInfo.debuggerPort});for(const n of t)try{const t=await e.installTemporaryAddon(n.sourceDir).then(e=>e.addon.id);if(!t)throw new o.e("Unexpected missing addonId in the installAsTemporaryAddon result");this.reloadableExtensions.set(n.sourceDir,t)}catch(e){throw e instanceof o.c?(a.debug("Caught: "+e),new o.e("Temporary add-on installation is not supported in this version of Firefox (you need Firefox 49 or higher). For older Firefox versions, use --pre-install")):e}}}}}.call(this,"src/extension-runners/firefox-desktop.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"FirefoxAndroidExtensionRunner",(function(){return b}));var r=n(1),i=n.n(r),o=n(2),s=n.n(o),a=n(33),c=n.n(a),d=n(10),l=n(54),u=(n(19),n(0)),f=(n(22),n(9)),h=n(3),p=n(8);const g=Object(h.createLogger)(e),m={profilePath:"--profile-path",keepProfileChanges:"--keep-profile-changes",browserConsole:"--browser-console",preInstall:"--pre-install",startUrl:"--start-url",args:"--args"};class b{constructor(e){i()(this,"params",void 0),i()(this,"adbUtils",void 0),i()(this,"exiting",void 0),i()(this,"selectedAdbDevice",void 0),i()(this,"selectedFirefoxApk",void 0),i()(this,"selectedArtifactsDir",void 0),i()(this,"selectedRDPSocketFile",void 0),i()(this,"selectedTCPPort",void 0),i()(this,"cleanupCallbacks",void 0),i()(this,"adbExtensionsPathBySourceDir",void 0),i()(this,"reloadableExtensions",void 0),i()(this,"remoteFirefox",void 0),this.params=e,this.cleanupCallbacks=new Set,this.adbExtensionsPathBySourceDir=new Map,this.reloadableExtensions=new Map,this.printIgnoredParamsWarnings()}async run(){const{adbBin:e,adbHost:t,adbPort:n,ADBUtils:r=l.a}=this.params;this.adbUtils=new r({adbBin:e,adbHost:t,adbPort:n}),await this.adbDevicesDiscoveryAndSelect(),await this.apkPackagesDiscoveryAndSelect(),await this.adbCheckRuntimePermissions(),await this.adbForceStopSelectedPackage(),await this.adbPrepareProfileDir(),await Promise.all([this.adbStartSelectedPackage(),this.buildAndPushExtensions(),this.adbDiscoveryAndForwardRDPUnixSocket()]),await this.rdpInstallExtensions()}getName(){return"Firefox Android"}async reloadAllExtensions(){const e=this.getName(),t=new Map;for(const{sourceDir:e}of this.params.extensions){const[n]=await this.reloadExtensionBySourceDir(e);n.reloadError instanceof Error&&t.set(e,n.reloadError)}return t.size>0?[{runnerName:e,reloadError:new u.b(t)}]:[{runnerName:e}]}async reloadExtensionBySourceDir(e){const t=this.getName(),n=this.reloadableExtensions.get(e);if(!n)return[{sourceDir:e,reloadError:new u.e(`Extension not reloadable: no addonId has been mapped to "${e}"`),runnerName:t}];try{await this.buildAndPushExtension(e),await this.remoteFirefox.reloadAddon(n)}catch(n){return[{sourceDir:e,reloadError:n,runnerName:t}]}return[{runnerName:t,sourceDir:e}]}registerCleanup(e){this.cleanupCallbacks.add(e)}async exit(){const{adbUtils:e,selectedAdbDevice:t,selectedArtifactsDir:n}=this;this.exiting=!0,await this.adbForceStopSelectedPackage(),n&&(g.debug("Cleaning up artifacts directory on the Android device..."),await e.clearArtifactsDir(t));for(const e of this.cleanupCallbacks)try{e()}catch(e){g.error(e)}}getDeviceProfileDir(){return this.selectedArtifactsDir+"/profile"}printIgnoredParamsWarnings(){Object.keys(m).forEach(e=>{this.params[e]&&g.warn("The Firefox for Android target does not support "+m[e])})}async adbDevicesDiscoveryAndSelect(){const{adbUtils:e}=this,{adbDevice:t}=this.params;let n=[];if(g.debug("Listing android devices"),n=await e.discoverDevices(),0===n.length)throw new u.d("No Android device found through ADB. Make sure the device is connected and USB debugging is enabled.");if(!t){const e=n.map(e=>" - "+e).join("\n");throw g.info("\nAndroid devices found:\n"+e),new u.d("Select an android device using --android-device=<name>")}const r=n.filter(e=>e===t);if(0===r.length){const e=JSON.stringify(n);throw new u.d(`Android device ${t} was not found in list: ${e}`)}this.selectedAdbDevice=r[0],g.info("Selected ADB device: "+this.selectedAdbDevice)}async apkPackagesDiscoveryAndSelect(){const{adbUtils:e,selectedAdbDevice:t,params:{firefoxApk:n}}=this,r=await e.discoverInstalledFirefoxAPKs(t,n);if(0===r.length)throw new u.d("No Firefox packages were found on the selected Android device");const i=e=>e.map(e=>" - "+e).join("\n");if(!n){if(g.info("\nPackages found:\n"+i(r)),r.length>1)throw new u.d("Select one of the packages using --firefox-apk");return this.selectedFirefoxApk=r[0],void g.info("Selected Firefox for Android APK: "+this.selectedFirefoxApk)}const o=r.filter(e=>e===n);if(0===o.length){const e=i(o);throw new u.d(`Package ${n} was not found in list: ${e}`)}this.selectedFirefoxApk=o[0],g.debug("Selected Firefox for Android APK: "+this.selectedFirefoxApk)}async adbForceStopSelectedPackage(){const{adbUtils:e,selectedAdbDevice:t,selectedFirefoxApk:n}=this;g.info(`Stopping existing instances of ${n}...`),await e.amForceStopAPK(t,n)}async adbCheckRuntimePermissions(){const{adbUtils:e,selectedAdbDevice:t,selectedFirefoxApk:n}=this;g.debug(`Discovering Android version for ${t}...`);const r=await e.getAndroidVersionNumber(t);if("number"!=typeof r||Number.isNaN(r))throw new u.e("Invalid Android version: "+r);if(g.debug("Detected Android version "+r),r<23)return;g.debug(`Checking read/write permissions needed for web-exton ${n}...`);await e.ensureRequiredAPKRuntimePermissions(t,n,["android.permission.READ_EXTERNAL_STORAGE","android.permission.WRITE_EXTERNAL_STORAGE"])}async adbPrepareProfileDir(){const{adbUtils:e,selectedAdbDevice:t,selectedFirefoxApk:n,params:{customPrefs:r,firefoxApp:i,adbRemoveOldArtifacts:o}}=this;g.debug(`Preparing a temporary profile for ${n}...`);const a=await i.createProfile({app:"fennec",customPrefs:r});await e.detectOrRemoveOldArtifacts(t,o)&&(o?g.info(`Old web-ext artifacts have been found and removed from ${t} device`):g.warn(`Old artifacts directories have been found on ${t} device. Use --adb-remove-old-artifacts to remove them automatically.`)),this.selectedArtifactsDir=await e.getOrCreateArtifactsDir(t);const c=this.getDeviceProfileDir();await e.runShellCommand(t,["mkdir","-p",c]),await e.pushFile(t,s.a.join(a.profileDir,"user.js"),c+"/user.js"),g.debug(`Created temporary profile at ${c}.`)}async adbStartSelectedPackage(){const{adbUtils:e,selectedFirefoxApk:t,selectedAdbDevice:n,params:{firefoxApkComponent:r}}=this,i=this.getDeviceProfileDir();g.info(`Starting ${t}...`),g.debug(`Using profile ${i} (ignored by Fenix)`),await e.startFirefoxAPK(n,t,r,i)}async buildAndPushExtension(e){const{adbUtils:t,selectedAdbDevice:n,selectedArtifactsDir:r,params:{buildSourceDir:i}}=this;await Object(d.b)(async o=>{const{extensionPath:a}=await i(e,o.path()),c=s.a.basename(a,".zip");let d=this.adbExtensionsPathBySourceDir.get(e);d||(d=`${r}/${c}.xpi`),g.debug(`Uploading ${c} on the android device`),await t.pushFile(n,a,d),g.debug("Upload completed: "+d),this.adbExtensionsPathBySourceDir.set(e,d)})}async buildAndPushExtensions(){for(const{sourceDir:e}of this.params.extensions)await this.buildAndPushExtension(e)}async adbDiscoveryAndForwardRDPUnixSocket(){const{adbUtils:e,selectedAdbDevice:t,selectedFirefoxApk:n,params:{adbDiscoveryTimeout:r}}=this,i=this.params.stdin||process.stdin,{unixSocketDiscoveryRetryInterval:o}=b;let{unixSocketDiscoveryMaxTime:s}=b;"number"==typeof r&&(s=r);const a=(t,n)=>{n.ctrl&&"c"===n.name&&e.setUserAbortDiscovery(!0)};Object(p.a)(i)&&(c.a.emitKeypressEvents(i),Object(p.b)(i,!0),i.on("keypress",a));try{const r=`Waiting for ${n} Remote Debugging Server...\nMake sure to enable "Remote Debugging via USB" from Settings -> Developer Tools if it is not yet enabled.`;g.info(`\n${r}\n`),this.selectedRDPSocketFile=await e.discoverRDPUnixSocket(t,n,{maxDiscoveryTime:s,retryInterval:o})}finally{Object(p.a)(i)&&i.removeListener("keypress",a)}g.debug("RDP Socket File selected: "+this.selectedRDPSocketFile);const d=await Object(f.b)();g.info("You can connect to this Android device on TCP port "+d);const l=this.selectedRDPSocketFile.startsWith("@")?"localabstract:"+this.selectedRDPSocketFile.substr(1):"localfilesystem:"+this.selectedRDPSocketFile;await e.setupForward(t,l,"tcp:"+d),this.selectedTCPPort=d}async rdpInstallExtensions(){const{selectedTCPPort:e,params:{extensions:t,firefoxClient:n}}=this,r=this.remoteFirefox=await n({port:e});r.client.on("end",()=>{this.exiting||(g.info("Exiting the device because Firefox for Android disconnected"),this.exit())});for(const e of t){const{sourceDir:t}=e,n=this.adbExtensionsPathBySourceDir.get(t);if(!n)throw new u.e(`ADB extension path for "${t}" was unexpectedly empty`);const i=await r.installTemporaryAddon(n).then(e=>e.addon.id);if(!i)throw new u.e(`Received an empty addonId from remoteFirefox.installTemporaryAddon("${n}")`);this.reloadableExtensions.set(e.sourceDir,i)}}}i()(b,"unixSocketDiscoveryRetryInterval",3e3),i()(b,"unixSocketDiscoveryMaxTime",18e4)}.call(this,"src/extension-runners/firefox-android.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"DEFAULT_CHROME_FLAGS",(function(){return y})),n.d(t,"ChromiumExtensionRunner",(function(){return v}));var r=n(1),i=n.n(r),o=n(2),s=n.n(o),a=n(21),c=n.n(a),d=n(31),l=n.n(d),u=n(38),f=n(39),h=n.n(f),p=n(3),g=n(10),m=n(15),b=n(20);const w=Object(p.createLogger)(e),x=["--disable-extensions","--mute-audio"],y=u.Launcher.defaultFlags().filter(e=>!x.includes(e));class v{constructor(e){i()(this,"cleanupCallbacks",void 0),i()(this,"params",void 0),i()(this,"chromiumInstance",void 0),i()(this,"chromiumLaunch",void 0),i()(this,"reloadManagerExtension",void 0),i()(this,"wss",void 0),i()(this,"exiting",void 0),i()(this,"_promiseSetupDone",void 0);const{chromiumLaunch:t=u.launch}=e;this.params=e,this.chromiumLaunch=t,this.cleanupCallbacks=new Set}getName(){return"Chromium"}async run(){this._promiseSetupDone=this.setupInstance(),await this._promiseSetupDone}static async isUserDataDir(e){const t=s.a.join(e,"Local State"),n=s.a.join(e,"Default");return await Object(b.a)(t)&&await Object(m.a)(n)}static async isProfileDir(e){const t=s.a.join(e,"Secure Preferences");return await Object(b.a)(t)}static async getProfilePaths(e){if(!e)return{userDataDir:null,profileDirName:null};if(await v.isProfileDir(e)&&!await v.isUserDataDir(e)){const{dir:t,base:n}=s.a.parse(e);return{userDataDir:t,profileDirName:n}}return{userDataDir:e,profileDirName:null}}async setupInstance(){this.wss=await new Promise(e=>{const t=new h.a.Server({port:0,host:"localhost"},()=>e(t))}),this.wss.on("connection",(function(e){e.on("error",e=>{w.debug("websocket connection error: "+e)})})),this.reloadManagerExtension=await this.createReloadManagerExtension();const e=[this.reloadManagerExtension].concat(this.params.extensions.map(({sourceDir:e})=>e)).join(","),{chromiumBinary:t}=this.params;w.debug("Starting Chromium instance..."),t&&w.debug(`(chromiumBinary: ${t})`);const n=[...y];n.push("--load-extension="+e),this.params.args&&n.push(...this.params.args);let r,{userDataDir:i,profileDirName:o}=await v.getProfilePaths(this.params.chromiumProfile);if(i&&this.params.keepProfileChanges){if(o&&!await v.isUserDataDir(i))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")}else if(!this.params.keepProfileChanges){const e=new g.a;await e.create();const t=e.path();i&&o?await c.a.copy(s.a.join(i,o),s.a.join(t,o)):i&&await c.a.copy(i,t),i=t}if(o&&n.push("--profile-directory="+o),this.params.startUrl){const e=Array.isArray(this.params.startUrl)?this.params.startUrl:[this.params.startUrl];r=e.shift(),n.push(...e)}this.chromiumInstance=await this.chromiumLaunch({enableExtensions:!0,chromePath:t,chromeFlags:n,startingUrl:r,userDataDir:i,ignoreDefaultFlags:!0}),this.chromiumInstance.process.once("close",()=>{this.chromiumInstance=null,this.exiting||(w.info("Exiting on Chromium instance disconnected."),this.exit())})}async wssBroadcast(e){return new Promise(t=>{const n=this.wss?new Set(this.wss.clients):new Set;function r(){this.removeEventListener("message",i),this.removeEventListener("close",r),n.delete(this)}const i=async e=>{if("webExtReloadExtensionComplete"===JSON.parse(e.data).type){for(const e of n)r.call(e);t()}};for(const t of n)t.readyState===h.a.OPEN?(t.addEventListener("message",i),t.addEventListener("close",r),t.send(JSON.stringify(e))):n.delete(t);0===n.size&&t()})}async createReloadManagerExtension(){const e=new g.a;await e.create(),this.registerCleanup(()=>e.remove());const t=s.a.join(e.path(),"reload-manager-extension-"+Date.now());w.debug("Creating reload-manager-extension in "+t),await l()(t),await c.a.writeFile(s.a.join(t,"manifest.json"),JSON.stringify({manifest_version:2,name:"web-ext Reload Manager Extension",version:"1.0",permissions:["management","tabs"],background:{scripts:["bg.js"]}}));const n=this.wss.address(),r=`(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.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://${n.address}:${n.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 })()`;return await c.a.writeFile(s.a.join(t,"bg.js"),r),t}async reloadAllExtensions(){const e=this.getName();return await this.wssBroadcast({type:"webExtReloadAllExtensions"}),process.stdout.write("\rLast extension reload: "+(new Date).toTimeString()),w.debug("\n"),[{runnerName:e}]}async reloadExtensionBySourceDir(e){return this.reloadAllExtensions()}registerCleanup(e){this.cleanupCallbacks.add(e)}async exit(){this.exiting=!0,this._promiseSetupDone&&await this._promiseSetupDone.catch(e=>{w.debug("ignored setup error on chromium runner shutdown: "+e)}),this.chromiumInstance&&(await this.chromiumInstance.kill(),this.chromiumInstance=null),this.wss&&(await new Promise(e=>this.wss.close(e)),this.wss=null);for(const e of this.cleanupCallbacks)try{e()}catch(e){w.error(e)}}}}.call(this,"src/extension-runners/chromium.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"extensionIdFile",(function(){return g})),n.d(t,"default",(function(){return m})),n.d(t,"getIdFromSourceDir",(function(){return b})),n.d(t,"saveIdToSourceDir",(function(){return w}));var r=n(2),i=n.n(r),o=n(4),s=n(56),a=n(18),c=n(6),d=n(10),l=n(0),u=n(30),f=n(3);const h=Object(f.createLogger)(e),p=o.fs.readFile.bind(o.fs),g=".web-extension-id";function m({apiKey:e,apiProxy:t,apiSecret:n,apiUrlPrefix:r,artifactsDir:i,id:o,ignoreFiles:f=[],sourceDir:p,timeout:g,verbose:m,channel:x},{build:y=a.default,preValidatedManifest:v,signAddon:D=s.signAddon}={}){return Object(d.b)((async function(s){let a;await Object(u.a)(i),a=v||await Object(c.a)(p);const[d,P]=await Promise.all([y({sourceDir:p,ignoreFiles:f,artifactsDir:s.path()},{manifestData:a,showReadyMessage:!1}),b(p)]),A=Object(c.b)(a);if(o&&A)throw new l.d(`Cannot set custom ID ${o} because manifest.json declares ID `+A);o&&h.debug("Using custom ID declared as --id="+o),A&&(o=A),!o&&P&&(h.info("Using previously auto-generated extension ID: "+P),o=P),o||h.warn("No extension ID specified (it will be auto-generated)");const E=await D({apiKey:e,apiSecret:n,apiUrlPrefix:r,apiProxy:t,timeout:g,verbose:m,id:o,xpiPath:d.extensionPath,version:a.version,downloadDir:i,channel:x});if(E.id&&await w(p,E.id),!E.success)throw h.info("FAIL"),new l.e("The extension could not be signed");return h.info("Extension ID: "+E.id),h.info("SUCCESS"),E}))}async function b(e,t=p){const n=i.a.join(e,g);let r;try{r=await t(n)}catch(e){if(Object(l.f)("ENOENT",e))return void h.debug("No ID file found at: "+n);throw e}let o=r.toString().split("\n");o=o.filter(e=>{if((e=e.trim())&&!e.startsWith("#"))return e});const s=o[0];if(h.debug(`Found extension ID ${s} in ${n}`),!s)throw new l.d("No ID found in extension ID file "+n);return s}async function w(e,t){const n=i.a.join(e,g);await o.fs.writeFile(n,["# This file was created by https://github.com/mozilla/web-ext","# Your auto-generated extension ID for addons.mozilla.org is:",t.toString()].join("\n")),h.debug(`Saved auto-generated ID ${t} to ${n}`)}}.call(this,"src/cmd/sign.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"url",(function(){return a})),n.d(t,"default",(function(){return c}));var r=n(57),i=n.n(r),o=n(3);const s=Object(o.createLogger)(e),a="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Getting_started_with_web-ext";function c(e,{openUrl:t=i.a}={}){return new Promise((e,n)=>{t(a,t=>{t?(s.debug("Encountered an error while opening URL "+a,t),n(t)):e()})})}}.call(this,"src/cmd/docs.js")},function(e,t){e.exports=require("git-rev-sync")}]).default;
|
|
1
|
+
require("source-map-support").install(),module.exports=function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=61)}([function(e,t,n){"use strict";n.d(t,"e",(function(){return o})),n.d(t,"d",(function(){return s})),n.d(t,"a",(function(){return a})),n.d(t,"c",(function(){return c})),n.d(t,"b",(function(){return d})),n.d(t,"g",(function(){return l})),n.d(t,"f",(function(){return u}));var r=n(45),i=n.n(r);class o extends i.a{constructor(e){super(e)}}class s extends o{constructor(e){super(e)}}class a extends s{constructor(e){super(e)}}class c extends o{constructor(e){super(e)}}class d extends o{constructor(e){let t="";for(const[n,r]of e){t+=`\nError on extension loaded from ${n}: ${String(r)}\n`}super("Reload errors: "+t),this.errorsBySourceDir=e}}function l(e,t){return n=>{let r=!0;if(Array.isArray(e)?-1===e.indexOf(n.code)&&-1===e.indexOf(n.errno)||(r=!1):n.code!==e&&n.errno!==e||(r=!1),r)throw n;return t(n)}}function u(e,t){return!(!Array.isArray(e)||-1===e.indexOf(t.code))||t.code===e}},function(e,t){e.exports=require("@babel/runtime/helpers/defineProperty")},function(e,t){e.exports=require("path")},function(e,t,n){"use strict";n.r(t),n.d(t,"ConsoleStream",(function(){return a})),n.d(t,"consoleStream",(function(){return c})),n.d(t,"createLogger",(function(){return d}));var r=n(1),i=n.n(r),o=n(16),s=n.n(o);class a{constructor({verbose:e=!1}={}){i()(this,"verbose",void 0),i()(this,"isCapturing",void 0),i()(this,"capturedMessages",void 0),this.verbose=e,this.isCapturing=!1,this.capturedMessages=[]}format({name:e,msg:t,level:n}){return`${this.verbose?`[${e}][${o.nameFromLevel[n]}] `:""}${t}\n`}makeVerbose(){this.verbose=!0}write(e,{localProcess:t=process}={}){const n=this.verbose?s.a.TRACE:s.a.INFO;if(e.level>=n){const n=this.format(e);this.isCapturing?this.capturedMessages.push(n):t.stdout.write(n)}}startCapturing(){this.isCapturing=!0}stopCapturing(){this.isCapturing=!1,this.capturedMessages=[]}flushCapturedLogs({localProcess:e=process}={}){for(const t of this.capturedMessages)e.stdout.write(t);this.capturedMessages=[]}}const c=new a;function d(e,{createBunyanLog:t=o.createLogger}={}){return t({name:e.replace(/^src\//,""),level:s.a.TRACE,streams:[{type:"raw",stream:c}]})}},function(e,t){e.exports=require("mz")},function(e,t){e.exports=require("util")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return g})),n.d(t,"b",(function(){return m}));var r=n(2),i=n.n(r),o=n(4),s=n(27),a=n.n(s),c=n(28),d=n.n(c),l=n(29),u=n.n(l),f=n(0),h=n(3);const p=Object(h.createLogger)(e);async function g(e){const t=i.a.join(e,"manifest.json");let n,r;p.debug("Validating manifest at "+t);try{n=await o.fs.readFile(t,{encoding:"utf-8"})}catch(e){throw new f.a(`Could not read manifest.json file at ${t}: ${e}`)}n=d()(n);try{r=a()(u()(n))}catch(e){throw new f.a(`Error parsing manifest.json file at ${t}: ${e}`)}const s=[];if(r.name||s.push('missing "name" property'),r.version||s.push('missing "version" property'),r.applications&&!r.applications.gecko&&s.push('missing "applications.gecko" property'),s.length)throw new f.a(`Manifest at ${t} is invalid: ${s.join("; ")}`);return r}function m(e){const t=[e.browser_specific_settings,e.applications];for(const e of t)if(null!=e&&e.gecko)return e.gecko.id}}).call(this,"src/util/manifest.js")},function(e,t){e.exports=require("fs")},function(e,t,n){"use strict";function r(e){return e.isTTY}function i(e,t){e.setRawMode(t)}n.d(t,"a",(function(){return r})),n.d(t,"b",(function(){return i}))},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return p})),n.d(t,"b",(function(){return g}));var r=n(1),i=n.n(r),o=n(52),s=n.n(o),a=n(53),c=n.n(a),d=n(3),l=n(0);const u=Object(d.createLogger)(e);class f{constructor(e){i()(this,"client",void 0),i()(this,"checkedForAddonReloading",void 0),this.client=e,this.checkedForAddonReloading=!1,e.client.on("disconnect",()=>{u.debug('Received "disconnect" from Firefox client')}),e.client.on("end",()=>{u.debug('Received "end" from Firefox client')}),e.client.on("message",e=>{u.debug("Received message from client: "+JSON.stringify(e))})}disconnect(){this.client.disconnect()}addonRequest(e,t){return new Promise((n,r)=>{this.client.client.makeRequest({to:e.actor,type:t},e=>{if(e.error){const n=`${e.error}: ${e.message}`;u.debug(`Client responded to '${t}' request with error:`,n),r(new l.e(n))}else n(e)})})}getAddonsActor(){return new Promise((e,t)=>{this.client.request("getRoot",(n,r)=>{n?(u.debug("Falling back to listTabs because getRoot failed: "+n),this.client.request("listTabs",(n,r)=>n?t(new l.e("Remote Firefox: listTabs() error: "+n)):r.addonsActor?void e(r.addonsActor):(u.debug("listTabs returned a falsey addonsActor: "+r.addonsActor),t(new l.c("This is an older version of Firefox that does not provide an add-ons actor for remote installation. Try Firefox 49 or higher."))))):r.addonsActor?e(r.addonsActor):t(new l.c("This version of Firefox does not provide an add-ons actor for remote installation."))})})}installTemporaryAddon(e){return new Promise((t,n)=>{this.getAddonsActor().then(r=>{this.client.client.makeRequest({to:r,type:"installTemporaryAddon",addonPath:e},r=>{if(r.error)return n(new l.e(`installTemporaryAddon: Error: ${r.error}: ${r.message}`));u.debug("installTemporaryAddon: "+JSON.stringify(r)),u.info(`Installed ${e} as a temporary add-on`),t(r)})}).catch(n)})}getInstalledAddon(e){return new Promise((e,t)=>{this.client.request("listAddons",(n,r)=>{n?t(new l.e("Remote Firefox: listAddons() error: "+n)):e(r.addons)})}).then(t=>{for(const n of t)if(n.id===e)return n;throw u.debug("Remote Firefox has these addons: "+t.map(e=>e.id)),new l.e("The remote Firefox does not have your extension installed")})}async checkForAddonReloading(e){if(this.checkedForAddonReloading)return e;{const t=await this.addonRequest(e,"requestTypes");if(-1===t.requestTypes.indexOf("reload")){const e=JSON.stringify(t.requestTypes);throw u.debug("Remote Firefox only supports: "+e),new l.d("This Firefox version does not support add-on reloading. Re-run with --no-reload")}return this.checkedForAddonReloading=!0,e}}async reloadAddon(e){const t=await this.getInstalledAddon(e);await this.checkForAddonReloading(t),await this.addonRequest(t,"reload"),process.stdout.write("\rLast extension reload: "+(new Date).toTimeString()),u.debug("\n")}}async function h(e,{connectToFirefox:t=c.a}={}){u.debug("Connecting to Firefox on port "+e);const n=await t(e);return u.debug("Connected to the remote Firefox debugger on port "+e),new f(n)}async function p({maxRetries:e=250,retryInterval:t=120,port:n},{connectToFirefox:r=h}={}){return u.debug("Connecting to the remote Firefox debugger"),async function(){var i;for(let o=0;o<=e;o++)try{return await r(n)}catch(e){if(!Object(l.f)("ECONNREFUSED",e))throw u.error(e.stack),e;await new Promise(e=>{setTimeout(e,t)}),i=e,u.debug(`Retrying Firefox (${o}); connection error: ${e}`)}throw u.debug("Connect to Firefox debugger: too many retries"),i}()}function g(){return new Promise(e=>{const t=s.a.createServer();t.listen(0,"127.0.0.1",()=>{const n=t.address().port;t.close(()=>e(n))})})}}).call(this,"src/firefox/remote.js")},function(e,t,n){"use strict";(function(e){n.d(t,"b",(function(){return f})),n.d(t,"a",(function(){return h}));var r=n(1),i=n.n(r),o=n(5),s=n(35),a=n.n(s),c=n(3),d=n(38);const l=Object(c.createLogger)(e);a.a.dir[d.b]=Object(d.a)(a.a.dir);const u=Object(o.promisify)(a.a.dir);function f(e){const t=new h;return t.create().then(()=>e(t)).catch(t.errorHandler()).then(t.successHandler())}class h{constructor(){i()(this,"_path",void 0),i()(this,"_removeTempDir",void 0),this._path=void 0,this._removeTempDir=void 0}create(){return u({prefix:"tmp-web-ext-",unsafeCleanup:!0}).then(([e,t])=>(this._path=e,this._removeTempDir=()=>new Promise((e,n)=>{t(t=>t?n(t):e())}),l.debug("Created temporary directory: "+this.path()),this))}path(){if(!this._path)throw new Error("You cannot access path() before calling create()");return this._path}errorHandler(){return async e=>{throw await this.remove(),e}}successHandler(){return async e=>(await this.remove(),e)}remove(){if(this._removeTempDir)return l.debug("Removing temporary directory: "+this.path()),this._removeTempDir&&this._removeTempDir()}}}).call(this,"src/util/temp-dir.js")},function(e,t){e.exports=require("firefox-profile")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return f}));var r=n(1),i=n.n(r),o=n(2),s=n.n(o),a=n(48),c=n.n(a),d=n(3);const l=Object(d.createLogger)(e);class u{constructor({baseIgnoredPatterns:e=["**/*.xpi","**/*.zip","**/.*","**/.*/**/*","**/node_modules","**/node_modules/**/*"],ignoreFiles:t=[],sourceDir:n,artifactsDir:r}={}){i()(this,"filesToIgnore",void 0),i()(this,"sourceDir",void 0),n=s.a.resolve(n),this.filesToIgnore=[],this.sourceDir=n,this.addToIgnoreList(e),t&&this.addToIgnoreList(t),r&&((e,t)=>{const n=s.a.relative(e,t);return!!n&&(".."!==n&&!n.startsWith(".."+s.a.sep))})(n,r)&&(r=s.a.resolve(r),l.debug(`Ignoring artifacts directory "${r}" and all its subdirectories`),this.addToIgnoreList([r,s.a.join(r,"**","*")]))}resolveWithSourceDir(e){const t=s.a.resolve(this.sourceDir,e);return l.debug(`Resolved path ${e} with sourceDir ${this.sourceDir} to `+t),t}addToIgnoreList(e){for(const t of e)if("!"===t.charAt(0)){const e=this.resolveWithSourceDir(t.substr(1));this.filesToIgnore.push("!"+e)}else this.filesToIgnore.push(this.resolveWithSourceDir(t))}wantFile(e){const t=this.resolveWithSourceDir(e);return!(c()(t,this.filesToIgnore).length>0)||(l.debug("FileFilter: ignoring file "+t),!1)}}const f=e=>new u(e)}).call(this,"src/util/file-filter.js")},function(e,t){e.exports=require("camelcase")},function(e,t){e.exports=require("event-to-promise")},function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var r=n(4),i=n(0);function o(e){return r.fs.stat(e).then(e=>e.isDirectory()).catch(Object(i.g)(["ENOENT","ENOTDIR"],()=>!1))}},function(e,t){e.exports=require("bunyan")},function(e,t,n){"use strict";(function(e){n.d(t,"b",(function(){return h})),n.d(t,"a",(function(){return p})),n.d(t,"c",(function(){return m}));var r=n(1),i=n.n(r),o=n(34),s=n.n(o),a=n(0),c=(n(19),n(3)),d=n(12),l=n(8),u=n(30);const f=Object(c.createLogger)(e);async function h(e){switch(e.target){case"firefox-desktop":{const{FirefoxDesktopExtensionRunner:t}=n(64);return new t(e.params)}case"firefox-android":{const{FirefoxAndroidExtensionRunner:t}=n(65);return new t(e.params)}case"chromium":{const{ChromiumExtensionRunner:t}=n(66);return new t(e.params)}default:throw new a.e(`Unknown target: "${e.target}"`)}}class p{constructor(e){i()(this,"extensionRunners",void 0),i()(this,"desktopNotifications",void 0),this.extensionRunners=e.runners,this.desktopNotifications=e.desktopNotifications}getName(){return"Multi Extension Runner"}async run(){const e=[];for(const t of this.extensionRunners)e.push(t.run());await Promise.all(e)}async reloadAllExtensions(){f.debug("Reloading all reloadable add-ons");const e=[];for(const t of this.extensionRunners){const n=t.reloadAllExtensions().then(()=>({runnerName:t.getName()}),e=>({runnerName:t.getName(),reloadError:e}));e.push(n)}return await Promise.all(e).then(e=>(this.handleReloadResults(e),e))}async reloadExtensionBySourceDir(e){f.debug("Reloading add-on at "+e);const t=[];for(const n of this.extensionRunners){const r=n.reloadExtensionBySourceDir(e).then(()=>({runnerName:n.getName(),sourceDir:e}),t=>({runnerName:n.getName(),reloadError:t,sourceDir:e}));t.push(r)}return await Promise.all(t).then(e=>(this.handleReloadResults(e),e))}registerCleanup(e){const t=[];for(const e of this.extensionRunners)t.push(new Promise(t=>{e.registerCleanup(t)}));Promise.all(t).then(e,e)}async exit(){const e=[];for(const t of this.extensionRunners)e.push(t.exit());await Promise.all(e)}handleReloadResults(e){for(const{runnerName:t,reloadError:n,sourceDir:r}of e)if(n instanceof Error){let e="Error occurred while reloading";r&&(e+=` "${r}" `),e+=`on "${t}" - ${n.message}`,f.error("\n"+e),f.debug(n.stack),this.desktopNotifications({title:"web-ext run: extension reload error",message:e})}}}function g({reloadExtension:e,sourceDir:t,watchFile:n,watchIgnored:r,artifactsDir:i,ignoreFiles:o,onSourceChange:s=u.a,createFileFilter:a=d.a}){const c=a({sourceDir:t,artifactsDir:i,ignoreFiles:o});return s({sourceDir:t,watchFile:n,watchIgnored:r,artifactsDir:i,onChange:()=>e(t),shouldWatchFile:e=>c.wantFile(e)})}function m({artifactsDir:e,extensionRunner:t,ignoreFiles:n,noInput:r=!1,sourceDir:i,watchFile:o,watchIgnored:a},{createWatcher:c=g,stdin:d=process.stdin,kill:u=process.kill}={}){const h=!r;h||f.debug("Input has been disabled because of noInput==true");const p=c({reloadExtension:e=>{t.reloadExtensionBySourceDir(e)},sourceDir:i,watchFile:o,watchIgnored:a,artifactsDir:e,ignoreFiles:n});if(t.registerCleanup(()=>{p.close(),h&&d.pause()}),h&&Object(l.a)(d)){s.a.emitKeypressEvents(d),Object(l.b)(d,!0);const e="Press R to reload (and Ctrl-C to quit)";Promise.resolve().then((async function(){f.info(e);let n=!1;for(;!n;){const r=await new Promise(e=>{d.once("keypress",(t,n)=>e(n))});r.ctrl&&"c"===r.name?n=!0:"z"===r.name?(Object(l.b)(d,!1),f.info("\nweb-ext has been suspended on user request"),u(process.pid,"SIGTSTP"),f.info("\nweb-ext has been resumed. "+e),Object(l.b)(d,!0)):"r"===r.name&&(f.debug("Reloading installed extensions on user request"),await t.reloadAllExtensions().catch(e=>{f.warn("\nError reloading extension: "+e),f.debug("Reloading extension error stack: "+e.stack)}))}f.info("\nExiting web-ext on user request"),t.exit()}))}}}).call(this,"src/extension-runners/index.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"safeFileName",(function(){return P})),n.d(t,"getDefaultLocalizedName",(function(){return A})),n.d(t,"getStringPropertyValue",(function(){return E})),n.d(t,"defaultPackageCreator",(function(){return F})),n.d(t,"default",(function(){return k}));var r=n(2),i=n.n(r),o=n(7),s=n(4),a=n(27),c=n.n(a),d=n(28),l=n.n(d),u=n(29),f=n.n(u),h=n(14),p=n.n(h),g=n(30),m=n(46),b=n(6),w=n(31),x=n(3),y=n(0),v=n(12);const D=Object(x.createLogger)(e);function P(e){return e.toLowerCase().replace(/[^a-z0-9.-]+/g,"_")}async function A({messageFile:e,manifestData:t}){let n,r,i=t.name;try{r=await s.fs.readFile(e,{encoding:"utf-8"})}catch(t){throw new y.d(`Error reading messages.json file at ${e}: ${t}`)}r=l()(r);try{n=c()(f()(r))}catch(t){throw new y.d(`Error parsing messages.json file at ${e}: ${t}`)}return i=t.name.replace(/__MSG_([A-Za-z0-9@_]+?)__/g,(t,r)=>{if(n[r]&&n[r].message)return n[r].message;throw new y.d(`The locale file ${e} is missing key: `+r)}),Promise.resolve(i)}function E(e,t){const n=e.split(".").reduce((e,t)=>e&&e[t],t);if(!["string","number"].includes(typeof n))throw new y.d(`Manifest key "${e}" is missing or has an invalid type: ${n}`);const r=""+n;if(!r.length)throw new y.d(`Manifest key "${e}" value is an empty string`);return r}async function F({manifestData:e,sourceDir:t,fileFilter:n,artifactsDir:r,overwriteDest:s,showReadyMessage:a,filename:c="{name}-{version}.zip"},{eventToPromise:d=p.a}={}){let l;e?(l=Object(b.b)(e),D.debug("Using manifest id="+(l||"[not specified]"))):e=await Object(b.a)(t);const u=await Object(m.a)(t,{filter:(...e)=>n.wantFile(...e)});let f=c,{default_locale:h}=e;if(h){h=h.replace(/-/g,"_");const n=i.a.join(t,"_locales",h,"messages.json");D.debug("Manifest declared default_locale, localizing extension name");const r=await A({messageFile:n,manifestData:e});f=f.replace(/{name}/g,r)}const g=P(function(e,t){const n=e.replace(/{([A-Za-z0-9._]+?)}/g,(e,n)=>E(n,t)),r=i.a.parse(n);if(r.dir)throw new y.d(`Invalid filename template "${e}". Filename "${n}" should not contain a path`);if(![".zip",".xpi"].includes(r.ext))throw new y.d(`Invalid filename template "${e}". Filename "${n}" should have a zip or xpi extension`);return n}(f,e)),w=i.a.join(r,g),x=Object(o.createWriteStream)(w,{flags:"wx"});x.write(u,()=>{x.end()});try{await d(x,"close")}catch(e){if(!Object(y.f)("EEXIST",e))throw e;if(!s)throw new y.d(`Extension exists at the destination path: ${w}\nUse --overwrite-dest to enable overwriting.`);D.info("Destination exists, overwriting: "+w);const t=Object(o.createWriteStream)(w);t.write(u,()=>{t.end()}),await d(t,"close")}return a&&D.info("Your web extension is ready: "+w),{extensionPath:w}}async function k({sourceDir:e,artifactsDir:t,asNeeded:n=!1,overwriteDest:r=!1,ignoreFiles:i=[],filename:o="{name}-{version}.zip"},{manifestData:s,createFileFilter:a=v.a,fileFilter:c=a({sourceDir:e,artifactsDir:t,ignoreFiles:i}),onSourceChange:d=g.a,packageCreator:l=F,showReadyMessage:u=!0}={}){const f=n;D.info("Building web extension from "+e);const h=()=>l({manifestData:s,sourceDir:e,fileFilter:c,artifactsDir:t,overwriteDest:r,showReadyMessage:u,filename:o});await Object(w.a)(t);const p=await h();return f&&(D.info("Rebuilding when files change..."),d({sourceDir:e,artifactsDir:t,onChange:()=>h().catch(e=>{throw D.error(e.stack),e}),shouldWatchFile:(...e)=>c.wantFile(...e)})),p}}.call(this,"src/cmd/build.js")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return a}));var r=n(50),i=n.n(r),o=n(3);const s=Object(o.createLogger)(e);function a({title:e,message:t,icon:n},{notifier:r=i.a,log:o=s}={}){return new Promise((i,s)=>{r.notify({title:e,message:t,icon:n},(e,t)=>{e?(o.debug(`Desktop notifier error: ${e.message}, response: `+t),s(e)):i()})})}}).call(this,"src/util/desktop-notifier.js")},function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var r=n(4),i=n(0);async function o(e,{fileIsReadable:t=(e=>r.fs.access(e,r.fs.constants.R_OK))}={}){try{await t(e);return(await r.fs.stat(e)).isFile()}catch(e){if(Object(i.f)(["EACCES","ENOENT"],e))return!1;throw e}}},function(e,t,n){"use strict";n.d(t,"b",(function(){return r})),t.a=["org.mozilla.fennec","org.mozilla.fenix","org.mozilla.geckoview_example","org.mozilla.geckoview","org.mozilla.firefox","org.mozilla.reference.browser"];const r={"org.mozilla.reference.browser":".BrowserActivity"}},function(e,t){e.exports=require("fs-extra")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"defaultFirefoxEnv",(function(){return A})),n.d(t,"run",(function(){return E})),n.d(t,"isDefaultProfile",(function(){return k})),n.d(t,"configureProfile",(function(){return O})),n.d(t,"defaultCreateProfileFinder",(function(){return S})),n.d(t,"useProfile",(function(){return j})),n.d(t,"createProfile",(function(){return C})),n.d(t,"copyProfile",(function(){return R})),n.d(t,"installExtension",(function(){return $}));var r=n(7),i=n.n(r),o=n(2),s=n.n(o),a=n(5),c=n(51),d=n.n(c),l=n(11),u=n.n(l),f=n(4),h=n(14),p=n.n(h),g=n(15),m=n(0),b=n(33),w=n(6),x=n(9),y=n(3);const v=Object(y.createLogger)(e),D=f.fs.stat.bind(f.fs),P=u.a.copyFromUserProfile,A={XPCOM_DEBUG_BREAK:"stack",NS_TRACE_MALLOC_DISABLE_STACKS:"1"};async function E(e,{fxRunner:t=d.a,findRemotePort:n=x.b,firefoxBinary:r,binaryArgs:i}={}){v.debug("Running Firefox with profile at "+e.path());const o=await n(),s=await t({binary:r,"binary-args":i,"no-remote":!0,listen:o,foreground:!0,profile:e.path(),env:{...process.env,...A},verbose:!0}),a=s.process;return v.debug("Executing Firefox binary: "+s.binary),v.debug("Firefox args: "+s.args.join(" ")),a.on("error",e=>{throw v.error("Firefox error: "+e),e}),v.info("Use --verbose or open Tools > Web Developer > Browser Console to see logging"),a.stderr.on("data",e=>{v.debug("Firefox stderr: "+e.toString().trim())}),a.stdout.on("data",e=>{v.debug("Firefox stdout: "+e.toString().trim())}),a.on("close",()=>{v.debug("Firefox closed")}),{firefox:a,debuggerPort:o}}const F=["default","dev-edition-default"];async function k(e,t=u.a.Finder,n=f.fs.stat){if(F.includes(e))return!0;const r=t.locateUserDirectory(),i=s.a.join(r,"profiles.ini");try{await n(i)}catch(e){if(Object(m.f)("ENOENT",e))return v.debug("profiles.ini not found: "+e),!1;throw e}const o=new t(r),c=Object(a.promisify)(o.readProfiles.bind(o));await c();const d=s.a.normalize(s.a.join(s.a.resolve(e),s.a.sep));for(const t of o.profiles)if(F.includes(t.Name)||"1"===t.Default){let n;if(t.Name===e)return!0;if(n="1"===t.IsRelative?s.a.join(r,t.Path,s.a.sep):s.a.join(t.Path,s.a.sep),s.a.normalize(n)===d)return!0}return!1}function O(e,{app:t="firefox",getPrefs:n=b.b,customPrefs:r={}}={}){const i=n(t);if(Object.keys(i).forEach(t=>{e.setPreference(t,i[t])}),Object.keys(r).length>0){const t=JSON.stringify(r,null,2);v.info("Setting custom Firefox preferences: "+t),Object.keys(r).forEach(t=>{e.setPreference(t,r[t])})}return e.updatePreferences(),Promise.resolve(e)}function S({userDirectoryPath:e,FxProfile:t=u.a}={}){const n=new t.Finder(e),r=Object(a.promisify)(n.readProfiles.bind(n)),i=Object(a.promisify)(n.getPath.bind(n));return async e=>{try{await r();if(0!==n.profiles.filter(t=>t.Name===e).length)return await i(e)}catch(e){if(!Object(m.f)("ENOENT",e))throw e;v.warn("Unable to find Firefox profiles.ini")}}}async function j(e,{app:t,configureThisProfile:n=O,isFirefoxDefaultProfile:r=k,customPrefs:i={},createProfileFinder:o=S}={}){if(await r(e))throw new m.d(`Cannot use --keep-profile-changes on a default profile ("${e}") because web-ext will make it insecure and unsuitable for daily use.\nSee https://github.com/mozilla/web-ext/issues/1005`);let s;const a=o();if(await Object(g.a)(e))v.debug(`Using profile directory "${e}"`),s=e;else if(v.debug(`Assuming ${e} is a named profile`),s=await a(e),!s)throw new m.d(`The request "${e}" profile name cannot be resolved to a profile path`);const c=new u.a({destinationDirectory:s});return await n(c,{app:t,customPrefs:i})}async function C({app:e,configureThisProfile:t=O,customPrefs:n={}}={}){const r=new u.a;return await t(r,{app:e,customPrefs:n})}async function R(e,{app:t,configureThisProfile:n=O,copyFromUserProfile:r=P,customPrefs:i={}}={}){const o=Object(a.promisify)(u.a.copy),s=Object(a.promisify)(r);try{let r;return await Object(g.a)(e)?(v.debug(`Copying profile directory from "${e}"`),r=await o({profileDirectory:e})):(v.debug(`Assuming ${e} is a named profile`),r=await s({name:e})),n(r,{app:t,customPrefs:i})}catch(t){throw new m.e(`Could not copy Firefox profile from ${e}: ${t}`)}}async function $({asProxy:e=!1,manifestData:t,profile:n,extensionPath:r,asyncFsStat:o=D}){if(!n.extensionsDir)throw new m.e("profile.extensionsDir was unexpectedly empty");try{await o(n.extensionsDir)}catch(e){if(!Object(m.f)("ENOENT",e))throw e;v.debug("Creating extensions directory: "+n.extensionsDir),await f.fs.mkdir(n.extensionsDir)}const a=Object(w.b)(t);if(!a)throw new m.d("An explicit extension ID is required when installing to a profile (applications.gecko.id not found in manifest.json)");if(e){v.debug("Installing as an extension proxy; source: "+r);if(!await Object(g.a)(r))throw new m.e("proxy install: extensionPath must be the extension source directory; got: "+r);const e=s.a.join(n.extensionsDir,""+a),t=i.a.createWriteStream(e);return t.write(r),t.end(),await p()(t,"close")}{const e=i.a.createReadStream(r),t=s.a.join(n.extensionsDir,a+".xpi"),o=i.a.createWriteStream(t);return v.debug(`Installing extension from ${r} to ${t}`),e.pipe(o),await Promise.all([p()(e,"close"),p()(o,"close")])}}}.call(this,"src/firefox/index.js")},function(e,t){e.exports=require("os")},function(e,t){e.exports=require("decamelize")},function(e,t,n){"use strict";t.a={build:async function(e,t){const{default:r}=n(18);return r(e,t)},lint:async function(e,t){const{default:r}=n(62);return r(e,t)},run:async function(e,t){const{default:r}=n(63);return r(e,t)},sign:async function(e,t){const{default:r}=n(67);return r(e,t)},docs:async function(e,t){const{default:r}=n(68);return r(e,t)}}},function(e,t){e.exports=require("parse-json")},function(e,t){e.exports=require("strip-bom")},function(e,t){e.exports=require("strip-json-comments")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return u}));var r=n(4),i=n(37),o=n.n(i),s=n(44),a=n.n(s),c=n(0),d=n(3);const l=Object(d.createLogger)(e);function u({sourceDir:e,watchFile:t,watchIgnored:n,artifactsDir:i,onChange:s,shouldWatchFile:d,debounceTime:u=1e3}){const f=n?new o.a({ignored:n}):new o.a;s=a()(s,u,!0),f.on("change",e=>{!function({artifactsDir:e,onChange:t,filePath:n,shouldWatchFile:r}){0!==n.indexOf(e)&&r(n)?(l.debug("Changed: "+n),l.debug("Last change detection: "+(new Date).toTimeString()),t()):l.debug("Ignoring change to: "+n)}({artifactsDir:i,onChange:s,filePath:e,shouldWatchFile:d})}),l.debug("Watching for file changes in "+(t||e));const h=[],p=[];if(t){if(r.fs.existsSync(t)&&!r.fs.lstatSync(t).isFile())throw new c.d(`Invalid --watch-file value: "${t}" is not a file.`);p.push(t)}else h.push(e);return f.watch(p,h,Date.now()),process.on("SIGINT",()=>f.close()),f}}).call(this,"src/watcher.js")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return l}));var r=n(4),i=n(32),o=n.n(i),s=n(0),a=n(3);const c=Object(a.createLogger)(e),d=r.fs.access.bind(r.fs);async function l(e,{asyncMkdirp:t=o.a,asyncFsAccess:n=d}={}){try{if(!(await r.fs.stat(e)).isDirectory())throw new s.d(`--artifacts-dir="${e}" exists but it is not a directory.`);try{await n(e,r.fs.W_OK)}catch(t){throw Object(s.f)("EACCES",t)?new s.d(`--artifacts-dir="${e}" exists but the user lacks permissions on it.`):t}}catch(n){if(Object(s.f)("EACCES",n))throw new s.d(`Cannot access --artifacts-dir="${e}" because the user lacks permissions: `+n);if(!Object(s.f)("ENOENT",n))throw n;try{c.debug("Creating artifacts directory: "+e),await t(e)}catch(t){throw Object(s.f)("EACCES",t)?new s.d(`Cannot create --artifacts-dir="${e}" because the user lacks permissions: `+t):t}}return e}}).call(this,"src/util/artifacts.js")},function(e,t){e.exports=require("mkdirp")},function(e,t,n){"use strict";(function(e){n.d(t,"b",(function(){return d})),n.d(t,"a",(function(){return l}));var r=n(0),i=n(3);const o=Object(i.createLogger)(e),s=["devtools.debugger.remote-enabled","devtools.debugger.prompt-connection","xpinstall.signatures.required"],a={"browser.dom.window.dump.enabled":!0,"datareporting.policy.dataSubmissionEnabled":!1,"devtools.debugger.remote-enabled":!0,"devtools.debugger.prompt-connection":!1,"devtools.browserconsole.contentMessages":!0,"extensions.logging.enabled":!1,"extensions.checkCompatibility.nightly":!1,"extensions.update.enabled":!1,"extensions.update.notifyUser":!1,"extensions.enabledScopes":5,"extensions.getAddons.cache.enabled":!1,"extensions.installDistroAddons":!1,"extensions.autoDisableScopes":10,"app.update.enabled":!1,"xpinstall.signatures.required":!1,"browser.link.open_newwindow":3},c={common:a,fennec:{"browser.console.showInPanel":!0,"browser.firstrun.show.uidiscovery":!1,"devtools.remote.usb.enabled":!0},firefox:{"browser.startup.homepage":"about:blank","startup.homepage_welcome_url":"about:blank","startup.homepage_welcome_url.additional":"","devtools.errorconsole.enabled":!0,"devtools.chrome.enabled":!0,"urlclassifier.updateinterval":172800,"browser.safebrowsing.provider.0.gethashURL":"http://localhost/safebrowsing-dummy/gethash","browser.safebrowsing.provider.0.keyURL":"http://localhost/safebrowsing-dummy/newkey","browser.safebrowsing.provider.0.updateURL":"http://localhost/safebrowsing-dummy/update","browser.selfsupport.url":"https://localhost/selfrepair","browser.reader.detectedFirstArticle":!0,"datareporting.policy.firstRunURL":""}};function d(e="firefox"){const t=c[e];if(!t)throw new r.e("Unsupported application: "+e);return{...a,...t}}function l(e){const t={};for(const n of e){const e=n.split("=");if(e.length<2)throw new r.d(`Incomplete custom preference: "${n}". Syntax expected: "prefname=prefvalue".`);const i=e[0];let a=e.slice(1).join("=");if(/[^\w{@}.-]/.test(i))throw new r.d("Invalid custom preference name: "+i);a===""+parseInt(a)?a=parseInt(a,10):"true"!==a&&"false"!==a||(a="true"===a),s.includes(i)?o.warn(`'${i}' preference cannot be customized.`):t[""+i]=a}return t}}).call(this,"src/firefox/preferences.js")},function(e,t){e.exports=require("readline")},function(e,t){e.exports=require("tmp")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return b})),n.d(t,"c",(function(){return w})),n.d(t,"b",(function(){return x}));var r=n(24),i=n.n(r),o=n(2),s=n.n(o),a=n(60),c=n.n(a),d=n(13),l=n.n(d),u=n(25),f=n.n(u),h=n(20),p=n(3),g=n(0);const m=Object(p.createLogger)(e);function b({argv:e,argvFromCLI:t,configObject:n,options:r,configFileName:i}){let o={...e};for(const e of Object.keys(n)){if(l()(e)!==e)throw new g.d(`The config option "${e}" must be specified in camel case: "${l()(e)}"`);if(!Array.isArray(n[e])&&"object"==typeof r[e]&&"object"==typeof n[e]){o=b({argv:o,argvFromCLI:t,configObject:n[e],options:r[e],configFileName:i});continue}const s=f()(e,"-");if("object"!=typeof r[s])throw new g.d(`The config file at ${i} specified an unknown option: "${e}"`);if(void 0===r[s].type)throw new g.e(`Option: ${e} was defined without a type.`);const a="count"===r[s].type?"number":r[s].type,c=Array.isArray(n[e])?"array":typeof n[e];if(c!==a)throw new g.d(`The config file at ${i} specified the type of "${e}" incorrectly as "${c}" (expected type "${a}")`);let d;r[s]&&(void 0!==r[s].default?d=r[s].default:"boolean"===a&&(d=!1));if(void 0!==t[e]&&t[e]!==d){m.debug(`Favoring CLI: ${e}=${t[e]} over configuration: ${e}=${n[e]}`),o[e]=t[e];continue}o[e]=n[e];const u=r[s].coerce;u&&(m.debug("Calling coerce() on configured value for "+e),o[e]=u(o[e])),o[s]=o[e]}return o}function w(e){const t=s.a.resolve(e);let n;m.debug(`Loading JS config file: "${e}" (resolved to "${t}")`);try{n=c()(t)}catch(e){throw m.debug("Handling error:",e),new g.d(`Cannot read config file: ${t}\nError: `+e.message)}return e.endsWith("package.json")&&(m.debug("Looking for webExt key inside package.json file"),n=n.webExt||{}),0===Object.keys(n).length&&m.debug(`Config file ${t} did not define any options. Did you set module.exports = {...}?`),n}async function x({getHomeDir:e=i.a.homedir}={}){const t=[s.a.join(e(),".web-ext-config.js"),s.a.join(process.cwd(),"package.json"),s.a.join(process.cwd(),"web-ext-config.js")],n=await Promise.all(t.map(async e=>{const t=s.a.resolve(e);return await Object(h.a)(t)?t:void m.debug(`Discovered config "${t}" does not exist or is not readable`)})),r=[];return n.forEach(e=>{"string"==typeof e&&r.push(e)}),r}}).call(this,"src/config.js")},function(e,t){e.exports=require("watchpack")},function(e,t,n){"use strict";n.d(t,"b",(function(){return i})),n.d(t,"a",(function(){return o}));var r=n(5);const i=r.promisify.custom;function o(e){return(...t)=>new Promise((n,r)=>{e(...t,(e,...t)=>{e?r(e):n(t)})})}},function(e,t){e.exports=require("chrome-launcher")},function(e,t){e.exports=require("ws")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return F}));var r=n(1),i=n.n(r),o=n(24),s=n.n(o),a=n(2),c=n.n(a),d=n(7),l=n(13),u=n.n(l),f=n(25),h=n.n(f),p=n(42),g=n.n(p),m=n(43),b=n(26),w=n(0),x=n(3),y=n(33),v=n(58),D=n(36);const P=Object(x.createLogger)(e);class A{constructor(e,{absolutePackageDir:t=process.cwd()}={}){i()(this,"absolutePackageDir",void 0),i()(this,"yargs",void 0),i()(this,"commands",void 0),i()(this,"shouldExitProgram",void 0),i()(this,"verboseEnabled",void 0),i()(this,"options",void 0),i()(this,"programArgv",void 0),e=e||process.argv.slice(2),this.programArgv=e;const n=g()(e,t);this.absolutePackageDir=t,this.verboseEnabled=!1,this.shouldExitProgram=!0,this.yargs=n,this.yargs.parserConfiguration({"boolean-negation":!0}),this.yargs.strict(),this.commands={},this.options={}}command(e,t,n,r={}){return this.options[u()(e)]=r,this.yargs.command(e,t,e=>{if(r)return e.demandCommand(0,0,void 0,"This command does not take any arguments").strict().exitProcess(this.shouldExitProgram).env("WEB_EXT").options(r)}),this.commands[e]=n,this}setGlobalOptions(e){return this.options={...this.options,...e},Object.keys(e).forEach(t=>{e[t].global=!0,void 0===e[t].demandOption&&(e[t].demandOption=!0)}),this.yargs.options(e),this}enableVerboseMode(e,t){this.verboseEnabled||(e.makeVerbose(),P.info("Version:",t),this.verboseEnabled=!0)}getArguments(){const e=this.yargs.getValidationInstance(),{requiredArguments:t}=e;e.requiredArguments=()=>{};const n=this.yargs.argv;if(e.requiredArguments=t,null!=n.configDiscovery&&(n.noConfigDiscovery=!n.configDiscovery),null!=n.reload&&(n.noReload=!n.reload),null!=n.input&&(n.noInput=!n.input),n.ignoreFiles&&!n.ignoreFiles.length)throw new w.d("Not enough arguments following: ignore-files");if(n.startUrl&&!n.startUrl.length)throw new w.d("Not enough arguments following: start-url");return n}checkRequiredArguments(e){this.yargs.getValidationInstance().requiredArguments(e)}cleanupProcessEnvConfigs(e){const t=Object(m.Parser)(this.programArgv)._[0],n=e.env||{};t&&Object.keys(n).filter(e=>e.startsWith("WEB_EXT")).forEach(e=>{const r=(e=>h()(u()(e.replace("WEB_EXT","")),"-"))(e),i=this.options[r],o=this.options[t]&&this.options[t][r];i||o||(P.debug(`Environment ${e} not supported by web-ext ${t}`),delete n[e])})}async execute({checkForUpdates:e=v.a,systemProcess:t=process,logStream:n=x.consoleStream,getVersion:r=E,applyConfigToArgv:i=D.a,discoverConfigFiles:o=D.b,loadJSConfigFile:a=D.c,shouldExitProgram:d=!0,globalEnv:l="production"}={}){this.shouldExitProgram=d,this.yargs.exitProcess(this.shouldExitProgram),this.cleanupProcessEnvConfigs(t);const u=this.getArguments(),f=u._[0],h=r(this.absolutePackageDir),p=this.commands[f];u.verbose&&this.enableVerboseMode(n,h);let g={...u};try{if(void 0===f)throw new w.d("No sub-command was specified in the args");if(!p)throw new w.d("Unknown command: "+f);"production"===l&&e({version:h});const t=[];if(u.configDiscovery){P.debug("Discovering config files. Set --no-config-discovery to disable");const e=await o();t.push(...e)}else P.debug("Not discovering config files");if(u.config&&t.push(c.a.resolve(u.config)),t.length){const e=t.map(e=>e.replace(process.cwd(),".")).map(e=>e.replace(s.a.homedir(),"~")).join(", ");P.info("Applying config file"+(1!==t.length?"s":"")+": "+e)}t.forEach(e=>{const t=a(e);g=i({argv:g,argvFromCLI:u,configFileName:e,configObject:t,options:this.options})}),g.verbose&&this.enableVerboseMode(n,h),this.checkRequiredArguments(g),await p(g,{shouldExitProgram:d})}catch(e){if(e instanceof w.d&&!g.verbose?P.error(`\n${e}\n`):P.error(`\n${e.stack}\n`),e.code&&P.error(`Error code: ${e.code}\n`),P.debug("Command executed: "+f),!this.shouldExitProgram)throw e;t.exit(1)}}}function E(e,{globalEnv:t="production"}={}){if("production"===t){P.debug("Getting the version from package.json");const t=Object(d.readFileSync)(c.a.join(e,"package.json"));return JSON.parse(t).version}{P.debug("Getting version from the git revision");const t=n(69);return`${t.branch(e)}-${t.long(e)}`}}function F(e,{getVersion:t=E,commands:n=b.a,argv:r,runOptions:i={}}={}){const o=new A(r,{absolutePackageDir:e}),s=t(e);var a;return o.yargs.usage("Usage: $0 [options] command\n\nOption values can also be set by declaring an environment variable prefixed\nwith $WEB_EXT_. For example: $WEB_EXT_SOURCE_DIR=/path is the same as\n--source-dir=/path.\n\nTo view specific help for any given command, add the command name.\nExample: $0 --help run.\n").help("help").alias("h","help").env("WEB_EXT").version(s).demandCommand(1,"You must specify a command").strict().recommendCommands(),o.setGlobalOptions({"source-dir":{alias:"s",describe:"Web extension source directory.",default:process.cwd(),requiresArg:!0,type:"string",coerce:c.a.resolve},"artifacts-dir":{alias:"a",describe:"Directory where artifacts will be saved.",default:c.a.join(process.cwd(),"web-ext-artifacts"),normalize:!0,requiresArg:!0,type:"string"},verbose:{alias:"v",describe:"Show verbose output",type:"boolean",demandOption:!1},"ignore-files":{alias:"i",describe:'A list of glob patterns to define which files should be ignored. (Example: --ignore-files=path/to/first.js path/to/second.js "**/*.log")',demandOption:!1,type:"array"},"no-input":{describe:"Disable all features that require standard input",type:"boolean",demandOption:!1},input:{hidden:!0,type:"boolean",demandOption:!1},config:{alias:"c",describe:"Path to a CommonJS config file to set option defaults",default:void 0,demandOption:!1,requiresArg:!0,type:"string"},"config-discovery":{describe:"Discover config files in home directory and working directory. Disable with --no-config-discovery.",demandOption:!1,default:!0,type:"boolean"},filename:{alias:"n",describe:"Name of the created extension package file.",default:void 0,normalize:!1,demandOption:!1,requiresArg:!0,type:"string",coerce:(a="Multiple --filename/-n option are not allowed",e=>{if(Array.isArray(e))throw new w.d(a);return e})}}),o.command("build","Create an extension package from source",n.build,{"as-needed":{describe:"Watch for file changes and re-build as needed",type:"boolean"},"overwrite-dest":{alias:"o",describe:"Overwrite destination package if it exists.",type:"boolean"}}).command("sign","Sign the extension so it can be installed in Firefox",n.sign,{"api-key":{describe:"API key (JWT issuer) from addons.mozilla.org",demandOption:!0,type:"string"},"api-secret":{describe:"API secret (JWT secret) from addons.mozilla.org",demandOption:!0,type:"string"},"api-url-prefix":{describe:"Signing API URL prefix",default:"https://addons.mozilla.org/api/v3",demandOption:!0,type:"string"},"api-proxy":{describe:"Use a proxy to access the signing API. Example: https://yourproxy:6000 ",demandOption:!1,type:"string"},id:{describe:"A custom ID for the extension. This has no effect if the extension already declares an explicit ID in its manifest.",demandOption:!1,type:"string"},timeout:{describe:"Number of milliseconds to wait before giving up",type:"number"},channel:{describe:"The channel for which to sign the addon. Either 'listed' or 'unlisted'",type:"string"}}).command("run","Run the extension",n.run,{target:{alias:"t",describe:"The extensions runners to enable. Specify this option multiple times to run against multiple targets.",default:"firefox-desktop",demandOption:!1,type:"array",choices:["firefox-desktop","firefox-android","chromium"]},firefox:{alias:["f","firefox-binary"],describe:"Path or alias to a Firefox executable such as firefox-bin or firefox.exe. If not specified, the default Firefox will be used. You can specify the following aliases in lieu of a path: firefox, beta, nightly, firefoxdeveloperedition.",demandOption:!1,type:"string"},"firefox-profile":{alias:"p",describe:"Run Firefox using a copy of this profile. The profile can be specified as a directory or a name, such as one you would see in the Profile Manager. If not specified, a new temporary profile will be created.",demandOption:!1,type:"string"},"chromium-binary":{describe:"Path or alias to a Chromium executable such as google-chrome, google-chrome.exe or opera.exe etc. If not specified, the default Google Chrome will be used.",demandOption:!1,type:"string"},"chromium-profile":{describe:"Path to a custom Chromium profile",demandOption:!1,type:"string"},"profile-create-if-missing":{describe:"Create the profile directory if it does not already exist",demandOption:!1,type:"boolean"},"keep-profile-changes":{describe:"Run Firefox directly in custom profile. Any changes to the profile will be saved.",demandOption:!1,type:"boolean"},reload:{describe:"Reload the extension when source files change.Disable with --no-reload.",demandOption:!1,default:!0,type:"boolean"},"watch-file":{describe:"Reload the extension only when the contents of this file changes. This is useful if you use a custom build process for your extension",demandOption:!1,type:"string"},"watch-ignored":{describe:"Paths and globs patterns that should not be watched for changes. This is useful if you want to explicitly prevent web-ext from watching part of the extension directory tree, e.g. the node_modules folder.",demandOption:!1,type:"array"},"pre-install":{describe:"Pre-install the extension into the profile before startup. This is only needed to support older versions of Firefox.",demandOption:!1,type:"boolean"},pref:{describe:"Launch firefox with a custom preference (example: --pref=general.useragent.locale=fr-FR). You can repeat this option to set more than one preference.",demandOption:!1,requiresArg:!0,type:"array",coerce:y.a},"start-url":{alias:["u","url"],describe:"Launch firefox at specified page",demandOption:!1,type:"array"},"browser-console":{alias:["bc"],describe:"Open the DevTools Browser Console.",demandOption:!1,type:"boolean"},args:{alias:["arg"],describe:"Additional CLI options passed to the Browser binary",demandOption:!1,type:"array"},"adb-bin":{describe:"Specify a custom path to the adb binary",demandOption:!1,type:"string",requiresArg:!0},"adb-host":{describe:"Connect to adb on the specified host",demandOption:!1,type:"string",requiresArg:!0},"adb-port":{describe:"Connect to adb on the specified port",demandOption:!1,type:"string",requiresArg:!0},"adb-device":{alias:["android-device"],describe:"Connect to the specified adb device name",demandOption:!1,type:"string",requiresArg:!0},"adb-discovery-timeout":{describe:"Number of milliseconds to wait before giving up",demandOption:!1,type:"number",requiresArg:!0},"adb-remove-old-artifacts":{describe:"Remove old artifacts directories from the adb device",demandOption:!1,type:"boolean"},"firefox-apk":{describe:"Run a specific Firefox for Android APK. Example: org.mozilla.fennec_aurora",demandOption:!1,type:"string",requiresArg:!0},"firefox-apk-component":{describe:"Run a specific Android Component (defaults to <firefox-apk>/.App)",demandOption:!1,type:"string",requiresArg:!0}}).command("lint","Validate the extension source",n.lint,{output:{alias:"o",describe:"The type of output to generate",type:"string",default:"text",choices:["json","text"]},metadata:{describe:"Output only metadata as JSON",type:"boolean",default:!1},"warnings-as-errors":{describe:"Treat warnings as errors by exiting non-zero for warnings",alias:"w",type:"boolean",default:!1},pretty:{describe:"Prettify JSON output",type:"boolean",default:!1},"self-hosted":{describe:"Your extension will be self-hosted. This disables messages related to hosting on addons.mozilla.org.",type:"boolean",default:!1},boring:{describe:"Disables colorful shell output",type:"boolean",default:!1}}).command("docs","Open the web-ext documentation in a browser",n.docs,{}),o.execute({getVersion:t,...i})}}).call(this,"src/program.js")},function(e,t){e.exports=require("yargs")},function(e,t){e.exports=require("yargs/yargs")},function(e,t){e.exports=require("debounce")},function(e,t){e.exports=require("es6-error")},function(e,t,n){"use strict";n.d(t,"a",(function(){return s}));var r=n(5),i=n(47),o=n.n(i);const s=Object(r.promisify)(o.a)},function(e,t){e.exports=require("zip-dir")},function(e,t){e.exports=require("multimatch")},function(e,t){e.exports=require("addons-linter")},function(e,t){e.exports=require("node-notifier")},function(e,t){e.exports=require("fx-runner")},function(e,t){e.exports=require("net")},function(e,t){e.exports=require("@cliqz-oss/node-firefox-connect")},function(e,t,n){"use strict";(function(e){n.d(t,"a",(function(){return f}));var r=n(1),i=n.n(r),o=n(55),s=n.n(o),a=n(0),c=n(3),d=n(21);const l=Object(c.createLogger)(e);async function u(e){try{return await e()}catch(e){if(Object(a.f)("ENOENT",e)&&e.message.includes("spawn adb"))throw new a.d("No adb executable has been found. You can Use --adb-bin, --adb-host/--adb-port to configure it manually if needed.");throw e}}class f{constructor(e){i()(this,"params",void 0),i()(this,"adb",void 0),i()(this,"adbClient",void 0),i()(this,"artifactsDirMap",void 0),i()(this,"userAbortDiscovery",void 0),this.params=e;const{adb:t,adbBin:n,adbHost:r,adbPort:o}=e;this.adb=t||s.a,this.adbClient=this.adb.createClient({bin:n,host:r,port:o}),this.artifactsDirMap=new Map,this.userAbortDiscovery=!1}runShellCommand(e,t){const{adb:n,adbClient:r}=this;return l.debug(`Run adb shell command on ${e}: ${JSON.stringify(t)}`),u(async()=>await r.shell(e,t).then(n.util.readAll)).then(e=>e.toString())}async discoverDevices(){const{adbClient:e}=this;let t=[];return l.debug("Listing android devices"),t=await u(async()=>e.listDevices()),t.map(e=>e.id)}async discoverInstalledFirefoxAPKs(e,t){l.debug("Listing installed Firefox APKs on "+e);return(await this.runShellCommand(e,["pm","list","packages"])).split("\n").map(e=>e.replace("package:","").trim()).filter(e=>{if(t)return e===t;for(const t of d.a)if(e.startsWith(t))return!0;return!1})}async getAndroidVersionNumber(e){const t=(await this.runShellCommand(e,["getprop","ro.build.version.sdk"])).trim(),n=parseInt(t);if(isNaN(n))throw new a.e(`Unable to discovery android version on ${e}: ${t}`);return n}async ensureRequiredAPKRuntimePermissions(e,t,n){const r={};for(const e of n)r[e]=!1;const i=(await this.runShellCommand(e,["pm","dump",t])).split("\n");for(const e of i)for(const t of n)(e.includes(t+": granted=true")||e.includes(t+", granted=true"))&&(r[t]=!0);for(const e of n)if(!r[e])throw new a.d(`Required ${e} has not be granted for ${t}. Please grant them using the Android Settings or using the following adb command:\n\t adb shell pm grant ${t} ${e}\n`)}async amForceStopAPK(e,t){await this.runShellCommand(e,["am","force-stop",t])}async getOrCreateArtifactsDir(e){let t=this.artifactsDirMap.get(e);if(t)return t;t="/sdcard/web-ext-artifacts-"+Date.now();if("1"!==(await this.runShellCommand(e,`test -d ${t} ; echo $?`)).trim())throw new a.e(`Cannot create artifacts directory ${t} because it exists on ${e}.`);return await this.runShellCommand(e,["mkdir","-p",t]),this.artifactsDirMap.set(e,t),t}async detectOrRemoveOldArtifacts(e,t=!1){const{adbClient:n}=this;return l.debug("Checking adb device for existing web-ext artifacts dirs"),u(async()=>{const r=await n.readdir(e,"/sdcard/");let i=!1;for(const n of r){if(!n.isDirectory()||!n.name.startsWith("web-ext-artifacts-"))continue;if(!t)return!0;i=!0;const r="/sdcard/"+n.name;l.debug(`Removing artifacts directory ${r} from device ${e}`),await this.runShellCommand(e,["rm","-rf",r])}return i})}async clearArtifactsDir(e){const t=this.artifactsDirMap.get(e);t&&(this.artifactsDirMap.delete(e),l.debug(`Removing ${t} artifacts directory on ${e} device`),await this.runShellCommand(e,["rm","-rf",t]))}async pushFile(e,t,n){const{adbClient:r}=this;l.debug(`Pushing ${t} to ${n} on ${e}`),await u(async()=>{await r.push(e,t,n).then((function(e){return new Promise(t=>{e.on("end",t)})}))})}async startFirefoxAPK(e,t,n,r){const{adbClient:i}=this;l.debug(`Starting ${t} on ${e}`);const o=[{key:"args",value:"-profile "+r}];if(n?n.includes(".")||(n="."+n):(n=".App",d.b[t]&&(n=d.b[t])),n.startsWith("."))for(const e of d.a)(t===e||t.startsWith(e+"."))&&(n=e+n);const s=`${t}/${n}`;await u(async()=>{await i.startActivity(e,{wait:!0,action:"android.activity.MAIN",component:s,extras:o})})}setUserAbortDiscovery(e){this.userAbortDiscovery=e}async discoverRDPUnixSocket(e,t,{maxDiscoveryTime:n,retryInterval:r}={}){let i=[];const o=Date.now(),s=`Waiting for ${t} Remote Debugging Server...\nMake sure to enable "Remote Debugging via USB" from Settings -> Developer Tools if it is not yet enabled.`;for(;0===i.length;){if(l.info(s),this.userAbortDiscovery)throw new a.d("Exiting Firefox Remote Debugging socket discovery on user request");if(Date.now()-o>n)throw new a.e("Timeout while waiting for the Android Firefox Debugger Socket");i=(await this.runShellCommand(e,["cat","/proc/net/unix"])).split("\n").filter(e=>e.trim().endsWith(t+"/firefox-debugger-socket")),0===i.length&&await new Promise(e=>setTimeout(e,r))}if(i=i.map(e=>e.trim().split(/\s/).pop()),i.length>1)throw new a.e("Unexpected multiple RDP sockets: "+JSON.stringify(i));return i[0]}async setupForward(e,t,n){const{adbClient:r}=this;l.debug(`Configuring ADB forward for ${e}: ${t} -> ${n}`),await u(async()=>{await r.forward(e,n,t)})}}}).call(this,"src/util/adb.js")},function(e,t){e.exports=require("@devicefarmer/adbkit")},function(e,t){e.exports=require("sign-addon")},function(e,t){e.exports=require("open")},function(e,t,n){"use strict";n.d(t,"a",(function(){return o}));var r=n(59),i=n.n(r);function o({version:e,updateNotifier:t=i.a}){t({pkg:{name:"web-ext",version:e},updateCheckInterval:2592e5}).notify()}},function(e,t){e.exports=require("update-notifier")},function(e,t){e.exports=require("import-fresh")},function(e,t,n){"use strict";n.r(t);var r=n(41),i=n(26);const o={logger:n(3)};t.default={main:r.a,cmd:i.a,util:o}},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"default",(function(){return a}));var r=n(49),i=n(3),o=n(12);const s=Object(i.createLogger)(e);function a({artifactsDir:e,boring:t,ignoreFiles:n,metadata:i,output:a,pretty:c,sourceDir:d,selfHosted:l,verbose:u,warningsAsErrors:f},{createLinter:h=r.createInstance,createFileFilter:p=o.a,shouldExitProgram:g=!0}={}){const m=p({sourceDir:d,ignoreFiles:n,artifactsDir:e});s.debug("Running addons-linter on "+d);return h({config:{logLevel:u?"debug":"fatal",stack:Boolean(u),pretty:c,warningsAsErrors:f,metadata:i,output:a,boring:t,selfHosted:l,shouldScanFile:e=>m.wantFile(e),_:[d]},runAsBinary:g}).run()}}.call(this,"src/cmd/lint.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"default",(function(){return h}));var r=n(4),i=n(18),o=n(19),s=n(23),a=n(9),c=n(3),d=n(6),l=n(0),u=n(17);const f=Object(c.createLogger)(e);async function h({artifactsDir:e,browserConsole:t=!1,pref:n,firefox:c,firefoxProfile:h,profileCreateIfMissing:p,keepProfileChanges:g=!1,ignoreFiles:m,noInput:b=!1,noReload:w=!1,preInstall:x=!1,sourceDir:y,watchFile:v,watchIgnored:D,startUrl:P,target:A,args:E,adbBin:F,adbHost:k,adbPort:O,adbDevice:S,adbDiscoveryTimeout:j,adbRemoveOldArtifacts:C,firefoxApk:R,firefoxApkComponent:$,chromiumBinary:I,chromiumProfile:T},{buildExtension:N=i.default,desktopNotifications:q=o.a,firefoxApp:L=s,firefoxClient:U=a.a,reloadStrategy:_=u.c,MultiExtensionRunner:M=u.a,getValidatedManifest:B=d.a}={}){f.info("Running web extension from "+y),x&&(f.info("Disabled auto-reloading because it's not possible with --pre-install"),w=!0);const W=n,z=await B(y),J=h||T;if(p){if(!J)throw new l.d("--profile-create-if-missing requires --firefox-profile or --chromium-profile");r.fs.existsSync(J)?f.info(`Profile directory ${J} already exists`):(f.info("Profile directory not found. Creating directory "+J),await r.fs.mkdir(J))}const K=[],V={extensions:[{sourceDir:y,manifestData:z}],keepProfileChanges:g,startUrl:P,args:E,desktopNotifications:q};if(!A||0===A.length||A.includes("firefox-desktop")){const e={...V,firefoxBinary:c,profilePath:h,customPrefs:W,browserConsole:t,preInstall:x,firefoxApp:L,firefoxClient:U},n=await Object(u.b)({target:"firefox-desktop",params:e});K.push(n)}if(A&&A.includes("firefox-android")){const e={...V,profilePath:h,customPrefs:W,browserConsole:t,preInstall:x,firefoxApk:R,firefoxApkComponent:$,adbDevice:S,adbHost:k,adbPort:O,adbBin:F,adbDiscoveryTimeout:j,adbRemoveOldArtifacts:C,firefoxApp:L,firefoxClient:U,desktopNotifications:o.a,buildSourceDir:(e,t)=>N({sourceDir:e,ignoreFiles:m,asNeeded:!1,artifactsDir:t},{showReadyMessage:!1})},n=await Object(u.b)({target:"firefox-android",params:e});K.push(n)}if(A&&A.includes("chromium")){const e={...V,chromiumBinary:I,chromiumProfile:T},t=await Object(u.b)({target:"chromium",params:e});K.push(t)}const H=new M({desktopNotifications:q,runners:K});return await H.run(),w?f.info("Automatic extension reloading has been disabled"):(f.info("The extension will reload if any source file changes"),_({extensionRunner:H,sourceDir:y,watchFile:v,watchIgnored:D,artifactsDir:e,ignoreFiles:m,noInput:b})),H}}.call(this,"src/cmd/run.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"FirefoxDesktopExtensionRunner",(function(){return c}));var r=n(1),i=n.n(r),o=n(0),s=(n(23),n(9),n(3));const a=Object(s.createLogger)(e);class c{constructor(e){i()(this,"cleanupCallbacks",void 0),i()(this,"params",void 0),i()(this,"profile",void 0),i()(this,"reloadableExtensions",void 0),i()(this,"remoteFirefox",void 0),i()(this,"runningInfo",void 0),this.params=e,this.reloadableExtensions=new Map,this.cleanupCallbacks=new Set}getName(){return"Firefox Desktop"}async run(){await this.setupProfileDir(),await this.startFirefoxInstance()}async reloadAllExtensions(){const e=this.getName(),t=new Map;for(const{sourceDir:e}of this.params.extensions){const[n]=await this.reloadExtensionBySourceDir(e);n.reloadError instanceof Error&&t.set(e,n.reloadError)}return t.size>0?[{runnerName:e,reloadError:new o.b(t)}]:[{runnerName:e}]}async reloadExtensionBySourceDir(e){const t=this.getName(),n=this.reloadableExtensions.get(e);if(!n)return[{sourceDir:e,reloadError:new o.e(`Extension not reloadable: no addonId has been mapped to "${e}"`),runnerName:t}];try{await this.remoteFirefox.reloadAddon(n)}catch(n){return[{sourceDir:e,reloadError:n,runnerName:t}]}return[{runnerName:t,sourceDir:e}]}registerCleanup(e){this.cleanupCallbacks.add(e)}async exit(){if(!this.runningInfo||!this.runningInfo.firefox)throw new o.e("No firefox instance is currently running");this.runningInfo.firefox.kill()}async setupProfileDir(){const{customPrefs:e,extensions:t,keepProfileChanges:n,preInstall:r,profilePath:i,firefoxApp:o}=this.params;if(i?n?(a.debug("Using Firefox profile from "+i),this.profile=await o.useProfile(i,{customPrefs:e})):(a.debug("Copying Firefox profile from "+i),this.profile=await o.copyProfile(i,{customPrefs:e})):(a.debug("Creating new Firefox profile"),this.profile=await o.createProfile({customPrefs:e})),r)for(const e of t)await o.installExtension({asProxy:!0,extensionPath:e.sourceDir,manifestData:e.manifestData,profile:this.profile})}async startFirefoxInstance(){const{browserConsole:e,extensions:t,firefoxBinary:n,preInstall:r,startUrl:i,firefoxApp:s,firefoxClient:c,args:d}=this.params,l=[];if(e&&l.push("-jsconsole"),i){const e=Array.isArray(i)?i:[i];for(const t of e)l.push("--url",t)}if(d&&l.push(...d),this.runningInfo=await s.run(this.profile,{firefoxBinary:n,binaryArgs:l}),this.runningInfo.firefox.on("close",()=>{for(const e of this.cleanupCallbacks)try{e()}catch(e){a.error("Exception on executing cleanup callback: "+e)}}),!r){const e=this.remoteFirefox=await c({port:this.runningInfo.debuggerPort});for(const n of t)try{const t=await e.installTemporaryAddon(n.sourceDir).then(e=>e.addon.id);if(!t)throw new o.e("Unexpected missing addonId in the installAsTemporaryAddon result");this.reloadableExtensions.set(n.sourceDir,t)}catch(e){throw e instanceof o.c?(a.debug("Caught: "+e),new o.e("Temporary add-on installation is not supported in this version of Firefox (you need Firefox 49 or higher). For older Firefox versions, use --pre-install")):e}}}}}.call(this,"src/extension-runners/firefox-desktop.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"FirefoxAndroidExtensionRunner",(function(){return b}));var r=n(1),i=n.n(r),o=n(2),s=n.n(o),a=n(34),c=n.n(a),d=n(10),l=n(54),u=(n(19),n(0)),f=(n(23),n(9)),h=n(3),p=n(8);const g=Object(h.createLogger)(e),m={profilePath:"--profile-path",keepProfileChanges:"--keep-profile-changes",browserConsole:"--browser-console",preInstall:"--pre-install",startUrl:"--start-url",args:"--args"};class b{constructor(e){i()(this,"params",void 0),i()(this,"adbUtils",void 0),i()(this,"exiting",void 0),i()(this,"selectedAdbDevice",void 0),i()(this,"selectedFirefoxApk",void 0),i()(this,"selectedArtifactsDir",void 0),i()(this,"selectedRDPSocketFile",void 0),i()(this,"selectedTCPPort",void 0),i()(this,"cleanupCallbacks",void 0),i()(this,"adbExtensionsPathBySourceDir",void 0),i()(this,"reloadableExtensions",void 0),i()(this,"remoteFirefox",void 0),this.params=e,this.cleanupCallbacks=new Set,this.adbExtensionsPathBySourceDir=new Map,this.reloadableExtensions=new Map,this.printIgnoredParamsWarnings()}async run(){const{adbBin:e,adbHost:t,adbPort:n,ADBUtils:r=l.a}=this.params;this.adbUtils=new r({adbBin:e,adbHost:t,adbPort:n}),await this.adbDevicesDiscoveryAndSelect(),await this.apkPackagesDiscoveryAndSelect(),await this.adbCheckRuntimePermissions(),await this.adbForceStopSelectedPackage(),await this.adbPrepareProfileDir(),await Promise.all([this.adbStartSelectedPackage(),this.buildAndPushExtensions(),this.adbDiscoveryAndForwardRDPUnixSocket()]),await this.rdpInstallExtensions()}getName(){return"Firefox Android"}async reloadAllExtensions(){const e=this.getName(),t=new Map;for(const{sourceDir:e}of this.params.extensions){const[n]=await this.reloadExtensionBySourceDir(e);n.reloadError instanceof Error&&t.set(e,n.reloadError)}return t.size>0?[{runnerName:e,reloadError:new u.b(t)}]:[{runnerName:e}]}async reloadExtensionBySourceDir(e){const t=this.getName(),n=this.reloadableExtensions.get(e);if(!n)return[{sourceDir:e,reloadError:new u.e(`Extension not reloadable: no addonId has been mapped to "${e}"`),runnerName:t}];try{await this.buildAndPushExtension(e),await this.remoteFirefox.reloadAddon(n)}catch(n){return[{sourceDir:e,reloadError:n,runnerName:t}]}return[{runnerName:t,sourceDir:e}]}registerCleanup(e){this.cleanupCallbacks.add(e)}async exit(){const{adbUtils:e,selectedAdbDevice:t,selectedArtifactsDir:n}=this;this.exiting=!0,await this.adbForceStopSelectedPackage(),n&&(g.debug("Cleaning up artifacts directory on the Android device..."),await e.clearArtifactsDir(t));for(const e of this.cleanupCallbacks)try{e()}catch(e){g.error(e)}}getDeviceProfileDir(){return this.selectedArtifactsDir+"/profile"}printIgnoredParamsWarnings(){Object.keys(m).forEach(e=>{this.params[e]&&g.warn("The Firefox for Android target does not support "+m[e])})}async adbDevicesDiscoveryAndSelect(){const{adbUtils:e}=this,{adbDevice:t}=this.params;let n=[];if(g.debug("Listing android devices"),n=await e.discoverDevices(),0===n.length)throw new u.d("No Android device found through ADB. Make sure the device is connected and USB debugging is enabled.");if(!t){const e=n.map(e=>" - "+e).join("\n");throw g.info("\nAndroid devices found:\n"+e),new u.d("Select an android device using --android-device=<name>")}const r=n.filter(e=>e===t);if(0===r.length){const e=JSON.stringify(n);throw new u.d(`Android device ${t} was not found in list: ${e}`)}this.selectedAdbDevice=r[0],g.info("Selected ADB device: "+this.selectedAdbDevice)}async apkPackagesDiscoveryAndSelect(){const{adbUtils:e,selectedAdbDevice:t,params:{firefoxApk:n}}=this,r=await e.discoverInstalledFirefoxAPKs(t,n);if(0===r.length)throw new u.d("No Firefox packages were found on the selected Android device");const i=e=>e.map(e=>" - "+e).join("\n");if(!n){if(g.info("\nPackages found:\n"+i(r)),r.length>1)throw new u.d("Select one of the packages using --firefox-apk");return this.selectedFirefoxApk=r[0],void g.info("Selected Firefox for Android APK: "+this.selectedFirefoxApk)}const o=r.filter(e=>e===n);if(0===o.length){const e=i(o);throw new u.d(`Package ${n} was not found in list: ${e}`)}this.selectedFirefoxApk=o[0],g.debug("Selected Firefox for Android APK: "+this.selectedFirefoxApk)}async adbForceStopSelectedPackage(){const{adbUtils:e,selectedAdbDevice:t,selectedFirefoxApk:n}=this;g.info(`Stopping existing instances of ${n}...`),await e.amForceStopAPK(t,n)}async adbCheckRuntimePermissions(){const{adbUtils:e,selectedAdbDevice:t,selectedFirefoxApk:n}=this;g.debug(`Discovering Android version for ${t}...`);const r=await e.getAndroidVersionNumber(t);if("number"!=typeof r||Number.isNaN(r))throw new u.e("Invalid Android version: "+r);if(g.debug("Detected Android version "+r),r<23)return;g.debug(`Checking read/write permissions needed for web-exton ${n}...`);await e.ensureRequiredAPKRuntimePermissions(t,n,["android.permission.READ_EXTERNAL_STORAGE","android.permission.WRITE_EXTERNAL_STORAGE"])}async adbPrepareProfileDir(){const{adbUtils:e,selectedAdbDevice:t,selectedFirefoxApk:n,params:{customPrefs:r,firefoxApp:i,adbRemoveOldArtifacts:o}}=this;g.debug(`Preparing a temporary profile for ${n}...`);const a=await i.createProfile({app:"fennec",customPrefs:r});await e.detectOrRemoveOldArtifacts(t,o)&&(o?g.info(`Old web-ext artifacts have been found and removed from ${t} device`):g.warn(`Old artifacts directories have been found on ${t} device. Use --adb-remove-old-artifacts to remove them automatically.`)),this.selectedArtifactsDir=await e.getOrCreateArtifactsDir(t);const c=this.getDeviceProfileDir();await e.runShellCommand(t,["mkdir","-p",c]),await e.pushFile(t,s.a.join(a.profileDir,"user.js"),c+"/user.js"),g.debug(`Created temporary profile at ${c}.`)}async adbStartSelectedPackage(){const{adbUtils:e,selectedFirefoxApk:t,selectedAdbDevice:n,params:{firefoxApkComponent:r}}=this,i=this.getDeviceProfileDir();g.info(`Starting ${t}...`),g.debug(`Using profile ${i} (ignored by Fenix)`),await e.startFirefoxAPK(n,t,r,i)}async buildAndPushExtension(e){const{adbUtils:t,selectedAdbDevice:n,selectedArtifactsDir:r,params:{buildSourceDir:i}}=this;await Object(d.b)(async o=>{const{extensionPath:a}=await i(e,o.path()),c=s.a.basename(a,".zip");let d=this.adbExtensionsPathBySourceDir.get(e);d||(d=`${r}/${c}.xpi`),g.debug(`Uploading ${c} on the android device`),await t.pushFile(n,a,d),g.debug("Upload completed: "+d),this.adbExtensionsPathBySourceDir.set(e,d)})}async buildAndPushExtensions(){for(const{sourceDir:e}of this.params.extensions)await this.buildAndPushExtension(e)}async adbDiscoveryAndForwardRDPUnixSocket(){const{adbUtils:e,selectedAdbDevice:t,selectedFirefoxApk:n,params:{adbDiscoveryTimeout:r}}=this,i=this.params.stdin||process.stdin,{unixSocketDiscoveryRetryInterval:o}=b;let{unixSocketDiscoveryMaxTime:s}=b;"number"==typeof r&&(s=r);const a=(t,n)=>{n.ctrl&&"c"===n.name&&e.setUserAbortDiscovery(!0)};Object(p.a)(i)&&(c.a.emitKeypressEvents(i),Object(p.b)(i,!0),i.on("keypress",a));try{this.selectedRDPSocketFile=await e.discoverRDPUnixSocket(t,n,{maxDiscoveryTime:s,retryInterval:o})}finally{Object(p.a)(i)&&i.removeListener("keypress",a)}g.debug("RDP Socket File selected: "+this.selectedRDPSocketFile);const d=await Object(f.b)();g.info("You can connect to this Android device on TCP port "+d);const l=this.selectedRDPSocketFile.startsWith("@")?"localabstract:"+this.selectedRDPSocketFile.substr(1):"localfilesystem:"+this.selectedRDPSocketFile;await e.setupForward(t,l,"tcp:"+d),this.selectedTCPPort=d}async rdpInstallExtensions(){const{selectedTCPPort:e,params:{extensions:t,firefoxClient:n}}=this,r=this.remoteFirefox=await n({port:e});r.client.on("end",()=>{this.exiting||(g.info("Exiting the device because Firefox for Android disconnected"),this.exit())});for(const e of t){const{sourceDir:t}=e,n=this.adbExtensionsPathBySourceDir.get(t);if(!n)throw new u.e(`ADB extension path for "${t}" was unexpectedly empty`);const i=await r.installTemporaryAddon(n).then(e=>e.addon.id);if(!i)throw new u.e(`Received an empty addonId from remoteFirefox.installTemporaryAddon("${n}")`);this.reloadableExtensions.set(e.sourceDir,i)}}}i()(b,"unixSocketDiscoveryRetryInterval",3e3),i()(b,"unixSocketDiscoveryMaxTime",18e4)}.call(this,"src/extension-runners/firefox-android.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"DEFAULT_CHROME_FLAGS",(function(){return y})),n.d(t,"ChromiumExtensionRunner",(function(){return v}));var r=n(1),i=n.n(r),o=n(2),s=n.n(o),a=n(22),c=n.n(a),d=n(32),l=n.n(d),u=n(39),f=n(40),h=n.n(f),p=n(3),g=n(10),m=n(15),b=n(20);const w=Object(p.createLogger)(e),x=["--disable-extensions","--mute-audio"],y=u.Launcher.defaultFlags().filter(e=>!x.includes(e));class v{constructor(e){i()(this,"cleanupCallbacks",void 0),i()(this,"params",void 0),i()(this,"chromiumInstance",void 0),i()(this,"chromiumLaunch",void 0),i()(this,"reloadManagerExtension",void 0),i()(this,"wss",void 0),i()(this,"exiting",void 0),i()(this,"_promiseSetupDone",void 0);const{chromiumLaunch:t=u.launch}=e;this.params=e,this.chromiumLaunch=t,this.cleanupCallbacks=new Set}getName(){return"Chromium"}async run(){this._promiseSetupDone=this.setupInstance(),await this._promiseSetupDone}static async isUserDataDir(e){const t=s.a.join(e,"Local State"),n=s.a.join(e,"Default");return await Object(b.a)(t)&&await Object(m.a)(n)}static async isProfileDir(e){const t=s.a.join(e,"Secure Preferences");return await Object(b.a)(t)}static async getProfilePaths(e){if(!e)return{userDataDir:null,profileDirName:null};if(await v.isProfileDir(e)&&!await v.isUserDataDir(e)){const{dir:t,base:n}=s.a.parse(e);return{userDataDir:t,profileDirName:n}}return{userDataDir:e,profileDirName:null}}async setupInstance(){this.wss=await new Promise(e=>{const t=new h.a.Server({port:0,host:"localhost"},()=>e(t))}),this.wss.on("connection",(function(e){e.on("error",e=>{w.debug("websocket connection error: "+e)})})),this.reloadManagerExtension=await this.createReloadManagerExtension();const e=[this.reloadManagerExtension].concat(this.params.extensions.map(({sourceDir:e})=>e)).join(","),{chromiumBinary:t}=this.params;w.debug("Starting Chromium instance..."),t&&w.debug(`(chromiumBinary: ${t})`);const n=[...y];n.push("--load-extension="+e),this.params.args&&n.push(...this.params.args);let r,{userDataDir:i,profileDirName:o}=await v.getProfilePaths(this.params.chromiumProfile);if(i&&this.params.keepProfileChanges){if(o&&!await v.isUserDataDir(i))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")}else if(!this.params.keepProfileChanges){const e=new g.a;await e.create();const t=e.path();i&&o?await c.a.copy(s.a.join(i,o),s.a.join(t,o)):i&&await c.a.copy(i,t),i=t}if(o&&n.push("--profile-directory="+o),this.params.startUrl){const e=Array.isArray(this.params.startUrl)?this.params.startUrl:[this.params.startUrl];r=e.shift(),n.push(...e)}this.chromiumInstance=await this.chromiumLaunch({enableExtensions:!0,chromePath:t,chromeFlags:n,startingUrl:r,userDataDir:i,ignoreDefaultFlags:!0}),this.chromiumInstance.process.once("close",()=>{this.chromiumInstance=null,this.exiting||(w.info("Exiting on Chromium instance disconnected."),this.exit())})}async wssBroadcast(e){return new Promise(t=>{const n=this.wss?new Set(this.wss.clients):new Set;function r(){this.removeEventListener("message",i),this.removeEventListener("close",r),n.delete(this)}const i=async e=>{if("webExtReloadExtensionComplete"===JSON.parse(e.data).type){for(const e of n)r.call(e);t()}};for(const t of n)t.readyState===h.a.OPEN?(t.addEventListener("message",i),t.addEventListener("close",r),t.send(JSON.stringify(e))):n.delete(t);0===n.size&&t()})}async createReloadManagerExtension(){const e=new g.a;await e.create(),this.registerCleanup(()=>e.remove());const t=s.a.join(e.path(),"reload-manager-extension-"+Date.now());w.debug("Creating reload-manager-extension in "+t),await l()(t),await c.a.writeFile(s.a.join(t,"manifest.json"),JSON.stringify({manifest_version:2,name:"web-ext Reload Manager Extension",version:"1.0",permissions:["management","tabs"],background:{scripts:["bg.js"]}}));const n=this.wss.address(),r=`(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.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://${n.address}:${n.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 })()`;return await c.a.writeFile(s.a.join(t,"bg.js"),r),t}async reloadAllExtensions(){const e=this.getName();return await this.wssBroadcast({type:"webExtReloadAllExtensions"}),process.stdout.write("\rLast extension reload: "+(new Date).toTimeString()),w.debug("\n"),[{runnerName:e}]}async reloadExtensionBySourceDir(e){return this.reloadAllExtensions()}registerCleanup(e){this.cleanupCallbacks.add(e)}async exit(){this.exiting=!0,this._promiseSetupDone&&await this._promiseSetupDone.catch(e=>{w.debug("ignored setup error on chromium runner shutdown: "+e)}),this.chromiumInstance&&(await this.chromiumInstance.kill(),this.chromiumInstance=null),this.wss&&(await new Promise(e=>this.wss?this.wss.close(e):e()),this.wss=null);for(const e of this.cleanupCallbacks)try{e()}catch(e){w.error(e)}}}}.call(this,"src/extension-runners/chromium.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"extensionIdFile",(function(){return g})),n.d(t,"default",(function(){return m})),n.d(t,"getIdFromSourceDir",(function(){return b})),n.d(t,"saveIdToSourceDir",(function(){return w}));var r=n(2),i=n.n(r),o=n(4),s=n(56),a=n(18),c=n(6),d=n(10),l=n(0),u=n(31),f=n(3);const h=Object(f.createLogger)(e),p=o.fs.readFile.bind(o.fs),g=".web-extension-id";function m({apiKey:e,apiProxy:t,apiSecret:n,apiUrlPrefix:r,artifactsDir:i,id:o,ignoreFiles:f=[],sourceDir:p,timeout:g,verbose:m,channel:x},{build:y=a.default,preValidatedManifest:v,signAddon:D=s.signAddon}={}){return Object(d.b)((async function(s){let a;await Object(u.a)(i),a=v||await Object(c.a)(p);const[d,P]=await Promise.all([y({sourceDir:p,ignoreFiles:f,artifactsDir:s.path()},{manifestData:a,showReadyMessage:!1}),b(p)]),A=Object(c.b)(a);if(o&&A)throw new l.d(`Cannot set custom ID ${o} because manifest.json declares ID `+A);o&&h.debug("Using custom ID declared as --id="+o),A&&(o=A),!o&&P&&(h.info("Using previously auto-generated extension ID: "+P),o=P),o||h.warn("No extension ID specified (it will be auto-generated)");const E=await D({apiKey:e,apiSecret:n,apiUrlPrefix:r,apiProxy:t,timeout:g,verbose:m,id:o,xpiPath:d.extensionPath,version:a.version,downloadDir:i,channel:x});if(E.id&&await w(p,E.id),!E.success)throw h.info("FAIL"),new l.e("The extension could not be signed");return h.info("Extension ID: "+E.id),h.info("SUCCESS"),E}))}async function b(e,t=p){const n=i.a.join(e,g);let r;try{r=await t(n)}catch(e){if(Object(l.f)("ENOENT",e))return void h.debug("No ID file found at: "+n);throw e}let o=r.toString().split("\n");o=o.filter(e=>{if((e=e.trim())&&!e.startsWith("#"))return e});const s=o[0];if(h.debug(`Found extension ID ${s} in ${n}`),!s)throw new l.d("No ID found in extension ID file "+n);return s}async function w(e,t){const n=i.a.join(e,g);await o.fs.writeFile(n,["# This file was created by https://github.com/mozilla/web-ext","# Your auto-generated extension ID for addons.mozilla.org is:",t.toString()].join("\n")),h.debug(`Saved auto-generated ID ${t} to ${n}`)}}.call(this,"src/cmd/sign.js")},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"url",(function(){return a})),n.d(t,"default",(function(){return c}));var r=n(57),i=n.n(r),o=n(3);const s=Object(o.createLogger)(e),a="https://extensionworkshop.com/documentation/develop/getting-started-with-web-ext/";function c(e,{openUrl:t=i.a}={}){return new Promise((e,n)=>{t(a,t=>{t?(s.debug("Encountered an error while opening URL "+a,t),n(t)):e()})})}}.call(this,"src/cmd/docs.js")},function(e,t){e.exports=require("git-rev-sync")}]).default;
|
|
2
2
|
//# sourceMappingURL=web-ext.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "web-ext",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.5.0",
|
|
4
4
|
"description": "A command line tool to help build, run, and test web extensions",
|
|
5
5
|
"main": "dist/web-ext.js",
|
|
6
6
|
"exports": {
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
"test": "node scripts/test",
|
|
29
29
|
"test-coverage": "node scripts/test --coverage",
|
|
30
30
|
"test-functional": "node scripts/test-functional",
|
|
31
|
-
"publish-coverage": "
|
|
31
|
+
"publish-coverage": "codecov",
|
|
32
32
|
"audit-deps": "node ./scripts/audit-deps",
|
|
33
33
|
"changelog": "npx conventional-changelog-cli -p angular -u",
|
|
34
34
|
"changelog-lint": "commitlint --from master",
|
|
35
35
|
"changelog-lint-from-stdin": "commitlint",
|
|
36
|
-
"
|
|
36
|
+
"github-pr-title-lint": "node ./scripts/github-pr-title-lint",
|
|
37
37
|
"gen-contributing-toc": "doctoc CONTRIBUTING.md"
|
|
38
38
|
},
|
|
39
39
|
"homepage": "https://github.com/mozilla/web-ext",
|
|
@@ -57,12 +57,12 @@
|
|
|
57
57
|
"opera"
|
|
58
58
|
],
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@babel/polyfill": "7.
|
|
61
|
-
"@babel/runtime": "7.
|
|
60
|
+
"@babel/polyfill": "7.12.1",
|
|
61
|
+
"@babel/runtime": "7.12.5",
|
|
62
62
|
"@cliqz-oss/firefox-client": "0.3.1",
|
|
63
63
|
"@cliqz-oss/node-firefox-connect": "1.2.1",
|
|
64
64
|
"@devicefarmer/adbkit": "2.11.3",
|
|
65
|
-
"addons-linter": "2.
|
|
65
|
+
"addons-linter": "2.13.1",
|
|
66
66
|
"bunyan": "1.8.14",
|
|
67
67
|
"camelcase": "6.0.0",
|
|
68
68
|
"chrome-launcher": "0.13.4",
|
|
@@ -73,11 +73,11 @@
|
|
|
73
73
|
"firefox-profile": "4.0.0",
|
|
74
74
|
"fs-extra": "9.0.1",
|
|
75
75
|
"fx-runner": "1.0.13",
|
|
76
|
-
"import-fresh": "3.
|
|
76
|
+
"import-fresh": "3.3.0",
|
|
77
77
|
"mkdirp": "1.0.4",
|
|
78
78
|
"multimatch": "4.0.0",
|
|
79
79
|
"mz": "2.7.0",
|
|
80
|
-
"node-notifier": "8.0.
|
|
80
|
+
"node-notifier": "8.0.1",
|
|
81
81
|
"open": "7.3.0",
|
|
82
82
|
"parse-json": "5.0.1",
|
|
83
83
|
"sign-addon": "3.1.0",
|
|
@@ -86,43 +86,43 @@
|
|
|
86
86
|
"strip-json-comments": "3.1.1",
|
|
87
87
|
"tmp": "0.2.1",
|
|
88
88
|
"update-notifier": "5.0.0",
|
|
89
|
-
"watchpack": "1.7.
|
|
90
|
-
"ws": "7.
|
|
89
|
+
"watchpack": "1.7.5",
|
|
90
|
+
"ws": "7.4.2",
|
|
91
91
|
"yargs": "15.4.1",
|
|
92
92
|
"zip-dir": "1.0.2"
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
|
-
"@babel/core": "7.
|
|
96
|
-
"@babel/plugin-proposal-class-properties": "7.
|
|
97
|
-
"@babel/plugin-transform-runtime": "7.
|
|
98
|
-
"@babel/preset-env": "7.
|
|
99
|
-
"@babel/preset-flow": "7.
|
|
100
|
-
"@babel/register": "7.
|
|
95
|
+
"@babel/core": "7.12.3",
|
|
96
|
+
"@babel/plugin-proposal-class-properties": "7.12.1",
|
|
97
|
+
"@babel/plugin-transform-runtime": "7.12.1",
|
|
98
|
+
"@babel/preset-env": "7.12.1",
|
|
99
|
+
"@babel/preset-flow": "7.12.1",
|
|
100
|
+
"@babel/register": "7.12.1",
|
|
101
101
|
"@commitlint/cli": "11.0.0",
|
|
102
102
|
"@commitlint/config-conventional": "11.0.0",
|
|
103
103
|
"babel-eslint": "10.1.0",
|
|
104
|
-
"babel-loader": "8.1
|
|
104
|
+
"babel-loader": "8.2.1",
|
|
105
105
|
"babel-plugin-istanbul": "6.0.0",
|
|
106
106
|
"chai": "4.2.0",
|
|
107
107
|
"chai-as-promised": "7.1.1",
|
|
108
|
+
"codecov": "3.8.1",
|
|
108
109
|
"copy-dir": "1.3.0",
|
|
109
|
-
"
|
|
110
|
-
"cross-env": "7.0.2",
|
|
110
|
+
"cross-env": "7.0.3",
|
|
111
111
|
"deepcopy": "2.1.0",
|
|
112
112
|
"doctoc": "1.4.0",
|
|
113
|
-
"eslint": "7.
|
|
113
|
+
"eslint": "7.17.0",
|
|
114
114
|
"eslint-plugin-async-await": "0.0.0",
|
|
115
115
|
"eslint-plugin-flowtype": "5.2.0",
|
|
116
116
|
"eslint-plugin-import": "2.22.1",
|
|
117
|
-
"flow-bin": "0.
|
|
117
|
+
"flow-bin": "0.141.0",
|
|
118
118
|
"git-rev-sync": "3.0.1",
|
|
119
|
-
"html-entities": "1.
|
|
120
|
-
"mocha": "8.1
|
|
119
|
+
"html-entities": "1.4.0",
|
|
120
|
+
"mocha": "8.2.1",
|
|
121
121
|
"nyc": "15.1.0",
|
|
122
122
|
"prettyjson": "1.2.1",
|
|
123
123
|
"shelljs": "0.8.4",
|
|
124
|
-
"sinon": "9.
|
|
125
|
-
"webpack": "4.
|
|
124
|
+
"sinon": "9.2.2",
|
|
125
|
+
"webpack": "4.45.0",
|
|
126
126
|
"webpack-node-externals": "2.5.2",
|
|
127
127
|
"yauzl": "2.10.0"
|
|
128
128
|
},
|
package/src/cmd/build.js
CHANGED
|
@@ -209,7 +209,9 @@ export async function defaultPackageCreator(
|
|
|
209
209
|
// Added 'wx' flags to avoid overwriting of existing package.
|
|
210
210
|
const stream = createWriteStream(extensionPath, {flags: 'wx'});
|
|
211
211
|
|
|
212
|
-
stream.write(buffer, () =>
|
|
212
|
+
stream.write(buffer, () => {
|
|
213
|
+
stream.end();
|
|
214
|
+
});
|
|
213
215
|
|
|
214
216
|
try {
|
|
215
217
|
await eventToPromise(stream, 'close');
|
|
@@ -224,7 +226,9 @@ export async function defaultPackageCreator(
|
|
|
224
226
|
}
|
|
225
227
|
log.info(`Destination exists, overwriting: ${extensionPath}`);
|
|
226
228
|
const overwriteStream = createWriteStream(extensionPath);
|
|
227
|
-
overwriteStream.write(buffer, () =>
|
|
229
|
+
overwriteStream.write(buffer, () => {
|
|
230
|
+
overwriteStream.end();
|
|
231
|
+
});
|
|
228
232
|
await eventToPromise(overwriteStream, 'close');
|
|
229
233
|
}
|
|
230
234
|
|
package/src/cmd/docs.js
CHANGED
|
@@ -14,8 +14,8 @@ export type DocsOptions = {
|
|
|
14
14
|
openUrl?: typeof open,
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
// eslint-disable-next-line max-len
|
|
18
|
+
export const url = 'https://extensionworkshop.com/documentation/develop/getting-started-with-web-ext/';
|
|
19
19
|
|
|
20
20
|
export default function docs(
|
|
21
21
|
params: DocsParams, {openUrl = open}: DocsOptions = {}
|
package/src/cmd/run.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/* @flow */
|
|
2
|
+
import { fs } from 'mz';
|
|
3
|
+
|
|
2
4
|
import defaultBuildExtension from './build';
|
|
3
5
|
import {
|
|
4
6
|
showDesktopNotification as defaultDesktopNotifications,
|
|
@@ -9,6 +11,7 @@ import {
|
|
|
9
11
|
} from '../firefox/remote';
|
|
10
12
|
import {createLogger} from '../util/logger';
|
|
11
13
|
import defaultGetValidatedManifest from '../util/manifest';
|
|
14
|
+
import {UsageError} from '../../src/errors';
|
|
12
15
|
import {
|
|
13
16
|
createExtensionRunner,
|
|
14
17
|
defaultReloadStrategy,
|
|
@@ -28,6 +31,7 @@ export type CmdRunParams = {|
|
|
|
28
31
|
pref?: FirefoxPreferences,
|
|
29
32
|
firefox: string,
|
|
30
33
|
firefoxProfile?: string,
|
|
34
|
+
profileCreateIfMissing?: boolean,
|
|
31
35
|
ignoreFiles?: Array<string>,
|
|
32
36
|
keepProfileChanges: boolean,
|
|
33
37
|
noInput?: boolean,
|
|
@@ -35,6 +39,7 @@ export type CmdRunParams = {|
|
|
|
35
39
|
preInstall: boolean,
|
|
36
40
|
sourceDir: string,
|
|
37
41
|
watchFile?: string,
|
|
42
|
+
watchIgnored?: Array<string>,
|
|
38
43
|
startUrl?: Array<string>,
|
|
39
44
|
target?: Array<string>,
|
|
40
45
|
args?: Array<string>,
|
|
@@ -72,6 +77,7 @@ export default async function run(
|
|
|
72
77
|
pref,
|
|
73
78
|
firefox,
|
|
74
79
|
firefoxProfile,
|
|
80
|
+
profileCreateIfMissing,
|
|
75
81
|
keepProfileChanges = false,
|
|
76
82
|
ignoreFiles,
|
|
77
83
|
noInput = false,
|
|
@@ -79,6 +85,7 @@ export default async function run(
|
|
|
79
85
|
preInstall = false,
|
|
80
86
|
sourceDir,
|
|
81
87
|
watchFile,
|
|
88
|
+
watchIgnored,
|
|
82
89
|
startUrl,
|
|
83
90
|
target,
|
|
84
91
|
args,
|
|
@@ -117,6 +124,24 @@ export default async function run(
|
|
|
117
124
|
const customPrefs = pref;
|
|
118
125
|
const manifestData = await getValidatedManifest(sourceDir);
|
|
119
126
|
|
|
127
|
+
const profileDir = firefoxProfile || chromiumProfile;
|
|
128
|
+
|
|
129
|
+
if (profileCreateIfMissing) {
|
|
130
|
+
if (!profileDir) {
|
|
131
|
+
throw new UsageError(
|
|
132
|
+
'--profile-create-if-missing requires ' +
|
|
133
|
+
'--firefox-profile or --chromium-profile'
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
const isDir = fs.existsSync(profileDir);
|
|
137
|
+
if (isDir) {
|
|
138
|
+
log.info(`Profile directory ${profileDir} already exists`);
|
|
139
|
+
} else {
|
|
140
|
+
log.info(`Profile directory not found. Creating directory ${profileDir}`);
|
|
141
|
+
await fs.mkdir(profileDir);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
120
145
|
const runners = [];
|
|
121
146
|
|
|
122
147
|
const commonRunnerParams = {
|
|
@@ -225,6 +250,7 @@ export default async function run(
|
|
|
225
250
|
extensionRunner,
|
|
226
251
|
sourceDir,
|
|
227
252
|
watchFile,
|
|
253
|
+
watchIgnored,
|
|
228
254
|
artifactsDir,
|
|
229
255
|
ignoreFiles,
|
|
230
256
|
noInput,
|
package/src/cmd/sign.js
CHANGED
|
@@ -15,7 +15,8 @@ import type {ExtensionManifest} from '../util/manifest';
|
|
|
15
15
|
|
|
16
16
|
const log = createLogger(__filename);
|
|
17
17
|
|
|
18
|
-
const defaultAsyncFsReadFile
|
|
18
|
+
const defaultAsyncFsReadFile: (string) => Promise<Buffer> =
|
|
19
|
+
fs.readFile.bind(fs);
|
|
19
20
|
|
|
20
21
|
export const extensionIdFile = '.web-extension-id';
|
|
21
22
|
|
|
@@ -43,7 +43,7 @@ const EXCLUDED_CHROME_FLAGS = [
|
|
|
43
43
|
'--mute-audio',
|
|
44
44
|
];
|
|
45
45
|
|
|
46
|
-
export const DEFAULT_CHROME_FLAGS = ChromeLauncher.defaultFlags()
|
|
46
|
+
export const DEFAULT_CHROME_FLAGS: Array<string> = ChromeLauncher.defaultFlags()
|
|
47
47
|
.filter((flag) => !EXCLUDED_CHROME_FLAGS.includes(flag));
|
|
48
48
|
|
|
49
49
|
/**
|
|
@@ -52,10 +52,10 @@ export const DEFAULT_CHROME_FLAGS = ChromeLauncher.defaultFlags()
|
|
|
52
52
|
export class ChromiumExtensionRunner {
|
|
53
53
|
cleanupCallbacks: Set<Function>;
|
|
54
54
|
params: ChromiumExtensionRunnerParams;
|
|
55
|
-
chromiumInstance: ChromeLauncher;
|
|
55
|
+
chromiumInstance: ?ChromeLauncher;
|
|
56
56
|
chromiumLaunch: typeof defaultChromiumLaunch;
|
|
57
57
|
reloadManagerExtension: string;
|
|
58
|
-
wss: WebSocket.Server;
|
|
58
|
+
wss: ?WebSocket.Server;
|
|
59
59
|
exiting: boolean;
|
|
60
60
|
_promiseSetupDone: ?Promise<void>;
|
|
61
61
|
|
|
@@ -73,7 +73,7 @@ export class ChromiumExtensionRunner {
|
|
|
73
73
|
/**
|
|
74
74
|
* Returns the runner name.
|
|
75
75
|
*/
|
|
76
|
-
getName() {
|
|
76
|
+
getName(): string {
|
|
77
77
|
return 'Chromium';
|
|
78
78
|
}
|
|
79
79
|
|
|
@@ -241,7 +241,7 @@ export class ChromiumExtensionRunner {
|
|
|
241
241
|
});
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
async wssBroadcast(data: Object) {
|
|
244
|
+
async wssBroadcast(data: Object): Promise<void> {
|
|
245
245
|
return new Promise((resolve) => {
|
|
246
246
|
const clients = this.wss ? new Set(this.wss.clients) : new Set();
|
|
247
247
|
|
|
@@ -280,7 +280,7 @@ export class ChromiumExtensionRunner {
|
|
|
280
280
|
});
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
async createReloadManagerExtension() {
|
|
283
|
+
async createReloadManagerExtension(): Promise<string> {
|
|
284
284
|
const tmpDir = new TempDir();
|
|
285
285
|
await tmpDir.create();
|
|
286
286
|
this.registerCleanup(() => tmpDir.remove());
|
|
@@ -307,6 +307,7 @@ export class ChromiumExtensionRunner {
|
|
|
307
307
|
})
|
|
308
308
|
);
|
|
309
309
|
|
|
310
|
+
// $FlowIgnore: this method is only called right after creating the server and so wss should be defined.
|
|
310
311
|
const wssInfo = this.wss.address();
|
|
311
312
|
|
|
312
313
|
const bgPage = `(function bgPage() {
|
|
@@ -408,7 +409,8 @@ export class ChromiumExtensionRunner {
|
|
|
408
409
|
}
|
|
409
410
|
|
|
410
411
|
if (this.wss) {
|
|
411
|
-
await new Promise((resolve) =>
|
|
412
|
+
await new Promise((resolve) =>
|
|
413
|
+
this.wss ? this.wss.close(resolve) : resolve());
|
|
412
414
|
this.wss = null;
|
|
413
415
|
}
|
|
414
416
|
|
|
@@ -89,9 +89,9 @@ export type FirefoxAndroidExtensionRunnerParams = {|
|
|
|
89
89
|
*/
|
|
90
90
|
export class FirefoxAndroidExtensionRunner {
|
|
91
91
|
// Wait 3s before the next unix socket discovery loop.
|
|
92
|
-
static unixSocketDiscoveryRetryInterval = 3 * 1000;
|
|
92
|
+
static unixSocketDiscoveryRetryInterval: number = 3 * 1000;
|
|
93
93
|
// Wait for at most 3 minutes before giving up.
|
|
94
|
-
static unixSocketDiscoveryMaxTime = 3 * 60 * 1000;
|
|
94
|
+
static unixSocketDiscoveryMaxTime: number = 3 * 60 * 1000;
|
|
95
95
|
|
|
96
96
|
params: FirefoxAndroidExtensionRunnerParams;
|
|
97
97
|
adbUtils: DefaultADBUtils;
|
|
@@ -168,7 +168,7 @@ export class FirefoxAndroidExtensionRunner {
|
|
|
168
168
|
/**
|
|
169
169
|
* Returns the runner name.
|
|
170
170
|
*/
|
|
171
|
-
getName() {
|
|
171
|
+
getName(): string {
|
|
172
172
|
return 'Firefox Android';
|
|
173
173
|
}
|
|
174
174
|
|
|
@@ -582,14 +582,6 @@ export class FirefoxAndroidExtensionRunner {
|
|
|
582
582
|
}
|
|
583
583
|
|
|
584
584
|
try {
|
|
585
|
-
const msg = (
|
|
586
|
-
`Waiting for ${selectedFirefoxApk} Remote Debugging Server...` +
|
|
587
|
-
'\nMake sure to enable "Remote Debugging via USB" ' +
|
|
588
|
-
'from Settings -> Developer Tools if it is not yet enabled.'
|
|
589
|
-
);
|
|
590
|
-
|
|
591
|
-
log.info(`\n${msg}\n`);
|
|
592
|
-
|
|
593
585
|
// Got a debugger socket file to connect.
|
|
594
586
|
this.selectedRDPSocketFile = (
|
|
595
587
|
await adbUtils.discoverRDPUnixSocket(
|
|
@@ -45,7 +45,9 @@ export type MultiExtensionRunnerParams = {|
|
|
|
45
45
|
desktopNotifications: typeof defaultDesktopNotifications,
|
|
46
46
|
|};
|
|
47
47
|
|
|
48
|
-
export async function createExtensionRunner(
|
|
48
|
+
export async function createExtensionRunner(
|
|
49
|
+
config: ExtensionRunnerConfig
|
|
50
|
+
): Promise<IExtensionRunner> {
|
|
49
51
|
switch (config.target) {
|
|
50
52
|
case 'firefox-desktop': {
|
|
51
53
|
// TODO: use async import instead of require - https://github.com/mozilla/web-ext/issues/1306
|
|
@@ -86,7 +88,7 @@ export class MultiExtensionRunner {
|
|
|
86
88
|
/**
|
|
87
89
|
* Returns the runner name.
|
|
88
90
|
*/
|
|
89
|
-
getName() {
|
|
91
|
+
getName(): string {
|
|
90
92
|
return 'Multi Extension Runner';
|
|
91
93
|
}
|
|
92
94
|
|
|
@@ -238,6 +240,7 @@ export type WatcherCreatorParams = {|
|
|
|
238
240
|
reloadExtension: (string) => void,
|
|
239
241
|
sourceDir: string,
|
|
240
242
|
watchFile?: string,
|
|
243
|
+
watchIgnored?: Array<string>,
|
|
241
244
|
artifactsDir: string,
|
|
242
245
|
onSourceChange?: OnSourceChangeFn,
|
|
243
246
|
ignoreFiles?: Array<string>,
|
|
@@ -248,7 +251,8 @@ export type WatcherCreatorFn = (params: WatcherCreatorParams) => Watchpack;
|
|
|
248
251
|
|
|
249
252
|
export function defaultWatcherCreator(
|
|
250
253
|
{
|
|
251
|
-
reloadExtension, sourceDir, watchFile,
|
|
254
|
+
reloadExtension, sourceDir, watchFile,
|
|
255
|
+
watchIgnored, artifactsDir, ignoreFiles,
|
|
252
256
|
onSourceChange = defaultSourceWatcher,
|
|
253
257
|
createFileFilter = defaultFileFilterCreator,
|
|
254
258
|
}: WatcherCreatorParams
|
|
@@ -259,6 +263,7 @@ export function defaultWatcherCreator(
|
|
|
259
263
|
return onSourceChange({
|
|
260
264
|
sourceDir,
|
|
261
265
|
watchFile,
|
|
266
|
+
watchIgnored,
|
|
262
267
|
artifactsDir,
|
|
263
268
|
onChange: () => reloadExtension(sourceDir),
|
|
264
269
|
shouldWatchFile: (file) => fileFilter.wantFile(file),
|
|
@@ -272,6 +277,7 @@ export type ReloadStrategyParams = {|
|
|
|
272
277
|
extensionRunner: IExtensionRunner,
|
|
273
278
|
sourceDir: string,
|
|
274
279
|
watchFile?: string,
|
|
280
|
+
watchIgnored?: Array<string>,
|
|
275
281
|
artifactsDir: string,
|
|
276
282
|
ignoreFiles?: Array<string>,
|
|
277
283
|
noInput?: boolean,
|
|
@@ -291,6 +297,7 @@ export function defaultReloadStrategy(
|
|
|
291
297
|
noInput = false,
|
|
292
298
|
sourceDir,
|
|
293
299
|
watchFile,
|
|
300
|
+
watchIgnored,
|
|
294
301
|
}: ReloadStrategyParams,
|
|
295
302
|
{
|
|
296
303
|
createWatcher = defaultWatcherCreator,
|
|
@@ -309,6 +316,7 @@ export function defaultReloadStrategy(
|
|
|
309
316
|
},
|
|
310
317
|
sourceDir,
|
|
311
318
|
watchFile,
|
|
319
|
+
watchIgnored,
|
|
312
320
|
artifactsDir,
|
|
313
321
|
ignoreFiles,
|
|
314
322
|
});
|
|
@@ -359,7 +367,10 @@ export function defaultReloadStrategy(
|
|
|
359
367
|
setRawMode(stdin, true);
|
|
360
368
|
} else if (keyPressed.name === 'r') {
|
|
361
369
|
log.debug('Reloading installed extensions on user request');
|
|
362
|
-
extensionRunner.reloadAllExtensions()
|
|
370
|
+
await extensionRunner.reloadAllExtensions().catch((err) => {
|
|
371
|
+
log.warn(`\nError reloading extension: ${err}`);
|
|
372
|
+
log.debug(`Reloading extension error stack: ${err.stack}`);
|
|
373
|
+
});
|
|
363
374
|
}
|
|
364
375
|
}
|
|
365
376
|
|
package/src/firefox/index.js
CHANGED
|
@@ -4,8 +4,7 @@ import path from 'path';
|
|
|
4
4
|
import {promisify} from 'util';
|
|
5
5
|
|
|
6
6
|
import {default as defaultFxRunner} from 'fx-runner';
|
|
7
|
-
import FirefoxProfile
|
|
8
|
-
from 'firefox-profile';
|
|
7
|
+
import FirefoxProfile from 'firefox-profile';
|
|
9
8
|
import {fs} from 'mz';
|
|
10
9
|
import eventToPromise from 'event-to-promise';
|
|
11
10
|
|
|
@@ -26,7 +25,9 @@ import type {ExtensionManifest} from '../util/manifest';
|
|
|
26
25
|
|
|
27
26
|
const log = createLogger(__filename);
|
|
28
27
|
|
|
29
|
-
const defaultAsyncFsStat = fs.stat.bind(fs);
|
|
28
|
+
const defaultAsyncFsStat: typeof fs.stat = fs.stat.bind(fs);
|
|
29
|
+
|
|
30
|
+
const defaultUserProfileCopier = FirefoxProfile.copyFromUserProfile;
|
|
30
31
|
|
|
31
32
|
export const defaultFirefoxEnv = {
|
|
32
33
|
XPCOM_DEBUG_BREAK: 'stack',
|
package/src/program.js
CHANGED
|
@@ -177,6 +177,15 @@ export class Program {
|
|
|
177
177
|
argv.noReload = !argv.reload;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
// Yargs doesn't accept --no-input as a valid option if there isn't a
|
|
181
|
+
// --input option defined to be negated, to fix that the --input is
|
|
182
|
+
// defined and hidden from the yargs help output and we define here
|
|
183
|
+
// the negated argument name that we expect to be set in the parsed
|
|
184
|
+
// arguments (and fix https://github.com/mozilla/web-ext/issues/1860).
|
|
185
|
+
if (argv.input != null) {
|
|
186
|
+
argv.noInput = !argv.input;
|
|
187
|
+
}
|
|
188
|
+
|
|
180
189
|
// Replacement for the "requiresArg: true" parameter until the following bug
|
|
181
190
|
// is fixed: https://github.com/yargs/yargs/issues/1098
|
|
182
191
|
if (argv.ignoreFiles && !argv.ignoreFiles.length) {
|
|
@@ -450,6 +459,13 @@ Example: $0 --help run.
|
|
|
450
459
|
type: 'boolean',
|
|
451
460
|
demandOption: false,
|
|
452
461
|
},
|
|
462
|
+
'input': {
|
|
463
|
+
// This option is defined to make yargs to accept the --no-input
|
|
464
|
+
// defined above, but we hide it from the yargs help output.
|
|
465
|
+
hidden: true,
|
|
466
|
+
type: 'boolean',
|
|
467
|
+
demandOption: false,
|
|
468
|
+
},
|
|
453
469
|
'config': {
|
|
454
470
|
alias: 'c',
|
|
455
471
|
describe: 'Path to a CommonJS config file to set ' +
|
|
@@ -580,6 +596,11 @@ Example: $0 --help run.
|
|
|
580
596
|
demandOption: false,
|
|
581
597
|
type: 'string',
|
|
582
598
|
},
|
|
599
|
+
'profile-create-if-missing': {
|
|
600
|
+
describe: 'Create the profile directory if it does not already exist',
|
|
601
|
+
demandOption: false,
|
|
602
|
+
type: 'boolean',
|
|
603
|
+
},
|
|
583
604
|
'keep-profile-changes': {
|
|
584
605
|
describe: 'Run Firefox directly in custom profile. Any changes to ' +
|
|
585
606
|
'the profile will be saved.',
|
|
@@ -595,11 +616,20 @@ Example: $0 --help run.
|
|
|
595
616
|
},
|
|
596
617
|
'watch-file': {
|
|
597
618
|
describe: 'Reload the extension only when the contents of this' +
|
|
598
|
-
'file changes. This is useful if you use a custom' +
|
|
619
|
+
' file changes. This is useful if you use a custom' +
|
|
599
620
|
' build process for your extension',
|
|
600
621
|
demandOption: false,
|
|
601
622
|
type: 'string',
|
|
602
623
|
},
|
|
624
|
+
'watch-ignored': {
|
|
625
|
+
describe: 'Paths and globs patterns that should not be ' +
|
|
626
|
+
'watched for changes. This is useful if you want ' +
|
|
627
|
+
'to explicitly prevent web-ext from watching part ' +
|
|
628
|
+
'of the extension directory tree, ' +
|
|
629
|
+
'e.g. the node_modules folder.',
|
|
630
|
+
demandOption: false,
|
|
631
|
+
type: 'array',
|
|
632
|
+
},
|
|
603
633
|
'pre-install': {
|
|
604
634
|
describe: 'Pre-install the extension into the profile before ' +
|
|
605
635
|
'startup. This is only needed to support older versions ' +
|
package/src/util/adb.js
CHANGED
|
@@ -7,7 +7,9 @@ import {
|
|
|
7
7
|
WebExtError,
|
|
8
8
|
} from '../errors';
|
|
9
9
|
import {createLogger} from '../util/logger';
|
|
10
|
-
import packageIdentifiers
|
|
10
|
+
import packageIdentifiers, {
|
|
11
|
+
defaultApkComponents,
|
|
12
|
+
} from '../firefox/package-identifiers';
|
|
11
13
|
|
|
12
14
|
export const DEVICE_DIR_BASE = '/sdcard/';
|
|
13
15
|
export const ARTIFACTS_DIR_PREFIX = 'web-ext-artifacts-';
|
|
@@ -313,6 +315,9 @@ export default class ADBUtils {
|
|
|
313
315
|
|
|
314
316
|
if (!apkComponent) {
|
|
315
317
|
apkComponent = '.App';
|
|
318
|
+
if (defaultApkComponents[apk]) {
|
|
319
|
+
apkComponent = defaultApkComponents[apk];
|
|
320
|
+
}
|
|
316
321
|
} else if (!apkComponent.includes('.')) {
|
|
317
322
|
apkComponent = `.${apkComponent}`;
|
|
318
323
|
}
|
|
@@ -353,8 +358,14 @@ export default class ADBUtils {
|
|
|
353
358
|
let rdpUnixSockets = [];
|
|
354
359
|
|
|
355
360
|
const discoveryStartedAt = Date.now();
|
|
361
|
+
const msg = (
|
|
362
|
+
`Waiting for ${apk} Remote Debugging Server...` +
|
|
363
|
+
'\nMake sure to enable "Remote Debugging via USB" ' +
|
|
364
|
+
'from Settings -> Developer Tools if it is not yet enabled.'
|
|
365
|
+
);
|
|
356
366
|
|
|
357
367
|
while (rdpUnixSockets.length === 0) {
|
|
368
|
+
log.info(msg);
|
|
358
369
|
if (this.userAbortDiscovery) {
|
|
359
370
|
throw new UsageError(
|
|
360
371
|
'Exiting Firefox Remote Debugging socket discovery on user request'
|
package/src/util/artifacts.js
CHANGED
|
@@ -7,7 +7,7 @@ import {createLogger} from './logger';
|
|
|
7
7
|
|
|
8
8
|
const log = createLogger(__filename);
|
|
9
9
|
|
|
10
|
-
const defaultAsyncFsAccess = fs.access.bind(fs);
|
|
10
|
+
const defaultAsyncFsAccess: typeof fs.access = fs.access.bind(fs);
|
|
11
11
|
|
|
12
12
|
type PrepareArtifactsDirOptions = {
|
|
13
13
|
asyncMkdirp?: typeof defaultAsyncMkdirp,
|
package/src/util/logger.js
CHANGED
package/src/util/temp-dir.js
CHANGED
package/src/util/zip-dir.js
CHANGED
|
@@ -3,4 +3,7 @@ import {promisify} from 'util';
|
|
|
3
3
|
|
|
4
4
|
import zipDirModule from 'zip-dir';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
type PromisedZipDir =
|
|
7
|
+
(sourceDir: string, { filter(...any): boolean }) => Promise<Buffer>;
|
|
8
|
+
|
|
9
|
+
export const zipDir: PromisedZipDir = promisify(zipDirModule);
|
package/src/watcher.js
CHANGED
|
@@ -19,9 +19,11 @@ export type OnChangeFn = () => any;
|
|
|
19
19
|
export type OnSourceChangeParams = {|
|
|
20
20
|
sourceDir: string,
|
|
21
21
|
watchFile?: string,
|
|
22
|
+
watchIgnored?: Array<string>,
|
|
22
23
|
artifactsDir: string,
|
|
23
24
|
onChange: OnChangeFn,
|
|
24
25
|
shouldWatchFile: ShouldWatchFn,
|
|
26
|
+
debounceTime?: number,
|
|
25
27
|
|};
|
|
26
28
|
|
|
27
29
|
// NOTE: this fix an issue with flow and default exports (which currently
|
|
@@ -36,16 +38,20 @@ export default function onSourceChange(
|
|
|
36
38
|
{
|
|
37
39
|
sourceDir,
|
|
38
40
|
watchFile,
|
|
41
|
+
watchIgnored,
|
|
39
42
|
artifactsDir,
|
|
40
43
|
onChange,
|
|
41
44
|
shouldWatchFile,
|
|
45
|
+
debounceTime = 1000,
|
|
42
46
|
}: OnSourceChangeParams
|
|
43
47
|
): Watchpack {
|
|
44
48
|
// TODO: For network disks, we would need to add {poll: true}.
|
|
45
|
-
const watcher =
|
|
49
|
+
const watcher = watchIgnored ?
|
|
50
|
+
new Watchpack({ignored: watchIgnored}) :
|
|
51
|
+
new Watchpack();
|
|
46
52
|
|
|
47
53
|
const executeImmediately = true;
|
|
48
|
-
onChange = debounce(onChange,
|
|
54
|
+
onChange = debounce(onChange, debounceTime, executeImmediately);
|
|
49
55
|
|
|
50
56
|
watcher.on('change', (filePath) => {
|
|
51
57
|
proxyFileChanges({artifactsDir, onChange, filePath, shouldWatchFile});
|