Experimental: Serverless Trace target (#8246)

* Experimental: Serverless Trace target
The Serverless Trace target produces Serverless-handler wrapped entrypoints, but does not bundle all of `node_modules`.

This behavior increases bundling performance to be more akin to `target: 'server'`.

This mode is expected to be used with smart platforms (like [ZEIT Now](https://zeit.co/now) that can trace a program to its minimum dependencies.

* Use more generic variables

* Add asset relocator for production mode of serverless trace

* Verify Firebase compatiblity

* Revert "Add asset relocator for production mode of serverless trace"

This reverts commit 8404f1dcf28b60edab41a56c94b38dcd3fddec20.

* Add serverless trace tests

* Add _isLikeServerless helper

* Make constants

* Fix export

* Update packages/next-server/server/config.ts

Co-Authored-By: JJ Kasper <jj@jjsweb.site>

* Use a global helper for is like serverless

* Update import for isTargetLikeServerless

* Update packages/next/build/index.ts

Co-Authored-By: JJ Kasper <jj@jjsweb.site>
This commit is contained in:
Joe Haddad 2019-08-05 18:26:20 -04:00 committed by GitHub
parent f40a90159b
commit b31c296730
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 859 additions and 82 deletions

View file

@ -81,6 +81,7 @@
"execa": "2.0.3",
"express": "4.17.0",
"faunadb": "2.6.1",
"firebase": "6.3.4",
"fs-extra": "7.0.1",
"get-port": "5.0.0",
"isomorphic-unfetch": "3.0.0",

View file

@ -1,9 +1,10 @@
import os from 'os'
import findUp from 'find-up'
import os from 'os'
import { CONFIG_FILE } from '../lib/constants'
import { execOnce } from '../lib/utils'
const targets = ['server', 'serverless']
const targets = ['server', 'serverless', 'experimental-serverless-trace']
const defaultConfig: { [key: string]: any } = {
env: [],
@ -120,10 +121,12 @@ export default function loadConfig(
}
if (
userConfig.target === 'serverless' &&
userConfig.target &&
userConfig.target !== 'server' &&
userConfig.publicRuntimeConfig &&
Object.keys(userConfig.publicRuntimeConfig).length !== 0
) {
// TODO: change error message tone to "Only compatible with [fat] server mode"
throw new Error(
'Cannot use publicRuntimeConfig with target=serverless https://err.sh/zeit/next.js/serverless-publicRuntimeConfig'
)
@ -134,3 +137,9 @@ export default function loadConfig(
return defaultConfig
}
export function isTargetLikeServerless(target: string) {
const isServerless = target === 'serverless'
const isServerlessTrace = target === 'experimental-serverless-trace'
return isServerless || isServerlessTrace
}

View file

@ -1,13 +1,12 @@
import compression from 'compression'
import fs from 'fs'
import { IncomingMessage, ServerResponse } from 'http'
import { join, resolve, sep } from 'path'
import { parse as parseQs, ParsedUrlQuery } from 'querystring'
import { parse as parseUrl, UrlWithParsedQuery } from 'url'
import compression from 'compression'
import {
BUILD_ID_FILE,
BUILD_MANIFEST,
CLIENT_PUBLIC_FILES_PATH,
CLIENT_STATIC_FILES_PATH,
CLIENT_STATIC_FILES_RUNTIME,
@ -25,12 +24,12 @@ import {
import * as envConfig from '../lib/runtime-config'
import { NextApiRequest, NextApiResponse } from '../lib/utils'
import { apiResolver } from './api-utils'
import loadConfig from './config'
import loadConfig, { isTargetLikeServerless } from './config'
import { recursiveReadDirSync } from './lib/recursive-readdir-sync'
import { loadComponents, LoadComponentsReturnType } from './load-components'
import { renderToHTML } from './render'
import { getPagePath } from './require'
import Router, { route, Route, RouteMatch, Params } from './router'
import Router, { Params, route, Route, RouteMatch } from './router'
import { sendHTML } from './send-html'
import { serveStatic } from './serve-static'
import { isBlockedPage, isInternalUrl } from './utils'
@ -98,7 +97,9 @@ export default class Server {
this.publicDir = join(this.dir, CLIENT_PUBLIC_FILES_PATH)
this.pagesManifest = join(
this.distDir,
this.nextConfig.target || 'server',
this.nextConfig.target === 'server'
? SERVER_DIRECTORY
: SERVERLESS_DIRECTORY,
PAGES_MANIFEST
)
@ -131,7 +132,7 @@ export default class Server {
this.renderOpts.runtimeConfig = publicRuntimeConfig
}
if (compress && this.nextConfig.target !== 'serverless') {
if (compress && this.nextConfig.target === 'server') {
this.compression = compression() as Middleware
}
@ -319,7 +320,7 @@ export default class Server {
return this.render404(req, res)
}
if (!this.renderOpts.dev && this.nextConfig.target === 'serverless') {
if (!this.renderOpts.dev && this._isLikeServerless) {
const mod = require(resolverFunction)
if (typeof mod.default === 'function') {
return mod.default(req, res)
@ -342,7 +343,7 @@ export default class Server {
return getPagePath(
pathname,
this.distDir,
this.nextConfig.target === 'serverless',
this._isLikeServerless,
this.renderOpts.dev
)
}
@ -352,9 +353,7 @@ export default class Server {
const publicFiles = recursiveReadDirSync(this.publicDir)
const serverBuildPath = join(
this.distDir,
this.nextConfig.target === 'serverless'
? SERVERLESS_DIRECTORY
: SERVER_DIRECTORY
this._isLikeServerless ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY
)
const pagesManifest = require(join(serverBuildPath, PAGES_MANIFEST))
@ -458,8 +457,7 @@ export default class Server {
pathname: string,
query: ParsedUrlQuery = {}
) {
const serverless =
!this.renderOpts.dev && this.nextConfig.target === 'serverless'
const serverless = !this.renderOpts.dev && this._isLikeServerless
// try serving a static AMP version first
if (query.amp) {
try {
@ -708,4 +706,8 @@ export default class Server {
throw err
}
}
private get _isLikeServerless(): boolean {
return isTargetLikeServerless(this.nextConfig.target)
}
}

View file

@ -1,6 +1,8 @@
import { isTargetLikeServerless } from 'next-server/dist/server/config'
import { join } from 'path'
import { stringify } from 'querystring'
import { PAGES_DIR_ALIAS, DOT_NEXT_ALIAS, API_ROUTE } from '../lib/constants'
import { API_ROUTE, DOT_NEXT_ALIAS, PAGES_DIR_ALIAS } from '../lib/constants'
import { ServerlessLoaderQuery } from './webpack/loaders/next-serverless-loader'
type PagesMapping = {
@ -45,7 +47,7 @@ type Entrypoints = {
export function createEntrypoints(
pages: PagesMapping,
target: 'server' | 'serverless',
target: 'server' | 'serverless' | 'experimental-serverless-trace',
buildId: string,
dynamicBuildId: boolean,
config: any
@ -72,7 +74,9 @@ export function createEntrypoints(
const bundlePath = join('static', buildId, 'pages', bundleFile)
if (isApiRoute && target === 'serverless') {
const isLikeServerless = isTargetLikeServerless(target)
if (isApiRoute && isLikeServerless) {
const serverlessLoaderOptions: ServerlessLoaderQuery = {
page,
absolutePagePath,
@ -83,11 +87,7 @@ export function createEntrypoints(
)}!`
} else if (isApiRoute || target === 'server') {
server[bundlePath] = [absolutePagePath]
} else if (
target === 'serverless' &&
page !== '/_app' &&
page !== '/_document'
) {
} else if (isLikeServerless && page !== '/_app' && page !== '/_document') {
const serverlessLoaderOptions: ServerlessLoaderQuery = {
page,
absolutePagePath,

View file

@ -1,18 +1,25 @@
import { Sema } from 'async-sema'
import chalk from 'chalk'
import fs from 'fs'
import mkdirpOrig from 'mkdirp'
import {
CHUNK_GRAPH_MANIFEST,
PAGES_MANIFEST,
PHASE_PRODUCTION_BUILD,
SERVER_DIRECTORY,
SERVERLESS_DIRECTORY,
PAGES_MANIFEST,
CHUNK_GRAPH_MANIFEST,
PHASE_PRODUCTION_BUILD,
} from 'next-server/constants'
import loadConfig from 'next-server/next-config'
import loadConfig, {
isTargetLikeServerless,
} from 'next-server/dist/server/config'
import nanoid from 'next/dist/compiled/nanoid/index.js'
import path from 'path'
import fs from 'fs'
import { promisify } from 'util'
import workerFarm from 'worker-farm'
import formatWebpackMessages from '../client/dev/error-overlay/format-webpack-messages'
import { recursiveDelete } from '../lib/recursive-delete'
import { recursiveReadDir } from '../lib/recursive-readdir'
import { verifyTypeScriptSetup } from '../lib/verifyTypeScriptSetup'
import { CompilerResult, runCompiler } from './compiler'
import { createEntrypoints, createPagesMapping } from './entries'
@ -25,9 +32,9 @@ import {
getFileForPage,
getPageSizeInKb,
getSpecifiedPages,
printTreeView,
PageInfo,
hasCustomAppGetInitialProps,
PageInfo,
printTreeView,
} from './utils'
import getBaseWebpackConfig from './webpack-config'
import {
@ -35,10 +42,6 @@ import {
getPageChunks,
} from './webpack/plugins/chunk-graph-plugin'
import { writeBuildId } from './write-build-id'
import { recursiveReadDir } from '../lib/recursive-readdir'
import mkdirpOrig from 'mkdirp'
import workerFarm from 'worker-farm'
import { Sema } from 'async-sema'
const fsUnlink = promisify(fs.unlink)
const fsRmdir = promisify(fs.rmdir)
@ -75,11 +78,13 @@ export default async function build(dir: string, conf = null): Promise<void> {
isFlyingShuttle || process.env.__NEXT_BUILDER_EXPERIMENTAL_PAGE
)
const isLikeServerless = isTargetLikeServerless(target)
if (selectivePageBuilding && target !== 'serverless') {
throw new Error(
`Cannot use ${
isFlyingShuttle ? 'flying shuttle' : '`now dev`'
} without the serverless target.`
} without the \`serverless\` target.`
)
}
@ -199,7 +204,8 @@ export default async function build(dir: string, conf = null): Promise<void> {
])
let result: CompilerResult = { warnings: [], errors: [] }
if (target === 'serverless') {
// TODO: why do we need this?? https://github.com/zeit/next.js/issues/8253
if (isLikeServerless) {
const clientResult = await runCompiler(configs[0])
// Fail build if clientResult contains errors
if (clientResult.errors.length > 0) {
@ -273,7 +279,7 @@ export default async function build(dir: string, conf = null): Promise<void> {
const pageKeys = Object.keys(mappedPages)
const manifestPath = path.join(
distDir,
target === 'serverless' ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY,
isLikeServerless ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY,
PAGES_MANIFEST
)
@ -303,12 +309,12 @@ export default async function build(dir: string, conf = null): Promise<void> {
const actualPage = page === '/' ? '/index' : page
const size = await getPageSizeInKb(actualPage, distPath, buildId)
const bundleRelative = path.join(
target === 'serverless' ? 'pages' : `static/${buildId}/pages`,
isLikeServerless ? 'pages' : `static/${buildId}/pages`,
actualPage + '.js'
)
const serverBundle = path.join(
distPath,
target === 'serverless' ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY,
isLikeServerless ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY,
bundleRelative
)
@ -324,7 +330,7 @@ export default async function build(dir: string, conf = null): Promise<void> {
if (nonReservedPage && customAppGetInitialProps === undefined) {
customAppGetInitialProps = hasCustomAppGetInitialProps(
target === 'serverless'
isLikeServerless
? serverBundle
: path.join(
distPath,
@ -437,7 +443,7 @@ export default async function build(dir: string, conf = null): Promise<void> {
for (const file of toMove) {
const orig = path.join(exportOptions.outdir, file)
const dest = path.join(serverDir, file)
const relativeDest = (target === 'serverless'
const relativeDest = (isLikeServerless
? path.join('pages', file)
: path.join('static', buildId, 'pages', file)
).replace(/\\/g, '/')
@ -465,9 +471,5 @@ export default async function build(dir: string, conf = null): Promise<void> {
await flyingShuttle.save(allStaticPages, pageInfos)
}
printTreeView(
Object.keys(allMappedPages),
allPageInfos,
target === 'serverless'
)
printTreeView(Object.keys(allMappedPages), allPageInfos, isLikeServerless)
}

View file

@ -1,10 +1,10 @@
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'
import fs from 'fs'
import {
CLIENT_STATIC_FILES_RUNTIME_MAIN,
CLIENT_STATIC_FILES_RUNTIME_WEBPACK,
REACT_LOADABLE_MANIFEST,
SERVER_DIRECTORY,
SERVERLESS_DIRECTORY,
} from 'next-server/constants'
import resolve from 'next/dist/compiled/resolve/index.js'
import path from 'path'
@ -25,6 +25,7 @@ import ChunkNamesPlugin from './webpack/plugins/chunk-names-plugin'
import { importAutoDllPlugin } from './webpack/plugins/dll-import'
import { HashedChunkIdsPlugin } from './webpack/plugins/hashed-chunk-ids-plugin'
import { DropClientPage } from './webpack/plugins/next-drop-client-page-plugin'
import NextEsmPlugin from './webpack/plugins/next-esm-plugin'
import NextJsSsrImportPlugin from './webpack/plugins/nextjs-ssr-import'
import NextJsSSRModuleCachePlugin from './webpack/plugins/nextjs-ssr-module-cache'
import PagesManifestPlugin from './webpack/plugins/pages-manifest-plugin'
@ -32,7 +33,6 @@ import { ReactLoadablePlugin } from './webpack/plugins/react-loadable-plugin'
import { ServerlessPlugin } from './webpack/plugins/serverless-plugin'
import { SharedRuntimePlugin } from './webpack/plugins/shared-runtime-plugin'
import { TerserPlugin } from './webpack/plugins/terser-webpack-plugin/src/index'
import NextEsmPlugin from './webpack/plugins/next-esm-plugin'
type ExcludesFalse = <T>(x: T | false) => x is T
@ -79,7 +79,12 @@ export default async function getBaseWebpackConfig(
.split(process.platform === 'win32' ? ';' : ':')
.filter(p => !!p)
const outputDir = target === 'serverless' ? 'serverless' : SERVER_DIRECTORY
const isServerless = target === 'serverless'
const isServerlessTrace = target === 'experimental-serverless-trace'
// Intentionally not using isTargetLikeServerless helper
const isLikeServerless = isServerless || isServerlessTrace
const outputDir = isLikeServerless ? SERVERLESS_DIRECTORY : SERVER_DIRECTORY
const outputPath = path.join(distDir, isServer ? outputDir : '')
const totalPages = Object.keys(entrypoints).length
const clientEntries = !isServer
@ -238,7 +243,7 @@ export default async function getBaseWebpackConfig(
target: isServer ? 'node' : 'web',
externals: !isServer
? undefined
: target !== 'serverless'
: !isServerless
? [
(context, request, callback) => {
const notExternalModules = [
@ -293,8 +298,8 @@ export default async function getBaseWebpackConfig(
},
]
: [
// When the serverless target is used all node_modules will be compiled into the output bundles
// So that the serverless bundles have 0 runtime dependencies
// When the 'serverless' target is used all node_modules will be compiled into the output bundles
// So that the 'serverless' bundles have 0 runtime dependencies
'amp-toolbox-optimizer', // except this one
(context, request, callback) => {
if (
@ -561,11 +566,14 @@ export default async function getBaseWebpackConfig(
)
},
}),
target === 'serverless' &&
(isServer || selectivePageBuilding) &&
new ServerlessPlugin(buildId, { isServer }),
isServer && new PagesManifestPlugin(target === 'serverless'),
target !== 'serverless' &&
isLikeServerless &&
new ServerlessPlugin(buildId, {
isServer,
isFlyingShuttle: selectivePageBuilding,
isTrace: isServerlessTrace,
}),
isServer && new PagesManifestPlugin(isLikeServerless),
target === 'server' &&
isServer &&
new NextJsSSRModuleCachePlugin({ outputPath }),
isServer && new NextJsSsrImportPlugin(),

View file

@ -54,18 +54,47 @@ function interceptFileWrites(
export class ServerlessPlugin {
private buildId: string
private isServer: boolean
private isTrace: boolean
private isFlyingShuttle: boolean
constructor(buildId: string, { isServer = false } = {}) {
constructor(
buildId: string,
{
isServer,
isTrace,
isFlyingShuttle,
}: { isServer: boolean; isTrace: boolean; isFlyingShuttle: boolean }
) {
this.buildId = buildId
this.isServer = isServer
this.isTrace = isTrace
this.isFlyingShuttle = isFlyingShuttle
}
apply(compiler: Compiler) {
if (this.isServer) {
interceptFileWrites(compiler, content =>
replaceInBuffer(content, NEXT_REPLACE_BUILD_ID, this.buildId)
)
if (!this.isServer) {
if (this.isFlyingShuttle) {
compiler.hooks.emit.tap('ServerlessPlugin', compilation => {
const assetNames = Object.keys(compilation.assets).filter(f =>
f.includes(this.buildId)
)
for (const name of assetNames) {
compilation.assets[
name
.replace(new RegExp(`${this.buildId}[\\/\\\\]`), 'client/')
.replace(/[.]js$/, `.${this.buildId}.js`)
] = compilation.assets[name]
}
})
}
return
}
interceptFileWrites(compiler, content =>
replaceInBuffer(content, NEXT_REPLACE_BUILD_ID, this.buildId)
)
if (!this.isTrace) {
compiler.hooks.compilation.tap('ServerlessPlugin', compilation => {
compilation.hooks.optimizeChunksBasic.tap(
'ServerlessPlugin',
@ -86,19 +115,6 @@ export class ServerlessPlugin {
}
)
})
} else {
compiler.hooks.emit.tap('ServerlessPlugin', compilation => {
const assetNames = Object.keys(compilation.assets).filter(f =>
f.includes(this.buildId)
)
for (const name of assetNames) {
compilation.assets[
name
.replace(new RegExp(`${this.buildId}[\\/\\\\]`), 'client/')
.replace(/[.]js$/, `.${this.buildId}.js`)
] = compilation.assets[name]
}
})
}
}
}

View file

@ -4,7 +4,9 @@ import { recursiveCopy } from '../lib/recursive-copy'
import mkdirpModule from 'mkdirp'
import { resolve, join } from 'path'
import { existsSync, readFileSync } from 'fs'
import loadConfig from 'next-server/next-config'
import loadConfig, {
isTargetLikeServerless
} from 'next-server/dist/server/config'
import {
PHASE_EXPORT,
SERVER_DIRECTORY,
@ -183,7 +185,7 @@ export default async function (dir, options, configuration) {
serverRuntimeConfig,
concurrency,
subFolders,
serverless: nextConfig.target === 'serverless'
serverless: isTargetLikeServerless(nextConfig.target)
})
worker.on('message', ({ type, payload }) => {
if (type === 'progress' && progress) {

View file

@ -0,0 +1,6 @@
module.exports = {
target: 'experimental-serverless-trace',
onDemandEntries: {
maxInactiveAge: 1000 * 60 * 60
}
}

View file

@ -0,0 +1,19 @@
import firebase from 'firebase/app'
import 'firebase/firestore'
if (!firebase.apps.length) {
firebase.initializeApp({ projectId: 'noop' })
}
const store = firebase.firestore()
const Comp = ({ results }) => {
return <div>Hello Firebase: {results}</div>
}
Comp.getInitialProps = async () => {
const query = await store.collection('users').get()
return { results: query.size }
}
export default Comp

View file

@ -0,0 +1,29 @@
/* eslint-env jest */
/* global jasmine */
import { join } from 'path'
import {
killApp,
findPort,
nextBuild,
nextStart,
renderViaHTTP
} from 'next-test-utils'
const appDir = join(__dirname, '../')
let appPort
let app
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
describe('External Assets', () => {
beforeAll(async () => {
await nextBuild(appDir, [])
appPort = await findPort()
app = await nextStart(appDir, appPort)
})
afterAll(() => killApp(app))
it('should support Firebase', async () => {
const html = await renderViaHTTP(appPort, '/about/history')
expect(html).toMatch(/Hello Firebase: <!-- -->0/)
})
})

View file

@ -0,0 +1 @@
export default () => <h1>Hello!</h1>

View file

@ -0,0 +1,12 @@
module.exports = {
target: 'experimental-serverless-trace',
onDemandEntries: {
// Make sure entries are not getting disposed.
maxInactiveAge: 1000 * 60 * 60
},
experimental: {
publicDirectory: true
},
// make sure error isn't thrown from empty publicRuntimeConfig
publicRuntimeConfig: {}
}

View file

@ -0,0 +1 @@
export default () => <div>test</div>

View file

@ -0,0 +1,3 @@
export default (req, res) => {
res.send('hello world')
}

View file

@ -0,0 +1,3 @@
export default (req, res) => {
res.json({ post: req.query.id })
}

View file

@ -0,0 +1,9 @@
import dynamic from 'next/dynamic'
const Hello = dynamic(() => import('../components/hello'))
export default () => (
<div>
<Hello />
</div>
)

View file

@ -0,0 +1,9 @@
import dynamic from 'next/dynamic'
const Hello = dynamic(() => import('../components/hello'))
export default () => (
<div>
<Hello />
</div>
)

View file

@ -0,0 +1,29 @@
import fetch from 'isomorphic-unfetch'
import React from 'react'
export default class extends React.Component {
static async getInitialProps () {
try {
const res = await fetch('')
const text = await res.text()
console.log(text)
return { text }
} catch (err) {
if (err.message.includes('is not a function')) {
return { failed: true, error: err.toString() }
}
return { error: err.toString() }
}
}
render () {
const { failed, error, text } = this.props
return (
<div className='fetch-page'>
{failed ? 'failed' : ''}
{error}
<div id='text'>{text}</div>
</div>
)
}
}

View file

@ -0,0 +1,11 @@
import Link from 'next/link'
export default () => {
return (
<div>
Hello World
<Link href='/fetch'>
<a id='fetchlink'>fetch page</a>
</Link>
</div>
)
}

View file

@ -0,0 +1,2 @@
export default () => `Hi Im an AMP page!`
export const config = { amp: 'hybrid' }

View file

@ -0,0 +1 @@
hello world

View file

@ -0,0 +1,149 @@
/* eslint-env jest */
/* global jasmine */
import webdriver from 'next-webdriver'
import { join } from 'path'
import { existsSync } from 'fs'
import {
killApp,
findPort,
nextBuild,
nextStart,
fetchViaHTTP,
renderViaHTTP
} from 'next-test-utils'
import fetch from 'node-fetch'
const appDir = join(__dirname, '../')
const serverlessDir = join(appDir, '.next/serverless/pages')
let appPort
let app
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 5
describe('Serverless', () => {
beforeAll(async () => {
await nextBuild(appDir)
appPort = await findPort()
app = await nextStart(appDir, appPort)
})
afterAll(() => killApp(app))
it('should render the page', async () => {
const html = await renderViaHTTP(appPort, '/')
expect(html).toMatch(/Hello World/)
})
it('should serve file from public folder', async () => {
const content = await renderViaHTTP(appPort, '/hello.txt')
expect(content.trim()).toBe('hello world')
})
it('should render the page with dynamic import', async () => {
const html = await renderViaHTTP(appPort, '/dynamic')
expect(html).toMatch(/Hello!/)
})
it('should render the page with same dynamic import', async () => {
const html = await renderViaHTTP(appPort, '/dynamic-two')
expect(html).toMatch(/Hello!/)
})
it('should render 404', async () => {
const html = await renderViaHTTP(appPort, '/404')
expect(html).toMatch(/This page could not be found/)
})
it('should render an AMP page', async () => {
const html = await renderViaHTTP(appPort, '/some-amp?amp=1')
expect(html).toMatch(/Hi Im an AMP page/)
expect(html).toMatch(/ampproject\.org/)
})
it('should have correct amphtml rel link', async () => {
const html = await renderViaHTTP(appPort, '/some-amp')
expect(html).toMatch(/Hi Im an AMP page/)
expect(html).toMatch(/rel="amphtml" href="\/some-amp\?amp=1"/)
})
it('should have correct canonical link', async () => {
const html = await renderViaHTTP(appPort, '/some-amp?amp=1')
expect(html).toMatch(/rel="canonical" href="\/some-amp"/)
})
it('should render correctly when importing isomorphic-unfetch', async () => {
const url = `http://localhost:${appPort}/fetch`
const res = await fetch(url)
expect(res.status).toBe(200)
const text = await res.text()
expect(text.includes('failed')).toBe(false)
})
it('should render correctly when importing isomorphic-unfetch on the client side', async () => {
const browser = await webdriver(appPort, '/')
try {
const text = await browser
.elementByCss('a')
.click()
.waitForElementByCss('.fetch-page')
.elementByCss('#text')
.text()
expect(text).toMatch(/fetch page/)
} finally {
await browser.close()
}
})
it('should not output _app.js and _document.js to serverless build', () => {
expect(existsSync(join(serverlessDir, '_app.js'))).toBeFalsy()
expect(existsSync(join(serverlessDir, '_document.js'))).toBeFalsy()
})
it('should replace static pages with HTML files', async () => {
const staticFiles = ['abc', 'dynamic', 'dynamic-two', 'some-amp']
for (const file of staticFiles) {
expect(existsSync(join(serverlessDir, file + '.html'))).toBe(true)
expect(existsSync(join(serverlessDir, file + '.js'))).toBe(false)
}
})
it('should not replace non-static pages with HTML files', async () => {
const nonStaticFiles = ['fetch', '_error']
for (const file of nonStaticFiles) {
expect(existsSync(join(serverlessDir, file + '.js'))).toBe(true)
expect(existsSync(join(serverlessDir, file + '.html'))).toBe(false)
}
})
it('should reply on API request successfully', async () => {
const content = await renderViaHTTP(appPort, '/api/hello')
expect(content).toMatch(/hello world/)
})
it('should reply on dynamic API request successfully', async () => {
const result = await renderViaHTTP(appPort, '/api/posts/post-1')
const { post } = JSON.parse(result)
expect(post).toBe('post-1')
})
it('should 404 on API request with trailing slash', async () => {
const res = await fetchViaHTTP(appPort, '/api/hello/')
expect(res.status).toBe(404)
})
describe('With basic usage', () => {
it('should allow etag header support', async () => {
const url = `http://localhost:${appPort}/`
const etag = (await fetch(url)).headers.get('ETag')
const headers = { 'If-None-Match': etag }
const res2 = await fetch(url, { headers })
expect(res2.status).toBe(304)
})
it('should set Content-Length header', async () => {
const url = `http://localhost:${appPort}`
const res = await fetch(url)
expect(res.headers.get('Content-Length')).toBeDefined()
})
})
})

461
yarn.lock
View file

@ -782,6 +782,177 @@
exec-sh "^0.3.2"
minimist "^1.2.0"
"@firebase/app-types@0.4.3":
version "0.4.3"
resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.4.3.tgz#80d2b6e5ee43ac99892329ab02301ee7ed82da45"
integrity sha512-VU5c+ZjejvefLVH4cjiX3Hy1w9HYMv7TtZ1tF9ZmOqT4DSIU1a3VISWoo8///cGGffr5IirMO+Q/WZLI4p8VcA==
"@firebase/app@0.4.13":
version "0.4.13"
resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.4.13.tgz#5997214002f5a56b88154566e483dc3440e3d57e"
integrity sha512-LWiIKRoik1dFsY24k3pQ6NrQyWvSt+HzJKratUHfzqDBACdxcw7+9kwFMnS4MHGc/GGFVC42rHrI0PHeRe779w==
dependencies:
"@firebase/app-types" "0.4.3"
"@firebase/logger" "0.1.21"
"@firebase/util" "0.2.24"
dom-storage "2.1.0"
tslib "1.10.0"
xmlhttprequest "1.8.0"
"@firebase/auth-types@0.7.2":
version "0.7.2"
resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.7.2.tgz#6343639d422ea84feddf619e22d8db7f63b0eb62"
integrity sha512-xm3evp6671LoI+6M8Om3OhikabLf88Ivz1e7aR8uZjVBYptEYbF3seDIyHn/3wWdVYbp20WK4aWixKlRnHl+6Q==
"@firebase/auth@0.11.7":
version "0.11.7"
resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-0.11.7.tgz#febfcbb6281db73e47446394be3d6370416af26e"
integrity sha512-qloLTfUPja0ivRvyC0FnEMif6bYPZb9DsJsV83KiBWaYMSkCeNHuA34p73JvjmgHrT571t+zFpJ3OrBH+va4ow==
dependencies:
"@firebase/auth-types" "0.7.2"
"@firebase/database-types@0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.4.2.tgz#7bb2e605b914ad5cca7b1f4f5d8e7940fa37a708"
integrity sha512-rBF/Sp4S4zzVg+a6h0iEiXR2GdNRrvx2BR6IcvGHnSPF7XVpj9UuUWtZMJyO+vWP3zlIGDvlNRJ4qF01Y6KxGg==
"@firebase/database@0.4.11":
version "0.4.11"
resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.4.11.tgz#671a7da8195d02b8cbcd3e0c23adbd6226d8df38"
integrity sha512-g6VcEiw1HqBbV31p0j61CleLKZQ2XEOqpv1MSuiH9YYMsbHI7uUaebj3dxIdLSdLMoWNpGYmlXva/AWkirAV8Q==
dependencies:
"@firebase/database-types" "0.4.2"
"@firebase/logger" "0.1.21"
"@firebase/util" "0.2.24"
faye-websocket "0.11.3"
tslib "1.10.0"
"@firebase/firestore-types@1.4.4":
version "1.4.4"
resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-1.4.4.tgz#3051a9c163b4b76ae04544629ff5e0777e452548"
integrity sha512-kFpmzkUKfzrXkcMad+TQlMs55dWNY0q1UxGICW82EneX3Yg6HN3Nx36kYfqH+SLBFUN1ZTikN07alMp0MA9p9g==
"@firebase/firestore@1.4.8":
version "1.4.8"
resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-1.4.8.tgz#a17ee01463b546a2adfb2162a0613c74d0a25208"
integrity sha512-/Ult2LpbweinNnpqGrGiMw+EAaMEy6uA71DWN868oZoUmnn/+s/DCe2J0P+On2HATqvg5WggrQRa9I0in8fFag==
dependencies:
"@firebase/firestore-types" "1.4.4"
"@firebase/logger" "0.1.21"
"@firebase/util" "0.2.24"
"@firebase/webchannel-wrapper" "0.2.23"
"@grpc/proto-loader" "^0.5.0"
grpc "1.22.2"
tslib "1.10.0"
"@firebase/functions-types@0.3.8":
version "0.3.8"
resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.3.8.tgz#c01f670bbca04365e680d048b0fe5770a946f643"
integrity sha512-9hajHxA4UWVCGFmoL8PBYHpamE3JTNjObieMmnvZw3cMRTP2EwipMpzZi+GPbMlA/9swF9yHCY/XFAEkwbvdgQ==
"@firebase/functions@0.4.14":
version "0.4.14"
resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.4.14.tgz#c222086222ec072e0c9c6602500d6d2435b09355"
integrity sha512-rWYWIp2NIRfNGREkSEhu9fD7WsqkUARnonn7+g+DOCxlf23AkwwDwp6q9cnSia7iJ9kmkiz4hyQVI0vB1QlV5A==
dependencies:
"@firebase/functions-types" "0.3.8"
"@firebase/messaging-types" "0.3.2"
isomorphic-fetch "2.2.1"
tslib "1.10.0"
"@firebase/installations-types@0.1.2":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.1.2.tgz#ac2a912e078282fd270b03b571b4639ed88d871a"
integrity sha512-fQaWIW8hyX1XUN7+FCSPjvM1agFjGidVuF4Sxi7aFwfyh5t+4fD2VpM4wCQbWmodnx4fZLvsuQd9mkxxU+lGYQ==
"@firebase/installations@0.2.3":
version "0.2.3"
resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.2.3.tgz#d0203a7e3dac00a5d57f9b25a2ab4ba082bc8851"
integrity sha512-HhHMn1xvyqBCvw8HmjZ5w856BQ0+xX4tKe/48k+dyKUzzSjwrFjILWTDV2GIHZcVyMHuSS3/bX9ehIBULB5yAA==
dependencies:
"@firebase/installations-types" "0.1.2"
"@firebase/util" "0.2.24"
idb "3.0.2"
tslib "1.10.0"
"@firebase/logger@0.1.21":
version "0.1.21"
resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.1.21.tgz#4918944ae01561afa8801f2bc4fc609351418007"
integrity sha512-O4aIK1wkMpczqnDSwzDaEcQ8a5puVU4Bpt+16PfenicsBSrIR+gKq44crPM3nv/LURWtDpUVSYGoqhKPeodPAg==
"@firebase/messaging-types@0.3.2":
version "0.3.2"
resolved "https://registry.yarnpkg.com/@firebase/messaging-types/-/messaging-types-0.3.2.tgz#cf802617c161434a02fe029290a79f422821d12f"
integrity sha512-2qa2qNKqpalmtwaUV3+wQqfCm5myP/dViIBv+pXF8HinemIfO1IPQtr9pCNfsSYyus78qEhtfldnPWXxUH5v0w==
"@firebase/messaging@0.4.7":
version "0.4.7"
resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.4.7.tgz#d55d63b9f48c04b6c380ff4fafd2461597961e9a"
integrity sha512-Kzx64ELqOhEniyKawyCmDiQo8tX+wiF7Jsk5kp7moh7090dOPb8p8snkq770UFwUZjhouVrl8tOKzD3SInVIFA==
dependencies:
"@firebase/messaging-types" "0.3.2"
"@firebase/util" "0.2.24"
tslib "1.10.0"
"@firebase/performance-types@0.0.3":
version "0.0.3"
resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.0.3.tgz#bdd37975cd5f12a55d3951f4942c3fa2661b354f"
integrity sha512-RuC63nYJPJU65AsrNMc3fTRcRgHiyNcQLh9ufeKUT1mEsFgpxr167gMb+tpzNU4jsbvM6+c6nQAFdHpqcGkRlQ==
"@firebase/performance@0.2.14":
version "0.2.14"
resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.2.14.tgz#a868dc9f50bcfe55a091ee30aea50f7674fa2357"
integrity sha512-WNhJkVEq9q6OazUldzeRcESmGl0W2kw82CfUII/uPATdMvF5wXvda60BN0zwquRVSdLTt7qVRQA/8wLQYnX/Kw==
dependencies:
"@firebase/installations" "0.2.3"
"@firebase/logger" "0.1.21"
"@firebase/performance-types" "0.0.3"
"@firebase/util" "0.2.24"
tslib "1.10.0"
"@firebase/polyfill@0.3.18":
version "0.3.18"
resolved "https://registry.yarnpkg.com/@firebase/polyfill/-/polyfill-0.3.18.tgz#cb064aa19774c4d2b9bfc82450786957a65d60ae"
integrity sha512-Erp0vuFYMS8BlQzuAWR6zf10rxDT4GHRGJypxoW7arU4J61KIb6CPmrO9tVtf/rVEZuUXsDO65etDEFA8elCYA==
dependencies:
core-js "3.1.4"
promise-polyfill "8.1.3"
whatwg-fetch "2.0.4"
"@firebase/storage-types@0.3.3":
version "0.3.3"
resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.3.3.tgz#179ad38485d450023406cf9731560d690ef39d19"
integrity sha512-fUp4kpbxwDiWs/aIBJqBvXgFHZvgoND2JA0gJYSEsXtWtVwfgzY/710plErgZDeQKopX5eOR1sHskZkQUy0U6w==
"@firebase/storage@0.3.8":
version "0.3.8"
resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.3.8.tgz#1422fe583c57a712d03a155d2ce6bef8526e7c33"
integrity sha512-u/JHEkoIPKkRigHhcHcmHq6Ymu27Iyei6SqDFPm17vfC85jDetdg6aO9K+UxbtdDICa60P86UguqDHTMLVwKIg==
dependencies:
"@firebase/storage-types" "0.3.3"
"@firebase/util" "0.2.24"
tslib "1.10.0"
"@firebase/util@0.2.24":
version "0.2.24"
resolved "https://registry.yarnpkg.com/@firebase/util/-/util-0.2.24.tgz#5ccb7888f3dacf911c1c6ec51b68a17dea5c9b74"
integrity sha512-XFBNxfkMajl2zSUdcCQ3H32IN9JSM7Dacv8RK72DKoFV8Zn8dx4iZvtx8RB/VTFpXfcl435A0RzXqkLfSSEK/A==
dependencies:
tslib "1.10.0"
"@firebase/webchannel-wrapper@0.2.23":
version "0.2.23"
resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.2.23.tgz#a0df05b210ff03c65ecb3589390095631b95e1f8"
integrity sha512-BJqOF51sPQjmRoX+WFMbZ5mhuy53JrFN0t1KY+HffcvDRb+82+vkFatKnwG3wTCKV183vJW5tGQIytb4T8pUBg==
"@grpc/proto-loader@^0.5.0":
version "0.5.1"
resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.5.1.tgz#48492b53cdda353110b51a4b02f465974729c76f"
integrity sha512-3y0FhacYAwWvyXshH18eDkUI40wT/uGio7MAegzY8lO5+wVsc19+1A7T0pPptae4kl7bdITL+0cHpnAPmryBjQ==
dependencies:
lodash.camelcase "^4.3.0"
protobufjs "^6.8.6"
"@jest/console@^24.7.1":
version "24.7.1"
resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.7.1.tgz#32a9e42535a97aedfe037e725bd67e954b459545"
@ -1708,6 +1879,59 @@
universal-user-agent "^2.0.0"
url-template "^2.0.8"
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78=
"@protobufjs/base64@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735"
integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==
"@protobufjs/codegen@^2.0.4":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb"
integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==
"@protobufjs/eventemitter@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70"
integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A=
"@protobufjs/fetch@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45"
integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=
dependencies:
"@protobufjs/aspromise" "^1.1.1"
"@protobufjs/inquire" "^1.1.0"
"@protobufjs/float@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1"
integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=
"@protobufjs/inquire@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089"
integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=
"@protobufjs/path@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d"
integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=
"@protobufjs/pool@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54"
integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=
"@protobufjs/utf8@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=
"@samverschueren/stream-to-observable@^0.3.0":
version "0.3.0"
resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"
@ -1936,6 +2160,11 @@
"@types/node" "*"
"@types/webpack" "*"
"@types/long@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.0.tgz#719551d2352d301ac8b81db732acb6bdc28dbdef"
integrity sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==
"@types/mime@*":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d"
@ -1979,6 +2208,11 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.2.tgz#3452a24edf9fea138b48fad4a0a028a683da1e40"
integrity sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==
"@types/node@^10.1.0":
version "10.14.14"
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.14.tgz#a47955df2acf76ba7f0ac3b205d325da193dc9ad"
integrity sha512-xXD08vZsvpv4xptQXj1+ky22f7ZoKu5ZNI/4l+/BXG3X+XaeZsmaFbbTKuhSE3NjjvRuZFxFf9sQBMXIcZNFMQ==
"@types/node@^12.6.8":
version "12.6.8"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.8.tgz#e469b4bf9d1c9832aee4907ba8a051494357c12c"
@ -2769,6 +3003,14 @@ asap@^2.0.0, asap@~2.0.3:
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
ascli@~1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ascli/-/ascli-1.0.1.tgz#bcfa5974a62f18e81cabaeb49732ab4a88f906bc"
integrity sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=
dependencies:
colour "~0.7.1"
optjs "~3.2.2"
asn1.js@^4.0.0:
version "4.10.1"
resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
@ -3330,6 +3572,13 @@ byte-size@^4.0.3:
resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-4.0.4.tgz#29d381709f41aae0d89c631f1c81aec88cd40b23"
integrity sha512-82RPeneC6nqCdSwCX2hZUz3JPOvN5at/nTEw/CMf05Smu3Hrpo9Psb7LjN+k+XndNArG1EY8L4+BM3aTM4BCvw==
bytebuffer@~5:
version "5.0.1"
resolved "https://registry.yarnpkg.com/bytebuffer/-/bytebuffer-5.0.1.tgz#582eea4b1a873b6d020a48d58df85f0bba6cfddd"
integrity sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=
dependencies:
long "~3"
bytes@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
@ -3480,7 +3729,7 @@ camelcase@5.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42"
integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==
camelcase@^2.0.0:
camelcase@^2.0.0, camelcase@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
@ -3771,7 +4020,7 @@ cli-width@^2.0.0:
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
cliui@^3.2.0:
cliui@^3.0.3, cliui@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
@ -3904,6 +4153,11 @@ colors@1.1.2:
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM=
colour@~0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/colour/-/colour-0.7.1.tgz#9cb169917ec5d12c0736d3e8685746df1cadf778"
integrity sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g=
columnify@^1.5.4:
version "1.5.4"
resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb"
@ -4207,6 +4461,11 @@ core-js-pure@3.1.2:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.1.2.tgz#62fc435f35b7374b9b782013cdcb2f97e9f6dffa"
integrity sha512-5ckIdBF26B3ldK9PM177y2ZcATP2oweam9RskHSoqfZCrJ2As6wVg8zJ1zTriFsZf6clj/N1ThDFRGaomMsh9w==
core-js@3.1.4:
version "3.1.4"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.4.tgz#3a2837fc48e582e1ae25907afcd6cf03b0cc7a07"
integrity sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ==
core-js@^2.4.0, core-js@^2.6.5:
version "2.6.8"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.8.tgz#dc3a1e633a04267944e0cb850d3880f340248139"
@ -4951,6 +5210,11 @@ dom-serializer@0, dom-serializer@~0.1.0:
domelementtype "^1.3.0"
entities "^1.1.1"
dom-storage@2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/dom-storage/-/dom-storage-2.1.0.tgz#00fb868bc9201357ea243c7bcfd3304c1e34ea39"
integrity sha512-g6RpyWXzl0RR6OTElHKBl7nwnK87GUyZMYC7JWsB/IA73vpqK2K6LT39x4VepLxlSsWBFrPVLnsSR5Jyty0+2Q==
domain-browser@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
@ -5783,6 +6047,13 @@ faunadb@2.6.1:
superagent "^3.8.1"
util-deprecate "^1.0.2"
faye-websocket@0.11.3:
version "0.11.3"
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e"
integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==
dependencies:
websocket-driver ">=0.5.1"
fb-watchman@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58"
@ -5953,6 +6224,24 @@ find-up@^3.0.0:
dependencies:
locate-path "^3.0.0"
firebase@6.3.4:
version "6.3.4"
resolved "https://registry.yarnpkg.com/firebase/-/firebase-6.3.4.tgz#a96301d5308871a9afe8b06195fac967e893778d"
integrity sha512-UvLCXApdrhYZkGl1N/4dPPFVa3zFd+K963guaP9ckQhagch66Hv1xLwL8urmlBAGk9UZECMAk8f7YcLD217HkA==
dependencies:
"@firebase/app" "0.4.13"
"@firebase/app-types" "0.4.3"
"@firebase/auth" "0.11.7"
"@firebase/database" "0.4.11"
"@firebase/firestore" "1.4.8"
"@firebase/functions" "0.4.14"
"@firebase/installations" "0.2.3"
"@firebase/messaging" "0.4.7"
"@firebase/performance" "0.2.14"
"@firebase/polyfill" "0.3.18"
"@firebase/storage" "0.3.8"
"@firebase/util" "0.2.24"
flat-cache@^1.2.1:
version "1.3.4"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f"
@ -6580,6 +6869,17 @@ growly@^1.3.0:
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=
grpc@1.22.2:
version "1.22.2"
resolved "https://registry.yarnpkg.com/grpc/-/grpc-1.22.2.tgz#1a60c728c692a93a85e855e35c2e0216654f0198"
integrity sha512-gaK59oAA5/mlOIn+hQO5JROPoAzsaGRpEMcrAayW5WGETS8QScpBoQ+XBxEWAAF0kbeGIELuGRCVEObKS1SLmw==
dependencies:
lodash.camelcase "^4.3.0"
lodash.clone "^4.5.0"
nan "^2.13.2"
node-pre-gyp "^0.13.0"
protobufjs "^5.0.3"
gulp-mocha@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/gulp-mocha/-/gulp-mocha-6.0.0.tgz#80f32bc705ce30747f355ddb8ccd96a1c73bef13"
@ -6850,6 +7150,11 @@ http-errors@~1.6.2:
setprototypeof "1.1.0"
statuses ">= 1.4.0 < 2"
"http-parser-js@>=0.4.0 <0.4.11":
version "0.4.10"
resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4"
integrity sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=
http-proxy-agent@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405"
@ -6906,6 +7211,11 @@ icss-utils@^2.1.0:
dependencies:
postcss "^6.0.1"
idb@3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/idb/-/idb-3.0.2.tgz#c8e9122d5ddd40f13b60ae665e4862f8b13fa384"
integrity sha512-+FLa/0sTXqyux0o6C+i2lOR0VoS60LU/jzUo5xjfY6+7sEEgy4Gz1O7yFBXvjd7N0NyIGWIRg8DcQSLEG+VSPw==
ieee754@^1.1.4:
version "1.1.13"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
@ -7503,7 +7813,7 @@ is-ssh@^1.3.0:
dependencies:
protocols "^1.1.0"
is-stream@^1.0.0, is-stream@^1.1.0:
is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
@ -7622,6 +7932,14 @@ isobject@^4.0.0:
resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0"
integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==
isomorphic-fetch@2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=
dependencies:
node-fetch "^1.0.1"
whatwg-fetch ">=0.10.0"
isomorphic-unfetch@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.0.0.tgz#de6d80abde487b17de2c400a7ef9e5ecc2efb362"
@ -8529,6 +8847,11 @@ lodash.camelcase@^4.3.0:
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
lodash.clone@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6"
integrity sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=
lodash.clonedeep@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
@ -8697,6 +9020,16 @@ lolex@1.3.2:
resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.3.2.tgz#7c3da62ffcb30f0f5a80a2566ca24e45d8a01f31"
integrity sha1-fD2mL/yzDw9agKJWbKJORdigHzE=
long@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==
long@~3:
version "3.2.0"
resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b"
integrity sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
@ -9339,6 +9672,14 @@ node-fetch@2.6.0, node-fetch@^2.1.1, node-fetch@^2.2.0, node-fetch@^2.3.0:
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
node-fetch@^1.0.1:
version "1.7.3"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==
dependencies:
encoding "^0.1.11"
is-stream "^1.0.1"
node-gyp@^3.8.0:
version "3.8.0"
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
@ -9440,6 +9781,22 @@ node-pre-gyp@^0.12.0:
semver "^5.3.0"
tar "^4"
node-pre-gyp@^0.13.0:
version "0.13.0"
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz#df9ab7b68dd6498137717838e4f92a33fc9daa42"
integrity sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ==
dependencies:
detect-libc "^1.0.2"
mkdirp "^0.5.1"
needle "^2.2.1"
nopt "^4.0.1"
npm-packlist "^1.1.6"
npmlog "^4.0.2"
rc "^1.2.7"
rimraf "^2.6.1"
semver "^5.3.0"
tar "^4"
node-releases@^1.1.19:
version "1.1.21"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.21.tgz#46c86f9adaceae4d63c75d3c2f2e6eee618e55f3"
@ -9819,6 +10176,11 @@ optionator@^0.8.1, optionator@^0.8.2:
type-check "~0.3.2"
wordwrap "~1.0.0"
optjs@~3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/optjs/-/optjs-3.2.2.tgz#69a6ce89c442a44403141ad2f9b370bd5bb6f4ee"
integrity sha1-aabOicRCpEQDFBrS+bNwvVu29O4=
ora@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ora/-/ora-2.0.0.tgz#8ec3a37fa7bffb54a3a0c188a1f6798e7e1827cd"
@ -10825,6 +11187,11 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
promise-polyfill@8.1.3:
version "8.1.3"
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.1.3.tgz#8c99b3cf53f3a91c68226ffde7bde81d7f904116"
integrity sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g==
promise-polyfill@^6.0.1:
version "6.1.0"
resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-6.1.0.tgz#dfa96943ea9c121fca4de9b5868cb39d3472e057"
@ -10893,6 +11260,35 @@ proto-list@~1.2.1:
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=
protobufjs@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-5.0.3.tgz#e4dfe9fb67c90b2630d15868249bcc4961467a17"
integrity sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA==
dependencies:
ascli "~1"
bytebuffer "~5"
glob "^7.0.5"
yargs "^3.10.0"
protobufjs@^6.8.6:
version "6.8.8"
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c"
integrity sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==
dependencies:
"@protobufjs/aspromise" "^1.1.2"
"@protobufjs/base64" "^1.1.2"
"@protobufjs/codegen" "^2.0.4"
"@protobufjs/eventemitter" "^1.1.0"
"@protobufjs/fetch" "^1.1.0"
"@protobufjs/float" "^1.0.2"
"@protobufjs/inquire" "^1.1.0"
"@protobufjs/path" "^1.1.2"
"@protobufjs/pool" "^1.1.0"
"@protobufjs/utf8" "^1.1.0"
"@types/long" "^4.0.0"
"@types/node" "^10.1.0"
long "^4.0.0"
protocols@^1.1.0, protocols@^1.4.0:
version "1.4.7"
resolved "https://registry.yarnpkg.com/protocols/-/protocols-1.4.7.tgz#95f788a4f0e979b291ffefcf5636ad113d037d32"
@ -11781,6 +12177,11 @@ safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, s
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safe-buffer@>=5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
safe-regex@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
@ -13142,6 +13543,11 @@ tryer@^1.0.0:
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
tslib@1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
tslib@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
@ -13785,6 +14191,20 @@ webpack@4.39.0:
watchpack "^1.6.0"
webpack-sources "^1.4.1"
websocket-driver@>=0.5.1:
version "0.7.3"
resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.3.tgz#a2d4e0d4f4f116f1e6297eba58b05d430100e9f9"
integrity sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==
dependencies:
http-parser-js ">=0.4.0 <0.4.11"
safe-buffer ">=5.1.0"
websocket-extensions ">=0.1.1"
websocket-extensions@>=0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29"
integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==
whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3:
version "1.0.5"
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
@ -13792,6 +14212,16 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3:
dependencies:
iconv-lite "0.4.24"
whatwg-fetch@2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f"
integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==
whatwg-fetch@>=0.10.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb"
integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==
whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
@ -13846,6 +14276,11 @@ wide-align@^1.1.0:
dependencies:
string-width "^1.0.2 || 2"
window-size@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876"
integrity sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=
windows-release@^3.1.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.2.0.tgz#8122dad5afc303d833422380680a79cdfa91785f"
@ -13984,6 +14419,11 @@ xml@^1.0.1:
resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5"
integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=
xmlhttprequest@1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc"
integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw=
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
@ -13996,7 +14436,7 @@ xtend@~2.1.1:
dependencies:
object-keys "~0.4.0"
y18n@^3.2.1:
y18n@^3.2.0, y18n@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
@ -14049,6 +14489,19 @@ yargs@^12.0.1, yargs@^12.0.2:
y18n "^3.2.1 || ^4.0.0"
yargs-parser "^11.1.1"
yargs@^3.10.0:
version "3.32.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995"
integrity sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=
dependencies:
camelcase "^2.0.1"
cliui "^3.0.3"
decamelize "^1.1.1"
os-locale "^1.4.0"
string-width "^1.0.1"
window-size "^0.1.4"
y18n "^3.2.0"
yargs@^7.0.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"