From 9f4820ee987ac6d2af382f1a6672dad97bac8d47 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 15 Jul 2021 10:59:34 -0700 Subject: [PATCH] Build - refactor for bundle factoring and swappable runtime (#11080) * wip * build - breakout sentry-install bundle * deps - move new build sys deps to published versions * chore: lint fix * clean - remove unused file * clean - remove unsused package script * lavamoat - update build system policy * build - render html to all platforms * development - improve sourcemap debugger output * deps - update lavapack * lint - fix * deps - update lavapack for bugfix * deps - update lavapack for bugfix * deps - bump lavapack for line ending normalization * sourcemap explorer - disable boundary validation * ci - reset normal ci flow * build - re-enable minification on prod * build - remove noisy log about html dest * build - update terser and remove gulp wrapper for sourcemap fix * Revert "sourcemap explorer - disable boundary validation" This reverts commit 94112209ed880a6ebf4ee2ded411e59db6908162. * build - reenable react-devtools in dev mode * wip * build - breakout sentry-install bundle * deps - move new build sys deps to published versions * chore: lint fix * clean - remove unused file * clean - remove unsused package script * lavamoat - update build system policy * build - render html to all platforms * development - improve sourcemap debugger output * deps - update lavapack * lint - fix * deps - update lavapack for bugfix * deps - update lavapack for bugfix * deps - bump lavapack for line ending normalization * sourcemap explorer - disable boundary validation * ci - reset normal ci flow * build - re-enable minification on prod * build - remove noisy log about html dest * build - update terser and remove gulp wrapper for sourcemap fix * Revert "sourcemap explorer - disable boundary validation" This reverts commit 94112209ed880a6ebf4ee2ded411e59db6908162. * build - reenable react-devtools in dev mode * Updating lockfile * lint fix * build/dev - patch watchifys incompatible binary stats output * ui - add comment about conditional import * build - improve comment * Update development/stream-flat-map.js Co-authored-by: Brad Decker * Outputting all bundle file links (metamaskbot) Co-authored-by: ryanml Co-authored-by: Brad Decker --- .eslintrc.js | 2 +- app/background.html | 12 +- app/home.html | 12 +- app/manifest/_base.json | 4 +- app/notification.html | 12 +- app/phishing.html | 4 +- app/popup.html | 12 +- .../{runLockdown.js => lockdown-run.js} | 4 +- .../{initSentry.js => sentry-install.js} | 0 app/scripts/ui.js | 3 + development/build/scripts.js | 329 ++++++++++++------ development/build/static.js | 17 +- development/build/task.js | 5 +- development/metamaskbot-build-announce.js | 23 +- development/require-react-devtools.js | 1 - development/sourcemap-validator.js | 65 ++-- development/stream-flat-map.js | 43 +++ lavamoat/node/policy.json | 282 +++------------ package.json | 16 +- patches/squirrelly+8.0.8.patch | 13 + patches/watchify+3.11.1.patch | 38 ++ test/unit-global/frozenPromise.test.js | 2 +- yarn.lock | 133 ++++++- 23 files changed, 573 insertions(+), 459 deletions(-) rename app/scripts/{runLockdown.js => lockdown-run.js} (83%) rename app/scripts/{initSentry.js => sentry-install.js} (100%) delete mode 100644 development/require-react-devtools.js create mode 100644 development/stream-flat-map.js create mode 100644 patches/squirrelly+8.0.8.patch create mode 100644 patches/watchify+3.11.1.patch diff --git a/.eslintrc.js b/.eslintrc.js index 56c2d4b86..d3763fdef 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -154,7 +154,7 @@ module.exports = { 'babel.config.js', 'nyc.config.js', 'stylelint.config.js', - 'app/scripts/runLockdown.js', + 'app/scripts/lockdown-run.js', 'development/**/*.js', 'test/e2e/**/*.js', 'test/lib/wait-until-called.js', diff --git a/app/background.html b/app/background.html index 290576939..2faa31411 100644 --- a/app/background.html +++ b/app/background.html @@ -5,11 +5,13 @@ - - - - - + + + + + {{@each(it.jsBundles) => val}} + + {{/each}} diff --git a/app/home.html b/app/home.html index d952983c9..5350b31dd 100644 --- a/app/home.html +++ b/app/home.html @@ -11,10 +11,12 @@
- - - - - + + + + + {{@each(it.jsBundles) => val}} + + {{/each}} diff --git a/app/manifest/_base.json b/app/manifest/_base.json index 437ef1d2e..6c328d0c6 100644 --- a/app/manifest/_base.json +++ b/app/manifest/_base.json @@ -33,8 +33,8 @@ "js": [ "disable-console.js", "globalthis.js", - "lockdown.js", - "runLockdown.js", + "lockdown-install.js", + "lockdown-run.js", "contentscript.js" ], "run_at": "document_start", diff --git a/app/notification.html b/app/notification.html index 8d82c41b2..55b98c960 100644 --- a/app/notification.html +++ b/app/notification.html @@ -34,10 +34,12 @@
- - - - - + + + + + {{@each(it.jsBundles) => val}} + + {{/each}} diff --git a/app/phishing.html b/app/phishing.html index 7bbc11dab..5460447b9 100644 --- a/app/phishing.html +++ b/app/phishing.html @@ -3,8 +3,8 @@ Ethereum Phishing Detection - MetaMask - - + + diff --git a/app/popup.html b/app/popup.html index d16257992..c94b82df8 100644 --- a/app/popup.html +++ b/app/popup.html @@ -11,10 +11,12 @@
- - - - - + + + + + {{@each(it.jsBundles) => val}} + + {{/each}} diff --git a/app/scripts/runLockdown.js b/app/scripts/lockdown-run.js similarity index 83% rename from app/scripts/runLockdown.js rename to app/scripts/lockdown-run.js index 2918368e7..f0682654e 100644 --- a/app/scripts/runLockdown.js +++ b/app/scripts/lockdown-run.js @@ -14,7 +14,7 @@ try { // caught and logged here so that the contentscript still gets injected. // This affects Firefox v56 and Waterfox Classic console.error('Lockdown failed:', error); - if (window.sentry && window.sentry.captureException) { - window.sentry.captureException(error); + if (globalThis.sentry && globalThis.sentry.captureException) { + globalThis.sentry.captureException(error); } } diff --git a/app/scripts/initSentry.js b/app/scripts/sentry-install.js similarity index 100% rename from app/scripts/initSentry.js rename to app/scripts/sentry-install.js diff --git a/app/scripts/ui.js b/app/scripts/ui.js index b00c3d6da..ee4539370 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -2,6 +2,9 @@ import 'abortcontroller-polyfill/dist/polyfill-patch-fetch'; import '@formatjs/intl-relativetimeformat/polyfill'; +// dev only, "react-devtools" import is skipped in prod builds +import 'react-devtools'; + import PortStream from 'extension-port-stream'; import extension from 'extensionizer'; diff --git a/development/build/scripts.js b/development/build/scripts.js index 50fa4f8db..d0007ec74 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -1,19 +1,29 @@ +const { callbackify } = require('util'); +const path = require('path'); +const { writeFileSync, readFileSync } = require('fs'); const EventEmitter = require('events'); const gulp = require('gulp'); const watch = require('gulp-watch'); const source = require('vinyl-source-stream'); const buffer = require('vinyl-buffer'); const log = require('fancy-log'); -const watchify = require('watchify'); const browserify = require('browserify'); -const envify = require('loose-envify/custom'); -const sourcemaps = require('gulp-sourcemaps'); -const terser = require('gulp-terser-js'); +const watchify = require('watchify'); const babelify = require('babelify'); const brfs = require('brfs'); +const envify = require('loose-envify/custom'); +const sourcemaps = require('gulp-sourcemaps'); +const applySourceMap = require('vinyl-sourcemaps-apply'); const pify = require('pify'); +const through = require('through2'); const endOfStream = pify(require('end-of-stream')); const labeledStreamSplicer = require('labeled-stream-splicer').obj; +const wrapInStream = require('pumpify').obj; +const Sqrl = require('squirrelly'); +const lavaPack = require('@lavamoat/lavapack'); +const terser = require('terser'); + +const bifyModuleGroups = require('bify-module-groups'); const metamaskrc = require('rc')('metamask', { INFURA_PROJECT_ID: process.env.INFURA_PROJECT_ID, @@ -25,9 +35,8 @@ const metamaskrc = require('rc')('metamask', { 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496', }); -const { version } = require('../../package.json'); - -const packageJSON = require('../../package.json'); +const { streamFlatMap } = require('../stream-flat-map.js'); +const baseManifest = require('../../app/manifest/_base.json'); const { createTask, composeParallel, @@ -37,17 +46,6 @@ const { module.exports = createScriptTasks; -const dependencies = Object.keys( - (packageJSON && packageJSON.dependencies) || {}, -); -const materialUIDependencies = ['@material-ui/core']; -const reactDepenendencies = dependencies.filter((dep) => dep.match(/react/u)); - -const externalDependenciesMap = { - background: ['3box', '@ethereumjs/common', 'unicode-confusables'], - ui: [...materialUIDependencies, ...reactDepenendencies], -}; - function createScriptTasks({ browserPlatforms, livereload }) { // internal tasks const core = { @@ -69,72 +67,43 @@ function createScriptTasks({ browserPlatforms, livereload }) { // production prod: createTasksForBuildJsExtension({ taskPrefix: 'scripts:core:prod' }), }; - const deps = { - background: createTasksForBuildJsDeps({ - label: 'bg-libs', - key: 'background', - }), - ui: createTasksForBuildJsDeps({ label: 'ui-libs', key: 'ui' }), - }; // high level tasks - const prod = composeParallel(deps.background, deps.ui, core.prod); - - const { dev, testDev } = core; - - const test = composeParallel(deps.background, deps.ui, core.test); + const { dev, test, testDev, prod } = core; + return { dev, test, testDev, prod }; - return { prod, dev, testDev, test }; - - function createTasksForBuildJsDeps({ key, label }) { - return createTask( - `scripts:deps:${key}`, - createNormalBundle({ - label, - destFilepath: `${label}.js`, - modulesToExpose: externalDependenciesMap[key], - devMode: false, + function createTasksForBuildJsExtension({ taskPrefix, devMode, testing }) { + const standardEntryPoints = ['background', 'ui', 'phishing-detect']; + const standardSubtask = createTask( + `${taskPrefix}:standardEntryPoints`, + createFactoredBuild({ + entryFiles: standardEntryPoints.map( + (label) => `./app/scripts/${label}.js`, + ), + devMode, + testing, browserPlatforms, }), ); - } - - function createTasksForBuildJsExtension({ taskPrefix, devMode, testing }) { - const standardBundles = [ - 'background', - 'ui', - 'phishing-detect', - 'initSentry', - ]; - - const standardSubtasks = standardBundles.map((label) => { - let extraEntries; - if (devMode && label === 'ui') { - extraEntries = ['./development/require-react-devtools.js']; - } - return createTask( - `${taskPrefix}:${label}`, - createBundleTaskForBuildJsExtensionNormal({ - label, - devMode, - testing, - extraEntries, - }), - ); - }); // inpage must be built before contentscript // because inpage bundle result is included inside contentscript const contentscriptSubtask = createTask( `${taskPrefix}:contentscript`, - createTaskForBuildJsExtensionContentscript({ devMode, testing }), + createTaskForBundleContentscript({ devMode, testing }), ); // this can run whenever const disableConsoleSubtask = createTask( `${taskPrefix}:disable-console`, - createTaskForBuildJsExtensionDisableConsole({ devMode }), + createTaskForBundleDisableConsole({ devMode }), + ); + + // this can run whenever + const installSentrySubtask = createTask( + `${taskPrefix}:sentry`, + createTaskForBundleSentry({ devMode }), ); // task for initiating browser livereload @@ -155,37 +124,28 @@ function createScriptTasks({ browserPlatforms, livereload }) { // make each bundle run in a separate process const allSubtasks = [ - ...standardSubtasks, + standardSubtask, contentscriptSubtask, disableConsoleSubtask, + installSentrySubtask, ].map((subtask) => runInChildProcess(subtask)); - // const allSubtasks = [...standardSubtasks, contentscriptSubtask].map(subtask => (subtask)) // make a parent task that runs each task in a child thread return composeParallel(initiateLiveReload, ...allSubtasks); } - function createBundleTaskForBuildJsExtensionNormal({ - label, - devMode, - testing, - extraEntries, - }) { + function createTaskForBundleDisableConsole({ devMode }) { + const label = 'disable-console'; return createNormalBundle({ label, entryFilepath: `./app/scripts/${label}.js`, destFilepath: `${label}.js`, - extraEntries, - externalDependencies: devMode - ? undefined - : externalDependenciesMap[label], devMode, - testing, browserPlatforms, }); } - function createTaskForBuildJsExtensionDisableConsole({ devMode }) { - const label = 'disable-console'; + function createTaskForBundleSentry({ devMode }) { + const label = 'sentry-install'; return createNormalBundle({ label, entryFilepath: `./app/scripts/${label}.js`, @@ -195,7 +155,8 @@ function createScriptTasks({ browserPlatforms, livereload }) { }); } - function createTaskForBuildJsExtensionContentscript({ devMode, testing }) { + // the "contentscript" bundle contains the "inpage" bundle + function createTaskForBundleContentscript({ devMode, testing }) { const inpage = 'inpage'; const contentscript = 'contentscript'; return composeSeries( @@ -203,9 +164,6 @@ function createScriptTasks({ browserPlatforms, livereload }) { label: inpage, entryFilepath: `./app/scripts/${inpage}.js`, destFilepath: `${inpage}.js`, - externalDependencies: devMode - ? undefined - : externalDependenciesMap[inpage], devMode, testing, browserPlatforms, @@ -214,9 +172,6 @@ function createScriptTasks({ browserPlatforms, livereload }) { label: contentscript, entryFilepath: `./app/scripts/${contentscript}.js`, destFilepath: `${contentscript}.js`, - externalDependencies: devMode - ? undefined - : externalDependenciesMap[contentscript], devMode, testing, browserPlatforms, @@ -225,12 +180,118 @@ function createScriptTasks({ browserPlatforms, livereload }) { } } +function createFactoredBuild({ + entryFiles, + devMode, + testing, + browserPlatforms, +}) { + return async function () { + // create bundler setup and apply defaults + const buildConfiguration = createBuildConfiguration(); + const { bundlerOpts, events } = buildConfiguration; + + // devMode options + const reloadOnChange = Boolean(devMode); + const minify = Boolean(devMode) === false; + + const envVars = getEnvironmentVariables({ devMode, testing }); + setupBundlerDefaults(buildConfiguration, { + devMode, + envVars, + reloadOnChange, + minify, + }); + + // set bundle entries + bundlerOpts.entries = [...entryFiles]; + + // setup bundle factoring with bify-module-groups plugin + Object.assign(bundlerOpts, bifyModuleGroups.plugin.args); + bundlerOpts.plugin = [...bundlerOpts.plugin, [bifyModuleGroups.plugin]]; + + // instrument pipeline + let sizeGroupMap; + events.on('configurePipeline', ({ pipeline }) => { + // to be populated by the group-by-size transform + sizeGroupMap = new Map(); + pipeline.get('groups').unshift( + // factor modules + bifyModuleGroups.groupByFactor({ + entryFileToLabel(filepath) { + return path.parse(filepath).name; + }, + }), + // cap files at 2 mb + bifyModuleGroups.groupBySize({ + sizeLimit: 2e6, + groupingMap: sizeGroupMap, + }), + ); + pipeline.get('vinyl').unshift( + // convert each module group into a stream with a single vinyl file + streamFlatMap((moduleGroup) => { + const filename = `${moduleGroup.label}.js`; + const childStream = wrapInStream( + moduleGroup.stream, + lavaPack({ raw: true, hasExports: true, includePrelude: false }), + source(filename), + ); + return childStream; + }), + buffer(), + ); + // setup bundle destination + browserPlatforms.forEach((platform) => { + const dest = `./dist/${platform}/`; + pipeline.get('dest').push(gulp.dest(dest)); + }); + }); + + // wait for bundle completion for postprocessing + events.on('bundleDone', () => { + const commonSet = sizeGroupMap.get('common'); + // create entry points for each file + for (const [groupLabel, groupSet] of sizeGroupMap.entries()) { + // skip "common" group, they are added tp all other groups + if (groupSet === commonSet) continue; + + switch (groupLabel) { + case 'ui': { + renderHtmlFile('popup', groupSet, commonSet, browserPlatforms); + renderHtmlFile( + 'notification', + groupSet, + commonSet, + browserPlatforms, + ); + renderHtmlFile('home', groupSet, commonSet, browserPlatforms); + break; + } + case 'phishing-detect': { + renderHtmlFile('phishing', groupSet, commonSet, browserPlatforms); + break; + } + case 'background': { + renderHtmlFile('background', groupSet, commonSet, browserPlatforms); + break; + } + default: { + throw new Error(`buildsys - unknown groupLabel "${groupLabel}"`); + } + } + } + }); + + await bundleIt(buildConfiguration); + }; +} + function createNormalBundle({ destFilepath, entryFilepath, extraEntries = [], modulesToExpose, - externalDependencies, devMode, testing, browserPlatforms, @@ -240,10 +301,16 @@ function createNormalBundle({ const buildConfiguration = createBuildConfiguration(); const { bundlerOpts, events } = buildConfiguration; + // devMode options + const reloadOnChange = Boolean(devMode); + const minify = Boolean(devMode) === false; + const envVars = getEnvironmentVariables({ devMode, testing }); setupBundlerDefaults(buildConfiguration, { devMode, envVars, + reloadOnChange, + minify, }); // set bundle entries @@ -256,14 +323,6 @@ function createNormalBundle({ bundlerOpts.require = bundlerOpts.require.concat(modulesToExpose); } - if (externalDependencies) { - // there doesnt seem to be a standard bify option for this - // so we'll put it here but manually call it after bundle - bundlerOpts.manualExternal = bundlerOpts.manualExternal.concat( - externalDependencies, - ); - } - // instrument pipeline events.on('configurePipeline', ({ pipeline }) => { // convert bundle stream to gulp vinyl stream @@ -288,17 +347,18 @@ function createBuildConfiguration() { transform: [], plugin: [], require: [], - // not a standard bify option + // non-standard bify options manualExternal: [], + manualIgnore: [], }; return { bundlerOpts, events }; } -function setupBundlerDefaults(buildConfiguration, { devMode, envVars }) { +function setupBundlerDefaults( + buildConfiguration, + { devMode, envVars, reloadOnChange, minify }, +) { const { bundlerOpts } = buildConfiguration; - // devMode options - const reloadOnChange = Boolean(devMode); - const minify = Boolean(devMode) === false; Object.assign(bundlerOpts, { // source transforms @@ -314,6 +374,11 @@ function setupBundlerDefaults(buildConfiguration, { devMode, envVars }) { debug: true, }); + // ensure react-devtools are not included in non-dev builds + if (!devMode) { + bundlerOpts.manualIgnore.push('react-devtools'); + } + // inject environment variables via node-style `process.env` if (envVars) { bundlerOpts.transform.push([envify(envVars), { global: true }]); @@ -351,17 +416,33 @@ function setupReloadOnChange({ bundlerOpts, events }) { } function setupMinification(buildConfiguration) { + const minifyOpts = { + mangle: { + reserved: ['MetamaskInpageProvider'], + }, + }; const { events } = buildConfiguration; events.on('configurePipeline', ({ pipeline }) => { pipeline.get('minify').push( - terser({ - mangle: { - reserved: ['MetamaskInpageProvider'], - }, - sourceMap: { - content: true, - }, - }), + // this is the "gulp-terser-js" wrapper around the latest version of terser + through.obj( + callbackify(async (file, _enc) => { + const input = { + [file.sourceMap.file]: file.contents.toString(), + }; + const opts = { + sourceMap: { + filename: file.sourceMap.file, + content: file.sourceMap, + }, + ...minifyOpts, + }; + const res = await terser.minify(input, opts); + file.contents = Buffer.from(res.code); + applySourceMap(file, res.map); + return file; + }), + ), ); }); } @@ -385,18 +466,22 @@ function setupSourcemaps(buildConfiguration, { devMode }) { async function bundleIt(buildConfiguration) { const { bundlerOpts, events } = buildConfiguration; const bundler = browserify(bundlerOpts); - // manually apply non-standard option + // manually apply non-standard options bundler.external(bundlerOpts.manualExternal); + bundler.ignore(bundlerOpts.manualIgnore); // output build logs to terminal bundler.on('log', log); // forward update event (used by watchify) bundler.on('update', () => performBundle()); + await performBundle(); async function performBundle() { // this pipeline is created for every bundle // the labels are all the steps you can hook into const pipeline = labeledStreamSplicer([ + 'groups', + [], 'vinyl', [], 'sourcemaps:init', @@ -415,7 +500,11 @@ async function bundleIt(buildConfiguration) { bundleStream.pipe(pipeline); // nothing will consume pipeline, so let it flow pipeline.resume(); + await endOfStream(pipeline); + + // call the completion event to handle any post-processing + events.emit('bundleDone'); } } @@ -427,7 +516,7 @@ function getEnvironmentVariables({ devMode, testing }) { return { METAMASK_DEBUG: devMode, METAMASK_ENVIRONMENT: environment, - METAMASK_VERSION: version, + METAMASK_VERSION: baseManifest.version, NODE_ENV: devMode ? 'development' : 'production', IN_TEST: testing ? 'true' : false, PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY || '', @@ -478,6 +567,20 @@ function getEnvironment({ devMode, testing }) { return 'other'; } +function renderHtmlFile(htmlName, groupSet, commonSet, browserPlatforms) { + const htmlFilePath = `./app/${htmlName}.html`; + const htmlTemplate = readFileSync(htmlFilePath, 'utf8'); + const jsBundles = [...commonSet.values(), ...groupSet.values()].map( + (label) => `./${label}.js`, + ); + const htmlOutput = Sqrl.render(htmlTemplate, { jsBundles }); + browserPlatforms.forEach((platform) => { + const dest = `./dist/${platform}/${htmlName}.html`; + // we dont have a way of creating async events atm + writeFileSync(dest, htmlOutput); + }); +} + function beep() { process.stdout.write('\x07'); } diff --git a/development/build/static.js b/development/build/static.js index 636af1106..300134806 100644 --- a/development/build/static.js +++ b/development/build/static.js @@ -40,9 +40,8 @@ const copyTargets = [ dest: ``, }, { - src: `./app/`, - pattern: `*.html`, - dest: ``, + src: `./app/loading.html`, + dest: `loading.html`, }, { src: `./node_modules/globalthis/dist/browser.js`, @@ -50,12 +49,16 @@ const copyTargets = [ }, { src: `./node_modules/ses/dist/lockdown.cjs`, - dest: `lockdown.js`, + dest: `lockdown-install.js`, }, { - src: `./app/scripts/`, - pattern: `runLockdown.js`, - dest: ``, + src: `./app/scripts/lockdown-run.js`, + dest: `lockdown-run.js`, + }, + { + // eslint-disable-next-line node/no-extraneous-require + src: require.resolve('@lavamoat/lavapack/src/runtime-cjs.js'), + dest: `runtime-cjs.js`, }, ]; diff --git a/development/build/task.js b/development/build/task.js index b6e0f554b..22c70ad4a 100644 --- a/development/build/task.js +++ b/development/build/task.js @@ -71,8 +71,9 @@ function runInChildProcess(task) { let childProcess; // don't run subprocesses in lavamoat for dev mode if main process not run in lavamoat if ( - taskName.includes('scripts:core:dev') && - !process.argv[0].includes('lavamoat') + process.env.npm_lifecycle_event === 'build:dev' || + (taskName.includes('scripts:core:dev') && + !process.argv[0].includes('lavamoat')) ) { childProcess = spawn('yarn', ['build:dev', taskName, '--skip-stats'], { env: process.env, diff --git a/development/metamaskbot-build-announce.js b/development/metamaskbot-build-announce.js index a1f6e3659..26f2174dc 100755 --- a/development/metamaskbot-build-announce.js +++ b/development/metamaskbot-build-announce.js @@ -2,6 +2,7 @@ const { promises: fs } = require('fs'); const path = require('path'); const fetch = require('node-fetch'); +const glob = require('fast-glob'); const VERSION = require('../dist/chrome/manifest.json').version; // eslint-disable-line import/no-unresolved start().catch(console.error); @@ -39,19 +40,15 @@ async function start() { .join(', '); // links to bundle browser builds - const bundles = [ - 'background', - 'ui', - 'inpage', - 'contentscript', - 'ui-libs', - 'bg-libs', - 'phishing-detect', - ]; - const bundleLinks = bundles - .map((bundle) => { - const url = `${BUILD_LINK_BASE}/build-artifacts/source-map-explorer/${bundle}.html`; - return `${bundle}`; + const fileType = '.html'; + const sourceMapRoot = '/build-artifacts/source-map-explorer/'; + const bundleFiles = await glob(`.${sourceMapRoot}*${fileType}`); + const bundleLinks = bundleFiles + .map((bundleFile) => { + const fileName = bundleFile.split(sourceMapRoot)[1]; + const bundleName = fileName.split(fileType)[0]; + const url = `${BUILD_LINK_BASE}${sourceMapRoot}${fileName}`; + return `${bundleName}`; }) .join(', '); diff --git a/development/require-react-devtools.js b/development/require-react-devtools.js deleted file mode 100644 index 9af12aa87..000000000 --- a/development/require-react-devtools.js +++ /dev/null @@ -1 +0,0 @@ -require('react-devtools'); diff --git a/development/sourcemap-validator.js b/development/sourcemap-validator.js index 15feb56f1..504e87e80 100644 --- a/development/sourcemap-validator.js +++ b/development/sourcemap-validator.js @@ -2,6 +2,7 @@ const fs = require('fs'); const path = require('path'); const { SourceMapConsumer } = require('source-map'); const pify = require('pify'); +const { codeFrameColumns } = require('@babel/code-frame'); const fsAsync = pify(fs); @@ -20,13 +21,12 @@ start().catch((error) => { async function start() { const targetFiles = [ - `background.js`, - // `bg-libs`, skipped because source maps are invalid due to browserify bug: https://github.com/browserify/browserify/issues/1971 + `common-0.js`, + `background-0.js`, + `ui-0.js`, + 'phishing-detect-0.js', // `contentscript.js`, skipped because the validator is erroneously sampling the inlined `inpage.js` script `inpage.js`, - 'phishing-detect.js', - `ui.js`, - // `ui-libs.js`, skipped because source maps are invalid due to browserify bug: https://github.com/browserify/browserify/issues/1971 ]; let valid = true; @@ -102,7 +102,6 @@ async function validateSourcemapForFile({ buildName }) { const buildLines = rawBuild.split('\n'); const targetString = 'new Error'; - // const targetString = 'null' const matchesPerLine = buildLines.map((line) => indicesOf(targetString, line), ); @@ -114,26 +113,35 @@ async function validateSourcemapForFile({ buildName }) { // warn if source content is missing if (!result.source) { valid = false; - console.warn( - `!! missing source for position: ${JSON.stringify(position)}`, + const location = { + start: { line: position.line, column: position.column + 1 }, + }; + const codeSample = codeFrameColumns(rawBuild, location, { + message: `missing source for position`, + highlightCode: true, + }); + console.error( + `missing source for position, in bundle "${buildName}"\n${codeSample}`, ); - // const buildLine = buildLines[position.line - 1] - console.warn(` origin in build:`); - console.warn(` ${buildLines[position.line - 2]}`); - console.warn(`-> ${buildLines[position.line - 1]}`); - console.warn(` ${buildLines[position.line - 0]}`); return; } const sourceContent = consumer.sourceContentFor(result.source); const sourceLines = sourceContent.split('\n'); - const line = sourceLines[result.line - 1]; + const sourceLine = sourceLines[result.line - 1]; // this sometimes includes the whole line though we tried to match somewhere in the middle - const portion = line.slice(result.column); - const isMaybeValid = portion.includes(targetString); - if (!isMaybeValid) { + const portion = sourceLine.slice(result.column); + const foundValidSource = portion.includes(targetString); + if (!foundValidSource) { valid = false; + const location = { + start: { line: result.line + 1, column: result.column + 1 }, + }; + const codeSample = codeFrameColumns(sourceContent, location, { + message: `expected to see ${JSON.stringify(targetString)}`, + highlightCode: true, + }); console.error( - `Sourcemap seems invalid:\n${getFencedCode(result.source, line)}`, + `Sourcemap seems invalid, ${result.source}\n${codeSample}`, ); } }); @@ -142,27 +150,6 @@ async function validateSourcemapForFile({ buildName }) { return valid; } -const CODE_FENCE_LENGTH = 80; -const TITLE_PADDING_LENGTH = 1; - -function getFencedCode(filename, code) { - const title = `${' '.repeat(TITLE_PADDING_LENGTH)}${filename}${' '.repeat( - TITLE_PADDING_LENGTH, - )}`; - const openingFenceLength = Math.max( - CODE_FENCE_LENGTH - (filename.length + TITLE_PADDING_LENGTH * 2), - 0, - ); - const startOpeningFenceLength = Math.floor(openingFenceLength / 2); - const endOpeningFenceLength = Math.ceil(openingFenceLength / 2); - const openingFence = `${'='.repeat( - startOpeningFenceLength, - )}${title}${'='.repeat(endOpeningFenceLength)}`; - const closingFence = '='.repeat(CODE_FENCE_LENGTH); - - return `${openingFence}\n${code}\n${closingFence}\n`; -} - function indicesOf(substring, string) { const a = []; let i = -1; diff --git a/development/stream-flat-map.js b/development/stream-flat-map.js new file mode 100644 index 000000000..0e84f3514 --- /dev/null +++ b/development/stream-flat-map.js @@ -0,0 +1,43 @@ +const { PassThrough: ThroughStream } = require('stream'); +// eslint-ignore-next-line node/no-extraneous-require +const duplexify = require('duplexify').obj; + +module.exports = { + streamFlatMap, + asyncGeneratorToStream, +}; + +// returns an async generator that maps each chunk to a stream with the specified +// "entryToStream" mapping fn, and forwards child streams out +// useable with streams.pipeline +function streamFlatMap(entryToStream) { + const duplex = asyncGeneratorToStream(flatMapGenerator); + return duplex; + + async function* flatMapGenerator(source) { + for await (const entry of source) { + const subStream = entryToStream(entry); + yield* subStream; + } + } +} + +// this stupid utility turns an async iterator factory into a duplex stream +function asyncGeneratorToStream(factoryFn) { + const writableStream = new ThroughStream({ objectMode: true }); + const readableStream = new ThroughStream({ objectMode: true }); + const duplex = duplexify(writableStream, readableStream); + const asyncIter = factoryFn(writableStream); + // drain iterator into readable stream + process.nextTick(async () => { + try { + for await (const item of asyncIter) { + readableStream.write(item); + } + readableStream.end(); + } catch (err) { + readableStream.destroy(err); + } + }); + return duplex; +} diff --git a/lavamoat/node/policy.json b/lavamoat/node/policy.json index e744f1175..d9eef720a 100644 --- a/lavamoat/node/policy.json +++ b/lavamoat/node/policy.json @@ -223,11 +223,6 @@ "js-tokens": true } }, - "@babel/parser": { - "globals": { - "BigInt": true - } - }, "@babel/plugin-proposal-async-generator-functions": { "packages": { "@babel/core": true, @@ -805,6 +800,26 @@ "through2": true } }, + "@lavamoat/lavapack": { + "builtin": { + "assert": true, + "buffer.Buffer.from": true, + "path.join": true, + "path.relative": true + }, + "globals": { + "__dirname": true, + "process.cwd": true + }, + "packages": { + "JSONStream": true, + "combine-source-map": true, + "convert-source-map": true, + "json-stable-stringify": true, + "through2": true, + "umd": true + } + }, "@nodelib/fs.scandir": { "builtin": { "fs.lstat": true, @@ -874,7 +889,6 @@ }, "acorn": { "globals": { - "BigInt": true, "define": true } }, @@ -884,9 +898,6 @@ } }, "acorn-node": { - "globals": { - "BigInt": true - }, "packages": { "acorn": true, "acorn-dynamic-import": true, @@ -959,16 +970,6 @@ "buffer-equal": true } }, - "are-we-there-yet": { - "builtin": { - "events.EventEmitter": true, - "util.inherits": true - }, - "packages": { - "delegates": true, - "readable-stream": true - } - }, "arr-diff": { "packages": { "arr-flatten": true, @@ -1091,6 +1092,13 @@ "pascalcase": true } }, + "bify-module-groups": { + "packages": { + "pify": true, + "pump": true, + "through2": true + } + }, "bl": { "builtin": { "util.inherits": true @@ -1321,7 +1329,6 @@ "anymatch": true, "async-each": true, "braces": true, - "fsevents": true, "glob-parent": true, "inherits": true, "is-binary-path": true, @@ -1573,16 +1580,6 @@ "through2": true } }, - "detect-libc": { - "builtin": { - "child_process.spawnSync": true, - "fs.readdirSync": true, - "os.platform": true - }, - "globals": { - "process.env": true - } - }, "detective": { "packages": { "acorn-node": true, @@ -1670,10 +1667,7 @@ "es-abstract": { "globals": { "AggregateError": true, - "Atomics": true, - "BigInt": true, "FinalizationRegistry": true, - "SharedArrayBuffer": true, "WeakRef": true }, "packages": { @@ -2026,45 +2020,6 @@ "process.version": true } }, - "fsevents": { - "builtin": { - "events.EventEmitter": true, - "fs.stat": true, - "path.join": true, - "util.inherits": true - }, - "globals": { - "__dirname": true, - "process.nextTick": true, - "process.platform": true, - "setImmediate": true - }, - "native": true, - "packages": { - "node-pre-gyp": true - } - }, - "gauge": { - "builtin": { - "util.format": true - }, - "globals": { - "clearInterval": true, - "process": true, - "setImmediate": true, - "setInterval": true - }, - "packages": { - "aproba": true, - "console-control-strings": true, - "has-unicode": true, - "object-assign": true, - "signal-exit": true, - "string-width": true, - "strip-ansi": true, - "wide-align": true - } - }, "get-assigned-identifiers": { "builtin": { "assert.equal": true @@ -2375,26 +2330,6 @@ "through2": true } }, - "gulp-terser-js": { - "builtin": { - "fs.readFileSync": true, - "path.basename": true, - "path.resolve": true - }, - "globals": { - "Buffer.from": true, - "console.error": true, - "console.log": true, - "process.stdout.columns": true - }, - "packages": { - "plugin-error": true, - "source-map": true, - "terser": true, - "through2": true, - "vinyl-sourcemaps-apply": true - } - }, "gulp-watch": { "builtin": { "path.dirname": true, @@ -2445,16 +2380,6 @@ "process.argv": true } }, - "has-unicode": { - "builtin": { - "os.type": true - }, - "globals": { - "process.env.LANG": true, - "process.env.LC_ALL": true, - "process.env.LC_CTYPE": true - } - }, "has-value": { "packages": { "get-value": true, @@ -2608,11 +2533,6 @@ "is-plain-object": true } }, - "is-fullwidth-code-point": { - "packages": { - "number-is-nan": true - } - }, "is-glob": { "packages": { "is-extglob": true @@ -2997,56 +2917,6 @@ "setTimeout": true } }, - "node-pre-gyp": { - "builtin": { - "events.EventEmitter": true, - "fs.existsSync": true, - "fs.readFileSync": true, - "fs.renameSync": true, - "path.dirname": true, - "path.existsSync": true, - "path.join": true, - "path.resolve": true, - "url.parse": true, - "url.resolve": true, - "util.inherits": true - }, - "globals": { - "__dirname": true, - "console.log": true, - "process.arch": true, - "process.cwd": true, - "process.env": true, - "process.platform": true, - "process.version.substr": true, - "process.versions": true - }, - "packages": { - "detect-libc": true, - "nopt": true, - "npmlog": true, - "rimraf": true, - "semver": true - } - }, - "nopt": { - "builtin": { - "path": true, - "stream.Stream": true, - "url": true - }, - "globals": { - "console": true, - "process.argv": true, - "process.env.DEBUG_NOPT": true, - "process.env.NOPT_DEBUG": true, - "process.platform": true - }, - "packages": { - "abbrev": true, - "osenv": true - } - }, "normalize-path": { "packages": { "remove-trailing-separator": true @@ -3062,22 +2932,6 @@ "once": true } }, - "npmlog": { - "builtin": { - "events.EventEmitter": true, - "util": true - }, - "globals": { - "process.nextTick": true, - "process.stderr": true - }, - "packages": { - "are-we-there-yet": true, - "console-control-strings": true, - "gauge": true, - "set-blocking": true - } - }, "object-copy": { "packages": { "copy-descriptor": true, @@ -3090,7 +2944,6 @@ "util.inspect": true }, "globals": { - "BigInt": true, "HTMLElement": true } }, @@ -3145,54 +2998,6 @@ "readable-stream": true } }, - "os-homedir": { - "builtin": { - "os.homedir": true - }, - "globals": { - "process.env": true, - "process.getuid": true, - "process.platform": true - } - }, - "os-tmpdir": { - "globals": { - "process.env.SystemRoot": true, - "process.env.TEMP": true, - "process.env.TMP": true, - "process.env.TMPDIR": true, - "process.env.windir": true, - "process.platform": true - } - }, - "osenv": { - "builtin": { - "child_process.exec": true, - "path": true - }, - "globals": { - "process.env.COMPUTERNAME": true, - "process.env.ComSpec": true, - "process.env.EDITOR": true, - "process.env.HOSTNAME": true, - "process.env.PATH": true, - "process.env.PROMPT": true, - "process.env.PS1": true, - "process.env.Path": true, - "process.env.SHELL": true, - "process.env.USER": true, - "process.env.USERDOMAIN": true, - "process.env.USERNAME": true, - "process.env.VISUAL": true, - "process.env.path": true, - "process.nextTick": true, - "process.platform": true - }, - "packages": { - "os-homedir": true, - "os-tmpdir": true - } - }, "parent-module": { "packages": { "callsites": true @@ -3775,12 +3580,6 @@ "process": true } }, - "set-blocking": { - "globals": { - "process.stderr": true, - "process.stdout": true - } - }, "set-value": { "packages": { "extend-shallow": true, @@ -3910,6 +3709,15 @@ "extend-shallow": true } }, + "squirrelly": { + "builtin": { + "fs.existsSync": true, + "fs.readFileSync": true, + "path.dirname": true, + "path.extname": true, + "path.resolve": true + } + }, "static-eval": { "packages": { "escodegen": true @@ -3974,7 +3782,6 @@ }, "string-width": { "packages": { - "code-point-at": true, "emoji-regex": true, "is-fullwidth-code-point": true, "strip-ansi": true @@ -4130,9 +3937,19 @@ "Buffer.from": true, "atob": true, "btoa": true, - "define": true + "console.log": true, + "console.warn": true, + "define": true, + "process.argv": true, + "process.exit": true, + "process.platform": true, + "process.stderr.write": true, + "process.stdin.on": true, + "process.stdin.resume": true, + "process.stdin.setEncoding": true }, "packages": { + "acorn": true, "source-map": true } }, @@ -4531,11 +4348,6 @@ "isexe": true } }, - "wide-align": { - "packages": { - "string-width": true - } - }, "write": { "builtin": { "fs.createWriteStream": true, diff --git a/package.json b/package.json index 210687128..f4a1ea337 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "scripts": { "setup": "yarn install && yarn setup:postinstall", "setup:postinstall": "yarn patch-package && yarn allow-scripts", - "start": "node development/build/index.js dev", + "start": "yarn build:dev dev", "start:lavamoat": "yarn build dev", "dist": "yarn build prod", "build": "lavamoat development/build/index.js", @@ -191,6 +191,7 @@ "readable-stream": "^2.3.3", "redux": "^4.0.5", "redux-thunk": "^2.3.0", + "requirejs": "^2.3.6", "reselect": "^3.0.1", "rpc-cap": "^3.2.1", "safe-event-emitter": "^1.0.1", @@ -204,6 +205,7 @@ "web3-stream-provider": "^4.0.0" }, "devDependencies": { + "@babel/code-frame": "^7.12.13", "@babel/core": "^7.12.1", "@babel/eslint-parser": "^7.13.14", "@babel/eslint-plugin": "^7.12.1", @@ -216,6 +218,7 @@ "@babel/preset-react": "^7.0.0", "@babel/register": "^7.5.5", "@lavamoat/allow-scripts": "^1.0.6", + "@lavamoat/lavapack": "^1.0.4", "@metamask/auto-changelog": "^2.1.0", "@metamask/eslint-config": "^6.0.0", "@metamask/eslint-config-jest": "^6.0.0", @@ -237,7 +240,10 @@ "@types/react": "^16.9.53", "addons-linter": "1.14.0", "babelify": "^10.0.0", + "bify-module-groups": "^1.0.0", + "bify-vinyl-gator": "^1.0.0", "brfs": "^2.0.2", + "browser-pack": "^6.1.0", "browserify": "^16.5.1", "chalk": "^3.0.0", "chromedriver": "^79.0.0", @@ -247,6 +253,7 @@ "css-loader": "^2.1.1", "css-to-xpath": "^0.1.0", "del": "^3.0.0", + "duplexify": "^4.1.1", "enzyme": "^3.10.0", "enzyme-adapter-react-16": "^1.15.1", "eslint": "^7.23.0", @@ -273,7 +280,6 @@ "gulp-rtlcss": "^1.4.0", "gulp-sourcemaps": "^2.6.0", "gulp-stylelint": "^13.0.0", - "gulp-terser-js": "^5.2.2", "gulp-watch": "^5.0.1", "gulp-zip": "^4.0.0", "history": "^5.0.0", @@ -293,6 +299,7 @@ "prettier": "^2.2.1", "prettier-plugin-sort-json": "^0.0.1", "proxyquire": "^2.1.3", + "pumpify": "^2.0.1", "randomcolor": "^0.5.4", "rc": "^1.2.8", "react-devtools": "^4.10.1", @@ -308,13 +315,16 @@ "sinon": "^9.0.0", "source-map": "^0.7.2", "source-map-explorer": "^2.4.2", + "squirrelly": "^8.0.8", "string.prototype.matchall": "^4.0.2", "style-loader": "^0.21.0", "stylelint": "^13.6.1", - "through2": "^2.0.3", + "terser": "^5.7.0", + "through2": "^4.0.2", "ttest": "^2.1.1", "vinyl-buffer": "^1.0.1", "vinyl-source-stream": "^2.0.0", + "vinyl-sourcemaps-apply": "^0.2.1", "watchify": "^3.11.1", "webpack": "^4.41.6", "yargs": "^17.0.1" diff --git a/patches/squirrelly+8.0.8.patch b/patches/squirrelly+8.0.8.patch new file mode 100644 index 000000000..f43a50ef5 --- /dev/null +++ b/patches/squirrelly+8.0.8.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/squirrelly/dist/squirrelly.cjs.js b/node_modules/squirrelly/dist/squirrelly.cjs.js +index 7908a34..044e348 100644 +--- a/node_modules/squirrelly/dist/squirrelly.cjs.js ++++ b/node_modules/squirrelly/dist/squirrelly.cjs.js +@@ -5,7 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true }); + // TODO: allow '-' to trim up until newline. Use [^\S\n\r] instead of \s + // TODO: only include trimLeft polyfill if not in ES6 + /* END TYPES */ +-var promiseImpl = new Function('return this')().Promise; ++var promiseImpl = globalThis.Promise; + var asyncFunc = false; + try { + asyncFunc = new Function('return (async function(){}).constructor')(); diff --git a/patches/watchify+3.11.1.patch b/patches/watchify+3.11.1.patch new file mode 100644 index 000000000..cf3e489ad --- /dev/null +++ b/patches/watchify+3.11.1.patch @@ -0,0 +1,38 @@ +diff --git a/node_modules/watchify/index.js b/node_modules/watchify/index.js +index 0753b9f..4fea9e1 100644 +--- a/node_modules/watchify/index.js ++++ b/node_modules/watchify/index.js +@@ -58,33 +58,6 @@ function watchify (b, opts) { + if (pkgcache) pkgcache[file] = pkg; + }); + +- b.on('reset', reset); +- reset(); +- +- function reset () { +- var time = null; +- var bytes = 0; +- b.pipeline.get('record').on('end', function () { +- time = Date.now(); +- }); +- +- b.pipeline.get('wrap').push(through(write, end)); +- function write (buf, enc, next) { +- bytes += buf.length; +- this.push(buf); +- next(); +- } +- function end () { +- var delta = Date.now() - time; +- b.emit('time', delta); +- b.emit('bytes', bytes); +- b.emit('log', bytes + ' bytes written (' +- + (delta / 1000).toFixed(2) + ' seconds)' +- ); +- this.push(null); +- } +- } +- + var fwatchers = {}; + var fwatcherFiles = {}; + var ignoredFiles = {}; diff --git a/test/unit-global/frozenPromise.test.js b/test/unit-global/frozenPromise.test.js index f96af0d2a..b41362266 100644 --- a/test/unit-global/frozenPromise.test.js +++ b/test/unit-global/frozenPromise.test.js @@ -1,7 +1,7 @@ // Should occur before anything else import './globalPatch'; import 'ses/lockdown'; -import '../../app/scripts/runLockdown'; +import '../../app/scripts/lockdown-run'; import { strict as assert } from 'assert'; /* eslint-disable-line import/first,import/order */ describe('Promise global is immutable', function () { diff --git a/yarn.lock b/yarn.lock index 20e5dc2c4..a3fc83e86 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2567,6 +2567,18 @@ semver "^7.3.4" yargs "^16.2.0" +"@lavamoat/lavapack@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@lavamoat/lavapack/-/lavapack-1.0.4.tgz#e72d6b29fa70da8236a127c1d95cb581cda6941e" + integrity sha512-Zhcn+eJyHIS4AAmN9IIjs8WCh12Q7NpFXXz0pI3Y54uknTdx5TPlwr3ARKf0jEXDOWNok/TuK2uPld54BSG/FQ== + dependencies: + JSONStream "^1.3.5" + combine-source-map "^0.8.0" + convert-source-map "^1.7.0" + json-stable-stringify "^1.0.1" + through2 "^4.0.2" + umd "^3.0.3" + "@lavamoat/preinstall-always-fail@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@lavamoat/preinstall-always-fail/-/preinstall-always-fail-1.0.0.tgz#e78a6e3d9e212a4fef869ec37d4f5fb498dea373" @@ -4299,7 +4311,7 @@ optionalDependencies: text-encoding "^0.6.4" -JSONStream@^1.0.3: +JSONStream@^1.0.3, JSONStream@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== @@ -6435,6 +6447,33 @@ better-opn@^2.0.0: dependencies: open "^7.0.3" +bify-module-groups@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bify-module-groups/-/bify-module-groups-1.0.0.tgz#6fba8f96a8b0f9e8f0b04035650fd56249b6119d" + integrity sha512-JAAkE9L5vZoALCEqawXipQNlDn3D0nUyjt0cHgRXj0Kce2RNLQsBxA6wTmnYpQDna6g6VVyC8IUi3n02ppmbhA== + dependencies: + bify-packagedata-stream "1.0.0" + pump "^3.0.0" + through2 "^3.0.1" + +bify-packagedata-stream@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bify-packagedata-stream/-/bify-packagedata-stream-1.0.0.tgz#a6dbdcba64f9bf1c87bdc02ba9586fff7b94ccb3" + integrity sha512-ckOCceDpAOySFrt89saOShpVbP/iQbmZeWlYSxZV2e3HPTPhcd3JSudMJZhpsihQTyZut39efDo4+8aOb4vo2w== + dependencies: + module-name-from-path "git+https://git@github.com/kumavis/module-name-from-path.git" + resolve-package-path "^1.2.7" + through2 "^3.0.0" + +bify-vinyl-gator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bify-vinyl-gator/-/bify-vinyl-gator-1.0.0.tgz#aa1ce5c6a5829c75250fea6b04ec6a45c558efde" + integrity sha512-mGR/U+veqIrMWRWV1TUayNEmSIhaGDggYLwIBwDA7v2bTSHrEZcyyLs6FN3cF2cuyCzvpV1w4eH6P/So0nhCbA== + dependencies: + requirejs "^2.3.6" + through2 "^4.0.2" + vinyl "^2.2.1" + big-integer@1.6.36: version "1.6.36" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.36.tgz#78631076265d4ae3555c04f85e7d9d2f3a071a36" @@ -6792,7 +6831,7 @@ brorand@^1.0.1, brorand@^1.0.5, brorand@^1.1.0: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= -browser-pack@^6.0.1: +browser-pack@^6.0.1, browser-pack@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.1.0.tgz#c34ba10d0b9ce162b5af227c7131c92c2ecd5774" integrity sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA== @@ -9556,6 +9595,16 @@ duplexify@^3.1.2, duplexify@^3.4.2: readable-stream "^2.0.0" stream-shift "^1.0.0" +duplexify@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.1.tgz#7027dc374f157b122a8ae08c2d3ea4d2d953aa61" + integrity sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA== + dependencies: + end-of-stream "^1.4.1" + inherits "^2.0.3" + readable-stream "^3.1.1" + stream-shift "^1.0.0" + each-props@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/each-props/-/each-props-1.3.2.tgz#ea45a414d16dd5cfa419b1a81720d5ca06892333" @@ -13225,17 +13274,6 @@ gulp-stylelint@^13.0.0: strip-ansi "^6.0.0" through2 "^3.0.1" -gulp-terser-js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/gulp-terser-js/-/gulp-terser-js-5.2.2.tgz#3d93db9b2b83f35dfcc5b209af6b1762756eb6a3" - integrity sha512-4ull0HzTWeWjRPiGmAFmdhRcEDOG+r7aXivNHOBQzElLzMaeVKQwmCPDi2juBzUUkjAkPkKb1jHVoJN/PKTvcA== - dependencies: - plugin-error "^1.0.1" - source-map "^0.7.3" - terser "^4.6.12" - through2 "^3.0.1" - vinyl-sourcemaps-apply "^0.2.1" - gulp-watch@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/gulp-watch/-/gulp-watch-5.0.1.tgz#83d378752f5bfb46da023e73c17ed1da7066215d" @@ -18548,6 +18586,10 @@ module-deps@^6.0.0: through2 "^2.0.0" xtend "^4.0.0" +"module-name-from-path@git+https://git@github.com/kumavis/module-name-from-path.git": + version "1.0.4" + resolved "git+https://git@github.com/kumavis/module-name-from-path.git#fd9c592663a1af6cc48b1be7b8045ea547fca79a" + module-not-found-error@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/module-not-found-error/-/module-not-found-error-1.0.1.tgz#cf8b4ff4f29640674d6cdd02b0e3bc523c2bbdc0" @@ -21605,6 +21647,15 @@ pumpify@^1.3.3, pumpify@^1.3.5: inherits "^2.0.1" pump "^1.0.0" +pumpify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-2.0.1.tgz#abfc7b5a621307c728b551decbbefb51f0e4aa1e" + integrity sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw== + dependencies: + duplexify "^4.1.1" + inherits "^2.0.3" + pump "^3.0.0" + punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -22354,7 +22405,7 @@ readable-stream@1.1.x, readable-stream@^1.0.33: isarray "0.0.1" string_decoder "~0.10.x" -"readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.0.1, readable-stream@^3.0.2, readable-stream@^3.0.5, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: +"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.1, readable-stream@^3.0.2, readable-stream@^3.0.5, readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -22919,6 +22970,11 @@ require-uncached@^1.0.2: caller-path "^0.1.0" resolve-from "^1.0.0" +requirejs@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9" + integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg== + reselect@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" @@ -22971,6 +23027,14 @@ resolve-options@^1.1.0: dependencies: value-or-function "^3.0.0" +resolve-package-path@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-1.2.7.tgz#2a7bc37ad96865e239330e3102c31322847e652e" + integrity sha512-fVEKHGeK85bGbVFuwO9o1aU0n3vqQGrezPc51JGu9UTXpFQfWq5qCeKxyaRUSvephs+06c5j5rPq/dzHGEo8+Q== + dependencies: + path-root "^0.1.1" + resolve "^1.10.0" + resolve-pathname@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" @@ -24188,7 +24252,7 @@ source-map-support@^0.4.15: dependencies: source-map "^0.5.6" -source-map-support@^0.5.11, source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.4: +source-map-support@^0.5.11, source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.19, source-map-support@~0.5.4: version "0.5.19" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== @@ -24206,7 +24270,7 @@ source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, sourc resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@0.X, source-map@^0.7.2, source-map@^0.7.3: +source-map@0.X, source-map@^0.7.2, source-map@^0.7.3, source-map@~0.7.2: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== @@ -24313,6 +24377,11 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= +squirrelly@^8.0.8: + version "8.0.8" + resolved "https://registry.yarnpkg.com/squirrelly/-/squirrelly-8.0.8.tgz#d6704650b2170b8040d5de5bff9fa69cb62b5e0f" + integrity sha512-7dyZJ9Gw86MmH0dYLiESsjGOTj6KG8IWToTaqBuB6LwPI+hyNb6mbQaZwrfnAQ4cMDnSWMUvX/zAYDLTSWLk/w== + sshpk@^1.7.0: version "1.16.1" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" @@ -25257,7 +25326,7 @@ terser-webpack-plugin@^3.0.0: terser "^4.8.0" webpack-sources "^1.4.3" -terser@^4.1.2, terser@^4.6.12, terser@^4.6.3, terser@^4.8.0: +terser@^4.1.2, terser@^4.6.3, terser@^4.8.0: version "4.8.0" resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== @@ -25266,6 +25335,15 @@ terser@^4.1.2, terser@^4.6.12, terser@^4.6.3, terser@^4.8.0: source-map "~0.6.1" source-map-support "~0.5.12" +terser@^5.7.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.0.tgz#a761eeec206bc87b605ab13029876ead938ae693" + integrity sha512-HP5/9hp2UaZt5fYkuhNBR8YyRcT8juw8+uFbAme53iN9hblvKnLUTKkmwJG6ocWpIKf8UK4DoeWG4ty0J6S6/g== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.19" + test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -25323,6 +25401,13 @@ through2@^3.0.0, through2@^3.0.1: dependencies: readable-stream "2 || 3" +through2@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" + integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== + dependencies: + readable-stream "3" + through@2, "through@>=2.2.7 <3", through@^2.3.6, through@~2.3, through@~2.3.1, through@~2.3.4, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -25868,7 +25953,7 @@ typical@^5.0.0: resolved "https://registry.yarnpkg.com/typical/-/typical-5.1.0.tgz#7116ca103caf2574985fc84fbaa8fd0ee5ea1684" integrity sha512-t5Ik8UAwBal1P1XzuVE4dc+RYQZicLUGJdvqr/vdqsED7SQECgsGBylldSsfWZL7RQjxT3xhQcKHWhLaVSR6YQ== -umd@^3.0.0: +umd@^3.0.0, umd@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.3.tgz#aa9fe653c42b9097678489c01000acb69f0b26cf" integrity sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow== @@ -26566,6 +26651,18 @@ vinyl@^2.0.0, vinyl@^2.1.0, vinyl@^2.2.0: remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" +vinyl@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974" + integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw== + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + vm-browserify@^1.0.0, vm-browserify@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"