diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 121a4095..ff89b601 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -8,3 +8,5 @@ Fixes #0000 * Change 1 * Change 2 + + diff --git a/.travis.yml b/.travis.yml index 14fb2308..4e7c8d72 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,20 @@ language: node_js node_js: -- 10.4.0 + - 10.4.0 before_install: + # Only deploy if the version number has changed + - | + if git diff --unified=0 $TRAVIS_COMMIT_RANGE package.json | grep version ; then + export VERSION_CHANGED="yes" + fi - npm i -g npm@6.4.1 install: -- npm install + - npm install script: -- npm run lint -- bash scripts/versionCheck.sh $TRAVIS_BRANCH $TRAVIS_PULL_REQUEST -- npm test + - npm run lint + - npm test before_deploy: -- npm run build + - npm run build deploy: skip_cleanup: true provider: npm @@ -18,3 +22,4 @@ deploy: api_key: $NPM_KEY on: branch: master + condition: "$VERSION_CHANGED == 'yes'" diff --git a/CHANGELOG.md b/CHANGELOG.md index bbb9857a..ed06d71f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,60 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [4.2.2] - 2020-09-16 + +### Changed +- Fix for package build. Thank you @michaelgmcd ([#382](https://github.com/amplify-education/serverless-domain-manager/pull/382)) + +## [4.2.1] - 2020-09-16 + +### Changed +- Added support for using CloudFormation Fn::ImportValue. Thank you @sampsasaarela ([#220](https://github.com/amplify-education/serverless-domain-manager/pull/220)), @rddimon ([#380](https://github.com/amplify-education/serverless-domain-manager/pull/380)) + +## [4.2.0] - 2020-07-14 + +### Changed +- Added support for automatically creating/destroying custom domains on deploy/remove via the autoDomain option. Thank you @bryan-hunter ([#356](https://github.com/amplify-education/serverless-domain-manager/pull/356)) + +## [4.1.1] - 2020-05-25 + +### Changed +- Fix support for TLS 1.0 regional domains which were broken in the 4.0.0 release. Discovered by @jufemaiz ([#348](https://github.com/amplify-education/serverless-domain-manager/pull/348)) + +## [4.1.0] - 2020-05-18 + +### Changed +- Fixed issue when there are multiple pages of base path mappings. Also refactored how paging is handled throughout the code. Thanks @kzhou57 for discovering this ([#345](https://github.com/amplify-education/serverless-domain-manager/pull/345)) + +## [4.0.1] - 2020-05-12 + +### Changed +- Fix issue updating domains that use a blank base path. Thanks @fabiancook ([#337](https://github.com/amplify-education/serverless-domain-manager/pull/337)) + +## [4.0.0] - 2020-05-06 + +### Breaking Changes +- Regional domains with TLS 1.0 no longer work. Fixed in 4.1.1 + +### Added +- Add support for WebSocket and HTTP APIs. A domain name can be created for each API type (Rest, WebSocket, HTTP) +for up to 3 domain names in a single Serverless config. Thanks @TehNrd ([#319](https://github.com/amplify-education/serverless-domain-manager/pull/319)) + +## [3.3.2] - 2020-04-21 + +### Changed +- Fix CloudFormation stack's Outputs. Thanks @davidrosson ([#320](https://github.com/amplify-education/serverless-domain-manager/pull/320)) +- Use pagination when there are too many certificates. Thanks @cbm-gplassard ([#315](https://github.com/amplify-education/serverless-domain-manager/pull/315)) + +## [3.3.1] - 2020-01-16 + +### Changed +- Fix AWS SDK initialization after internal change in serverless. Thanks @medikoo ([#307](https://github.com/amplify-education/serverless-domain-manager/pull/307)) + +## [3.3.0] - 2019-08-12 + +### Added +- Add ability to choose TLS version. Thanks @drexler ([#240](https://github.com/amplify-education/serverless-domain-manager/pull/240)) ## [3.2.7] - 2019-08-02 diff --git a/README.md b/README.md index e259439d..062421aa 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ plugins: - serverless-domain-manager ``` -Add the plugin configuration (example for `serverless.foo.com/api`). +Add the plugin configuration (example for `serverless.foo.com/api`). For a single domain and API type the following structure can be used. ```yaml custom: @@ -70,7 +70,39 @@ custom: createRoute53Record: true endpointType: 'regional' securityPolicy: tls_1_2 - apiType: http + apiType: rest + autoDomain: false +``` + +Multiple API types mapped to different domains can also be supported with the following structure. The key is the API Gateway API type. + +```yaml +custom: + customDomain: + rest: + domainName: rest.serverless.foo.com + stage: ci + basePath: api + certificateName: '*.foo.com' + createRoute53Record: true + endpointType: 'regional' + securityPolicy: tls_1_2 + http: + domainName: http.serverless.foo.com + stage: ci + basePath: api + certificateName: '*.foo.com' + createRoute53Record: true + endpointType: 'regional' + securityPolicy: tls_1_2 + websocket: + domainName: ws.serverless.foo.com + stage: ci + basePath: api + certificateName: '*.foo.com' + createRoute53Record: true + endpointType: 'regional' + securityPolicy: tls_1_2 ``` | Parameter Name | Default Value | Description | @@ -87,6 +119,10 @@ custom: | hostedZonePrivate | | If hostedZonePrivate is set to `true` then only private hosted zones will be used for route 53 records. If it is set to `false` then only public hosted zones will be used for route53 records. Setting this parameter is specially useful if you have multiple hosted zones with the same domain name (e.g. a public and a private one) | | enabled | true | Sometimes there are stages for which is not desired to have custom domain names. This flag allows the developer to disable the plugin for such cases. Accepts either `boolean` or `string` values and defaults to `true` for backwards compatibility. | securityPolicy | tls_1_2 | The security policy to apply to the custom domain name. Accepts `tls_1_0` or `tls_1_2`| +allowPathMatching | false | When updating an existing api mapping this will match on the basePath instead of the API ID to find existing mappings for an upsate. This should only be used when changing API types. For example, migrating a REST API to an HTTP API. See Changing API Types for more information. | +| autoDomain | `false` | Toggles whether or not the plugin will run `create_domain/delete_domain` as part of `sls deploy/remove` so that multiple commands are not required. | +| autoDomainWaitFor | `120` | How long to wait for create_domain to finish before starting deployment if domain does not exist immediately. | + ## Running @@ -107,8 +143,6 @@ serverless delete_domain # How it works Creating the custom domain takes advantage of Amazon's Certificate Manager to assign a certificate to the given domain name. Based on already created certificate names, the plugin will search for the certificate that resembles the custom domain's name the most and assign the ARN to that domain name. The plugin then creates the proper A Alias and AAAA Alias records for the domain through Route 53. Once the domain name is set it takes up to 40 minutes before it is initialized. After the certificate is initialized, `sls deploy` will create the base path mapping and assign the lambda to the custom domain name through CloudFront. All resources are created independent of CloudFormation. However, deploying will also output the domain name and distribution domain name to the CloudFormation stack outputs under the keys `DomainName` and `DistributionDomainName`, respectively. -Note: In 1.0, we only created CNAME records. In 2.0 we deprecated CNAME creation and started creating A Alias records and migrated CNAME records to A Alias records. Now in 3.0, we only create A Alias records. Starting in version 3.2, we create AAAA Alias records as well. - ### Behavior Change in Version 3 In version 3, we decided to create/update/delete all resources through the API. Previously, only the basepath mapping was managed through CloudFormation. We moved away from creating anything through the stack for two reasons. @@ -139,7 +173,26 @@ npm install ``` ## Writing Integration Tests -Unit tests are found in `test/unit-tests`. Integration tests are found in `test/integration-tests`. Each folder in `tests/integration-tests` contains the serverless-domain-manager configuration being tested. To create a new integration test, create a new folder for the `handler.js` and `serverless.yml` with the same naming convention and update `integration.test.js`. +Unit tests are found in `test/unit-tests`. Integration tests are found in `test/integration-tests`. Each folder in `tests/integration-tests` contains the serverless-domain-manager configuration being tested. To create a new integration test, create a new folder for the `handler.js` and `serverless.yml` with the same naming convention and update `deploy.test.ts` or create a separate one with the `test.ts` ending. + +## Changing API Types +AWS API Gateway has three different API types: REST, HTTP, and WebSocket. Special steps need to be taken when migrating from one api type to another. A common migration will be from a REST API to an HTTP API given the potential cost savings. Below are the steps required to change from REST to HTTP. A similar process can be applied for other API type migrations. + +**REST to HTTP** +1) Confirm the Domain name is a Regional domain name. Edge domains are not supported by AWS for HTTP APIs. See this [guide for migrating an edge-optimized custom domain name to regional]( +https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-regional-api-custom-domain-migrate.html). +2) Wait for all DNS changes to take effect/propagate and ensure all traffic is being routed to the regional domain name before proceeding. +3) Make sure you have setup new or modified existing routes to use [httpApi event](https://serverless.com/framework/docs/providers/aws/events/http-api) in your serverless.yml file. +4) Make the following changes to the `customDomain` properties in the serverless.yml confg: + ```yaml + endpointType: regional + apiType: http + allowPathMatching: true # Only for one deploy + ``` +5) Run `sls deploy` +6) Remove the `allowPathMatching` option, it should only be used once when migrating a base path from one API type to another. + +NOTE: Always test this process in a lower level staging or development environment before performing it in production. # Known Issues diff --git a/index.ts b/index.ts deleted file mode 100644 index ab647a18..00000000 --- a/index.ts +++ /dev/null @@ -1,760 +0,0 @@ -"use strict"; - -import chalk from "chalk"; -import DomainInfo = require("./DomainInfo"); -import { ServerlessInstance, ServerlessOptions } from "./types"; - -const endpointTypes = { - edge: "EDGE", - regional: "REGIONAL", -}; - -const apiTypes = { - http: "HTTP", - rest: "REST", - websocket: "WEBSOCKET", -}; - -const tlsVersions = { - tls_1_0: "TLS_1_0", - tls_1_2: "TLS_1_2", -}; - -const certStatuses = ["PENDING_VALIDATION", "ISSUED", "INACTIVE"]; - -class ServerlessCustomDomain { - - // AWS SDK resources - public apigateway: any; - public apigatewayV2: any; - public route53: any; - public acm: any; - public acmRegion: string; - public cloudformation: any; - - // Serverless specific properties - public serverless: ServerlessInstance; - public options: ServerlessOptions; - public commands: object; - public hooks: object; - - // Domain Manager specific properties - public enabled: boolean; - public givenDomainName: string; - public hostedZonePrivate: boolean; - public basePath: string; - private endpointType: string; - private stage: string; - private securityPolicy: string; - private apiType: string; - - constructor(serverless: ServerlessInstance, options: ServerlessOptions) { - this.serverless = serverless; - this.options = options; - - this.commands = { - create_domain: { - lifecycleEvents: [ - "create", - "initialize", - ], - usage: "Creates a domain using the domain name defined in the serverless file", - }, - delete_domain: { - lifecycleEvents: [ - "delete", - "initialize", - ], - usage: "Deletes a domain using the domain name defined in the serverless file", - }, - }; - this.hooks = { - "after:deploy:deploy": this.hookWrapper.bind(this, this.setupBasePathMapping), - "after:info:info": this.hookWrapper.bind(this, this.domainSummary), - "before:remove:remove": this.hookWrapper.bind(this, this.removeBasePathMapping), - "create_domain:create": this.hookWrapper.bind(this, this.createDomain), - "delete_domain:delete": this.hookWrapper.bind(this, this.deleteDomain), - }; - } - - /** - * Wrapper for lifecycle function, initializes variables and checks if enabled. - * @param lifecycleFunc lifecycle function that actually does desired action - */ - public async hookWrapper(lifecycleFunc: any) { - this.initializeVariables(); - if (!this.enabled) { - this.serverless.cli.log("serverless-domain-manager: Custom domain is disabled."); - return; - } else { - return await lifecycleFunc.call(this); - } - } - - /** - * Lifecycle function to create a domain - * Wraps creating a domain and resource record set - */ - public async createDomain(): Promise { - let domainInfo; - try { - domainInfo = await this.getDomainInfo(); - } catch (err) { - if (err.message !== `Error: ${this.givenDomainName} not found.`) { - throw err; - } - } - if (!domainInfo) { - const certArn = await this.getCertArn(); - domainInfo = await this.createCustomDomain(certArn); - await this.changeResourceRecordSet("UPSERT", domainInfo); - this.serverless.cli.log( - `Custom domain ${this.givenDomainName} was created. - New domains may take up to 40 minutes to be initialized.`, - ); - } else { - this.serverless.cli.log(`Custom domain ${this.givenDomainName} already exists.`); - } - } - - /** - * Lifecycle function to delete a domain - * Wraps deleting a domain and resource record set - */ - public async deleteDomain(): Promise { - let domainInfo; - try { - domainInfo = await this.getDomainInfo(); - } catch (err) { - if (err.message === `Error: ${this.givenDomainName} not found.`) { - this.serverless.cli.log(`Unable to delete custom domain ${this.givenDomainName}.`); - return; - } - throw err; - } - await this.deleteCustomDomain(); - await this.changeResourceRecordSet("DELETE", domainInfo); - this.serverless.cli.log(`Custom domain ${this.givenDomainName} was deleted.`); - } - - /** - * Lifecycle function to create basepath mapping - * Wraps creation of basepath mapping and adds domain name info as output to cloudformation stack - */ - public async setupBasePathMapping(): Promise { - // check if basepathmapping exists - const apiId = await this.getApiId(); - const currentBasePath = await this.getBasePathMapping(apiId); - - // if basepath that matches apiId exists, update; else, create - if (!currentBasePath) { - await this.createBasePathMapping(apiId); - } else { - await this.updateBasePathMapping(currentBasePath); - } - const domainInfo = await this.getDomainInfo(); - this.addOutputs(domainInfo); - await this.printDomainSummary(domainInfo); - } - - /** - * Lifecycle function to delete basepath mapping - * Wraps deletion of basepath mapping - */ - public async removeBasePathMapping(): Promise { - await this.deleteBasePathMapping(); - } - - /** - * Lifecycle function to print domain summary - * Wraps printing of all domain manager related info - */ - public async domainSummary(): Promise { - const domainInfo = await this.getDomainInfo(); - if (domainInfo) { - this.printDomainSummary(domainInfo); - } else { - this.serverless.cli.log("Unable to print Serverless Domain Manager Summary"); - } - } - - /** - * Goes through custom domain property and initializes local variables and cloudformation template - */ - public initializeVariables(): void { - this.enabled = this.evaluateEnabled(); - if (this.enabled) { - const credentials = this.serverless.providers.aws.getCredentials(); - credentials.region = this.serverless.providers.aws.getRegion(); - - this.serverless.providers.aws.sdk.config.update({maxRetries: 20}); - this.apigateway = new this.serverless.providers.aws.sdk.APIGateway(credentials); - this.apigatewayV2 = new this.serverless.providers.aws.sdk.ApiGatewayV2(credentials); - this.route53 = new this.serverless.providers.aws.sdk.Route53(credentials); - this.cloudformation = new this.serverless.providers.aws.sdk.CloudFormation(credentials); - - this.givenDomainName = this.serverless.service.custom.customDomain.domainName; - this.hostedZonePrivate = this.serverless.service.custom.customDomain.hostedZonePrivate; - let basePath = this.serverless.service.custom.customDomain.basePath; - if (basePath == null || basePath.trim() === "") { - basePath = "(none)"; - } - this.basePath = basePath; - let stage = this.serverless.service.custom.customDomain.stage; - if (typeof stage === "undefined") { - stage = this.options.stage || this.serverless.service.provider.stage; - } - this.stage = stage; - - const endpointTypeWithDefault = this.serverless.service.custom.customDomain.endpointType || - endpointTypes.edge; - const endpointTypeToUse = endpointTypes[endpointTypeWithDefault.toLowerCase()]; - if (!endpointTypeToUse) { - throw new Error(`${endpointTypeWithDefault} is not supported endpointType, use edge or regional.`); - } - this.endpointType = endpointTypeToUse; - - const apiTypeWithDefault = this.serverless.service.custom.customDomain.apiType || - apiTypes.rest; - const apiTypeToUse = apiTypes[apiTypeWithDefault.toLowerCase()]; - if (!apiTypeToUse) { - throw new Error(`${apiTypeWithDefault} is not supported api type, use REST, HTTP or WEBSOCKET.`); - } - this.apiType = apiTypeToUse; - - const securityPolicyDefault = this.serverless.service.custom.customDomain.securityPolicy || - tlsVersions.tls_1_2; - const tlsVersionToUse = tlsVersions[securityPolicyDefault.toLowerCase()]; - if (!tlsVersionToUse) { - throw new Error(`${securityPolicyDefault} is not a supported securityPolicy, use tls_1_0 or tls_1_2.`); - } - this.securityPolicy = tlsVersionToUse; - - this.acmRegion = this.endpointType === endpointTypes.regional ? - this.serverless.providers.aws.getRegion() : "us-east-1"; - const acmCredentials = Object.assign({}, credentials, { region: this.acmRegion }); - this.acm = new this.serverless.providers.aws.sdk.ACM(acmCredentials); - } - } - - /** - * Determines whether this plug-in is enabled. - * - * This method reads the customDomain property "enabled" to see if this plug-in should be enabled. - * If the property's value is undefined, a default value of true is assumed (for backwards - * compatibility). - * If the property's value is provided, this should be boolean, otherwise an exception is thrown. - * If no customDomain object exists, an exception is thrown. - */ - public evaluateEnabled(): boolean { - if (typeof this.serverless.service.custom === "undefined" - || typeof this.serverless.service.custom.customDomain === "undefined") { - throw new Error("serverless-domain-manager: Plugin configuration is missing."); - } - - const enabled = this.serverless.service.custom.customDomain.enabled; - if (enabled === undefined) { - return true; - } - if (typeof enabled === "boolean") { - return enabled; - } else if (typeof enabled === "string" && enabled === "true") { - return true; - } else if (typeof enabled === "string" && enabled === "false") { - return false; - } - throw new Error(`serverless-domain-manager: Ambiguous enablement boolean: "${enabled}"`); - } - - /** - * Gets Certificate ARN that most closely matches domain name OR given Cert ARN if provided - */ - public async getCertArn(): Promise { - if (this.serverless.service.custom.customDomain.certificateArn) { - this.serverless.cli.log( - `Selected specific certificateArn ${this.serverless.service.custom.customDomain.certificateArn}`); - return this.serverless.service.custom.customDomain.certificateArn; - } - - let certificateArn; // The arn of the choosen certificate - let certificateName = this.serverless.service.custom.customDomain.certificateName; // The certificate name - let certData; - try { - certData = await this.acm.listCertificates( - { CertificateStatuses: certStatuses }).promise(); - // The more specific name will be the longest - let nameLength = 0; - const certificates = certData.CertificateSummaryList; - - // Checks if a certificate name is given - if (certificateName != null) { - const foundCertificate = certificates - .find((certificate) => (certificate.DomainName === certificateName)); - if (foundCertificate != null) { - certificateArn = foundCertificate.CertificateArn; - } - } else { - certificateName = this.givenDomainName; - certificates.forEach((certificate) => { - let certificateListName = certificate.DomainName; - // Looks for wild card and takes it out when checking - if (certificateListName[0] === "*") { - certificateListName = certificateListName.substr(1); - } - // Looks to see if the name in the list is within the given domain - // Also checks if the name is more specific than previous ones - if (certificateName.includes(certificateListName) - && certificateListName.length > nameLength) { - nameLength = certificateListName.length; - certificateArn = certificate.CertificateArn; - } - }); - } - } catch (err) { - this.logIfDebug(err); - throw Error(`Error: Could not list certificates in Certificate Manager.\n${err}`); - } - if (certificateArn == null) { - throw Error(`Error: Could not find the certificate ${certificateName}.`); - } - return certificateArn; - } - - /** - * Gets domain info as DomainInfo object if domain exists, otherwise returns false - */ - public async getDomainInfo(): Promise { - let domainInfo; - try { - domainInfo = await this.apigateway.getDomainName({ domainName: this.givenDomainName }).promise(); - return new DomainInfo(domainInfo); - } catch (err) { - this.logIfDebug(err); - if (err.code === "NotFoundException") { - throw new Error(`Error: ${this.givenDomainName} not found.`); - } - throw new Error(`Error: Unable to fetch information about ${this.givenDomainName}`); - } - } - - /** - * Creates Custom Domain Name through API Gateway - * @param certificateArn: Certificate ARN to use for custom domain - */ - public async createCustomDomain(certificateArn: string): Promise { - - let createdDomain = {}; - - // Gateway API is completely different for v1 and v2 so seperating into two blocks - if (this.apiType === "REST") { - // Set up parameters - const params = { - certificateArn, - domainName: this.givenDomainName, - endpointConfiguration: { - types: [this.endpointType], - }, - regionalCertificateArn: certificateArn, - securityPolicy: this.securityPolicy, - }; - if (this.endpointType === endpointTypes.edge) { - params.regionalCertificateArn = undefined; - } else if (this.endpointType === endpointTypes.regional) { - params.certificateArn = undefined; - } - - // Make API call to create domain - try { - // If creating REST api use v1 of api gateway, else use v2 for HTTP and Websocket - createdDomain = await this.apigateway.createDomainName(params).promise(); - } catch (err) { - this.logIfDebug(err); - throw new Error(`Error: Failed to create custom domain ${this.givenDomainName}\n`); - } - - } else if (this.apiType === "HTTP" || this.apiType === "WEBSOCKET") { - const params = { - DomainName: this.givenDomainName, - DomainNameConfigurations: [{ - CertificateArn: certificateArn, - EndpointType: this.endpointType, - SecurityPolicy: this.securityPolicy, - }], - }; - - // Make API call to create domain - try { - // If creating REST api use v1 of api gateway, else use v2 for HTTP and Websocket - createdDomain = await this.apigatewayV2.createDomainName(params).promise(); - } catch (err) { - this.logIfDebug(err); - throw new Error(`Error: Failed to create custom domain ${this.givenDomainName}\n`); - } - } - - return new DomainInfo(createdDomain); - } - - /** - * Delete Custom Domain Name through API Gateway - */ - public async deleteCustomDomain(): Promise { - const params = { - domainName: this.givenDomainName, - }; - - // Make API call - try { - await this.apigateway.deleteDomainName(params).promise(); - } catch (err) { - this.logIfDebug(err); - throw new Error(`Error: Failed to delete custom domain ${this.givenDomainName}\n`); - } - } - - /** - * Change A Alias record through Route53 based on given action - * @param action: String descriptor of change to be made. Valid actions are ['UPSERT', 'DELETE'] - * @param domain: DomainInfo object containing info about custom domain - */ - public async changeResourceRecordSet(action: string, domain: DomainInfo): Promise { - if (action !== "UPSERT" && action !== "DELETE") { - throw new Error(`Error: Invalid action "${action}" when changing Route53 Record. - Action must be either UPSERT or DELETE.\n`); - } - - const createRoute53Record = this.serverless.service.custom.customDomain.createRoute53Record; - if (createRoute53Record !== undefined && createRoute53Record === false) { - this.serverless.cli.log("Skipping creation of Route53 record."); - return; - } - // Set up parameters - const route53HostedZoneId = await this.getRoute53HostedZoneId(); - const Changes = ["A", "AAAA"].map((Type) => ({ - Action: action, - ResourceRecordSet: { - AliasTarget: { - DNSName: domain.domainName, - EvaluateTargetHealth: false, - HostedZoneId: domain.hostedZoneId, - }, - Name: this.givenDomainName, - Type, - }, - })); - const params = { - ChangeBatch: { - Changes, - Comment: "Record created by serverless-domain-manager", - }, - HostedZoneId: route53HostedZoneId, - }; - // Make API call - try { - await this.route53.changeResourceRecordSets(params).promise(); - } catch (err) { - this.logIfDebug(err); - throw new Error(`Error: Failed to ${action} A Alias for ${this.givenDomainName}\n`); - } - } - - /** - * Gets Route53 HostedZoneId from user or from AWS - */ - public async getRoute53HostedZoneId(): Promise { - if (this.serverless.service.custom.customDomain.hostedZoneId) { - this.serverless.cli.log( - `Selected specific hostedZoneId ${this.serverless.service.custom.customDomain.hostedZoneId}`); - return this.serverless.service.custom.customDomain.hostedZoneId; - } - - const filterZone = this.hostedZonePrivate !== undefined; - if (filterZone && this.hostedZonePrivate) { - this.serverless.cli.log("Filtering to only private zones."); - } else if (filterZone && !this.hostedZonePrivate) { - this.serverless.cli.log("Filtering to only public zones."); - } - - let hostedZoneData; - const givenDomainNameReverse = this.givenDomainName.split(".").reverse(); - - try { - hostedZoneData = await this.route53.listHostedZones({}).promise(); - const targetHostedZone = hostedZoneData.HostedZones - .filter((hostedZone) => { - let hostedZoneName; - if (hostedZone.Name.endsWith(".")) { - hostedZoneName = hostedZone.Name.slice(0, -1); - } else { - hostedZoneName = hostedZone.Name; - } - if (!filterZone || this.hostedZonePrivate === hostedZone.Config.PrivateZone) { - const hostedZoneNameReverse = hostedZoneName.split(".").reverse(); - - if (givenDomainNameReverse.length === 1 - || (givenDomainNameReverse.length >= hostedZoneNameReverse.length)) { - for (let i = 0; i < hostedZoneNameReverse.length; i += 1) { - if (givenDomainNameReverse[i] !== hostedZoneNameReverse[i]) { - return false; - } - } - return true; - } - } - return false; - }) - .sort((zone1, zone2) => zone2.Name.length - zone1.Name.length) - .shift(); - - if (targetHostedZone) { - const hostedZoneId = targetHostedZone.Id; - // Extracts the hostzone Id - const startPos = hostedZoneId.indexOf("e/") + 2; - const endPos = hostedZoneId.length; - return hostedZoneId.substring(startPos, endPos); - } - } catch (err) { - this.logIfDebug(err); - throw new Error(`Error: Unable to list hosted zones in Route53.\n${err}`); - } - throw new Error(`Error: Could not find hosted zone "${this.givenDomainName}"`); - } - - public async getBasePathMapping(restApiId: string): Promise { - let basepathInfo; - let currentBasePath; - - if (this.apiType === "REST") { - const params = { - domainName: this.givenDomainName, - }; - try { - basepathInfo = await this.apigateway.getBasePathMappings(params).promise(); - } catch (err) { - this.logIfDebug(err); - throw new Error(`Error: Unable to get BasePathMappings for ${this.givenDomainName}`); - } - if (basepathInfo.items !== undefined && basepathInfo.items instanceof Array) { - for (const basepathObj of basepathInfo.items) { - if (basepathObj.restApiId === restApiId) { - currentBasePath = basepathObj.basePath; - break; - } - } - } - return currentBasePath; - - } else if (this.apiType === "HTTP" || this.apiType === "WEBSOCKET") { // V2 HTTP and WEBSOCKET - const params = { - DomainName: this.givenDomainName, - }; - try { - basepathInfo = await this.apigatewayV2.getApiMappings(params).promise(); - } catch (err) { - this.logIfDebug(err); - throw new Error(`Error: Unable to get BasePathMappings for ${this.givenDomainName}`); - } - if (basepathInfo.Items !== undefined && basepathInfo.Items instanceof Array) { - for (const basepathObj of basepathInfo.Items) { - if (basepathObj.ApiId === restApiId) { - currentBasePath = basepathObj.ApiMappingKey; - break; - } - } - } - return currentBasePath; - } - } - - /** - * Creates basepath mapping - */ - public async createBasePathMapping(restApiId: string): Promise { - if (this.apiType === "REST") { - const params = { - basePath: this.basePath, - domainName: this.givenDomainName, - restApiId, - stage: this.stage, - }; - // Make API call - try { - const resp = await this.apigateway.createBasePathMapping(params).promise(); - this.serverless.cli.log("Created basepath mapping."); - } catch (err) { - this.logIfDebug(err); - throw new Error(`Error: Unable to create basepath mapping.\n API Gateway: ${err.message}`); - } - - } else if (this.apiType === "HTTP" || this.apiType === "WEBSOCKET") { // V2 HTTP and WEBSOCKET - const params = { - ApiId: restApiId, - ApiMappingKey: this.basePath, - DomainName: this.givenDomainName, - Stage: this.stage, - }; - // Make API call - try { - await this.apigatewayV2.createApiMapping(params).promise(); - this.serverless.cli.log("Created basepath mapping."); - } catch (err) { - this.logIfDebug(err); - throw new Error(`Error: Unable to create basepath mapping.\n`); - } - } - } - - /** - * Updates basepath mapping - */ - public async updateBasePathMapping(oldBasePath: string): Promise { - const params = { - basePath: oldBasePath, - domainName: this.givenDomainName, - patchOperations: [ - { - op: "replace", - path: "/basePath", - value: this.basePath, - }, - ], - }; - // Make API call - try { - await this.apigateway.updateBasePathMapping(params).promise(); - this.serverless.cli.log("Updated basepath mapping."); - } catch (err) { - this.logIfDebug(err); - throw new Error(`Error: Unable to update basepath mapping.\n`); - } - } - - /** - * Gets rest API id from CloudFormation stack - */ - public async getApiId(): Promise { - if (this.serverless.service.provider.apiGateway && this.serverless.service.provider.apiGateway.restApiId) { - this.serverless.cli.log(`Mapping custom domain to existing API - ${this.serverless.service.provider.apiGateway.restApiId}.`); - return this.serverless.service.provider.apiGateway.restApiId; - } - - const stackFamilyName = this.serverless.service.provider.stackName || - `${this.serverless.service.service}-${this.stage}`; - - let LogicalResourceId = "ApiGatewayRestApi"; - if (this.apiType === "HTTP") { - LogicalResourceId = "HttpApi"; - } else if (this.apiType === "WEBSOCKET") { - LogicalResourceId = "WebsocketsApi"; - } - - const allStackDescriptions = []; - let nextToken = true; - this.serverless.cli.log("Searching for apiId in stacks"); - while (nextToken) { - try { - const params = { NextToken: undefined }; - if (typeof nextToken === "string") { - params.NextToken = nextToken; - } - const describeStacksResponse = await this.cloudformation.describeStacks(params).promise(); - for (const stackDescription of describeStacksResponse.Stacks) { - allStackDescriptions.push(stackDescription); - } - nextToken = describeStacksResponse.NextToken; - } catch (err) { - this.logIfDebug(err); - } - } - const familyStackNames = allStackDescriptions - .map((stack) => stack.StackName) - .filter((stackName) => stackName.includes(stackFamilyName)); - let response; - for (const familyStackName of familyStackNames) { - try { - response = await this.cloudformation.describeStackResource({ - LogicalResourceId, - StackName: familyStackName, - }).promise(); - break; - } catch (err) { - this.logIfDebug(err); - } - } - if (!response) { - throw new Error(`Error: Failed to find a stack ${stackFamilyName}\n`); - } - - const apiId = response.StackResourceDetail.PhysicalResourceId; - this.serverless.cli.log(`Found apiId: ${apiId}`); - if (!apiId) { - throw new Error(`Error: No ApiId associated with CloudFormation stack ${stackFamilyName}`); - } - return apiId; - } - - /** - * Deletes basepath mapping - */ - public async deleteBasePathMapping(): Promise { - const params = { - basePath: this.basePath, - domainName: this.givenDomainName, - }; - // Make API call - try { - await this.apigateway.deleteBasePathMapping(params).promise(); - this.serverless.cli.log("Removed basepath mapping."); - } catch (err) { - this.logIfDebug(err); - this.serverless.cli.log("Unable to remove basepath mapping."); - } - } - - /** - * Adds the domain name and distribution domain name to the CloudFormation outputs - */ - public addOutputs(domainInfo: DomainInfo): void { - const service = this.serverless.service; - if (!service.provider.compiledCloudFormationTemplate.Outputs) { - service.provider.compiledCloudFormationTemplate.Outputs = {}; - } - service.provider.compiledCloudFormationTemplate.Outputs.DomainName = { - Value: domainInfo.domainName, - }; - if (domainInfo.hostedZoneId) { - service.provider.compiledCloudFormationTemplate.Outputs.HostedZoneId = { - Value: domainInfo.hostedZoneId, - }; - } - } - - /** - * Logs message if SLS_DEBUG is set - * @param message message to be printed - */ - public logIfDebug(message: any): void { - if (process.env.SLS_DEBUG) { - this.serverless.cli.log(message, "Serverless Domain Manager"); - } - } - - /** - * Prints out a summary of all domain manager related info - */ - private printDomainSummary(domainInfo: DomainInfo): void { - this.serverless.cli.consoleLog(chalk.yellow.underline("Serverless Domain Manager Summary")); - - if (this.serverless.service.custom.customDomain.createRoute53Record !== false) { - this.serverless.cli.consoleLog(chalk.yellow("Domain Name")); - this.serverless.cli.consoleLog(` ${this.givenDomainName}`); - } - - this.serverless.cli.consoleLog(chalk.yellow("Distribution Domain Name")); - this.serverless.cli.consoleLog(` Target Domain: ${domainInfo.domainName}`); - this.serverless.cli.consoleLog(` Hosted Zone Id: ${domainInfo.hostedZoneId}`); - } -} - -export = ServerlessCustomDomain; diff --git a/package-lock.json b/package-lock.json index c66bcd2e..372f64a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,19 @@ { "name": "serverless-domain-manager", - "version": "3.3.1", + "version": "4.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { + "2-thenable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/2-thenable/-/2-thenable-1.0.0.tgz", + "integrity": "sha512-HqiDzaLDFCXkcCO/SwoyhRwqYtINFHF7t9BDRq4x90TOKNAJpiqUt9X5lQ08bwxYzc067HUywDjGySpebHcUpw==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.47" + } + }, "@babel/code-frame": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", @@ -144,285 +154,1592 @@ "to-fast-properties": "^2.0.0" } }, - "@types/chai": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", - "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", - "dev": true - }, - "@types/chai-spies": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/chai-spies/-/chai-spies-1.0.0.tgz", - "integrity": "sha512-Bj/froHomMnlAPEYEeqhmSuNSjTWW/VuSvCVdhLdcb67+dy4ffjTR6fC0YYw9tHP6KR3U8fkF1mgzmzlChHc5Q==", + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "dev": true, "requires": { - "@types/chai": "*" + "call-me-maybe": "^1.0.1", + "glob-to-regexp": "^0.3.0" } }, - "@types/mocha": { - "version": "5.2.5", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.5.tgz", - "integrity": "sha512-lAVp+Kj54ui/vLUFxsJTMtWvZraZxum3w3Nwkble2dNuV5VnPA+Mi2oGX9XYJAaIvZi3tn3cbjS/qcJXRb6Bww==", - "dev": true - }, - "@types/node": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.0.tgz", - "integrity": "sha512-Jrb/x3HT4PTJp6a4avhmJCDEVrPdqLfl3e8GGMbpkGGdwAV5UGlIs4vVEfsHHfylZVOKZWpOqmqFH8CbfOZ6kg==", - "dev": true - }, - "abbrev": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", - "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", - "dev": true - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { - "color-convert": "^1.9.0" + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" } }, - "append-transform": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", - "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", "dev": true, "requires": { - "default-require-extensions": "^2.0.0" + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" } }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=", "dev": true }, - "arg": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", - "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==", + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", "dev": true }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "dev": true }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=", "dev": true }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", "dev": true, "requires": { - "safer-buffer": "~2.1.0" + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=", "dev": true }, - "assertion-error": { + "@protobufjs/inquire": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=", "dev": true }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=", "dev": true }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=", "dev": true }, - "aws-sdk": { - "version": "2.490.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.490.0.tgz", - "integrity": "sha512-8dCf+F360XEwOorTk0wVV/haaxYvUZnfZI6PVXfR8xbcVd7Ioh9KWRe+MqHNStEttE4UQzknEPrUj/mDW++NDw==", - "requires": { - "buffer": "4.9.1", - "events": "1.1.1", - "ieee754": "1.1.8", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.3.2", - "xml2js": "0.4.19" + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=", + "dev": true + }, + "@serverless/component-metrics": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@serverless/component-metrics/-/component-metrics-1.0.8.tgz", + "integrity": "sha512-lOUyRopNTKJYVEU9T6stp2irwlTDsYMmUKBOUjnMcwGveuUfIJqrCOtFLtIPPj3XJlbZy5F68l4KP9rZ8Ipang==", + "dev": true, + "requires": { + "node-fetch": "^2.6.0", + "shortid": "^2.2.14" + } + }, + "@serverless/components": { + "version": "2.34.9", + "resolved": "https://registry.npmjs.org/@serverless/components/-/components-2.34.9.tgz", + "integrity": "sha512-qFjIeGgR4SjS32Tbl4BvoxOtLpv3Vx4s/81HdmmpdIrMPe7ePGUfkBVBu3axxAXHf4ajlb4WC1HmhTmZAHHSLQ==", + "dev": true, + "requires": { + "@serverless/inquirer": "^1.1.2", + "@serverless/platform-client": "^1.1.3", + "@serverless/platform-client-china": "^1.0.37", + "@serverless/platform-sdk": "^2.3.1", + "@serverless/utils": "^1.2.0", + "adm-zip": "^0.4.16", + "ansi-escapes": "^4.3.1", + "chalk": "^2.4.2", + "child-process-ext": "^2.1.1", + "chokidar": "^3.4.1", + "dotenv": "^8.2.0", + "figures": "^3.2.0", + "fs-extra": "^8.1.0", + "globby": "^10.0.2", + "got": "^9.6.0", + "graphlib": "^2.1.8", + "https-proxy-agent": "^5.0.0", + "ini": "^1.3.5", + "inquirer-autocomplete-prompt": "^1.0.2", + "js-yaml": "^3.14.0", + "minimist": "^1.2.5", + "moment": "^2.27.0", + "open": "^7.1.0", + "prettyoutput": "^1.2.0", + "ramda": "^0.26.1", + "semver": "^7.3.2", + "stream.pipeline-shim": "^1.1.0", + "strip-ansi": "^5.2.0", + "traverse": "^0.6.6", + "uuid": "^3.4.0", + "ws": "^7.3.1" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "chokidar": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", + "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" + } + }, + "globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + } + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "readdirp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } } }, - "aws-sdk-mock": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws-sdk-mock/-/aws-sdk-mock-1.7.0.tgz", - "integrity": "sha1-dpizuoL0k/cf8GCuISPNCAathnY=", + "@serverless/core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@serverless/core/-/core-1.1.2.tgz", + "integrity": "sha512-PY7gH+7aQ+MltcUD7SRDuQODJ9Sav9HhFJsgOiyf8IVo7XVD6FxZIsSnpMI6paSkptOB7n+0Jz03gNlEkKetQQ==", "dev": true, "requires": { - "aws-sdk": "^2.3.0", - "sinon": "^1.17.3", - "traverse": "^0.6.6" + "fs-extra": "^7.0.1", + "js-yaml": "^3.13.1", + "package-json": "^6.3.0", + "ramda": "^0.26.1", + "semver": "^6.1.1" + }, + "dependencies": { + "fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", - "dev": true - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "esutils": "^2.0.2", - "js-tokens": "^3.0.2" + "@serverless/enterprise-plugin": { + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/@serverless/enterprise-plugin/-/enterprise-plugin-3.8.4.tgz", + "integrity": "sha512-pUrREqLXdO4AhO0lSS8nXDe2E56WR8aNVz2N6F+0QnAKEsfvyUxMYybwK0diLd4UAD/sMzMHpoohDgeqpHrdwQ==", + "dev": true, + "requires": { + "@serverless/event-mocks": "^1.1.1", + "@serverless/platform-client": "^1.1.10", + "@serverless/platform-sdk": "^2.3.1", + "chalk": "^2.4.2", + "child-process-ext": "^2.1.1", + "chokidar": "^3.4.2", + "cli-color": "^2.0.0", + "find-process": "^1.4.3", + "flat": "^5.0.2", + "fs-extra": "^8.1.0", + "iso8601-duration": "^1.2.0", + "js-yaml": "^3.14.0", + "jsonata": "^1.8.3", + "jszip": "^3.5.0", + "lodash": "^4.17.20", + "memoizee": "^0.4.14", + "moment": "^2.27.0", + "ncjsm": "^4.1.0", + "node-dir": "^0.1.17", + "node-fetch": "^2.6.1", + "regenerator-runtime": "^0.13.7", + "semver": "^6.3.0", + "simple-git": "^1.132.0", + "source-map-support": "^0.5.19", + "uuid": "^3.4.0", + "yamljs": "^0.3.0" }, "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "chokidar": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", + "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "readdirp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true } } }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base64-js": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "@serverless/event-mocks": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@serverless/event-mocks/-/event-mocks-1.1.1.tgz", + "integrity": "sha512-YAV5V/y+XIOfd+HEVeXfPWZb8C6QLruFk9tBivoX2roQLWVq145s4uxf8D0QioCueuRzkukHUS4JIj+KVoS34A==", "dev": true, "requires": { - "tweetnacl": "^0.14.3" + "@types/lodash": "^4.14.123", + "lodash": "^4.17.11" } }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "@serverless/inquirer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@serverless/inquirer/-/inquirer-1.1.2.tgz", + "integrity": "sha512-2c5A6HSWwXluknPNJ2s+Z4WfBwP7Kn6kgsEKD+5xlXpDpBFsRku/xJyO9eqRCwxTM41stgHNC6TRsZ03+wH/rw==", "dev": true, "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "chalk": "^2.0.1", + "inquirer": "^6.5.2", + "ncjsm": "^4.0.1" } }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "@serverless/platform-client": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@serverless/platform-client/-/platform-client-1.1.10.tgz", + "integrity": "sha512-vMCYRdDaqQjPDlny3+mVNy0lr1P6RJ7hVkR2w9Bk783ZB894hobtMrTm8V8OQPwOvlAypmLnQsLPXwRNM+AMsw==", + "dev": true, "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4", - "isarray": "^1.0.0" + "adm-zip": "^0.4.13", + "axios": "^0.19.2", + "https-proxy-agent": "^5.0.0", + "isomorphic-ws": "^4.0.1", + "js-yaml": "^3.13.1", + "jwt-decode": "^2.2.0", + "minimatch": "^3.0.4", + "querystring": "^0.2.0", + "traverse": "^0.6.6", + "ws": "^7.2.1" } }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "caching-transform": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", - "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", + "@serverless/platform-client-china": { + "version": "1.0.37", + "resolved": "https://registry.npmjs.org/@serverless/platform-client-china/-/platform-client-china-1.0.37.tgz", + "integrity": "sha512-eN2UBK51Z9RkRY5Im0j2wCl3XuHBKiuY3kpQIxtGs52yuQx8PA0I/HBsYwyRgoTpvATK3MM/SsyeKpvNs90+uw==", "dev": true, "requires": { - "hasha": "^3.0.0", - "make-dir": "^2.0.0", - "package-hash": "^3.0.0", - "write-file-atomic": "^2.4.2" - } - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chai": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "@serverless/utils-china": "^0.1.27", + "archiver": "^4.0.1", + "dotenv": "^8.2.0", + "fs-extra": "^8.1.0", + "https-proxy-agent": "^5.0.0", + "js-yaml": "^3.14.0", + "minimatch": "^3.0.4", + "pify": "^5.0.0", + "querystring": "^0.2.0", + "stream.pipeline-shim": "^1.1.0", + "traverse": "^0.6.6", + "urlencode": "^1.1.0", + "ws": "^7.3.0" + }, + "dependencies": { + "archiver": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-4.0.2.tgz", + "integrity": "sha512-B9IZjlGwaxF33UN4oPbfBkyA4V1SxNLeIhR1qY8sRXSsbdUkEHrrOvwlYFPx+8uQeCe9M+FG6KgO+imDmQ79CQ==", + "dev": true, + "requires": { + "archiver-utils": "^2.1.0", + "async": "^3.2.0", + "buffer-crc32": "^0.2.1", + "glob": "^7.1.6", + "readable-stream": "^3.6.0", + "tar-stream": "^2.1.2", + "zip-stream": "^3.0.1" + } + }, + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", + "dev": true + } + } + }, + "@serverless/platform-sdk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@serverless/platform-sdk/-/platform-sdk-2.3.2.tgz", + "integrity": "sha512-JSX0/EphGVvnb4RAgZYewtBXPuVsU2TFCuXh6EEZ4jxK3WgUwNYeYdwB8EuVLrm1/dYqu/UWUC0rPKb+ZDycJg==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "https-proxy-agent": "^4.0.0", + "is-docker": "^1.1.0", + "jwt-decode": "^2.2.0", + "node-fetch": "^2.6.1", + "opn": "^5.5.0", + "querystring": "^0.2.0", + "ramda": "^0.25.0", + "rc": "^1.2.8", + "regenerator-runtime": "^0.13.7", + "source-map-support": "^0.5.19", + "uuid": "^3.4.0", + "write-file-atomic": "^2.4.3", + "ws": "<7.0.0" + }, + "dependencies": { + "agent-base": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-5.1.1.tgz", + "integrity": "sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "https-proxy-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz", + "integrity": "sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==", + "dev": true, + "requires": { + "agent-base": "5", + "debug": "4" + } + }, + "ramda": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz", + "integrity": "sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "@serverless/template": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@serverless/template/-/template-1.1.3.tgz", + "integrity": "sha512-hcMiX523rkp6kHeKnM1x6/dXEY+d1UFSr901yVKeeCgpFy4u33UI9vlKaPweAZCF6Ahzqywf01IsFTuBVadCrQ==", + "dev": true, + "requires": { + "@serverless/component-metrics": "^1.0.8", + "@serverless/core": "^1.0.0", + "graphlib": "^2.1.7", + "traverse": "^0.6.6" + } + }, + "@serverless/utils": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@serverless/utils/-/utils-1.2.0.tgz", + "integrity": "sha512-aI/cpGVUhWbJUR8QDMtPue28EU4ViG/L4/XKuZDfAN2uNQv3NRjwEFIBi/cxyfQnMTYVtMLe9wDjuwzOT4ENzA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "lodash": "^4.17.15", + "rc": "^1.2.8", + "type": "^2.0.0", + "uuid": "^3.4.0", + "write-file-atomic": "^2.4.3" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "@serverless/utils-china": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/@serverless/utils-china/-/utils-china-0.1.27.tgz", + "integrity": "sha512-ZQDTtmFBD2xl23YFFMVOTmqsgqtcxk9WKBGdixZ3ZY2MxAjrNJvBE0vPCRsYrQCs0I+TzdPDRIPSrOUJh7cpiw==", + "dev": true, + "requires": { + "@tencent-sdk/capi": "^0.2.17", + "dijkstrajs": "^1.0.1", + "dot-qs": "0.2.0", + "duplexify": "^4.1.1", + "end-of-stream": "^1.4.4", + "https-proxy-agent": "^5.0.0", + "object-assign": "^4.1.1", + "protobufjs": "^6.9.0", + "socket.io-client": "^2.3.0", + "winston": "3.2.1" + }, + "dependencies": { + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + } + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@tencent-sdk/capi": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/@tencent-sdk/capi/-/capi-0.2.17.tgz", + "integrity": "sha512-DIenMFJXrd4yb35BbW/7LiikCQotbm9HEBG9S4HKV47tcKt6e4nZrNPO3R2hHgQ2jdo0xfqmlUlCP0O4Q3b9pw==", + "dev": true, + "requires": { + "@types/chalk": "^2.2.0", + "@types/object-assign": "^4.0.30", + "@types/request": "^2.48.3", + "@types/request-promise-native": "^1.0.17", + "object-assign": "^4.1.1", + "querystring": "^0.2.0", + "request": "^2.88.0", + "request-promise-native": "^1.0.8" + }, + "dependencies": { + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dev": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "dev": true, + "requires": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + } + } + }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==", + "dev": true + }, + "@types/chai": { + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.2.12.tgz", + "integrity": "sha512-aN5IAC8QNtSUdQzxu7lGBgYAOuU1tmRU4c9dIq5OKGf/SBVjXo+ffM2wEjudAWbgpOhy60nLoAGH1xm8fpCKFQ==", + "dev": true + }, + "@types/chai-spies": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/chai-spies/-/chai-spies-1.0.2.tgz", + "integrity": "sha512-Z04E43GW/dnYdQyj/N868wT5HhMDw2DbfxfPV7DNOX70PqODv9BKXGriFWY508vk1rPAtYcgENaRh/YCikuFtQ==", + "dev": true, + "requires": { + "@types/chai": "*" + } + }, + "@types/chalk": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw==", + "dev": true, + "requires": { + "chalk": "*" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/lodash": { + "version": "4.14.161", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.161.tgz", + "integrity": "sha512-EP6O3Jkr7bXvZZSZYlsgt5DIjiGr0dXP1/jVEwVLTFgg0d+3lWVQkRavYVQszV7dYUwvg0B8R0MBDpcmXg7XIA==", + "dev": true + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==", + "dev": true + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, + "@types/node": { + "version": "12.12.58", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.58.tgz", + "integrity": "sha512-Be46CNIHWAagEfINOjmriSxuv7IVcqbGe+sDSg2SYCEz/0CRBy7LRASGfRbD8KZkqoePU73Wsx3UvOSFcq/9hA==", + "dev": true + }, + "@types/object-assign": { + "version": "4.0.30", + "resolved": "https://registry.npmjs.org/@types/object-assign/-/object-assign-4.0.30.tgz", + "integrity": "sha1-iUk3HVqZ9Dge4PHfCpt6GH4H5lI=", + "dev": true + }, + "@types/request": { + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", + "dev": true, + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + }, + "dependencies": { + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + } + } + }, + "@types/request-promise-native": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@types/request-promise-native/-/request-promise-native-1.0.17.tgz", + "integrity": "sha512-05/d0WbmuwjtGMYEdHIBZ0tqMJJQ2AD9LG2F6rKNBGX1SSFR27XveajH//2N/XYtual8T9Axwl+4v7oBtPUZqg==", + "dev": true, + "requires": { + "@types/request": "*" + } + }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==", + "dev": true + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "dev": true + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "agent-base": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.1.tgz", + "integrity": "sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg==", + "dev": true, + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "ajv": { + "version": "6.12.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", + "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "dependencies": { + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + } + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true, + "optional": true + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + } + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "requires": { + "type-fest": "^0.11.0" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "append-transform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", + "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "dev": true, + "requires": { + "default-require-extensions": "^2.0.0" + } + }, + "archive-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/archive-type/-/archive-type-4.0.0.tgz", + "integrity": "sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=", + "dev": true, + "requires": { + "file-type": "^4.2.0" + }, + "dependencies": { + "file-type": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-4.4.0.tgz", + "integrity": "sha1-G2AOX8ofvcboDApwxxyNul95BsU=", + "dev": true + } + } + }, + "archiver": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-3.1.1.tgz", + "integrity": "sha512-5Hxxcig7gw5Jod/8Gq0OneVgLYET+oNHcxgWItq4TbhOzRLKNAFUb9edAftiMKXvXfCB0vbGrJdZDNq0dWMsxg==", + "dev": true, + "requires": { + "archiver-utils": "^2.1.0", + "async": "^2.6.3", + "buffer-crc32": "^0.2.1", + "glob": "^7.1.4", + "readable-stream": "^3.4.0", + "tar-stream": "^2.1.0", + "zip-stream": "^2.1.2" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "compress-commons": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-2.1.1.tgz", + "integrity": "sha512-eVw6n7CnEMFzc3duyFVrQEuY1BlHR3rYsSztyG32ibGMW722i3C6IizEGMFmfMU+A+fALvBIwxN3czffTcdA+Q==", + "dev": true, + "requires": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^3.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^2.3.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "zip-stream": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-2.1.3.tgz", + "integrity": "sha512-EkXc2JGcKhO5N5aZ7TmuNo45budRaFGHOmz24wtJR7znbNqDPmdZtUauKX6et8KAVseAMBOyWJqEpXcHTBsh7Q==", + "dev": true, + "requires": { + "archiver-utils": "^2.1.0", + "compress-commons": "^2.1.1", + "readable-stream": "^3.4.0" + } + } + } + }, + "archiver-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz", + "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==", + "dev": true, + "requires": { + "glob": "^7.1.4", + "graceful-fs": "^4.2.0", + "lazystream": "^1.0.0", + "lodash.defaults": "^4.2.0", + "lodash.difference": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.union": "^4.6.0", + "normalize-path": "^3.0.0", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "aws-sdk": { + "version": "2.752.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.752.0.tgz", + "integrity": "sha512-0/8Pt8/qEgxt02IEvRjinR3cEj1YmmPlJqie4NhCWmmXmI4wDmEb5Em3A2XvU1dNwS0fpQEcuRcaQ/pWi/mScg==", + "requires": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" + }, + "dependencies": { + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + } + } + }, + "aws-sdk-mock": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/aws-sdk-mock/-/aws-sdk-mock-1.7.0.tgz", + "integrity": "sha1-dpizuoL0k/cf8GCuISPNCAathnY=", + "dev": true, + "requires": { + "aws-sdk": "^2.3.0", + "sinon": "^1.17.3", + "traverse": "^0.6.6" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz", + "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==", + "dev": true + }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "dev": true, + "requires": { + "follow-redirects": "1.5.10" + } + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64-js": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "bl": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", + "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + } + } + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "boxen": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz", + "integrity": "sha512-cU4J/+NodM3IHdSL2yN8bqYqnmlBTidDR4RC7nJs61ZmtGz8VZzM3HLQX0zY5mrSmPtR3xWwsq2jOUQqFZN8+A==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^2.4.2", + "cli-boxes": "^2.2.0", + "string-width": "^3.0.0", + "term-size": "^1.2.0", + "type-fest": "^0.3.0", + "widest-line": "^2.0.0" + }, + "dependencies": { + "type-fest": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "dev": true + }, + "caching-transform": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.2.tgz", + "integrity": "sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w==", + "dev": true, + "requires": { + "hasha": "^3.0.0", + "make-dir": "^2.0.0", + "package-hash": "^3.0.0", + "write-file-atomic": "^2.4.2" + } + }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", + "dev": true + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "caw": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", + "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", + "dev": true, + "requires": { + "get-proxy": "^2.0.0", + "isurl": "^1.0.0-alpha5", + "tunnel-agent": "^0.6.0", + "url-to-options": "^1.0.1" + } + }, + "chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", "dev": true, "requires": { @@ -438,15 +1755,131 @@ "dev": true }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "child-process-ext": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/child-process-ext/-/child-process-ext-2.1.1.tgz", + "integrity": "sha512-0UQ55f51JBkOFa+fvR76ywRzxiPwQS3Xe8oe5bZRphpv+dIMeerW5Zn5e4cUy4COJwVtJyU0R79RMnw+aCqmGA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.5", + "es5-ext": "^0.10.53", + "log": "^6.0.0", + "split2": "^3.1.1", + "stream-promise": "^3.2.0" + }, + "dependencies": { + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + } + } + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "cli-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-2.0.0.tgz", + "integrity": "sha512-a0VZ8LeraW0jTuCkuAGMNufareGHhyZU9z8OGsW0gXd1hZGi1SRuNRXdbGkraBBKnhyUhyebFWnRbp+dIn0f0A==", + "dev": true, + "requires": { + "ansi-regex": "^2.1.1", + "d": "^1.0.1", + "es5-ext": "^0.10.51", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.14", + "timers-ext": "^0.1.7" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + } + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "^2.0.0" + } + }, + "cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -475,6 +1908,35 @@ } } }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "dev": true, + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" + } + }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -488,12 +1950,38 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, + "color-string": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz", + "integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==", + "dev": true, + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colornames": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", + "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=", + "dev": true + }, "colors": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", "dev": true }, + "colorspace": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz", + "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==", + "dev": true, + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" + } + }, "combined-stream": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", @@ -515,12 +2003,87 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "compress-commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-3.0.0.tgz", + "integrity": "sha512-FyDqr8TKX5/X0qo+aVfaZ+PVmNJHJeckFBlq8jZGSJOgnynhfifoyl24qaqdUdDIBe0EVTHByN6NAkqYvE/2Xg==", + "dev": true, + "requires": { + "buffer-crc32": "^0.2.13", + "crc32-stream": "^3.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^2.3.7" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, "convert-source-map": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", @@ -530,6 +2093,18 @@ "safe-buffer": "~5.1.1" } }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -549,40 +2124,281 @@ "safe-buffer": "^5.0.1" } }, - "cross-spawn": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", - "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "requires": { + "buffer": "^5.1.0" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } + } + }, + "crc32-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-3.0.1.tgz", + "integrity": "sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==", + "dev": true, + "requires": { + "crc": "^3.4.4", + "readable-stream": "^3.4.0" + } + }, + "cross-spawn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + }, + "dependencies": { + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + } + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "dayjs": { + "version": "1.8.35", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.35.tgz", + "integrity": "sha512-isAbIEenO4ilm6f8cpqvgjZCsuerDAz2Kb7ri201AiNn58aqXuaLJEnCtfIMdCvERZHNGRY5lDMTr/jdAnKSWQ==", + "dev": true + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "decompress": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.1.tgz", + "integrity": "sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==", + "dev": true, + "requires": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + }, + "dependencies": { + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "dev": true, + "requires": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + }, + "dependencies": { + "bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "dev": true, + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "dev": true, + "requires": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + } + } + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", "dev": true, "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "dev": true + } } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" } }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", "dev": true, "requires": { - "ms": "2.0.0" + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "dependencies": { + "file-type": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", + "dev": true + }, + "get-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, "deep-eql": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", @@ -600,6 +2416,12 @@ } } }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -615,6 +2437,25 @@ "strip-bom": "^3.0.0" } }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "deferred": { + "version": "0.7.11", + "resolved": "https://registry.npmjs.org/deferred/-/deferred-0.7.11.tgz", + "integrity": "sha512-8eluCl/Blx4YOGwMapBvXRKxHXhA8ejDXYzEaK8+/gtcm8hRMhSLmXSqDmNUKNc/C8HNSmuyyp/hflhqDAvK2A==", + "dev": true, + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.50", + "event-emitter": "^0.3.5", + "next-tick": "^1.0.0", + "timers-ext": "^0.1.7" + } + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -624,18 +2465,277 @@ "object-keys": "^1.0.12" } }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, + "diagnostics": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "dev": true, + "requires": { + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" + } + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", "dev": true }, + "dijkstrajs": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.1.tgz", + "integrity": "sha1-082BIh4+pAdCz83lVtTpnpjdxxs=", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + }, + "dependencies": { + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + } + } + }, + "dot-qs": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dot-qs/-/dot-qs-0.2.0.tgz", + "integrity": "sha1-02UX/iS3zaYfznpQJqACSvr1pDk=", + "dev": true + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true + }, + "download": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/download/-/download-7.1.0.tgz", + "integrity": "sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ==", + "dev": true, + "requires": { + "archive-type": "^4.0.0", + "caw": "^2.0.1", + "content-disposition": "^0.5.2", + "decompress": "^4.2.0", + "ext-name": "^5.0.0", + "file-type": "^8.1.0", + "filenamify": "^2.0.0", + "get-stream": "^3.0.0", + "got": "^8.3.1", + "make-dir": "^1.2.0", + "p-event": "^2.1.0", + "pify": "^3.0.0" + }, + "dependencies": { + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "dev": true + }, + "cacheable-request": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", + "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "dev": true, + "requires": { + "clone-response": "1.0.2", + "get-stream": "3.0.0", + "http-cache-semantics": "3.8.1", + "keyv": "3.0.0", + "lowercase-keys": "1.0.0", + "normalize-url": "2.0.1", + "responselike": "1.0.2" + }, + "dependencies": { + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=", + "dev": true + } + } + }, + "file-type": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-8.1.0.tgz", + "integrity": "sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ==", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "got": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", + "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.7.0", + "cacheable-request": "^2.1.1", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "into-stream": "^3.1.0", + "is-retry-allowed": "^1.1.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "mimic-response": "^1.0.0", + "p-cancelable": "^0.4.0", + "p-timeout": "^2.0.1", + "pify": "^3.0.0", + "safe-buffer": "^5.1.1", + "timed-out": "^4.0.1", + "url-parse-lax": "^3.0.0", + "url-to-options": "^1.0.1" + } + }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, + "keyv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "dev": true, + "requires": { + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" + } + }, + "p-cancelable": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", + "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + } + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "dev": true, + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "duration": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/duration/-/duration-0.2.2.tgz", + "integrity": "sha512-06kgtea+bGreF5eKYgI/36A6pLXggY7oR4p1pq4SmdFBn1ReOL5D8RhG64VrqfTTKNucqqtBAwEj8aB88mcqrg==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.46" + } + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -652,6 +2752,15 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, + "enabled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "dev": true, + "requires": { + "env-variable": "0.0.x" + } + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -661,6 +2770,70 @@ "once": "^1.4.0" } }, + "engine.io-client": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.3.tgz", + "integrity": "sha512-0NGY+9hioejTEJCaSJZfWZLk4FPI9dN+1H1C4+wj2iuFba47UgZbJzfWs4aNFajnX/qAaYKbe2lLTfEEWzCmcw==", + "dev": true, + "requires": { + "component-emitter": "~1.3.0", + "component-inherit": "0.0.3", + "debug": "~4.1.0", + "engine.io-parser": "~2.2.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~6.1.0", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ws": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", + "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz", + "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "env-variable": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.6.tgz", + "integrity": "sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg==", + "dev": true + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -670,42 +2843,125 @@ "is-arrayish": "^0.2.1" } }, - "es-abstract": { - "version": "1.17.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", - "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "es-abstract": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", + "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + }, + "dependencies": { + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + } + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-promisify": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz", + "integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==", + "dev": true + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "~0.3.5" + }, + "dependencies": { + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + } + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", "dev": true, "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" + "d": "^1.0.1", + "ext": "^1.1.2" } }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", "dev": true, "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" } }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -738,18 +2994,44 @@ } } }, + "esniff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-1.1.0.tgz", + "integrity": "sha1-xmhJIp+RRk3t4uDUAgHtar9l8qw=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.12" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "essentials": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/essentials/-/essentials-1.1.1.tgz", + "integrity": "sha512-SmaxoAdVu86XkZQM/u6TYSu96ZlFGwhvSk1l9zAkznFuQkMb9mRDS2iq/XWDow7R8OwBwdYH8nLyDKznMD+GWw==", + "dev": true + }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", @@ -785,23 +3067,206 @@ } } }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dev": true, + "requires": { + "type": "^2.0.0" + } + }, + "ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "requires": { + "mime-db": "^1.28.0" + } + }, + "ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "requires": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true + "fast-glob": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", + "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2", + "picomatch": "^2.2.1" + } }, "fast-json-stable-stringify": { "version": "2.0.0", @@ -815,6 +3280,83 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==", + "dev": true + }, + "fastq": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz", + "integrity": "sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "fecha": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz", + "integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg==", + "dev": true + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", + "dev": true + }, + "filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", + "dev": true + }, + "filenamify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", + "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", + "dev": true, + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.0", + "trim-repeated": "^1.0.0" + } + }, + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "find-cache-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", @@ -826,6 +3368,44 @@ "pkg-dir": "^3.0.0" } }, + "find-process": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.3.tgz", + "integrity": "sha512-+IA+AUsQCf3uucawyTwMWcY+2M3FXq3BRvw3S+j5Jvydjk31f/+NPWpYZOJs+JUs2GvxH4Yfr6Wham0ZtRLlPA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "commander": "^2.11.0", + "debug": "^2.6.8" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "find-requires": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-requires/-/find-requires-1.0.0.tgz", + "integrity": "sha512-UME7hNwBfzeISSFQcBEDemEEskpOjI/shPrpJM5PI4DSdn6hX0dmz+2dL70blZER2z8tSnTRL+2rfzlYgtbBoQ==", + "dev": true, + "requires": { + "es5-ext": "^0.10.49", + "esniff": "^1.1.0" + } + }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -835,30 +3415,47 @@ "locate-path": "^3.0.0" } }, - "findup-sync": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", - "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", "dev": true, "requires": { - "glob": "~5.0.0" + "debug": "=3.1.0" }, "dependencies": { - "glob": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "2 || 3", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "ms": "2.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true } } }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, "foreground-child": { "version": "1.5.6", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", @@ -895,12 +3492,110 @@ "samsam": "~1.1" } }, + "formidable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", + "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + } + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "fs2": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/fs2/-/fs2-0.3.8.tgz", + "integrity": "sha512-HxOTRiFS3PqwAOmlp1mTwLA+xhQBdaP82b5aBamc/rHKFVyn4qL8YpngaAleD52PNMzBm6TsGOoU/Hq+bAfBhA==", + "dev": true, + "requires": { + "d": "^1.0.1", + "deferred": "^0.7.11", + "es5-ext": "^0.10.53", + "event-emitter": "^0.3.5", + "ignore": "^5.1.4", + "memoizee": "^0.4.14", + "type": "^2.0.0" + } + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -913,6 +3608,21 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-proxy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", + "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", + "dev": true, + "requires": { + "npm-conf": "^1.1.0" + } + }, + "get-stdin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz", + "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==", + "dev": true + }, "get-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", @@ -922,6 +3632,12 @@ "pump": "^3.0.0" } }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", @@ -945,18 +3661,259 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", + "dev": true + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, + "globby": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^1.0.2", + "dir-glob": "^2.2.2", + "fast-glob": "^2.2.6", + "glob": "^7.1.3", + "ignore": "^4.0.3", + "pify": "^4.0.1", + "slash": "^2.0.0" + }, + "dependencies": { + "@nodelib/fs.stat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "dir-glob": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz", + "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==", + "dev": true, + "requires": { + "path-type": "^3.0.0" + } + }, + "fast-glob": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", + "dev": true, + "requires": { + "@mrmlnc/readdir-enhanced": "^2.2.1", + "@nodelib/fs.stat": "^1.1.2", + "glob-parent": "^3.1.0", + "is-glob": "^4.0.0", + "merge2": "^1.2.3", + "micromatch": "^3.1.10" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, "graceful-fs": { "version": "4.1.15", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", "dev": true }, + "graphlib": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", + "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -964,17 +3921,24 @@ "dev": true }, "handlebars": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", - "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", "dev": true, "requires": { + "minimist": "^1.2.5", "neo-async": "^2.6.0", - "optimist": "^0.6.1", "source-map": "^0.6.1", - "uglify-js": "^3.1.4" + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" }, "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -990,27 +3954,13 @@ "dev": true }, "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "dev": true, "requires": { - "ajv": "^6.5.5", + "ajv": "^6.12.3", "har-schema": "^2.0.0" - }, - "dependencies": { - "ajv": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", - "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - } } }, "has": { @@ -1022,26 +3972,113 @@ "function-bind": "^1.1.1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "isarray": "2.0.1" + }, + "dependencies": { + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + } } }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true + }, "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", "dev": true }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "hasha": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", @@ -1052,9 +4089,9 @@ } }, "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, "hosted-git-info": { @@ -1063,6 +4100,18 @@ "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", @@ -1074,17 +4123,65 @@ "sshpk": "^1.7.0" } }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, "ieee754": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" }, + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -1101,18 +4198,209 @@ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, - "interpret": { + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "dev": true, + "requires": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + } + } + } + } + }, + "inquirer-autocomplete-prompt": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", - "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", + "resolved": "https://registry.npmjs.org/inquirer-autocomplete-prompt/-/inquirer-autocomplete-prompt-1.1.0.tgz", + "integrity": "sha512-mrSeUSFGnTSid/DCKG+E+IcN4MaOnT2bW7NuSagZAguD4k3hZ0UladdYNP4EstZOwgeqv0C3M1zYa1QIIf0Oyg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.1", + "chalk": "^4.0.0", + "figures": "^3.2.0", + "run-async": "^2.4.0", + "rxjs": "^6.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true }, + "into-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "dev": true, + "requires": { + "from2": "^2.1.1", + "p-is-promise": "^1.1.0" + }, + "dependencies": { + "p-is-promise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "dev": true + } + } + }, "invert-kv": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "is-arguments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", @@ -1125,18 +4413,96 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, "is-callable": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", "dev": true }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", "dev": true }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-docker": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-1.1.0.tgz", + "integrity": "sha1-8EN01O7lMQ6ajhE78UlUEeRhdqE=", + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -1149,6 +4515,54 @@ "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==", "dev": true }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, "is-regex": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", @@ -1158,6 +4572,12 @@ "has": "^1.0.3" } }, + "is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -1179,6 +4599,29 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + }, + "dependencies": { + "is-docker": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", + "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "dev": true + } + } + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -1190,6 +4633,24 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "iso8601-duration": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/iso8601-duration/-/iso8601-duration-1.2.0.tgz", + "integrity": "sha512-ErTBd++b17E8nmWII1K1uZtBgD1E8RjyvwmxlCjPHNqHMD7gmcMHOw0E8Ro/6+QT4PhHRSnnMo7bxa1vFPkwhg==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "dev": true + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -1357,12 +4818,22 @@ } }, "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz", + "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0" + } + }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", "dev": true, "requires": { - "handlebars": "^4.1.2" + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" } }, "jmespath": { @@ -1370,12 +4841,6 @@ "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true - }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", @@ -1398,12 +4863,48 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-cycle": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/json-cycle/-/json-cycle-1.3.0.tgz", + "integrity": "sha512-FD/SedD78LCdSvJaOUQAXseT8oQBb5z6IVYaQaCrVUlu9zOAr1BDdKyVYQaSD/GDsAMrXpKcOyBD4LIl8nfjHw==", + "dev": true + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, + "json-refs": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/json-refs/-/json-refs-3.0.15.tgz", + "integrity": "sha512-0vOQd9eLNBL18EGl5yYaO44GhixmImes2wiYn9Z3sag3QnehWrYWlB9AFtMxCL2Bj3fyxgDYkxGFEU/chlYssw==", + "dev": true, + "requires": { + "commander": "~4.1.1", + "graphlib": "^2.1.8", + "js-yaml": "^3.13.1", + "lodash": "^4.17.15", + "native-promise-only": "^0.8.1", + "path-loader": "^1.0.10", + "slash": "^3.0.0", + "uri-js": "^4.2.2" + }, + "dependencies": { + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + } + } + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -1422,6 +4923,21 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, + "jsonata": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/jsonata/-/jsonata-1.8.3.tgz", + "integrity": "sha512-r6ztI6ohbpRo77AxBm6vMs3aHZi2L2PaakW7TCPwSkeGcuAZ/SxXGLWH2Npwqq5+YBM/fg/g0EXg/pI9HvXQ8Q==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", @@ -1434,6 +4950,109 @@ "verror": "1.10.0" } }, + "jszip": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.5.0.tgz", + "integrity": "sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==", + "dev": true, + "requires": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "jwt-decode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz", + "integrity": "sha1-fYa9VmefWM5qhHBKZX3TkruoGnk=", + "dev": true + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "kuler": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", + "dev": true, + "requires": { + "colornames": "^1.1.1" + } + }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "dev": true, + "requires": { + "readable-stream": "^2.0.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "lcid": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", @@ -1453,6 +5072,15 @@ "type-check": "~0.3.2" } }, + "lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } + }, "load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -1484,9 +5112,27 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "dev": true + }, + "lodash.difference": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz", + "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=", + "dev": true + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", "dev": true }, "lodash.flattendeep": { @@ -1495,12 +5141,80 @@ "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "dev": true + }, + "lodash.union": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=", + "dev": true + }, + "log": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log/-/log-6.0.0.tgz", + "integrity": "sha512-sxChESNYJ/EcQv8C7xpmxhtTOngoXuMEqGDAkhXBEmt3MAzM3SM/TmIBOqnMEVdrOv1+VgZoYbo6U2GemQiU4g==", + "dev": true, + "requires": { + "d": "^1.0.0", + "duration": "^0.2.2", + "es5-ext": "^0.10.49", + "event-emitter": "^0.3.5", + "sprintf-kit": "^2.0.0", + "type": "^1.0.1" + }, + "dependencies": { + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + } + } + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "logform": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", + "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "dev": true, + "requires": { + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + } + }, "lolex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", "dev": true }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "dev": true + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -1511,6 +5225,15 @@ "yallist": "^2.1.2" } }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "dev": true, + "requires": { + "es5-ext": "~0.10.2" + } + }, "make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -1522,9 +5245,9 @@ } }, "make-error": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", - "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, "map-age-cleaner": { @@ -1536,6 +5259,21 @@ "p-defer": "^1.0.0" } }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, "mem": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", @@ -1547,6 +5285,22 @@ "p-is-promise": "^2.0.0" } }, + "memoizee": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", + "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.45", + "es6-weak-map": "^2.0.2", + "event-emitter": "^0.3.5", + "is-promise": "^2.1", + "lru-queue": "0.1", + "next-tick": "1", + "timers-ext": "^0.1.5" + } + }, "merge-source-map": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", @@ -1564,6 +5318,34 @@ } } }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, "mime-db": { "version": "1.37.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", @@ -1585,6 +5367,12 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -1595,76 +5383,180 @@ } }, "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, "requires": { - "minimist": "0.0.8" + "minimist": "^1.2.5" } }, "mocha": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", - "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", "dev": true, "requires": { + "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", - "commander": "2.15.1", - "debug": "3.1.0", + "chokidar": "3.3.0", + "debug": "3.2.6", "diff": "3.5.0", "escape-string-regexp": "1.0.5", - "glob": "7.1.2", + "find-up": "3.0.0", + "glob": "7.1.3", "growl": "1.10.5", - "he": "1.1.1", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "supports-color": "5.4.0" + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" }, "dependencies": { - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "has-flag": "^3.0.0" } }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" } } } }, - "mocha-param": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mocha-param/-/mocha-param-2.0.0.tgz", - "integrity": "sha512-fSdhAkOEEqGMO6MgyBwFD1/NzXaPSELZuz8I0sAKbd4CJRd2LKJpUQKlyX4VST4mT2zxn7Yh+Ek9GNVZTvdAXQ==", + "mocha-param": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mocha-param/-/mocha-param-2.0.1.tgz", + "integrity": "sha512-TDrDAChx9XtkGmRKWGOzMoQefwHsfYUxyjNWgkfAze+EFRIRT28yJVcpcNhw9iWg2NvfeMQZnSwWCNMYwPxZew==", + "dev": true + }, + "moment": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.28.0.tgz", + "integrity": "sha512-Z5KOjYmnHyd/ukynmFd/WwyXHd7L4J9vTI/nn5Ap9AVUgaAE15VvQ9MOGmJJygEUklupqIrFnor/tjTwRU+tQw==", "dev": true }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "nanoid": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.11.tgz", + "integrity": "sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA==", "dev": true }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=", + "dev": true + }, + "ncjsm": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ncjsm/-/ncjsm-4.1.0.tgz", + "integrity": "sha512-YElRGtbz5iIartetOI3we+XAkcGE29F0SdNC0qRy500/u4WceQd2z9Nhlx24OHmIDIKz9MHdJwf/fkSG0hdWcQ==", + "dev": true, + "requires": { + "builtin-modules": "^3.1.0", + "deferred": "^0.7.11", + "es5-ext": "^0.10.53", + "es6-set": "^0.1.5", + "find-requires": "^1.0.0", + "fs2": "^0.3.8", + "type": "^2.0.0" + }, + "dependencies": { + "builtin-modules": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz", + "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==", + "dev": true + } + } + }, "neo-async": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", @@ -1677,12 +5569,51 @@ "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==", "dev": true }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=", + "dev": true, + "requires": { + "minimatch": "^3.0.2" + } + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "dev": true + }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", @@ -1715,6 +5646,36 @@ } } }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true + }, + "npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "dev": true, + "requires": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -1759,7 +5720,7 @@ "dependencies": { "uuid": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "resolved": false, "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", "dev": true } @@ -1771,6 +5732,61 @@ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-hash": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.0.3.tgz", + "integrity": "sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg==", + "dev": true + }, "object-inspect": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", @@ -1783,6 +5799,15 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, "object.assign": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", @@ -1807,6 +5832,25 @@ "has": "^1.0.3" } }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1816,20 +5860,60 @@ "wrappy": "1" } }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "one-time": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", + "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "^1.0.0" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + } + } + }, + "open": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/open/-/open-7.2.1.tgz", + "integrity": "sha512-xbYCJib4spUdmcs0g/2mK1nKo/jO2T7INClWd/beL7PFkXRWgr8B23ssDHX/USPn2M2IjDR5UdpYs6I67SnTSA==", + "dev": true, + "requires": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "dependencies": { + "is-docker": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", + "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "dev": true + } + } + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", "dev": true, "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" + "is-wsl": "^1.1.0" }, "dependencies": { - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", "dev": true } } @@ -1865,12 +5949,33 @@ "mem": "^4.0.0" } }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, + "p-event": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-2.3.1.tgz", + "integrity": "sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA==", + "dev": true, + "requires": { + "p-timeout": "^2.0.1" + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -1901,6 +6006,15 @@ "p-limit": "^2.0.0" } }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -1919,6 +6033,32 @@ "release-zalgo": "^1.0.0" } }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, "parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -1929,6 +6069,36 @@ "json-parse-better-errors": "^1.0.1" } }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -1947,6 +6117,16 @@ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, + "path-loader": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/path-loader/-/path-loader-1.0.10.tgz", + "integrity": "sha512-CMP0v6S6z8PHeJ6NFVyVJm6WyJjIwFvyz2b0n2/4bKdS/0uZa/9sKUlYZzubrn3zuDRU0zIuEDX9DZYQ2ZI8TA==", + "dev": true, + "requires": { + "native-promise-only": "^0.8.1", + "superagent": "^3.8.3" + } + }, "path-parse": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", @@ -1970,18 +6150,45 @@ } } }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, "pkg-dir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", @@ -1991,12 +6198,90 @@ "find-up": "^3.0.0" } }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "prettyoutput": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/prettyoutput/-/prettyoutput-1.2.0.tgz", + "integrity": "sha512-G2gJwLzLcYS+2m6bTAe+CcDpwak9YpcvpScI0tE4WYb2O3lEZD/YywkMNpGqsSx5wttGvh2UXaKROTKKCyM2dw==", + "dev": true, + "requires": { + "colors": "1.3.x", + "commander": "2.19.x", + "lodash": "4.17.x" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", + "dev": true + } + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "promise-queue": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/promise-queue/-/promise-queue-2.2.5.tgz", + "integrity": "sha1-L29ffA9tCBCelnZZx5uIqe1ek7Q=", + "dev": true + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, + "protobufjs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz", + "integrity": "sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==", + "dev": true, + "requires": { + "@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.1", + "@types/node": "^13.7.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/node": { + "version": "13.13.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.19.tgz", + "integrity": "sha512-IVsULCpTdafcHhBDLYEPnV5l15xV0q065zvOHC1ZmzFYaBCMzku078eXnazoSG8907vZjRgEN/EQjku7GwwFyQ==", + "dev": true + } + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -2030,11 +6315,28 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" }, + "ramda": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", + "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==", + "dev": true + }, "randomstring": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.1.5.tgz", @@ -2052,6 +6354,18 @@ } } }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -2063,23 +6377,77 @@ "path-type": "^3.0.0" } }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "registry-auth-token": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.0.tgz", + "integrity": "sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w==", "dev": true, "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" + "rc": "^1.2.8" } }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", "dev": true, "requires": { - "resolve": "^1.1.6" + "rc": "^1.2.8" } }, "release-zalgo": { @@ -2091,10 +6459,28 @@ "es6-error": "^4.0.1" } }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "replaceall": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/replaceall/-/replaceall-0.1.6.tgz", + "integrity": "sha1-gdgax663LX9cSUKt8ml6MiBojY4=", + "dev": true + }, "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -2104,7 +6490,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.0", + "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", @@ -2114,37 +6500,47 @@ "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" }, "dependencies": { - "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } } } }, "request-promise-core": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz", - "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", "dev": true, "requires": { - "lodash": "^4.13.1" + "lodash": "^4.17.19" } }, "request-promise-native": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz", - "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", "dev": true, "requires": { - "request-promise-core": "1.1.1", - "stealthy-require": "^1.1.0", - "tough-cookie": ">=2.3.3" + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" } }, "require-directory": { @@ -2174,6 +6570,43 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, "rimraf": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", @@ -2183,12 +6616,42 @@ "glob": "^7.1.3" } }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", + "dev": true + }, + "rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -2206,60 +6669,587 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" }, + "seek-bzip": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.6.tgz", + "integrity": "sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==", + "dev": true, + "requires": { + "commander": "^2.8.1" + } + }, "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", "dev": true }, + "semver-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", + "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", + "dev": true + }, + "serverless": { + "version": "1.83.0", + "resolved": "https://registry.npmjs.org/serverless/-/serverless-1.83.0.tgz", + "integrity": "sha512-w/74YcSjJfR3osNMf4/EAAAIfzzI7reW3cDSHcwZeTOXQ//CCeAHy4XKhAXYa50tzRJVV8OUDt1RuXsZz7YbJQ==", + "dev": true, + "requires": { + "@serverless/cli": "^1.5.2", + "@serverless/components": "^2.34.9", + "@serverless/enterprise-plugin": "^3.8.4", + "@serverless/inquirer": "^1.1.2", + "@serverless/utils": "^1.2.0", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2", + "archiver": "^3.1.1", + "aws-sdk": "^2.749.0", + "bluebird": "^3.7.2", + "boxen": "^3.2.0", + "cachedir": "^2.3.0", + "chalk": "^2.4.2", + "child-process-ext": "^2.1.1", + "d": "^1.0.1", + "dayjs": "^1.8.35", + "decompress": "^4.2.1", + "download": "^7.1.0", + "essentials": "^1.1.1", + "fast-levenshtein": "^2.0.6", + "filesize": "^3.6.1", + "fs-extra": "^8.1.0", + "get-stdin": "^6.0.0", + "globby": "^9.2.0", + "graceful-fs": "^4.2.4", + "https-proxy-agent": "^5.0.0", + "is-docker": "^1.1.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.14.0", + "json-cycle": "^1.3.0", + "json-refs": "^3.0.15", + "jwt-decode": "^2.2.0", + "lodash": "^4.17.20", + "memoizee": "^0.4.14", + "mkdirp": "^0.5.4", + "nanomatch": "^1.2.13", + "ncjsm": "^4.1.0", + "node-fetch": "^2.6.1", + "object-hash": "^2.0.3", + "p-limit": "^2.3.0", + "promise-queue": "^2.2.5", + "rc": "^1.2.8", + "replaceall": "^0.1.6", + "semver": "^6.3.0", + "semver-regex": "^2.0.0", + "stream-promise": "^3.2.0", + "tabtab": "^3.0.2", + "timers-ext": "^0.1.7", + "type": "^2.1.0", + "untildify": "^3.0.3", + "uuid": "^3.4.0", + "write-file-atomic": "^2.4.3", + "yaml-ast-parser": "0.0.43", + "yargs-parser": "^18.1.3" + }, + "dependencies": { + "@serverless/cli": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@serverless/cli/-/cli-1.5.2.tgz", + "integrity": "sha512-FMACx0qPD6Uj8U+7jDmAxEe1tdF9DsuY5VsG45nvZ3olC9xYJe/PMwxWsjXfK3tg1HUNywYAGCsy7p5fdXhNzw==", + "dev": true, + "requires": { + "@serverless/core": "^1.1.2", + "@serverless/template": "^1.1.3", + "@serverless/utils": "^1.2.0", + "ansi-escapes": "^4.3.1", + "chalk": "^2.4.2", + "chokidar": "^3.4.1", + "dotenv": "^8.2.0", + "figures": "^3.2.0", + "minimist": "^1.2.5", + "prettyoutput": "^1.2.0", + "strip-ansi": "^5.2.0" + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "aws-sdk": { + "version": "2.752.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.752.0.tgz", + "integrity": "sha512-0/8Pt8/qEgxt02IEvRjinR3cEj1YmmPlJqie4NhCWmmXmI4wDmEb5Em3A2XvU1dNwS0fpQEcuRcaQ/pWi/mScg==", + "dev": true, + "requires": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.15.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "uuid": "3.3.2", + "xml2js": "0.4.19" + }, + "dependencies": { + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true + } + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "chokidar": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", + "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "readdirp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shelljs": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz", + "integrity": "sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, + "shortid": { + "version": "2.2.15", + "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.15.tgz", + "integrity": "sha512-5EaCy2mx2Jgc/Fdn9uuDuNIIfWBpzY4XIlhoqtXF6qsf+/+SGZ+FxDdX/ZsMZiWupIWNqAEmiNY4RC+LSmCeOw==", + "dev": true, + "requires": { + "nanoid": "^2.1.0" + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "simple-git": { + "version": "1.132.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-1.132.0.tgz", + "integrity": "sha512-xauHm1YqCTom1sC9eOjfq3/9RKiUA9iPnxBbrY2DdL8l4ADMu0jjM5l5lphQP5YWNqAL2aXC/OeuQ76vHtW5fg==", + "dev": true, + "requires": { + "debug": "^4.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + } + } + }, + "sinon": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", + "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", + "dev": true, + "requires": { + "formatio": "1.1.1", + "lolex": "1.3.2", + "samsam": "1.1.2", + "util": ">=0.10.3 <1" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", "dev": true, "requires": { - "shebang-regex": "^1.0.0" + "kind-of": "^3.2.0" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true + "socket.io-client": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz", + "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~4.1.0", + "engine.io-client": "~3.4.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.3.0", + "to-array": "0.1.4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } }, - "shelljs": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", - "integrity": "sha512-fc0BKlAWiLpwZljmOvAOTE/gXawtCoNrP5oaY7KIaQbbyHeQVg01pSEuEGvGh3HEdBU4baCD7wQBwADmM/7f7A==", + "socket.io-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", + "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", "dev": true, "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } } }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } }, - "sinon": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", - "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", + "sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", "dev": true, "requires": { - "formatio": "1.1.1", - "lolex": "1.3.2", - "samsam": "1.1.2", - "util": ">=0.10.3 <1" + "sort-keys": "^1.0.0" } }, "source-map": { @@ -2272,10 +7262,23 @@ "amdefine": ">=0.0.4" } }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, "source-map-support": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz", - "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==", + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -2290,10 +7293,16 @@ } } }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, "spawn-wrap": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", - "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.3.tgz", + "integrity": "sha512-IgB8md0QW/+tWqcavuFgKYR/qIRvJkRLPJDFaoXtLLUaVcCDK0+HeFTkmQHj3eprcYhc+gOl0aEA1w7qZlYezw==", "dev": true, "requires": { "foreground-child": "^1.5.6", @@ -2336,16 +7345,43 @@ "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", "dev": true }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "dev": true, + "requires": { + "readable-stream": "^3.0.0" + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, + "sprintf-kit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sprintf-kit/-/sprintf-kit-2.0.0.tgz", + "integrity": "sha512-/0d2YTn8ZFVpIPAU230S9ZLF8WDkSSRWvh/UOLM7zzvkCchum1TtouRgyV8OfgOaYilSGU4lSSqzwBXJVlAwUw==", + "dev": true, + "requires": { + "es5-ext": "^0.10.46" + } + }, "sshpk": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz", - "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -2359,12 +7395,83 @@ "tweetnacl": "~0.14.0" } }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "dev": true }, + "stream-promise": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-promise/-/stream-promise-3.2.0.tgz", + "integrity": "sha512-P+7muTGs2C8yRcgJw/PPt61q7O517tDHiwYEzMWo1GSBCcZedUMT/clz7vUNsSxFphIlJ6QUL4GexQKlfJoVtA==", + "dev": true, + "requires": { + "2-thenable": "^1.0.0", + "es5-ext": "^0.10.49", + "is-stream": "^1.1.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "stream.finished": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/stream.finished/-/stream.finished-1.2.0.tgz", + "integrity": "sha512-xSp45f/glqd035qAtFUxAGvhotjY/EfqDNV+rQW8o7ffligiOjPaguTEvRzeQAhiQMCdkPEBrp5++S/rQyavWQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "stream.pipeline-shim": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stream.pipeline-shim/-/stream.pipeline-shim-1.1.0.tgz", + "integrity": "sha512-pSi/SZZDbSA5l3YYjSmJadCoD74/qSe79r9ZVR21lD4bpf+khn5Umi6AlfJrD8I0KQfGSqm/7Yp48dmithM+Vw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1", + "stream.finished": "^1.2.0" + } + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -2403,63 +7510,331 @@ "function-bind": "^1.1.1" } }, - "string.prototype.trimright": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", - "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "string.prototype.trimright": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", + "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "dev": true, + "requires": { + "is-natural-number": "^4.0.1" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, + "superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "dev": true, + "requires": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.5" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "tabtab": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tabtab/-/tabtab-3.0.2.tgz", + "integrity": "sha512-jANKmUe0sIQc/zTALTBy186PoM/k6aPrh3A7p6AaAfF6WPSbTx1JYeGIGH162btpH+mmVEXln+UxwViZHO2Jhg==", + "dev": true, + "requires": { + "debug": "^4.0.1", + "es6-promisify": "^6.0.0", + "inquirer": "^6.0.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "untildify": "^3.0.3" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "tar-stream": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz", + "integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "term-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, + "requires": { + "execa": "^0.7.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + } + } + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" } }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "dev": true }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", "dev": true }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dev": true, "requires": { - "has-flag": "^3.0.0" + "es5-ext": "~0.10.46", + "next-tick": "1" } }, - "test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" + "os-tmpdir": "~1.0.2" } }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "dev": true + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, "tough-cookie": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", @@ -2484,24 +7859,46 @@ "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", "dev": true }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==", + "dev": true + }, "ts-node": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.0.1.tgz", - "integrity": "sha512-zER3Js6Iotp31ghen6nKjgX75UOipwTWX9T5fAVmHaaYAizWhOes4uAsLmDC8H51UG5tHL8gNjoa/wLFjo7wtA==", + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz", + "integrity": "sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA==", "dev": true, "requires": { "arg": "^4.1.0", - "arrify": "^1.0.0", - "diff": "^3.1.0", + "diff": "^4.0.1", "make-error": "^1.1.1", - "source-map-support": "^0.5.6", - "yn": "^2.0.0" + "source-map-support": "^0.5.17", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } } }, "tslib": { @@ -2511,26 +7908,38 @@ "dev": true }, "tslint": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.1.0.tgz", - "integrity": "sha1-UaR7rutYlW/NYXvSzwDi7w7qLtk=", + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", + "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", "dev": true, "requires": { - "babel-code-frame": "^6.22.0", - "colors": "^1.1.2", - "diff": "^3.2.0", - "findup-sync": "~0.3.0", + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", "glob": "^7.1.1", - "optimist": "~0.6.0", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", "resolve": "^1.3.2", "semver": "^5.3.0", - "tsutils": "^1.4.0" + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } } }, "tslint-microsoft-contrib": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tslint-microsoft-contrib/-/tslint-microsoft-contrib-6.0.0.tgz", - "integrity": "sha512-R//efwn+34IUjTJeYgNDAJdzG0jyLWIehygPt/PHuZAieTolFVS56FgeFW7DOLap9ghXzMiFPTmDgm54qaL7QA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tslint-microsoft-contrib/-/tslint-microsoft-contrib-6.2.0.tgz", + "integrity": "sha512-6tfi/2tHqV/3CL77pULBcK+foty11Rr0idRDxKnteTaKm6gWF9qmaCNU17HVssOuwlYNyOmd9Jsmjd+1t3a3qw==", "dev": true, "requires": { "tsutils": "^2.27.2 <2.29.0" @@ -2548,10 +7957,13 @@ } }, "tsutils": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-1.9.1.tgz", - "integrity": "sha1-ufmrROVa+WgYMdXyjQrur1x1DLA=", - "dev": true + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } }, "tunnel-agent": { "version": "0.6.0", @@ -2568,6 +7980,12 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "dev": true }, + "type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", + "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==", + "dev": true + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -2583,10 +8001,16 @@ "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", "dev": true }, + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true + }, "typescript": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz", - "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==", + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", "dev": true }, "uglify-js": { @@ -2616,6 +8040,92 @@ } } }, + "unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "requires": { + "buffer": "^5.2.1", + "through": "^2.3.8" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "untildify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", + "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", + "dev": true + }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -2633,6 +8143,12 @@ } } }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, "url": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", @@ -2642,6 +8158,36 @@ "querystring": "0.2.0" } }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true + }, + "urlencode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/urlencode/-/urlencode-1.1.0.tgz", + "integrity": "sha1-HyuibwE8hfATP3o61v8nMK33y7c=", + "dev": true, + "requires": { + "iconv-lite": "~0.4.11" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, "util": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/util/-/util-0.12.1.tgz", @@ -2655,6 +8201,12 @@ "safe-buffer": "^5.1.2" } }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", @@ -2696,6 +8248,112 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + } + } + }, + "widest-line": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "dev": true, + "requires": { + "string-width": "^2.1.1" + }, + "dependencies": { + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + } + } + }, + "winston": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", + "integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==", + "dev": true, + "requires": { + "async": "^2.6.1", + "diagnostics": "^1.1.1", + "is-stream": "^1.1.0", + "logform": "^2.1.1", + "one-time": "0.0.4", + "readable-stream": "^3.1.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.3.0" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + } + } + }, + "winston-transport": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", + "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "dev": true, + "requires": { + "readable-stream": "^2.3.7", + "triple-beam": "^1.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -2747,6 +8405,12 @@ "signal-exit": "^3.0.2" } }, + "ws": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", + "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==", + "dev": true + }, "xml2js": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", @@ -2761,6 +8425,18 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", @@ -2773,6 +8449,22 @@ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, + "yaml-ast-parser": { + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", + "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", + "dev": true + }, + "yamljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", + "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "glob": "^7.0.5" + } + }, "yargs": { "version": "13.2.4", "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", @@ -2793,20 +8485,78 @@ } }, "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + }, + "dependencies": { + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + } + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + }, "yn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true + }, + "zip-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-3.0.1.tgz", + "integrity": "sha512-r+JdDipt93ttDjsOVPU5zaq5bAyY+3H19bDrThkvuVxC0xMQzU1PJcS6D+KrP3u96gH9XLomcHPb+2skoDjulQ==", + "dev": true, + "requires": { + "archiver-utils": "^2.1.0", + "compress-commons": "^3.0.0", + "readable-stream": "^3.6.0" + } } } } diff --git a/package.json b/package.json index e7717b49..f37cf40a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "serverless-domain-manager", - "version": "3.3.2", + "version": "4.2.2", "engines": { "node": ">=4.0" }, @@ -27,16 +27,16 @@ "main": "dist/index.js", "bin": {}, "scripts": { - "test": "tsc --project . && nyc mocha -r ts-node/register test/unit-tests/index.test.ts && nyc report --reporter=text-summary", - "integration-test": "node ./node_modules/istanbul/lib/cli.js test _mocha test/integration-tests -- -R spec", - "lint": "tslint --project .", + "test": "nyc mocha -r ts-node/register --project tsconfig.tests.json test/unit-tests/index.test.ts && nyc report --reporter=text-summary", + "integration-test": "nyc mocha -r ts-node/register --project tsconfig.tests.json test/integration-tests/*.test.ts && nyc report --reporter=text-summary", + "lint": "tslint --project . && tslint --project tsconfig.tests.json", "build": "tsc --project ." }, "files": [ "*.js", "*.ts", "*.json", - "dist/*.js" + "dist" ], "nyc": { "extension": [ @@ -44,29 +44,30 @@ ] }, "devDependencies": { - "@types/chai": "^4.1.7", - "@types/chai-spies": "^1.0.0", - "@types/mocha": "^5.2.5", - "@types/node": "^12.0.0", + "@types/chai": "^4.2.12", + "@types/chai-spies": "^1.0.2", + "@types/mocha": "^5.2.7", + "@types/node": "^12.12.58", "aws-sdk-mock": "^1.7.0", "chai": "^3.5.0", "chai-spies": "^1.0.0", "istanbul": "^0.4.5", - "mocha": "^5.2.0", - "mocha-param": "^2.0.0", + "mocha": "^7.2.0", + "mocha-param": "^2.0.1", "nyc": "^14.1.1", "randomstring": "^1.1.5", - "request": "^2.88.0", - "request-promise-native": "^1.0.5", - "shelljs": "^0.8.3", - "ts-node": "^8.0.1", - "tslint": "^5.1.0", - "tslint-microsoft-contrib": "^6.0.0", - "typescript": "^3.2.2", + "request": "^2.88.2", + "request-promise-native": "^1.0.9", + "serverless": "^1.83.0", + "shelljs": "^0.8.4", + "ts-node": "^8.10.2", + "tslint": "^5.20.1", + "tslint-microsoft-contrib": "^6.2.0", + "typescript": "^3.9.7", "wrappy": "^1.0.2" }, "dependencies": { - "aws-sdk": "^2.490.0", - "chalk": "^2.4.1" + "aws-sdk": "^2.752.0", + "chalk": "^2.4.2" } } diff --git a/scripts/versionCheck.sh b/scripts/versionCheck.sh deleted file mode 100644 index 130650b8..00000000 --- a/scripts/versionCheck.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -set -e # halt script on error - -TARGET_BRANCH=$1 -IS_PULL_REQUEST=$2 # false if not a pull request, - -# Makes sure travis checks version only if doing a pull request -if [ "$IS_PULL_REQUEST" != "false" ] - then - PACKAGE_VERSION=$(grep version package.json | awk -F: '{ print $2 }' | sed 's/[\",]//g' | tr -d ':space:') && echo "Package Version: $PACKAGE_VERSION" - CURRENT_PACKAGE_VERSION=$(git show 'origin/'"$TARGET_BRANCH"':package.json' | grep version | head -1 | awk -F: '{ print $2 }' | sed 's/[\",]//g' | tr -d ':space:') && echo "Latest Version: $CURRENT_PACKAGE_VERSION" - - if [ "$CURRENT_PACKAGE_VERSION" = "$PACKAGE_VERSION" ] - then - echo "Failure reason: Version number should be bumped." - exit 1 - fi -fi diff --git a/src/DomainConfig.ts b/src/DomainConfig.ts new file mode 100644 index 00000000..09363675 --- /dev/null +++ b/src/DomainConfig.ts @@ -0,0 +1,100 @@ +/** + * Wrapper class for Custom Domain information + */ + +import * as AWS from "aws-sdk"; // imported for Types +import DomainInfo = require("./DomainInfo"); +import Globals from "./Globals"; + +class DomainConfig { + + public givenDomainName: string; + public basePath: string | undefined; + public stage: string | undefined; + public certificateName: string | undefined; + public certificateArn: string | undefined; + public createRoute53Record: boolean | undefined; + public endpointType: string | undefined; + public apiType: string | undefined; + public hostedZoneId: string | undefined; + public hostedZonePrivate: boolean | undefined; + public enabled: boolean | string | undefined; + public securityPolicy: string | undefined; + + public domainInfo: DomainInfo | undefined; + public apiId: string | undefined; + public apiMapping: AWS.ApiGatewayV2.GetApiMappingResponse; + public allowPathMatching: boolean | false; + + constructor(config: any) { + + this.enabled = this.evaluateEnabled(config.enabled); + this.givenDomainName = config.domainName; + this.hostedZonePrivate = config.hostedZonePrivate; + this.certificateArn = config.certificateArn; + this.certificateName = config.certificateName; + this.createRoute53Record = config.createRoute53Record; + this.hostedZoneId = config.hostedZoneId; + this.hostedZonePrivate = config.hostedZonePrivate; + this.allowPathMatching = config.allowPathMatching; + + let basePath = config.basePath; + if (basePath == null || basePath.trim() === "") { + basePath = "(none)"; + } + this.basePath = basePath; + + let stage = config.stage; + if (typeof stage === "undefined") { + stage = Globals.options.stage || Globals.serverless.service.provider.stage; + } + this.stage = stage; + + const endpointTypeWithDefault = config.endpointType || Globals.endpointTypes.edge; + const endpointTypeToUse = Globals.endpointTypes[endpointTypeWithDefault.toLowerCase()]; + if (!endpointTypeToUse) { + throw new Error(`${endpointTypeWithDefault} is not supported endpointType, use edge or regional.`); + } + this.endpointType = endpointTypeToUse; + + const apiTypeWithDefault = config.apiType || Globals.apiTypes.rest; + const apiTypeToUse = Globals.apiTypes[apiTypeWithDefault.toLowerCase()]; + if (!apiTypeToUse) { + throw new Error(`${apiTypeWithDefault} is not supported api type, use REST, HTTP or WEBSOCKET.`); + } + this.apiType = apiTypeToUse; + + const securityPolicyDefault = config.securityPolicy || Globals.tlsVersions.tls_1_2; + const tlsVersionToUse = Globals.tlsVersions[securityPolicyDefault.toLowerCase()]; + if (!tlsVersionToUse) { + throw new Error(`${securityPolicyDefault} is not a supported securityPolicy, use tls_1_0 or tls_1_2.`); + } + this.securityPolicy = tlsVersionToUse; + } + + /** + * Determines whether this plug-in is enabled. + * + * This method reads the customDomain property "enabled" to see if this plug-in should be enabled. + * If the property's value is undefined, a default value of true is assumed (for backwards + * compatibility). + * If the property's value is provided, this should be boolean, otherwise an exception is thrown. + * If no customDomain object exists, an exception is thrown. + */ + private evaluateEnabled(enabled: any): boolean { + // const enabled = this.serverless.service.custom.customDomain.enabled; + if (enabled === undefined) { + return true; + } + if (typeof enabled === "boolean") { + return enabled; + } else if (typeof enabled === "string" && enabled === "true") { + return true; + } else if (typeof enabled === "string" && enabled === "false") { + return false; + } + throw new Error(`serverless-domain-manager: Ambiguous enablement boolean: "${enabled}"`); + } +} + +export = DomainConfig; diff --git a/DomainInfo.ts b/src/DomainInfo.ts similarity index 77% rename from DomainInfo.ts rename to src/DomainInfo.ts index dbb1d24e..7b40fc26 100644 --- a/DomainInfo.ts +++ b/src/DomainInfo.ts @@ -18,10 +18,16 @@ class DomainInfo { private defaultSecurityPolicy: string = "TLS_1_2"; constructor(data: any) { - this.domainName = data.distributionDomainName || data.regionalDomainName || data.DomainName; - this.hostedZoneId = data.distributionHostedZoneId || data.regionalHostedZoneId + this.domainName = data.distributionDomainName + || data.regionalDomainName + || data.DomainNameConfigurations && data.DomainNameConfigurations[0].ApiGatewayDomainName + || data.DomainName; + + this.hostedZoneId = data.distributionHostedZoneId + || data.regionalHostedZoneId || data.DomainNameConfigurations && data.DomainNameConfigurations[0].HostedZoneId || this.defaultHostedZoneId; + this.securityPolicy = data.securityPolicy || data.DomainNameConfigurations && data.DomainNameConfigurations[0].SecurityPolicy || this.defaultSecurityPolicy; diff --git a/src/Globals.ts b/src/Globals.ts new file mode 100644 index 00000000..d95ee9de --- /dev/null +++ b/src/Globals.ts @@ -0,0 +1,23 @@ +import { ServerlessInstance, ServerlessOptions } from "./types"; + +export default class Globals { + + public static serverless: ServerlessInstance; + public static options: ServerlessOptions; + + public static endpointTypes = { + edge: "EDGE", + regional: "REGIONAL", + }; + + public static apiTypes = { + http: "HTTP", + rest: "REST", + websocket: "WEBSOCKET", + }; + + public static tlsVersions = { + tls_1_0: "TLS_1_0", + tls_1_2: "TLS_1_2", + }; +} diff --git a/src/aws/cloud-formation-wrapper.ts b/src/aws/cloud-formation-wrapper.ts new file mode 100644 index 00000000..ead9f469 --- /dev/null +++ b/src/aws/cloud-formation-wrapper.ts @@ -0,0 +1,69 @@ +/** + * Wrapper class for AWS CloudFormation provider + */ + +import {CloudFormation} from "aws-sdk"; +import DomainConfig = require("../DomainConfig"); +import Globals from "../Globals"; +import {getAWSPagedResults, throttledCall} from "../utils"; + +class CloudFormationWrapper { + public provider: CloudFormation; + + constructor(credentials: any) { + this.provider = new CloudFormation(credentials); + } + + /** + * Gets rest API id from CloudFormation stack + */ + public async getApiId(domain: DomainConfig, stackName: string): Promise { + let LogicalResourceId = "ApiGatewayRestApi"; + if (domain.apiType === Globals.apiTypes.http) { + LogicalResourceId = "HttpApi"; + } + if (domain.apiType === Globals.apiTypes.websocket) { + LogicalResourceId = "WebsocketsApi"; + } + + const params = { + LogicalResourceId, + StackName: stackName, + }; + + let response; + try { + response = await throttledCall(this.provider, "describeStackResource", params); + } catch (err) { + throw new Error(`Failed to find CloudFormation resources with an error: ${err}\n`); + } + + const apiId = response.StackResourceDetail.PhysicalResourceId; + if (!apiId) { + throw new Error(`No ApiId associated with CloudFormation stack ${stackName}`); + } + return apiId; + } + + /** + * Gets values by names from cloudformation exports + */ + public async getImportValues(names: string[]): Promise { + const exports = await getAWSPagedResults( + this.provider, + "listExports", + "Exports", + "NextToken", + "NextToken", + {}, + ); + + // filter Exports by names which we need + const filteredExports = exports.filter((item) => names.indexOf(item.Name) !== -1); + // converting a list of unique values to dict + // [{Name: "export-name", Value: "export-value"}, ...] - > {"export-name": "export-value"} + return filteredExports.reduce((prev, current) => ({...prev, [current.Name]: current.Value}), {}); + } +} + +export = CloudFormationWrapper; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 00000000..a088b929 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,832 @@ +"use strict"; + +import chalk from "chalk"; +import CloudFormationWrapper = require("./aws/cloud-formation-wrapper"); +import DomainConfig = require("./DomainConfig"); +import DomainInfo = require("./DomainInfo"); +import Globals from "./Globals"; +import {ServerlessInstance, ServerlessOptions} from "./types"; +import {getAWSPagedResults, sleep, throttledCall} from "./utils"; + +const certStatuses = ["PENDING_VALIDATION", "ISSUED", "INACTIVE"]; + +class ServerlessCustomDomain { + + // AWS SDK resources + public apigateway: any; + public apigatewayV2: any; + public route53: any; + public acm: any; + public acmRegion: string; + public cloudFormationWrapper: CloudFormationWrapper; + + // Serverless specific properties + public serverless: ServerlessInstance; + public options: ServerlessOptions; + public commands: object; + public hooks: object; + + // Domain Manager specific properties + public domains: DomainConfig[] = []; + + constructor(serverless: ServerlessInstance, options: ServerlessOptions) { + this.serverless = serverless; + Globals.serverless = serverless; + + this.options = options; + Globals.options = options; + + this.commands = { + create_domain: { + lifecycleEvents: [ + "create", + "initialize", + ], + usage: "Creates a domain using the domain name defined in the serverless file", + }, + delete_domain: { + lifecycleEvents: [ + "delete", + "initialize", + ], + usage: "Deletes a domain using the domain name defined in the serverless file", + }, + }; + this.hooks = { + "after:deploy:deploy": this.hookWrapper.bind(this, this.setupBasePathMappings), + "after:info:info": this.hookWrapper.bind(this, this.domainSummaries), + "before:deploy:deploy": this.hookWrapper.bind(this, this.createOrGetDomainForCfOutputs), + "before:remove:remove": this.hookWrapper.bind(this, this.removeBasePathMappings), + "create_domain:create": this.hookWrapper.bind(this, this.createDomains), + "delete_domain:delete": this.hookWrapper.bind(this, this.deleteDomains), + }; + } + + /** + * Wrapper for lifecycle function, initializes variables and checks if enabled. + * @param lifecycleFunc lifecycle function that actually does desired action + */ + public async hookWrapper(lifecycleFunc: any) { + + this.initializeVariables(); + + return await lifecycleFunc.call(this); + } + + /** + * Lifecycle function to create a domain + * Wraps creating a domain and resource record set + */ + public async createDomains(): Promise { + + await this.getDomainInfo(); + + await Promise.all(this.domains.map(async (domain) => { + try { + if (!domain.domainInfo) { + + domain.certificateArn = await this.getCertArn(domain); + + await this.createCustomDomain(domain); + + await this.changeResourceRecordSet("UPSERT", domain); + + this.serverless.cli.log( + `Custom domain ${domain.givenDomainName} was created. + New domains may take up to 40 minutes to be initialized.`, + ); + } else { + this.serverless.cli.log(`Custom domain ${domain.givenDomainName} already exists.`); + } + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: Unable to create domain ${domain.givenDomainName}`); + } + })); + } + + /** + * Lifecycle function to delete a domain + * Wraps deleting a domain and resource record set + */ + public async deleteDomains(): Promise { + + await this.getDomainInfo(); + + await Promise.all(this.domains.map(async (domain) => { + try { + if (domain.domainInfo) { + await this.deleteCustomDomain(domain); + await this.changeResourceRecordSet("DELETE", domain); + domain.domainInfo = undefined; + this.serverless.cli.log(`Custom domain ${domain.givenDomainName} was deleted.`); + } else { + this.serverless.cli.log(`Custom domain ${domain.givenDomainName} does not exist.`); + } + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: Unable to delete domain ${domain.givenDomainName}`); + } + })); + } + + /** + * Lifecycle function to createDomain before deploy and add domain info to the CloudFormation stack's Outputs + */ + public async createOrGetDomainForCfOutputs(): Promise { + const autoDomain = this.serverless.service.custom.customDomain.autoDomain; + if (autoDomain === true) { + this.serverless.cli.log("Creating domain name before deploy."); + await this.createDomains(); + } + + await this.getDomainInfo(); + + if (autoDomain === true) { + const atLeastOneDoesNotExist = () => this.domains.some((domain) => !domain.domainInfo); + const maxWaitFor = parseInt(this.serverless.service.custom.customDomain.autoDomainWaitFor, 10) || 120; + const pollInterval = 3; + for (let i = 0; i * pollInterval < maxWaitFor && atLeastOneDoesNotExist() === true; i++) { + this.serverless.cli.log(` + Poll #${i + 1}: polling every ${pollInterval} seconds + for domain to exist or until ${maxWaitFor} seconds + have elapsed before starting deployment + `); + + await sleep(pollInterval); + await this.getDomainInfo(); + } + } + + await Promise.all(this.domains.map(async (domain) => { + this.addOutputs(domain); + })); + } + + /** + * Lifecycle function to create basepath mapping + * Wraps creation of basepath mapping and adds domain name info as output to cloudformation stack + */ + public async setupBasePathMappings(): Promise { + await Promise.all(this.domains.map(async (domain) => { + try { + domain.apiId = await this.getApiId(domain); + + domain.apiMapping = await this.getBasePathMapping(domain); + + await this.getDomainInfo(); + + if (!domain.apiMapping) { + await this.createBasePathMapping(domain); + } else { + await this.updateBasePathMapping(domain); + } + + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: Unable to setup base domain mappings for ${domain.givenDomainName}`); + } + })).then(() => { + // Print summary upon completion + this.domains.forEach((domain) => { + this.printDomainSummary(domain); + }); + }); + } + + /** + * Lifecycle function to delete basepath mapping + * Wraps deletion of basepath mapping + */ + public async removeBasePathMappings(): Promise { + await Promise.all(this.domains.map(async (domain) => { + try { + domain.apiId = await this.getApiId(domain); + + // Unable to find the corresponding API, manual clean up will be required + if (!domain.apiId) { + this.serverless.cli.log(`Unable to find corresponding API for ${domain.givenDomainName}, + API Mappings may need to be manually removed.`, "Serverless Domain Manager"); + } else { + domain.apiMapping = await this.getBasePathMapping(domain); + await this.deleteBasePathMapping(domain); + } + } catch (err) { + if (err.message.indexOf("Failed to find CloudFormation") > -1) { + this.serverless.cli.log(`Unable to find Cloudformation Stack for ${domain.givenDomainName}, + API Mappings may need to be manually removed.`, "Serverless Domain Manager"); + } else { + this.logIfDebug(err, domain.givenDomainName); + this.serverless.cli.log(`Error: Unable to remove base path mappings + for domain ${domain.givenDomainName}`); + } + } + })); + + const autoDomain = this.serverless.service.custom.customDomain.autoDomain; + if (autoDomain === true) { + this.serverless.cli.log("Deleting domain name after removing base path mapping."); + await this.deleteDomains(); + } + } + + /** + * Lifecycle function to print domain summary + * Wraps printing of all domain manager related info + */ + public async domainSummaries(): Promise { + await this.getDomainInfo(); + + this.domains.forEach((domain) => { + if (domain.domainInfo) { + this.printDomainSummary(domain); + } else { + this.serverless.cli.log( + `Unable to print Serverless Domain Manager Summary for ${domain.givenDomainName}`, + ); + } + }); + } + + /** + * Goes through custom domain property and initializes local variables and cloudformation template + */ + public initializeVariables(): void { + + // Make sure customDomain configuration exists, stop if not + if (typeof this.serverless.service.custom === "undefined" + || typeof this.serverless.service.custom.customDomain === "undefined") { + throw new Error("serverless-domain-manager: Plugin configuration is missing."); + } + + const credentials = this.serverless.providers.aws.getCredentials(); + credentials.region = this.serverless.providers.aws.getRegion(); + + this.apigateway = new this.serverless.providers.aws.sdk.APIGateway(credentials); + this.apigatewayV2 = new this.serverless.providers.aws.sdk.ApiGatewayV2(credentials); + this.route53 = new this.serverless.providers.aws.sdk.Route53(credentials); + this.cloudFormationWrapper = new CloudFormationWrapper(credentials); + + // Loop over the domain configurations and populate the domains array with DomainConfigs + this.domains = []; + + // If the key of the item in config is an api type it is using per api type domain structure + if (Globals.apiTypes[Object.keys(this.serverless.service.custom.customDomain)[0]]) { + for (const configApiType in this.serverless.service.custom.customDomain) { + if (Globals.apiTypes[configApiType]) { // If statement check to follow tslint + this.serverless.service.custom.customDomain[configApiType].apiType = configApiType; + this.domains.push(new DomainConfig(this.serverless.service.custom.customDomain[configApiType])); + } else { + throw Error(`Error: Invalid API Type, ${configApiType}`); + } + } + } else { // Default to single domain config + this.domains.push(new DomainConfig(this.serverless.service.custom.customDomain)); + } + + // Filter inactive domains + this.domains = this.domains.filter((domain) => domain.enabled); + + // Set ACM Region on the domain configs + for (const dc of this.domains) { + this.acmRegion = dc.endpointType === Globals.endpointTypes.regional ? + this.serverless.providers.aws.getRegion() : "us-east-1"; + const acmCredentials = Object.assign({}, credentials, {region: this.acmRegion}); + this.acm = new this.serverless.providers.aws.sdk.ACM(acmCredentials); + } + + // Validate the domain configurations + this.validateDomainConfigs(); + } + + /** + * Validates domain configs to make sure they are valid, ie HTTP api cannot be used with EDGE domain + */ + public validateDomainConfigs() { + this.domains.forEach((domain) => { + + // Show warning if allowPathMatching is set to true + if (domain.allowPathMatching) { + this.serverless.cli.log(`WARNING: "allowPathMatching" is set for ${domain.givenDomainName}. + This should only be used when migrating a path to a different API type. e.g. REST to HTTP.`); + } + + if (domain.apiType === Globals.apiTypes.rest) { + // Currently no validation for REST API types + + } else if (domain.apiType === Globals.apiTypes.http) { // Validation for http apis + // HTTP Apis do not support edge domains + if (domain.endpointType === Globals.endpointTypes.edge) { + throw Error(`Error: 'edge' endpointType is not compatible with HTTP APIs`); + } + + } else if (domain.apiType === Globals.apiTypes.websocket) { // Validation for WebSocket apis + // Websocket Apis do not support edge domains + if (domain.endpointType === Globals.endpointTypes.edge) { + throw Error(`Error: 'edge' endpointType is not compatible with WebSocket APIs`); + } + } + }); + } + + /** + * Gets Certificate ARN that most closely matches domain name OR given Cert ARN if provided + */ + public async getCertArn(domain: DomainConfig): Promise { + if (domain.certificateArn) { + this.serverless.cli.log(`Selected specific certificateArn ${domain.certificateArn}`); + return domain.certificateArn; + } + + let certificateArn; // The arn of the selected certificate + + let certificateName = domain.certificateName; // The certificate name + + try { + const certificates = await getAWSPagedResults( + this.acm, + "listCertificates", + "CertificateSummaryList", + "NextToken", + "NextToken", + {CertificateStatuses: certStatuses}, + ); + + // The more specific name will be the longest + let nameLength = 0; + + // Checks if a certificate name is given + if (certificateName != null) { + const foundCertificate = certificates + .find((certificate) => (certificate.DomainName === certificateName)); + if (foundCertificate != null) { + certificateArn = foundCertificate.CertificateArn; + } + } else { + certificateName = domain.givenDomainName; + certificates.forEach((certificate) => { + let certificateListName = certificate.DomainName; + // Looks for wild card and takes it out when checking + if (certificateListName[0] === "*") { + certificateListName = certificateListName.substr(1); + } + // Looks to see if the name in the list is within the given domain + // Also checks if the name is more specific than previous ones + if (certificateName.includes(certificateListName) + && certificateListName.length > nameLength) { + nameLength = certificateListName.length; + certificateArn = certificate.CertificateArn; + } + }); + } + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw Error(`Error: Could not list certificates in Certificate Manager.\n${err}`); + } + if (certificateArn == null) { + throw Error(`Error: Could not find the certificate ${certificateName}.`); + } + return certificateArn; + } + + /** + * Populates the DomainInfo object on the Domains if custom domain in aws exists + */ + public async getDomainInfo(): Promise { + await Promise.all(this.domains.map(async (domain) => { + try { + const domainInfo = await throttledCall(this.apigatewayV2, "getDomainName", { + DomainName: domain.givenDomainName, + }); + + domain.domainInfo = new DomainInfo(domainInfo); + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + if (err.code !== "NotFoundException") { + throw new Error(`Error: Unable to fetch information about ${domain.givenDomainName}`); + } + } + })); + } + + /** + * Creates Custom Domain Name through API Gateway + * @param certificateArn: Certificate ARN to use for custom domain + */ + public async createCustomDomain(domain: DomainConfig): Promise { + + let createdDomain = {}; + + // For EDGE domain name or TLS 1.0, create with APIGateway (v1) + if (domain.endpointType === Globals.endpointTypes.edge || domain.securityPolicy === "TLS_1_0") { + // Set up parameters + const params = { + domainName: domain.givenDomainName, + endpointConfiguration: { + types: [domain.endpointType], + }, + securityPolicy: domain.securityPolicy, + }; + + /* tslint:disable:no-string-literal */ + if (domain.endpointType === Globals.endpointTypes.edge) { + params["certificateArn"] = domain.certificateArn; + } else { + params["regionalCertificateArn"] = domain.certificateArn; + } + /* tslint:enable:no-string-literal */ + + // Make API call to create domain + try { + // Creating EDGE domain so use APIGateway (v1) service + createdDomain = await throttledCall(this.apigateway, "createDomainName", params); + domain.domainInfo = new DomainInfo(createdDomain); + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: Failed to create custom domain ${domain.givenDomainName}\n`); + } + + } else { // For Regional domain name create with ApiGatewayV2 + const params = { + DomainName: domain.givenDomainName, + DomainNameConfigurations: [{ + CertificateArn: domain.certificateArn, + EndpointType: domain.endpointType, + SecurityPolicy: domain.securityPolicy, + }], + }; + + // Make API call to create domain + try { + // Creating Regional domain so use ApiGatewayV2 + createdDomain = await throttledCall(this.apigatewayV2, "createDomainName", params); + domain.domainInfo = new DomainInfo(createdDomain); + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: Failed to create custom domain ${domain.givenDomainName}\n`); + } + } + } + + /** + * Delete Custom Domain Name through API Gateway + */ + public async deleteCustomDomain(domain: DomainConfig): Promise { + // Make API call + try { + await throttledCall(this.apigatewayV2, "deleteDomainName", { + DomainName: domain.givenDomainName, + }); + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: Failed to delete custom domain ${domain.givenDomainName}\n`); + } + } + + /** + * Change A Alias record through Route53 based on given action + * @param action: String descriptor of change to be made. Valid actions are ['UPSERT', 'DELETE'] + * @param domain: DomainInfo object containing info about custom domain + */ + public async changeResourceRecordSet(action: string, domain: DomainConfig): Promise { + if (action !== "UPSERT" && action !== "DELETE") { + throw new Error(`Error: Invalid action "${action}" when changing Route53 Record. + Action must be either UPSERT or DELETE.\n`); + } + + const createRoute53Record = domain.createRoute53Record; + if (createRoute53Record !== undefined && createRoute53Record === false) { + this.serverless.cli.log(`Skipping ${action === "DELETE" ? "removal" : "creation"} of Route53 record.`); + return; + } + // Set up parameters + const route53HostedZoneId = await this.getRoute53HostedZoneId(domain); + const Changes = ["A", "AAAA"].map((Type) => ({ + Action: action, + ResourceRecordSet: { + AliasTarget: { + DNSName: domain.domainInfo.domainName, + EvaluateTargetHealth: false, + HostedZoneId: domain.domainInfo.hostedZoneId, + }, + Name: domain.givenDomainName, + Type, + }, + })); + const params = { + ChangeBatch: { + Changes, + Comment: "Record created by serverless-domain-manager", + }, + HostedZoneId: route53HostedZoneId, + }; + // Make API call + try { + await throttledCall(this.route53, "changeResourceRecordSets", params); + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: Failed to ${action} A Alias for ${domain.givenDomainName}\n`); + } + } + + /** + * Gets Route53 HostedZoneId from user or from AWS + */ + public async getRoute53HostedZoneId(domain: DomainConfig): Promise { + if (domain.hostedZoneId) { + this.serverless.cli.log( + `Selected specific hostedZoneId ${this.serverless.service.custom.customDomain.hostedZoneId}`); + return domain.hostedZoneId; + } + + const filterZone = domain.hostedZonePrivate !== undefined; + if (filterZone && domain.hostedZonePrivate) { + this.serverless.cli.log("Filtering to only private zones."); + } else if (filterZone && !domain.hostedZonePrivate) { + this.serverless.cli.log("Filtering to only public zones."); + } + + let hostedZoneData; + const givenDomainNameReverse = domain.givenDomainName.split(".").reverse(); + + try { + hostedZoneData = await throttledCall(this.route53, "listHostedZones", {}); + const targetHostedZone = hostedZoneData.HostedZones + .filter((hostedZone) => { + let hostedZoneName; + if (hostedZone.Name.endsWith(".")) { + hostedZoneName = hostedZone.Name.slice(0, -1); + } else { + hostedZoneName = hostedZone.Name; + } + if (!filterZone || domain.hostedZonePrivate === hostedZone.Config.PrivateZone) { + const hostedZoneNameReverse = hostedZoneName.split(".").reverse(); + + if (givenDomainNameReverse.length === 1 + || (givenDomainNameReverse.length >= hostedZoneNameReverse.length)) { + for (let i = 0; i < hostedZoneNameReverse.length; i += 1) { + if (givenDomainNameReverse[i] !== hostedZoneNameReverse[i]) { + return false; + } + } + return true; + } + } + return false; + }) + .sort((zone1, zone2) => zone2.Name.length - zone1.Name.length) + .shift(); + + if (targetHostedZone) { + const hostedZoneId = targetHostedZone.Id; + // Extracts the hostzone Id + const startPos = hostedZoneId.indexOf("e/") + 2; + const endPos = hostedZoneId.length; + return hostedZoneId.substring(startPos, endPos); + } + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: Unable to list hosted zones in Route53.\n${err}`); + } + throw new Error(`Error: Could not find hosted zone "${domain.givenDomainName}"`); + } + + public async getBasePathMapping(domain: DomainConfig): Promise { + try { + const mappings = await getAWSPagedResults( + this.apigatewayV2, + "getApiMappings", + "Items", + "NextToken", + "NextToken", + {DomainName: domain.givenDomainName}, + ); + for (const mapping of mappings) { + if (mapping.ApiId === domain.apiId + || (mapping.ApiMappingKey === domain.basePath && domain.allowPathMatching)) { + return mapping; + } + } + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: Unable to get API Mappings for ${domain.givenDomainName}`); + } + } + + /** + * Creates basepath mapping + */ + public async createBasePathMapping(domain: DomainConfig): Promise { + // Use APIGateway (v1) for EDGE or TLS 1.0 domains + if (domain.endpointType === Globals.endpointTypes.edge || domain.securityPolicy === "TLS_1_0") { + const params = { + basePath: domain.basePath, + domainName: domain.givenDomainName, + restApiId: domain.apiId, + stage: domain.stage, + }; + // Make API call + try { + await throttledCall(this.apigateway, "createBasePathMapping", params); + this.serverless.cli.log(`Created API mapping '${domain.basePath}' for ${domain.givenDomainName}`); + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: ${domain.givenDomainName}: Unable to create basepath mapping.\n`); + } + + } else { // Use ApiGatewayV2 for Regional domains + const params = { + ApiId: domain.apiId, + ApiMappingKey: domain.basePath, + DomainName: domain.givenDomainName, + Stage: domain.apiType === Globals.apiTypes.http ? "$default" : domain.stage, + }; + // Make API call + try { + await throttledCall(this.apigatewayV2, "createApiMapping", params); + this.serverless.cli.log(`Created API mapping '${domain.basePath}' for ${domain.givenDomainName}`); + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: ${domain.givenDomainName}: Unable to create basepath mapping.\n`); + } + } + } + + /** + * Updates basepath mapping + */ + public async updateBasePathMapping(domain: DomainConfig): Promise { + // Use APIGateway (v1) for EDGE or TLS 1.0 domains + // check here if the EXISTING domain is using TLS 1.0 regardless of what is configured + // We don't support updating custom domains so switching from TLS 1.0 to 1.2 will require recreating + // the domain + if (domain.endpointType === Globals.endpointTypes.edge || domain.domainInfo.securityPolicy === "TLS_1_0") { + const params = { + basePath: domain.apiMapping.ApiMappingKey || "(none)", + domainName: domain.givenDomainName, + patchOperations: [ + { + op: "replace", + path: "/basePath", + value: domain.basePath, + }, + ], + }; + + // Make API call + try { + await throttledCall(this.apigateway, "updateBasePathMapping", params); + this.serverless.cli.log(`Updated API mapping from '${domain.apiMapping.ApiMappingKey}' + to '${domain.basePath}' for ${domain.givenDomainName}`); + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: ${domain.givenDomainName}: Unable to update basepath mapping.\n`); + } + + } else { // Use ApiGatewayV2 for Regional domains + + const params = { + ApiId: domain.apiId, + ApiMappingId: domain.apiMapping.ApiMappingId, + ApiMappingKey: domain.basePath, + DomainName: domain.givenDomainName, + Stage: domain.apiType === Globals.apiTypes.http ? "$default" : domain.stage, + }; + + // Make API call + try { + await throttledCall(this.apigatewayV2, "updateApiMapping", params); + this.serverless.cli.log(`Updated API mapping to '${domain.basePath}' for ${domain.givenDomainName}`); + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Error: ${domain.givenDomainName}: Unable to update basepath mapping.\n`); + } + } + } + + /** + * Gets rest API id from existing config or CloudFormation stack + */ + public async getApiId(domain: DomainConfig): Promise { + const apiGateway = this.serverless.service.provider.apiGateway; + if (apiGateway && apiGateway.restApiId) { + const restApiId = apiGateway.restApiId; + // if string value exists return the value + if (typeof restApiId === "string") { + this.serverless.cli.log(`Mapping custom domain to existing API ${restApiId}.`); + return restApiId; + } + // in case object and Fn::ImportValue try to get restApiId from the CloudFormation exports + if (typeof restApiId === "object" && restApiId["Fn::ImportValue"]) { + const importName = restApiId["Fn::ImportValue"]; + let importValues; + try { + importValues = await this.cloudFormationWrapper.getImportValues([importName]); + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Failed to find CloudFormation ImportValue by ${importName}\n`); + } + if (!importValues[importName]) { + throw new Error(`CloudFormation ImportValue not found by ${importName}\n`); + } + return importValues[importName]; + } + // throw an exception in case not supported restApiId + throw new Error("Unsupported apiGateway.restApiId object"); + } + + const stackName = this.serverless.service.provider.stackName || + `${this.serverless.service.service}-${domain.stage}`; + + try { + return await this.cloudFormationWrapper.getApiId(domain, stackName); + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + throw new Error(`Failed to find CloudFormation resources for ${domain.givenDomainName}\n`); + } + } + + /** + * Deletes basepath mapping + */ + public async deleteBasePathMapping(domain: DomainConfig): Promise { + const params = { + ApiMappingId: domain.apiMapping.ApiMappingId, + DomainName: domain.givenDomainName, + }; + + // Make API call + try { + await throttledCall(this.apigatewayV2, "deleteApiMapping", params); + this.serverless.cli.log("Removed basepath mapping."); + } catch (err) { + this.logIfDebug(err, domain.givenDomainName); + this.serverless.cli.log(`Unable to remove basepath mapping for ${domain.givenDomainName}`); + } + } + + /** + * Adds the domain name and distribution domain name to the CloudFormation outputs + */ + public addOutputs(domain: DomainConfig): void { + const service = this.serverless.service; + if (!service.provider.compiledCloudFormationTemplate.Outputs) { + service.provider.compiledCloudFormationTemplate.Outputs = {}; + } + + // Defaults for REST and backwards compatibility + let distributionDomainNameOutputKey = "DistributionDomainName"; + let domainNameOutputKey = "DomainName"; + let hostedZoneIdOutputKey = "HostedZoneId"; + + if (domain.apiType === Globals.apiTypes.http) { + distributionDomainNameOutputKey += "Http"; + domainNameOutputKey += "Http"; + hostedZoneIdOutputKey += "Http"; + + } else if (domain.apiType === Globals.apiTypes.websocket) { + distributionDomainNameOutputKey += "Websocket"; + domainNameOutputKey += "Websocket"; + hostedZoneIdOutputKey += "Websocket"; + } + + service.provider.compiledCloudFormationTemplate.Outputs[distributionDomainNameOutputKey] = { + Value: domain.domainInfo.domainName, + }; + + service.provider.compiledCloudFormationTemplate.Outputs[domainNameOutputKey] = { + Value: domain.givenDomainName, + }; + + if (domain.domainInfo.hostedZoneId) { + service.provider.compiledCloudFormationTemplate.Outputs[hostedZoneIdOutputKey] = { + Value: domain.domainInfo.hostedZoneId, + }; + } + } + + /** + * Logs message if SLS_DEBUG is set + * @param message message to be printed + */ + public logIfDebug(message: any, domain?: string): void { + if (process.env.SLS_DEBUG) { + this.serverless.cli.log(`Error: ${domain ? domain + ": " : ""} ${message}`, "Serverless Domain Manager"); + } + } + + /** + * Prints out a summary of all domain manager related info + */ + + private printDomainSummary(domain: DomainConfig): void { + this.serverless.cli.consoleLog(chalk.yellow.underline("\nServerless Domain Manager Summary")); + + this.serverless.cli.consoleLog(chalk.yellow("Distribution Domain Name")); + this.serverless.cli.consoleLog(` Domain Name: ${domain.givenDomainName}`); + this.serverless.cli.consoleLog(` Target Domain: ${domain.domainInfo.domainName}`); + this.serverless.cli.consoleLog(` Hosted Zone Id: ${domain.domainInfo.hostedZoneId}`); + } +} + +export = ServerlessCustomDomain; diff --git a/types.ts b/src/types.ts similarity index 93% rename from types.ts rename to src/types.ts index 0e8c089c..34059e66 100644 --- a/types.ts +++ b/src/types.ts @@ -25,6 +25,8 @@ export interface ServerlessInstance { // tslint:disable-line hostedZonePrivate: boolean | undefined, enabled: boolean | string | undefined, securityPolicy: string | undefined, + autoDomain: boolean | undefined, + autoDomainWaitFor: string | undefined, }, }, }; diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 00000000..f9fef870 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,82 @@ +import {Service} from "aws-sdk"; + +const RETRYABLE_ERRORS = ["Throttling", "RequestLimitExceeded", "TooManyRequestsException"]; + +/** + * Iterate through the pages of a AWS SDK response and collect them into a single array + * + * @param service - The AWS service instance to use to make the calls + * @param funcName - The function name in the service to call + * @param resultsKey - The key name in the response that contains the items to return + * @param nextTokenKey - The request key name to append to the request that has the paging token value + * @param nextRequestTokenKey - The response key name that has the next paging token value + * @param params - Parameters to send in the request + */ +async function getAWSPagedResults( + service: Service, + funcName: string, + resultsKey: string, + nextTokenKey: string, + nextRequestTokenKey: string, + params: object, +): Promise { + let results = []; + let response = await throttledCall(service, funcName, params); + results = results.concat(response[resultsKey]); + while (response.hasOwnProperty(nextRequestTokenKey) && response[nextRequestTokenKey]) { + params[nextTokenKey] = response[nextRequestTokenKey]; + response = await service[funcName](params).promise(); + results = results.concat(response[resultsKey]); + } + return results; +} + +async function throttledCall(service: Service, funcName: string, params: object): Promise { + const maxTimePassed = 5 * 60; + + let timePassed = 0; + let previousInterval = 0; + + const minWait = 3; + const maxWait = 60; + + while (true) { + try { + return await service[funcName](params).promise(); + } catch (ex) { + // rethrow the exception if it is not a type of retryable exception + if (RETRYABLE_ERRORS.indexOf(ex.code) === -1) { + throw ex; + } + + // rethrow the exception if we have waited too long + if (timePassed >= maxTimePassed) { + throw ex; + } + + // Sleep using the Decorrelated Jitter algorithm recommended by AWS + // https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/ + let newInterval = Math.random() * Math.min(maxWait, previousInterval * 3); + newInterval = Math.max(minWait, newInterval); + + await sleep(newInterval); + previousInterval = newInterval; + timePassed += previousInterval; + } + } +} + +/** + * Stops event thread execution for given number of seconds. + * @param seconds + * @returns {Promise} Resolves after given number of seconds. + */ +async function sleep(seconds) { + return new Promise((resolve) => setTimeout(resolve, 1000 * seconds)); +} + +export { + sleep, + getAWSPagedResults, + throttledCall, +}; diff --git a/test/integration-tests/base.ts b/test/integration-tests/base.ts new file mode 100644 index 00000000..19420b24 --- /dev/null +++ b/test/integration-tests/base.ts @@ -0,0 +1,22 @@ +import randomstring = require("randomstring"); + +const TEST_DOMAIN = process.env.TEST_DOMAIN; + +if (!TEST_DOMAIN) { + throw new Error("TEST_DOMAIN environment variable not set"); +} + +const RANDOM_STRING = randomstring.generate({ + capitalization: "lowercase", + charset: "alphanumeric", + length: 5, +}); +const TEMP_DIR = `~/tmp/domain-manager-test-${RANDOM_STRING}`; +const FIFTEEN_MINUTES = 15 * 60 * 1000; // 15 minutes in milliseconds + +export { + FIFTEEN_MINUTES, + RANDOM_STRING, + TEMP_DIR, + TEST_DOMAIN, +}; diff --git a/test/integration-tests/basic.test.ts b/test/integration-tests/basic.test.ts new file mode 100644 index 00000000..03bc4a6b --- /dev/null +++ b/test/integration-tests/basic.test.ts @@ -0,0 +1,126 @@ +import chai = require("chai"); +import "mocha"; +import {FIFTEEN_MINUTES, RANDOM_STRING, TEMP_DIR, TEST_DOMAIN} from "./base"; +import utilities = require("./test-utilities"); + +const expect = chai.expect; +const CONFIGS_FOLDER = "basic"; + +describe("Integration Tests", function() { + this.timeout(FIFTEEN_MINUTES); + + it("Creates a empty basepath mapping", async () => { + const testName = "null-basepath-mapping"; + const configFolder = `${CONFIGS_FOLDER}/${testName}`; + const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; + // Perform sequence of commands to replicate basepath mapping issue + try { + await utilities.createTempDir(TEMP_DIR, configFolder); + await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeleteDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); + + const basePath = await utilities.getBasePath(testURL); + expect(basePath).to.equal("(none)"); + } finally { + await utilities.destroyResources(testURL, RANDOM_STRING); + } + }); + + it("Delete domain then recreate", async () => { + const testName = "basepath-mapping"; + const configFolder = `${CONFIGS_FOLDER}/${testName}`; + const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; + // Perform sequence of commands to replicate basepath mapping issue + try { + await utilities.createTempDir(TEMP_DIR, configFolder); + await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeleteDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); + + const basePath = await utilities.getBasePath(testURL); + expect(basePath).to.equal("api"); + } finally { + await utilities.destroyResources(testURL, RANDOM_STRING); + } + }); + + it("Delete domain then remove", async () => { + const testName = "null-basepath-mapping"; + const configFolder = `${CONFIGS_FOLDER}/${testName}`; + const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; + // Perform sequence of commands to replicate basepath mapping issue + try { + await utilities.createTempDir(TEMP_DIR, configFolder); + await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeleteDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsRemove(TEMP_DIR, RANDOM_STRING); + await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); + + const basePath = await utilities.getBasePath(testURL); + expect(basePath).to.equal("(none)"); + } finally { + await utilities.destroyResources(testURL, RANDOM_STRING); + } + }); + + it("API Gateway with export and import", async () => { + const testExportName = "apigateway-with-export"; + const configExportFolder = `${CONFIGS_FOLDER}/${testExportName}`; + const configImportFolder = `${CONFIGS_FOLDER}/apigateway-with-import`; + const testURL = `${testExportName}-${RANDOM_STRING}.${TEST_DOMAIN}`; + // Perform sequence of commands to replicate basepath mapping issue + try { + await utilities.createTempDir(TEMP_DIR, configExportFolder); + await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); + + await utilities.createTempDir(TEMP_DIR, configImportFolder); + await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); + + const basePath = await utilities.getBasePath(testURL); + expect(basePath).to.equal("hello-world"); + } finally { + // should destroy the last created config folder ( import config ) + await utilities.destroyResources(testURL, RANDOM_STRING); + // recreate config for removing export config + await utilities.createTempDir(TEMP_DIR, configExportFolder); + await utilities.destroyResources(testURL, RANDOM_STRING); + } + }); + + it("Creates a domain multiple times without failure", async () => { + const testName = "create-domain-idempotent"; + const configFolder = `${CONFIGS_FOLDER}/${testName}`; + const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; + try { + await utilities.createTempDir(TEMP_DIR, configFolder); + await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); + } finally { + await utilities.destroyResources(testURL, RANDOM_STRING); + } + }); + + it("Deploys multiple times without failure", async () => { + const testName = "deploy-idempotent"; + const configFolder = `${CONFIGS_FOLDER}/${testName}`; + const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; + try { + await utilities.createTempDir(TEMP_DIR, configFolder); + await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); + await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); + } finally { + await utilities.destroyResources(testURL, RANDOM_STRING); + } + }); +}); diff --git a/test/integration-tests/basepath-mapping/handler.js b/test/integration-tests/basic/apigateway-with-export/handler.js similarity index 100% rename from test/integration-tests/basepath-mapping/handler.js rename to test/integration-tests/basic/apigateway-with-export/handler.js diff --git a/test/integration-tests/basic/apigateway-with-export/serverless.yml b/test/integration-tests/basic/apigateway-with-export/serverless.yml new file mode 100644 index 00000000..a2973e5a --- /dev/null +++ b/test/integration-tests/basic/apigateway-with-export/serverless.yml @@ -0,0 +1,51 @@ +# APIGateway with export outputs +service: apigateway-with-export-${opt:RANDOM_STRING} + +provider: + name: aws + runtime: nodejs12.x + region: us-west-2 + endpointType: regional + stage: test + +functions: + helloWorld: + handler: handler.helloWorld + events: + - http: + path: hello-world + method: get + cors: true + +resources: + Outputs: + RestApi: + Description: Main service's API Gateway REST API ID + Value: + Ref: ApiGatewayRestApi # Logical ID + Export: + Name: api-${self:provider.stage}-restApiId-${opt:RANDOM_STRING} + RootResource: + Description: Main service's API Gateway Root Resource ID + Value: + Fn::GetAtt: + - ApiGatewayRestApi # Logical ID + - RootResourceId # Logical ID + Export: + Name: api-${self:provider.stage}-RootResourceId-${opt:RANDOM_STRING} + +plugins: + - serverless-domain-manager + +custom: + customDomain: + stage: ${self:provider.stage} + domainName: apigateway-with-export-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} + autoDomain: true + basePath: hello-world + endpointType: regional + createRoute53Record: false + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/create-domain-idempotent/handler.js b/test/integration-tests/basic/apigateway-with-import/handler.js similarity index 100% rename from test/integration-tests/create-domain-idempotent/handler.js rename to test/integration-tests/basic/apigateway-with-import/handler.js diff --git a/test/integration-tests/basic/apigateway-with-import/serverless.yml b/test/integration-tests/basic/apigateway-with-import/serverless.yml new file mode 100644 index 00000000..a7354049 --- /dev/null +++ b/test/integration-tests/basic/apigateway-with-import/serverless.yml @@ -0,0 +1,26 @@ +# APIGateway with import other CloudFormation stack outputs +service: apigateway-with-import-${opt:RANDOM_STRING} + +provider: + name: aws + runtime: nodejs12.x + region: us-west-2 + stage: test + apiGateway: + restApiId: + Fn::ImportValue: api-${self:provider.stage}-restApiId-${opt:RANDOM_STRING} + restApiRootResourceId: + Fn::ImportValue: api-${self:provider.stage}-RootResourceId-${opt:RANDOM_STRING} + +functions: + helloWorld: + handler: handler.helloWorld + events: + - http: + path: hello-world2 + method: get + cors: true + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/deploy-idempotent/handler.js b/test/integration-tests/basic/basepath-mapping/handler.js similarity index 100% rename from test/integration-tests/deploy-idempotent/handler.js rename to test/integration-tests/basic/basepath-mapping/handler.js diff --git a/test/integration-tests/basepath-mapping/serverless.yml b/test/integration-tests/basic/basepath-mapping/serverless.yml similarity index 78% rename from test/integration-tests/basepath-mapping/serverless.yml rename to test/integration-tests/basic/basepath-mapping/serverless.yml index bbfd38a6..e8b7c45d 100644 --- a/test/integration-tests/basepath-mapping/serverless.yml +++ b/test/integration-tests/basic/basepath-mapping/serverless.yml @@ -1,8 +1,8 @@ # Enabled and testing basepath mapping -service: basepath-mapping +service: basepath-mapping-${opt:RANDOM_STRING} provider: name: aws - runtime: nodejs6.10 + runtime: nodejs12.x region: us-west-2 stage: test functions: @@ -19,3 +19,7 @@ custom: customDomain: domainName: basepath-mapping-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} basePath: 'api' + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/disabled/handler.js b/test/integration-tests/basic/create-domain-idempotent/handler.js similarity index 100% rename from test/integration-tests/disabled/handler.js rename to test/integration-tests/basic/create-domain-idempotent/handler.js diff --git a/test/integration-tests/create-domain-idempotent/serverless.yml b/test/integration-tests/basic/create-domain-idempotent/serverless.yml similarity index 77% rename from test/integration-tests/create-domain-idempotent/serverless.yml rename to test/integration-tests/basic/create-domain-idempotent/serverless.yml index b0a4e43c..23535d93 100644 --- a/test/integration-tests/create-domain-idempotent/serverless.yml +++ b/test/integration-tests/basic/create-domain-idempotent/serverless.yml @@ -1,8 +1,8 @@ # Creating a domain should be idempotent -service: create-domain-idempotent +service: create-domain-idempotent-${opt:RANDOM_STRING} provider: name: aws - runtime: nodejs6.10 + runtime: nodejs12.x region: us-west-2 stage: test functions: @@ -19,3 +19,7 @@ custom: customDomain: domainName: create-domain-idempotent-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} basePath: '' + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/enabled-basepath/handler.js b/test/integration-tests/basic/deploy-idempotent/handler.js similarity index 100% rename from test/integration-tests/enabled-basepath/handler.js rename to test/integration-tests/basic/deploy-idempotent/handler.js diff --git a/test/integration-tests/deploy-idempotent/serverless.yml b/test/integration-tests/basic/deploy-idempotent/serverless.yml similarity index 77% rename from test/integration-tests/deploy-idempotent/serverless.yml rename to test/integration-tests/basic/deploy-idempotent/serverless.yml index e404d9fb..ee7a505d 100644 --- a/test/integration-tests/deploy-idempotent/serverless.yml +++ b/test/integration-tests/basic/deploy-idempotent/serverless.yml @@ -1,8 +1,8 @@ # Deploying should be idempotent -service: deploy-idempotent +service: deploy-idempotent-${opt:RANDOM_STRING} provider: name: aws - runtime: nodejs6.10 + runtime: nodejs12.x region: us-west-2 stage: test functions: @@ -19,3 +19,7 @@ custom: customDomain: domainName: deploy-idempotent-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} basePath: '' + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/enabled-custom-apigateway/handler.js b/test/integration-tests/basic/null-basepath-mapping/handler.js similarity index 100% rename from test/integration-tests/enabled-custom-apigateway/handler.js rename to test/integration-tests/basic/null-basepath-mapping/handler.js diff --git a/test/integration-tests/null-basepath-mapping/serverless.yml b/test/integration-tests/basic/null-basepath-mapping/serverless.yml similarity index 77% rename from test/integration-tests/null-basepath-mapping/serverless.yml rename to test/integration-tests/basic/null-basepath-mapping/serverless.yml index 38425351..1d1d5cc0 100644 --- a/test/integration-tests/null-basepath-mapping/serverless.yml +++ b/test/integration-tests/basic/null-basepath-mapping/serverless.yml @@ -1,8 +1,8 @@ # Enabled and testing basepath mapping -service: null-basepath-mapping +service: null-basepath-mapping-${opt:RANDOM_STRING} provider: name: aws - runtime: nodejs6.10 + runtime: nodejs12.x region: us-west-2 stage: test functions: @@ -19,3 +19,7 @@ custom: customDomain: domainName: null-basepath-mapping-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} basePath: '' + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/deploy.test.ts b/test/integration-tests/deploy.test.ts new file mode 100644 index 00000000..30c80aa5 --- /dev/null +++ b/test/integration-tests/deploy.test.ts @@ -0,0 +1,121 @@ +import chai = require("chai"); +import "mocha"; +import itParam = require("mocha-param"); +import {FIFTEEN_MINUTES, RANDOM_STRING, TEST_DOMAIN} from "./base"; +import utilities = require("./test-utilities"); + +const expect = chai.expect; +const CONFIGS_FOLDER = "deploy"; + +const testCases = [ + { + testBasePath: "(none)", + testDescription: "Creates domain as part of deploy", + testDomain: `auto-domain-${RANDOM_STRING}.${TEST_DOMAIN}`, + testEndpoint: "EDGE", + testFolder: `${CONFIGS_FOLDER}/auto-domain`, + testStage: "test", + }, + { + testBasePath: "(none)", + testDescription: "Enabled with default values", + testDomain: `enabled-default-${RANDOM_STRING}.${TEST_DOMAIN}`, + testEndpoint: "EDGE", + testFolder: `${CONFIGS_FOLDER}/enabled-default`, + testStage: "test", + }, + { + createApiGateway: true, + testBasePath: "(none)", + testDescription: "Enabled with custom api gateway", + testDomain: `enabled-custom-apigateway-${RANDOM_STRING}.${TEST_DOMAIN}`, + testEndpoint: "EDGE", + testFolder: `${CONFIGS_FOLDER}/enabled-custom-apigateway`, + testStage: "test", + }, + { + testBasePath: "api", + testDescription: "Enabled with custom basepath", + testDomain: `enabled-basepath-${RANDOM_STRING}.${TEST_DOMAIN}`, + testEndpoint: "EDGE", + testFolder: `${CONFIGS_FOLDER}/enabled-basepath`, + testStage: "test", + }, + { + testBasePath: "(none)", + testDescription: "Enabled with custom stage and empty basepath", + testDomain: `enabled-stage-basepath-${RANDOM_STRING}.${TEST_DOMAIN}`, + testEndpoint: "EDGE", + testFolder: `${CONFIGS_FOLDER}/enabled-stage-basepath`, + testStage: "test", + }, + { + testBasePath: "api", + testDescription: "Enabled with regional endpoint, custom basePath", + testDomain: `enabled-regional-basepath-${RANDOM_STRING}.${TEST_DOMAIN}`, + testEndpoint: "REGIONAL", + testFolder: `${CONFIGS_FOLDER}/enabled-regional-basepath`, + testStage: "test", + }, + { + testBasePath: "(none)", + testDescription: "Enabled with regional endpoint, custom stage, empty basepath", + testDomain: `enabled-regional-stage-basepath-${RANDOM_STRING}.${TEST_DOMAIN}`, + testEndpoint: "REGIONAL", + testFolder: `${CONFIGS_FOLDER}/enabled-regional-stage-basepath`, + testStage: "test", + }, + { + testBasePath: "(none)", + testDescription: "Create Web socket API and domain name", + testDomain: `web-socket-${RANDOM_STRING}.${TEST_DOMAIN}`, + testEndpoint: "REGIONAL", + testFolder: `${CONFIGS_FOLDER}/web-socket`, + testStage: "test", + }, + { + testBasePath: "(none)", + testDescription: "Create HTTP API and domain name", + testDomain: `http-api-${RANDOM_STRING}.${TEST_DOMAIN}`, + testEndpoint: "REGIONAL", + testFolder: `${CONFIGS_FOLDER}/http-api`, + testStage: "$default", + }, + { + testBasePath: "(none)", + testDescription: "Deploy regional domain with TLS 1.0", + testDomain: `regional-tls-1-0-${RANDOM_STRING}.${TEST_DOMAIN}`, + testEndpoint: "REGIONAL", + testFolder: `${CONFIGS_FOLDER}/regional-tls-1-0`, + testStage: "test", + }, +]; + +describe("Integration Tests", function() { + this.timeout(FIFTEEN_MINUTES); + + describe("Configuration Tests", () => { + itParam("${value.testDescription}", testCases, async (value) => { + let restApiInfo; + if (value.createApiGateway) { + restApiInfo = await utilities.setupApiGatewayResources(RANDOM_STRING); + } + try { + await utilities.createResources(value.testFolder, value.testDomain, RANDOM_STRING); + const stage = await utilities.getStage(value.testDomain); + expect(stage).to.equal(value.testStage); + + const basePath = await utilities.getBasePath(value.testDomain); + expect(basePath).to.equal(value.testBasePath); + + const endpoint = await utilities.getEndpointType(value.testDomain); + expect(endpoint).to.equal(value.testEndpoint); + } finally { + await utilities.destroyResources(value.testDomain, RANDOM_STRING); + if (value.createApiGateway) { + await utilities.deleteApiGatewayResources(restApiInfo.restApiId); + } + } + }); + }); +}); diff --git a/test/integration-tests/enabled-default/handler.js b/test/integration-tests/deploy/auto-domain/handler.js similarity index 100% rename from test/integration-tests/enabled-default/handler.js rename to test/integration-tests/deploy/auto-domain/handler.js diff --git a/test/integration-tests/deploy/auto-domain/serverless.yml b/test/integration-tests/deploy/auto-domain/serverless.yml new file mode 100644 index 00000000..594aa5a6 --- /dev/null +++ b/test/integration-tests/deploy/auto-domain/serverless.yml @@ -0,0 +1,27 @@ +# create_domain should be run as part of deployment +service: auto-domain-${opt:RANDOM_STRING} +provider: + name: aws + runtime: nodejs12.x + region: us-west-2 + stage: test +functions: + helloWorld: + handler: handler.helloWorld + events: + - http: + path: hello-world + method: get + cors: true +plugins: + - serverless-domain-manager +custom: + customDomain: + domainName: auto-domain-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} + basePath: '' + autoDomain: true + autoDomainWaitFor: 120 + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/enabled-regional-basepath/handler.js b/test/integration-tests/deploy/enabled-basepath/handler.js similarity index 100% rename from test/integration-tests/enabled-regional-basepath/handler.js rename to test/integration-tests/deploy/enabled-basepath/handler.js diff --git a/test/integration-tests/enabled-basepath/serverless.yml b/test/integration-tests/deploy/enabled-basepath/serverless.yml similarity index 75% rename from test/integration-tests/enabled-basepath/serverless.yml rename to test/integration-tests/deploy/enabled-basepath/serverless.yml index b00d7b93..3d98e353 100644 --- a/test/integration-tests/enabled-basepath/serverless.yml +++ b/test/integration-tests/deploy/enabled-basepath/serverless.yml @@ -1,9 +1,10 @@ # Enabled with custom basepath -service: enabled-basepath +service: enabled-basepath-${opt:RANDOM_STRING} provider: name: aws - runtime: nodejs6.10 + runtime: nodejs12.x region: us-west-2 + stage: test functions: helloWorld: handler: handler.helloWorld @@ -18,3 +19,7 @@ custom: customDomain: domainName: enabled-basepath-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} basePath: 'api' + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/enabled-regional-empty-basepath/handler.js b/test/integration-tests/deploy/enabled-custom-apigateway/handler.js similarity index 100% rename from test/integration-tests/enabled-regional-empty-basepath/handler.js rename to test/integration-tests/deploy/enabled-custom-apigateway/handler.js diff --git a/test/integration-tests/enabled-custom-apigateway/serverless.yml b/test/integration-tests/deploy/enabled-custom-apigateway/serverless.yml similarity index 78% rename from test/integration-tests/enabled-custom-apigateway/serverless.yml rename to test/integration-tests/deploy/enabled-custom-apigateway/serverless.yml index 0a8ab84f..0beb4641 100644 --- a/test/integration-tests/enabled-custom-apigateway/serverless.yml +++ b/test/integration-tests/deploy/enabled-custom-apigateway/serverless.yml @@ -1,9 +1,10 @@ # Enabled with default values -service: enabled-custom-apigateway +service: enabled-custom-apigateway-${opt:RANDOM_STRING} provider: name: aws - runtime: nodejs6.10 + runtime: nodejs12.x region: us-west-2 + stage: test apiGateway: restApiId: ${env:REST_API_ID} restApiResources: @@ -21,3 +22,7 @@ plugins: custom: customDomain: domainName: enabled-custom-apigateway-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/enabled-regional-stage-basepath/handler.js b/test/integration-tests/deploy/enabled-default/handler.js similarity index 100% rename from test/integration-tests/enabled-regional-stage-basepath/handler.js rename to test/integration-tests/deploy/enabled-default/handler.js diff --git a/test/integration-tests/enabled-default/serverless.yml b/test/integration-tests/deploy/enabled-default/serverless.yml similarity index 74% rename from test/integration-tests/enabled-default/serverless.yml rename to test/integration-tests/deploy/enabled-default/serverless.yml index 4a958c50..717fda4d 100644 --- a/test/integration-tests/enabled-default/serverless.yml +++ b/test/integration-tests/deploy/enabled-default/serverless.yml @@ -1,9 +1,10 @@ # Enabled with default values -service: enabled-default +service: enabled-default-${opt:RANDOM_STRING} provider: name: aws - runtime: nodejs6.10 + runtime: nodejs12.x region: us-west-2 + stage: test functions: helloWorld: handler: handler.helloWorld @@ -17,3 +18,7 @@ plugins: custom: customDomain: domainName: enabled-default-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/enabled-stage-basepath/handler.js b/test/integration-tests/deploy/enabled-regional-basepath/handler.js similarity index 100% rename from test/integration-tests/enabled-stage-basepath/handler.js rename to test/integration-tests/deploy/enabled-regional-basepath/handler.js diff --git a/test/integration-tests/enabled-regional-basepath/serverless.yml b/test/integration-tests/deploy/enabled-regional-basepath/serverless.yml similarity index 73% rename from test/integration-tests/enabled-regional-basepath/serverless.yml rename to test/integration-tests/deploy/enabled-regional-basepath/serverless.yml index e92dd62f..ccd9c0bd 100644 --- a/test/integration-tests/enabled-regional-basepath/serverless.yml +++ b/test/integration-tests/deploy/enabled-regional-basepath/serverless.yml @@ -1,9 +1,11 @@ # Enabled with regional endpoint, custom basePath -service: enabled-regional-basepath +service: enabled-regional-basepath-${opt:RANDOM_STRING} provider: name: aws - runtime: nodejs6.10 + runtime: nodejs12.x region: us-west-2 + endpointType: regional + stage: test functions: helloWorld: handler: handler.helloWorld @@ -19,3 +21,7 @@ custom: domainName: enabled-regional-basepath-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} basePath: 'api' endpointType: regional + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/null-basepath-mapping/handler.js b/test/integration-tests/deploy/enabled-regional-stage-basepath/handler.js similarity index 100% rename from test/integration-tests/null-basepath-mapping/handler.js rename to test/integration-tests/deploy/enabled-regional-stage-basepath/handler.js diff --git a/test/integration-tests/enabled-regional-stage-basepath/serverless.yml b/test/integration-tests/deploy/enabled-regional-stage-basepath/serverless.yml similarity index 76% rename from test/integration-tests/enabled-regional-stage-basepath/serverless.yml rename to test/integration-tests/deploy/enabled-regional-stage-basepath/serverless.yml index 65998c6e..f667cd3e 100644 --- a/test/integration-tests/enabled-regional-stage-basepath/serverless.yml +++ b/test/integration-tests/deploy/enabled-regional-stage-basepath/serverless.yml @@ -1,9 +1,10 @@ # Enabled with regional endpoint, custom stage, empty basepath -service: enabled-regional-stage-basepath +service: enabled-regional-stage-basepath-${opt:RANDOM_STRING} provider: name: aws - runtime: nodejs6.10 + runtime: nodejs12.x region: us-west-2 + endpointType: regional stage: test functions: helloWorld: @@ -21,3 +22,7 @@ custom: stage: test basePath: '' endpointType: regional + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/two-three-migration-basepath/handler.js b/test/integration-tests/deploy/enabled-stage-basepath/handler.js similarity index 100% rename from test/integration-tests/two-three-migration-basepath/handler.js rename to test/integration-tests/deploy/enabled-stage-basepath/handler.js diff --git a/test/integration-tests/enabled-stage-basepath/serverless.yml b/test/integration-tests/deploy/enabled-stage-basepath/serverless.yml similarity index 78% rename from test/integration-tests/enabled-stage-basepath/serverless.yml rename to test/integration-tests/deploy/enabled-stage-basepath/serverless.yml index e40396f5..9e8d4ca9 100644 --- a/test/integration-tests/enabled-stage-basepath/serverless.yml +++ b/test/integration-tests/deploy/enabled-stage-basepath/serverless.yml @@ -1,8 +1,8 @@ # Enabled with custom stage and empty basepath -service: enabled-stage-basepath +service: enabled-stage-basepath-${opt:RANDOM_STRING} provider: name: aws - runtime: nodejs6.10 + runtime: nodejs12.x region: us-west-2 stage: test functions: @@ -20,3 +20,7 @@ custom: domainName: enabled-stage-basepath-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} stage: test basePath: '' + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/two-three-migration-default/handler.js b/test/integration-tests/deploy/http-api/handler.js similarity index 100% rename from test/integration-tests/two-three-migration-default/handler.js rename to test/integration-tests/deploy/http-api/handler.js diff --git a/test/integration-tests/deploy/http-api/serverless.yml b/test/integration-tests/deploy/http-api/serverless.yml new file mode 100644 index 00000000..212f168b --- /dev/null +++ b/test/integration-tests/deploy/http-api/serverless.yml @@ -0,0 +1,25 @@ +service: http-api-${opt:RANDOM_STRING} +provider: + name: aws + runtime: nodejs12.x + region: us-west-2 + stage: test +functions: + helloWorld: + handler: handler.connect + events: + - httpApi: + method: GET + path: /hello-world +plugins: + - serverless-domain-manager +custom: + customDomain: + http: + domainName: http-api-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} + basePath: '' + endpointType: 'regional' + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/deploy/regional-tls-1-0/handler.js b/test/integration-tests/deploy/regional-tls-1-0/handler.js new file mode 100644 index 00000000..1bd222d6 --- /dev/null +++ b/test/integration-tests/deploy/regional-tls-1-0/handler.js @@ -0,0 +1,16 @@ +"use strict"; + +module.exports.helloWorld = (event, context, callback) => { + const response = { + statusCode: 200, + headers: { + "Access-Control-Allow-Origin": "*", // Required for CORS support to work + }, + body: JSON.stringify({ + message: "Go Serverless v1.0! Your function executed successfully!", + input: event, + }), + }; + + callback(null, response); +}; diff --git a/test/integration-tests/deploy/regional-tls-1-0/serverless.yml b/test/integration-tests/deploy/regional-tls-1-0/serverless.yml new file mode 100644 index 00000000..ede7818e --- /dev/null +++ b/test/integration-tests/deploy/regional-tls-1-0/serverless.yml @@ -0,0 +1,28 @@ +# Test regional domains with TLS 1.0 +service: regional-tls-1-0-${opt:RANDOM_STRING} +provider: + name: aws + runtime: nodejs12.x + region: us-west-2 + stage: test + endpointType: regional + +functions: + helloWorld: + handler: handler.helloWorld + events: + - http: + path: hello-world + method: get + cors: true +plugins: + - serverless-domain-manager +custom: + customDomain: + domainName: regional-tls-1-0-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} + securityPolicy: tls_1_0 + endpointType: regional + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/deploy/web-socket/handler.js b/test/integration-tests/deploy/web-socket/handler.js new file mode 100644 index 00000000..9d807dd4 --- /dev/null +++ b/test/integration-tests/deploy/web-socket/handler.js @@ -0,0 +1,9 @@ +"use strict"; + +module.exports.connect = (event, context, callback) => { + const response = { + statusCode: 200, + }; + + callback(null, response); +}; diff --git a/test/integration-tests/deploy/web-socket/serverless.yml b/test/integration-tests/deploy/web-socket/serverless.yml new file mode 100644 index 00000000..7bbe6f9b --- /dev/null +++ b/test/integration-tests/deploy/web-socket/serverless.yml @@ -0,0 +1,24 @@ +service: web-socket-${opt:RANDOM_STRING} +provider: + name: aws + runtime: nodejs12.x + region: us-west-2 + stage: test +functions: + connect: + handler: handler.connect + events: + - websocket: + route: $connect +plugins: + - serverless-domain-manager +custom: + customDomain: + websocket: + domainName: web-socket-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} + basePath: '' + endpointType: 'regional' + +package: + exclude: + - node_modules/** diff --git a/test/integration-tests/disabled/serverless.yml b/test/integration-tests/disabled/serverless.yml deleted file mode 100644 index 30ae630b..00000000 --- a/test/integration-tests/disabled/serverless.yml +++ /dev/null @@ -1,20 +0,0 @@ -# Disabled -service: domain-manager-disabled -provider: - name: aws - runtime: nodejs6.10 - region: us-west-2 -functions: - helloWorld: - handler: handler.helloWorld - events: - - http: - path: hello-world - method: get - cors: true -plugins: - - serverless-domain-manager -custom: - customDomain: - domainName: disabled-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} - enabled: false diff --git a/test/integration-tests/enabled-regional-empty-basepath/serverless.yml b/test/integration-tests/enabled-regional-empty-basepath/serverless.yml deleted file mode 100644 index c137f2b9..00000000 --- a/test/integration-tests/enabled-regional-empty-basepath/serverless.yml +++ /dev/null @@ -1,21 +0,0 @@ -# Enabled with regional endpoint and empty basepath -service: enabled-regional-empty-basepath -provider: - name: aws - runtime: nodejs6.10 - region: us-west-2 -functions: - helloWorld: - handler: handler.helloWorld - events: - - http: - path: hello-world - method: get - cors: true -plugins: - - serverless-domain-manager -custom: - customDomain: - domainName: enabled-regional-empty-basepath-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} - basePath: '' - endpointType: regional diff --git a/test/integration-tests/integration.test.js b/test/integration-tests/integration.test.js deleted file mode 100644 index 30d4c020..00000000 --- a/test/integration-tests/integration.test.js +++ /dev/null @@ -1,350 +0,0 @@ -"use strict"; - -const chai = require("chai"); -const itParam = require("mocha-param"); -const utilities = require("./test-utilities"); -const randomstring = require("randomstring"); - -const expect = chai.expect; - -const TEST_DOMAIN = process.env.TEST_DOMAIN; -const SIX_HOURS = 6 * 60 * 60 * 1000; // 6 hours in milliseconds -const RANDOM_STRING = randomstring.generate({ - length: 5, - charset: "alphanumeric", - capitalization: "lowercase", -}); -const TEMP_DIR = `~/tmp/domain-manager-test-${RANDOM_STRING}`; - -const testCases = [ - { - testDescription: "Enabled with default values", - testFolder: "enabled-default", - testDomain: `enabled-default-${RANDOM_STRING}.${TEST_DOMAIN}`, - testStage: "dev", - testBasePath: "(none)", - testEndpoint: "EDGE", - testURL: `https://enabled-default-${RANDOM_STRING}.${TEST_DOMAIN}/hello-world`, - }, - { - testDescription: "Enabled with custom api gateway", - testFolder: "enabled-custom-apigateway", - testDomain: `enabled-custom-apigateway-${RANDOM_STRING}.${TEST_DOMAIN}`, - testStage: "dev", - testBasePath: "(none)", - testEndpoint: "EDGE", - testURL: `https://enabled-custom-apigateway-${RANDOM_STRING}.${TEST_DOMAIN}`, - createApiGateway: true, - }, - { - testDescription: "Enabled with custom basepath", - testFolder: "enabled-basepath", - testDomain: `enabled-basepath-${RANDOM_STRING}.${TEST_DOMAIN}`, - testStage: "dev", - testBasePath: "api", - testEndpoint: "EDGE", - testURL: `https://enabled-basepath-${RANDOM_STRING}.${TEST_DOMAIN}/api/hello-world`, - }, - { - testDescription: "Enabled with custom stage and empty basepath", - testFolder: "enabled-stage-basepath", - testDomain: `enabled-stage-basepath-${RANDOM_STRING}.${TEST_DOMAIN}`, - testStage: "test", - testBasePath: "(none)", - testEndpoint: "EDGE", - testURL: `https://enabled-stage-basepath-${RANDOM_STRING}.${TEST_DOMAIN}/hello-world`, - }, - { - testDescription: "Enabled with regional endpoint, custom basePath", - testFolder: "enabled-regional-basepath", - testDomain: `enabled-regional-basepath-${RANDOM_STRING}.${TEST_DOMAIN}`, - testStage: "dev", - testBasePath: "api", - testEndpoint: "REGIONAL", - testURL: `https://enabled-regional-basepath-${RANDOM_STRING}.${TEST_DOMAIN}/api/hello-world`, - }, - { - testDescription: "Enabled with regional endpoint, custom stage, empty basepath", - testFolder: "enabled-regional-stage-basepath", - testDomain: `enabled-regional-stage-basepath-${RANDOM_STRING}.${TEST_DOMAIN}`, - testStage: "test", - testBasePath: "(none)", - testEndpoint: "REGIONAL", - testURL: `https://enabled-regional-stage-basepath-${RANDOM_STRING}.${TEST_DOMAIN}/hello-world`, - }, - { - testDescription: "Enabled with regional endpoint and empty basepath", - testFolder: "enabled-regional-empty-basepath", - testDomain: `enabled-regional-empty-basepath-${RANDOM_STRING}.${TEST_DOMAIN}`, - testStage: "dev", - testBasePath: "(none)", - testEndpoint: "REGIONAL", - testURL: `https://enabled-regional-empty-basepath-${RANDOM_STRING}.${TEST_DOMAIN}/hello-world`, - }, -]; - - -describe("Integration Tests", function () { // eslint-disable-line func-names - this.timeout(SIX_HOURS); // 6 hours to allow for dns to propogate - - describe("Domain Manager Is Enabled", function () { // eslint-disable-line func-names - this.timeout(SIX_HOURS); - - itParam("${value.testDescription}", testCases, async (value) => { // eslint-disable-line no-template-curly-in-string - let restApiInfo; - if (value.createApiGateway) { - restApiInfo = await utilities.setupApiGatewayResources(RANDOM_STRING); - } - const created = await utilities.createResources(value.testFolder, - value.testDomain, RANDOM_STRING, true); - if (!created) { - throw new utilities.CreationError("Resources failed to create."); - } else { - const stage = await utilities.getStage(value.testDomain); - expect(stage).to.equal(value.testStage); - - const basePath = await utilities.getBasePath(value.testDomain); - expect(basePath).to.equal(value.testBasePath); - - const endpoint = await utilities.getEndpointType(value.testDomain); - expect(endpoint).to.equal(value.testEndpoint); - - const status = await utilities.curlUrl(value.testURL); - expect(status).to.equal(200); - } - await utilities.destroyResources(value.testDomain, RANDOM_STRING); - if (value.createApiGateway) { - await utilities.deleteApiGatewayResources(restApiInfo.restApiId); - } - }); - }); - - describe("Domain Manager Is Not Enabled", function () { // eslint-disable-line func-names - this.timeout(5 * 60 * 1000); // 5 minutes in milliseconds - const testName = "disabled"; - const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; - - before(async () => { - const created = await utilities.createResources(testName, testURL, RANDOM_STRING, false); - if (!created) { - throw new utilities.CreationError("Resources failed to create."); - } - }); - - it("Does not create a domain", async () => { - const data = await utilities.curlUrl(`https://${testURL}/hello-world`); - expect(data).to.equal(null); - }); - - after(async () => { - await utilities.destroyResources(testURL, RANDOM_STRING); - }); - }); - - describe("Basepath Mapping Is Empty", function () { // eslint-disable-line func-names - this.timeout(15 * 60 * 1000); // 15 minutes in milliseconds - const testName = "null-basepath-mapping"; - const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; - - before(async () => { - // Perform sequence of commands to replicate basepath mapping issue - // Sleep for a min b/w commands in order to avoid rate limiting. - await utilities.createTempDir(TEMP_DIR, testName); - await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsDeleteDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); - }); - - it("Creates a basepath mapping", async () => { - const basePath = await utilities.getBasePath(testURL); - expect(basePath).to.equal("(none)"); - }); - - after(async () => { - await utilities.destroyResources(testURL, RANDOM_STRING); - }); - }); - - describe("Basepath Mapping Is Set", function () { // eslint-disable-line func-names - this.timeout(15 * 60 * 1000); // 15 minutes in milliseconds - const testName = "basepath-mapping"; - const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; - - before(async () => { - // Perform sequence of commands to replicate basepath mapping issue - // Sleep for a min b/w commands in order to avoid rate limiting. - await utilities.createTempDir(TEMP_DIR, testName); - await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsDeleteDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); - }); - - it("Creates a basepath mapping", async () => { - const basePath = await utilities.getBasePath(testURL); - expect(basePath).to.equal("api"); - }); - - after(async () => { - await utilities.destroyResources(testURL, RANDOM_STRING); - }); - }); - - - describe("Basepath Mapping Is Empty And Fix Works", function () { // eslint-disable-line func-names - this.timeout(15 * 60 * 1000); // 15 minutes in milliseconds - const testName = "null-basepath-mapping"; - const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; - - before(async () => { - // Perform sequence of commands to replicate basepath mapping issue - // Sleep for a min b/w commands in order to avoid rate limiting. - await utilities.createTempDir(TEMP_DIR, testName); - await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsDeleteDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsRemove(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); - }); - - it("Creates a basepath mapping", async () => { - const basePath = await utilities.getBasePath(testURL); - expect(basePath).to.equal("(none)"); - }); - - after(async () => { - await utilities.destroyResources(testURL, RANDOM_STRING); - }); - }); - - describe("Create domain is idempotent", function () { // eslint-disable-line func-names - this.timeout(15 * 60 * 1000); // 15 minutes in milliseconds - const testName = "create-domain-idempotent"; - const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; - - it("Creates a domain multiple times without failure", async () => { - let createDomainSuccess = true; - let deploySuccess; - await utilities.createTempDir(TEMP_DIR, testName); - createDomainSuccess = createDomainSuccess && await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - createDomainSuccess = createDomainSuccess && await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - createDomainSuccess = createDomainSuccess && await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - deploySuccess = await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); - expect(createDomainSuccess).to.equal(true); - expect(deploySuccess).to.equal(true); - }); - - after(async () => { - await utilities.destroyResources(testURL, RANDOM_STRING); - }); - }); - - describe("Deploy is idempotent", function () { // eslint-disable-line func-names - this.timeout(15 * 60 * 1000); // 15 minutes in milliseconds - const testName = "deploy-idempotent"; - const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; - - it("Deploys multiple times without failure", async () => { - let createDomainSuccess; - let deploySuccess = true; - await utilities.createTempDir(TEMP_DIR, testName); - createDomainSuccess = await utilities.slsCreateDomain(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - deploySuccess = deploySuccess && await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - deploySuccess = deploySuccess && await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); - await utilities.sleep(60); - deploySuccess = deploySuccess && await utilities.slsDeploy(TEMP_DIR, RANDOM_STRING); - expect(createDomainSuccess).to.equal(true); - expect(deploySuccess).to.equal(true); - }); - - after(async () => { - await utilities.destroyResources(testURL, RANDOM_STRING); - }); - }); - - describe("Migrating from 2.x.x to 3.x.x works", function () { // eslint-disable-line func-names - this.timeout(15 * 60 * 1000); // 15 minutes in milliseconds - const testName = "two-three-migration-default"; - const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; - - before(async () => { - await utilities.exec(`rm -rf ${TEMP_DIR}`); - await utilities.exec(`mkdir -p ${TEMP_DIR} && cp -R test/integration-tests/${testName}/. ${TEMP_DIR}`); - await utilities.exec(`cd ${TEMP_DIR}/ && npm install serverless-domain-manager@2.6.13`); - }); - - it("Creates a basepath mapping", async () => { - await utilities.exec(`cd ${TEMP_DIR} && sls create_domain --RANDOM_STRING ${RANDOM_STRING}`); - await utilities.sleep(60); - await utilities.exec(`cd ${TEMP_DIR} && sls deploy --RANDOM_STRING ${RANDOM_STRING}`); - await utilities.sleep(60); - await utilities.exec(`cp -R . ${TEMP_DIR}/node_modules/serverless-domain-manager`); - await utilities.exec(`cd ${TEMP_DIR} && sls deploy --RANDOM_STRING ${RANDOM_STRING}`); - - const basePath = await utilities.getBasePath(testURL); - expect(basePath).to.equal("(none)"); - }); - - after(async () => { - await utilities.exec(`cd ${TEMP_DIR} && sls remove --RANDOM_STRING ${RANDOM_STRING}`); - await utilities.sleep(60); - await utilities.exec(`cd ${TEMP_DIR} && sls delete_domain --RANDOM_STRING ${RANDOM_STRING}`); - await utilities.sleep(60); - await utilities.exec(`rm -rf ${TEMP_DIR}`); - }); - }); - - describe("Migrating from 2.x.x to 3.x.x works given basepath", function () { // eslint-disable-line func-names - this.timeout(15 * 60 * 1000); // 15 minutes in milliseconds - const testName = "two-three-migration-basepath"; - const testURL = `${testName}-${RANDOM_STRING}.${TEST_DOMAIN}`; - - before(async () => { - await utilities.exec(`rm -rf ${TEMP_DIR}`); - await utilities.exec(`mkdir -p ${TEMP_DIR} && cp -R test/integration-tests/${testName}/. ${TEMP_DIR}`); - await utilities.exec(`cd ${TEMP_DIR}/ && npm install serverless-domain-manager@2.6.13`); - }); - - it("Creates a basepath mapping", async () => { - await utilities.exec(`cd ${TEMP_DIR} && sls create_domain --RANDOM_STRING ${RANDOM_STRING}`); - await utilities.sleep(60); - await utilities.exec(`cd ${TEMP_DIR} && sls deploy --RANDOM_STRING ${RANDOM_STRING}`); - await utilities.sleep(60); - await utilities.exec(`cp -R . ${TEMP_DIR}/node_modules/serverless-domain-manager`); - await utilities.exec(`cd ${TEMP_DIR} && sls deploy --RANDOM_STRING ${RANDOM_STRING}`); - - const basePath = await utilities.getBasePath(testURL); - expect(basePath).to.equal("api"); - }); - - after(async () => { - await utilities.exec(`cd ${TEMP_DIR} && sls remove --RANDOM_STRING ${RANDOM_STRING}`); - await utilities.sleep(60); - await utilities.exec(`cd ${TEMP_DIR} && sls delete_domain --RANDOM_STRING ${RANDOM_STRING}`); - await utilities.sleep(60); - await utilities.exec(`rm -rf ${TEMP_DIR}`); - }); - }); -}); diff --git a/test/integration-tests/test-utilities.js b/test/integration-tests/test-utilities.js deleted file mode 100644 index 2a7234b5..00000000 --- a/test/integration-tests/test-utilities.js +++ /dev/null @@ -1,364 +0,0 @@ -"use strict"; - -const request = require("request-promise-native"); -const aws = require("aws-sdk"); -const dns = require("dns"); -const shell = require("shelljs"); - -const AWS_PROFILE = process.env.AWS_PROFILE; -const apiGateway = new aws.APIGateway({ - region: "us-west-2", - credentials: new aws.SharedIniFileCredentials( - { profile: AWS_PROFILE }, - ), -}); - -class CreationError extends Error {} - - -/** - * Stops event thread execution for given number of seconds. - * @param seconds - * @returns {Promise} Resolves after given number of seconds. - */ -function sleep(seconds) { - return new Promise((resolve) => setTimeout(resolve, 1000 * seconds)); -} - -/** - * Executes given shell command. - * @param cmd shell command to execute - * @returns {Promise} Resolves true if successfully executed, else false - */ -async function exec(cmd) { - return new Promise((resolve) => { - shell.exec(`${cmd}`, { silent: true }, (err, stdout, stderr) => { - if (err || stderr) { - return resolve(false); - } - return resolve(true); - }); - }); -} - -/** - * Move item in folderName to created tempDir - * @param {string} tempDir - * @param {string} folderName - */ -async function createTempDir(tempDir, folderName) { - await exec(`rm -rf ${tempDir}`); - await exec(`mkdir -p ${tempDir} && cp -R test/integration-tests/${folderName}/. ${tempDir}`); - await exec(`mkdir -p ${tempDir}/node_modules/serverless-domain-manager`); - await exec(`cp -R . ${tempDir}/node_modules/serverless-domain-manager`); -} - -/** - * Links current serverless-domain-manager to global node_modules in order to run tests. - * @returns {Promise} Resolves true if successfully linked, else false. - */ -async function linkPackages() { - return new Promise((resolve) => { - shell.exec("npm link serverless-domain-manager", { silent: true }, (err, stdout, stderr) => { - if (err || stderr) { - return resolve(false); - } - return resolve(true); - }); - }); -} - -/** - * Curls the given URL to see if it exists - * @param url - * @returns {Promise} Resolves to status code if exists, else null. - */ -async function curlUrl(url) { - let response = null; - response = await request.get({ - url, - resolveWithFullResponse: true, - }) - .catch((err) => { // eslint-disable-line no-unused-vars - response = null; - }); - if (response === undefined || response === null) { - return null; - } - return response.statusCode; -} - -/** - * Gets endpoint type of given URL from AWS - * @param url - * @returns {Promise} Resolves to String if endpoint exists, else null. - */ -async function getEndpointType(url) { - const params = { - domainName: url, - }; - try { - const result = await apiGateway.getDomainName(params).promise(); - return result.endpointConfiguration.types[0]; - } catch (err) { - return null; - } -} - -/** - * Gets stage of given URL from AWS - * @param url - * @returns {Promise} Resolves to String if stage exists, else null. - */ -async function getStage(url) { - const params = { - domainName: url, - }; - try { - const result = await apiGateway.getBasePathMappings(params).promise(); - return result.items[0].stage; - } catch (err) { - return null; - } -} - -/** - * Gets basePath of given URL from AWS - * @param url - * @returns {Promise} Resolves to String if basePath exists, else null. - */ -async function getBasePath(url) { - const params = { - domainName: url, - }; - try { - const result = await apiGateway.getBasePathMappings(params).promise(); - return result.items[0].basePath; - } catch (err) { - return null; - } -} - -/** - * Looks up DNS records for the given url - * @param url - * @returns {Promise} Resolves true if DNS records exist, else false. - */ -function dnsLookup(url) { - return new Promise((resolve) => { - dns.resolveAny(url, (err) => { - if (err) { - return resolve(false); - } - return resolve(true); - }); - }); -} - -/** - * Periodically calls dnsLookup until records found or 40 minutes elapse. - * @param url - * @param enabled - * @returns {Promise} Resolves true if records found, else false. - */ -async function verifyDnsPropogation(url, enabled) { - console.debug("\tWaiting for DNS to Propogate..."); // eslint-disable-line no-console - if (!enabled) { - return true; - } - let numRetries = 0; - let dnsPropogated = false; - while (numRetries < 40 && !dnsPropogated && enabled) { - dnsPropogated = await dnsLookup(url); // eslint-disable-line no-await-in-loop - if (dnsPropogated) { - break; - } - numRetries += 1; - await sleep(60); // eslint-disable-line no-await-in-loop - } - return dnsPropogated; -} - -/** - * Make API Gateway calls to create an API Gateway - * @param {string} randString - * @return {Object} Contains restApiId and resourceId - */ -async function setupApiGatewayResources(randString) { - const restApiInfo = await apiGateway.createRestApi({ name: `rest-api-${randString}` }).promise(); - const restApiId = restApiInfo.id; - const resourceInfo = await apiGateway.getResources({ restApiId }).promise(); - const resourceId = resourceInfo.items[0].id; - shell.env.REST_API_ID = restApiId; - shell.env.RESOURCE_ID = resourceId; - return { restApiId, resourceId }; -} - -/** - * Make API Gateway calls to delete an API Gateway - * @param {string} restApiId - * @return {boolean} Returns true if deleted - */ -async function deleteApiGatewayResources(restApiId) { - return apiGateway.deleteRestApi({ restApiId }).promise(); -} - -/** - * Runs `sls create_domain` for the given folder - * @param tempDir - * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. - * @returns {Promise} - */ -function slsCreateDomain(tempDir, domainIdentifier) { - return new Promise((resolve) => { - shell.exec(`cd ${tempDir} && sls create_domain --RANDOM_STRING ${domainIdentifier}`, { silent: true }, (err, stdout, stderr) => { - if (err || stderr) { - return resolve(false); - } - return resolve(true); - }); - }); -} - -/** - * Runs `sls deploy` for the given folder - * @param tempDir - * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. - * @returns {Promise} - */ -function slsDeploy(tempDir, domainIdentifier) { - return new Promise((resolve) => { - shell.exec(`cd ${tempDir} && sls deploy --RANDOM_STRING ${domainIdentifier}`, { silent: true }, (err, stdout, stderr) => { - if (err || stderr) { - return resolve(false); - } - return resolve(true); - }); - }); -} - -/** - * Runs `sls delete_domain` for the given folder - * @param tempDir - * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. - * @returns {Promise} - */ -function slsDeleteDomain(tempDir, domainIdentifier) { - return new Promise((resolve) => { - shell.exec(`cd ${tempDir} && sls delete_domain --RANDOM_STRING ${domainIdentifier}`, { silent: true }, (err, stdout, stderr) => { - if (err || stderr) { - return resolve(false); - } - return resolve(true); - }); - }); -} - -/** - * Runs `sls remove` for the given folder - * @param tempDir - * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. - * @returns {Promise} - */ -function slsRemove(tempDir, domainIdentifier) { - return new Promise((resolve) => { - shell.exec(`cd ${tempDir} && sls remove --RANDOM_STRING ${domainIdentifier}`, { silent: true }, (err, stdout, stderr) => { - if (err || stderr) { - return resolve(false); - } - return resolve(true); - }); - }); -} - -/** - * Runs both `sls create_domain` and `sls deploy` - * @param tempDir - * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. - * @returns {Promise<*>} - */ -async function deployLambdas(tempDir, domainIdentifier) { - const created = await slsCreateDomain(tempDir, domainIdentifier); - const deployed = await slsDeploy(tempDir, domainIdentifier); - return created && deployed; -} - -/** - * Runs both `sls delete_domain` and `sls remove` - * @param tempDir temp directory where code is being run from - * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. - * @returns {Promise<*>} - */ -async function removeLambdas(tempDir, domainIdentifier) { - const removed = await slsRemove(tempDir, domainIdentifier); - const deleted = await slsDeleteDomain(tempDir, domainIdentifier); - return deleted && removed; -} - -/** - * Wraps creation of testing resources. - * @param folderName - * @param url - * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. - * @param enabled - * @returns {Promise} Resolves true if resources created, else false. - */ -async function createResources(folderName, url, domainIdentifier, enabled) { - console.debug(`\tCreating Resources for ${url}`); // eslint-disable-line no-console - const tempDir = `~/tmp/domain-manager-test-${domainIdentifier}`; - await createTempDir(tempDir, folderName); - const created = await deployLambdas(tempDir, domainIdentifier); - let dnsVerified = false; - if (created) { - dnsVerified = await verifyDnsPropogation(url, enabled); - } - if (created && dnsVerified) { - console.debug("\tResources Created"); // eslint-disable-line no-console - } else { - console.debug("\tResources Failed to Create"); // eslint-disable-line no-console - } - return created && dnsVerified; -} - -/** - * Wraps deletion of testing resources. - * @param url - * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. - * @returns {Promise} Resolves true if resources destroyed, else false. - */ -async function destroyResources(url, domainIdentifier) { - console.debug(`\tCleaning Up Resources for ${url}`); // eslint-disable-line no-console - const tempDir = `~/tmp/domain-manager-test-${domainIdentifier}`; - const removed = await removeLambdas(tempDir, domainIdentifier); - await exec(`rm -rf ${tempDir}`); - if (removed) { - console.debug("\tResources Cleaned Up"); // eslint-disable-line no-console - } else { - console.debug("\tFailed to Clean Up Resources"); // eslint-disable-line no-console - } - return removed; -} - -module.exports = { - curlUrl, - createResources, - createTempDir, - destroyResources, - exec, - verifyDnsPropogation, - dnsLookup, - slsCreateDomain, - slsDeploy, - slsDeleteDomain, - slsRemove, - deployLambdas, - removeLambdas, - getEndpointType, - getBasePath, - getStage, - linkPackages, - sleep, - CreationError, - setupApiGatewayResources, - deleteApiGatewayResources, -}; diff --git a/test/integration-tests/test-utilities.ts b/test/integration-tests/test-utilities.ts new file mode 100644 index 00000000..95e8a4a7 --- /dev/null +++ b/test/integration-tests/test-utilities.ts @@ -0,0 +1,225 @@ +"use strict"; + +import aws = require("aws-sdk"); +import shell = require("shelljs"); + +const AWS_PROFILE = process.env.AWS_PROFILE; +const apiGateway = new aws.APIGateway({ + credentials: new aws.SharedIniFileCredentials( + { profile: AWS_PROFILE }, + ), + region: "us-west-2", +}); + +/** + * Executes given shell command. + * @param cmd shell command to execute + * @returns {Promise} Resolves if successfully executed, else rejects + */ +async function exec(cmd) { + console.debug(`\tRunning command: ${cmd}`); + return new Promise((resolve, reject) => { + shell.exec(cmd, {silent: false}, (err, stdout, stderr) => { + if (err || stderr) { + return reject(); + } + return resolve(); + }); + }); +} + +/** + * Move item in folderName to created tempDir + * @param {string} tempDir + * @param {string} folderName + */ +async function createTempDir(tempDir, folderName) { + await exec(`rm -rf ${tempDir}`); + await exec(`mkdir -p ${tempDir} && cp -R test/integration-tests/${folderName}/. ${tempDir}`); + await exec(`mkdir -p ${tempDir}/node_modules/.bin`); + await exec(`ln -s $(pwd) ${tempDir}/node_modules/`); + + await exec(`ln -s $(pwd)/node_modules/serverless ${tempDir}/node_modules/`); + // link serverless to the bin directory so we can use $(npm bin) to get the path to serverless + await exec(`ln -s $(pwd)/node_modules/serverless/bin/serverless.js ${tempDir}/node_modules/.bin/serverless`); +} + +/** + * Gets endpoint type of given URL from AWS + * @param url + * @returns {Promise} + */ +async function getEndpointType(url) { + const result = await apiGateway.getDomainName({ + domainName: url, + }).promise(); + + return result.endpointConfiguration.types[0]; +} + +/** + * Gets stage of given URL from AWS + * @param url + * @returns {Promise} + */ +async function getStage(url) { + const result = await apiGateway.getBasePathMappings({ + domainName: url, + }).promise(); + + return result.items[0].stage; +} + +/** + * Gets basePath of given URL from AWS + * @param url + * @returns {Promise} + */ +async function getBasePath(url) { + const result = await apiGateway.getBasePathMappings({ + domainName: url, + }).promise(); + + return result.items[0].basePath; +} + +/** + * Make API Gateway calls to create an API Gateway + * @param {string} randString + * @return {Object} Contains restApiId and resourceId + */ +async function setupApiGatewayResources(randString) { + const restApiInfo = await apiGateway.createRestApi({ name: `rest-api-${randString}` }).promise(); + const restApiId = restApiInfo.id; + const resourceInfo = await apiGateway.getResources({ restApiId }).promise(); + const resourceId = resourceInfo.items[0].id; + shell.env.REST_API_ID = restApiId; + shell.env.RESOURCE_ID = resourceId; + return { restApiId, resourceId }; +} + +/** + * Make API Gateway calls to delete an API Gateway + * @param {string} restApiId + * @return {boolean} Returns true if deleted + */ +async function deleteApiGatewayResources(restApiId) { + return apiGateway.deleteRestApi({ restApiId }).promise(); +} + +/** + * Runs `sls create_domain` for the given folder + * @param tempDir + * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. + * @returns {Promise} + */ +function slsCreateDomain(tempDir, domainIdentifier) { + return exec(`cd ${tempDir} && $(npm bin)/serverless create_domain --RANDOM_STRING ${domainIdentifier}`); +} + +/** + * Runs `sls deploy` for the given folder + * @param tempDir + * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. + * @returns {Promise} + */ +function slsDeploy(tempDir, domainIdentifier) { + return exec(`cd ${tempDir} && $(npm bin)/serverless deploy --RANDOM_STRING ${domainIdentifier}`); +} + +/** + * Runs `sls delete_domain` for the given folder + * @param tempDir + * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. + * @returns {Promise} + */ +function slsDeleteDomain(tempDir, domainIdentifier) { + return exec(`cd ${tempDir} && $(npm bin)/serverless delete_domain --RANDOM_STRING ${domainIdentifier}`); +} + +/** + * Runs `sls remove` for the given folder + * @param tempDir + * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. + * @returns {Promise} + */ +function slsRemove(tempDir, domainIdentifier) { + return exec(`cd ${tempDir} && $(npm bin)/serverless remove --RANDOM_STRING ${domainIdentifier}`); +} + +/** + * Runs both `sls create_domain` and `sls deploy` + * @param tempDir + * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. + * @returns {Promise} + */ +async function deployLambdas(tempDir, domainIdentifier) { + await slsCreateDomain(tempDir, domainIdentifier); + await slsDeploy(tempDir, domainIdentifier); +} + +/** + * Runs both `sls delete_domain` and `sls remove` + * @param tempDir temp directory where code is being run from + * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. + * @returns {Promise} + */ +async function removeLambdas(tempDir, domainIdentifier) { + await slsRemove(tempDir, domainIdentifier); + await slsDeleteDomain(tempDir, domainIdentifier); +} + +/** + * Wraps creation of testing resources. + * @param folderName + * @param url + * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. + * @returns {Promise} Resolves if successfully executed, else rejects + */ +async function createResources(folderName, url, domainIdentifier) { + console.debug(`\tCreating Resources for ${url}`); + const tempDir = `~/tmp/domain-manager-test-${domainIdentifier}`; + console.debug(`\tUsing tmp directory ${tempDir}`); + try { + await createTempDir(tempDir, folderName); + await deployLambdas(tempDir, domainIdentifier); + console.debug("\tResources Created"); + } catch (e) { + console.debug("\tResources Failed to Create"); + } +} + +/** + * Wraps deletion of testing resources. + * @param url + * @param domainIdentifier Random alphanumeric string to identify specific run of integration tests. + * @returns {Promise} Resolves if successfully executed, else rejects + */ +async function destroyResources(url, domainIdentifier) { + try { + console.debug(`\tCleaning Up Resources for ${url}`); + const tempDir = `~/tmp/domain-manager-test-${domainIdentifier}`; + await removeLambdas(tempDir, domainIdentifier); + await exec(`rm -rf ${tempDir}`); + + console.debug("\tResources Cleaned Up"); + } catch (e) { + console.debug("\tFailed to Clean Up Resources"); + } +} + +export { + createResources, + createTempDir, + destroyResources, + exec, + slsCreateDomain, + slsDeploy, + slsDeleteDomain, + slsRemove, + getEndpointType, + getBasePath, + getStage, + setupApiGatewayResources, + deleteApiGatewayResources, +}; diff --git a/test/integration-tests/two-three-migration-basepath/serverless.yml b/test/integration-tests/two-three-migration-basepath/serverless.yml deleted file mode 100644 index 71b2efcf..00000000 --- a/test/integration-tests/two-three-migration-basepath/serverless.yml +++ /dev/null @@ -1,20 +0,0 @@ -# Migrating from version 2 to version 3 -service: two-three-migration-basepath -provider: - name: aws - runtime: nodejs6.10 - region: us-west-2 -functions: - helloWorld: - handler: handler.helloWorld - events: - - http: - path: hello-world - method: get - cors: true -plugins: - - serverless-domain-manager -custom: - customDomain: - domainName: two-three-migration-basepath-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} - basePath: api diff --git a/test/integration-tests/two-three-migration-default/serverless.yml b/test/integration-tests/two-three-migration-default/serverless.yml deleted file mode 100644 index a9093dee..00000000 --- a/test/integration-tests/two-three-migration-default/serverless.yml +++ /dev/null @@ -1,19 +0,0 @@ -# Migrating from version 2 to version 3 -service: two-three-migration-default -provider: - name: aws - runtime: nodejs6.10 - region: us-west-2 -functions: - helloWorld: - handler: handler.helloWorld - events: - - http: - path: hello-world - method: get - cors: true -plugins: - - serverless-domain-manager -custom: - customDomain: - domainName: two-three-migration-default-${opt:RANDOM_STRING}.${env:TEST_DOMAIN} diff --git a/test/unit-tests/index.test.ts b/test/unit-tests/index.test.ts index 57d8cf95..b3c0d305 100644 --- a/test/unit-tests/index.test.ts +++ b/test/unit-tests/index.test.ts @@ -3,9 +3,11 @@ import * as AWS from "aws-sdk-mock"; import chai = require("chai"); import spies = require("chai-spies"); import "mocha"; -import DomainInfo = require("../../DomainInfo"); -import ServerlessCustomDomain = require("../../index"); -import { ServerlessInstance, ServerlessOptions } from "../../types"; +import DomainConfig = require("../../src/DomainConfig"); +import DomainInfo = require("../../src/DomainInfo"); +import Globals from "../../src/Globals"; +import ServerlessCustomDomain = require("../../src/index"); +import {getAWSPagedResults} from "../../src/utils"; const expect = chai.expect; chai.use(spies); @@ -62,6 +64,8 @@ const constructPlugin = (customDomainOptions) => { custom: { customDomain: { apiType: customDomainOptions.apiType, + autoDomain: customDomainOptions.autoDomain, + autoDomainWaitFor: customDomainOptions.autoDomainWaitFor, basePath: customDomainOptions.basePath, certificateArn: customDomainOptions.certificateArn, certificateName: customDomainOptions.certificateName, @@ -132,24 +136,54 @@ describe("Custom Domain Plugin", () => { expect(errored).to.equal(true); }); + it("Unsupported HTTP EDGE endpoint configuration", () => { + const plugin = constructPlugin({ apiType: "http" }); + + let errored = false; + try { + plugin.initializeVariables(); + } catch (err) { + errored = true; + expect(err.message).to.equal("Error: 'edge' endpointType is not compatible with HTTP APIs"); + } + expect(errored).to.equal(true); + }); + + it("Unsupported WS EDGE endpoint configuration", () => { + const plugin = constructPlugin({ apiType: "websocket" }); + + let errored = false; + try { + plugin.initializeVariables(); + } catch (err) { + errored = true; + expect(err.message).to.equal("Error: 'edge' endpointType is not compatible with WebSocket APIs"); + } + expect(errored).to.equal(true); + }); + }); describe("Set Domain Name and Base Path", () => { - it("Creates basepath mapping for REST api", async () => { + it("Creates basepath mapping for edge REST api", async () => { AWS.mock("APIGateway", "createBasePathMapping", (params, callback) => { callback(null, params); }); const plugin = constructPlugin({ basePath: "test_basepath", domainName: "test_domain", + endpointType: "edge", }); plugin.initializeVariables(); plugin.apigateway = new aws.APIGateway(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; - plugin.basePath = plugin.serverless.service.custom.customDomain.basePath; + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + dc.apiId = "test_rest_api_id"; + const spy = chai.spy.on(plugin.apigateway, "createBasePathMapping"); - await plugin.createBasePathMapping("test_rest_api_id"); + await plugin.createBasePathMapping(dc); + expect(spy).to.have.been.called.with({ basePath: "test_basepath", domainName: "test_domain", @@ -158,7 +192,90 @@ describe("Custom Domain Plugin", () => { }); }); - it("Updates basepath mapping for api", async () => { + it("Creates basepath mapping for regional tls 1.0 REST api", async () => { + AWS.mock("APIGateway", "createBasePathMapping", (params, callback) => { + callback(null, params); + }); + const plugin = constructPlugin({ + basePath: "test_basepath", + domainName: "test_domain", + endpointType: "regional", + securityPolicy: "tls_1_0", + }); + plugin.initializeVariables(); + plugin.apigateway = new aws.APIGateway(); + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + dc.apiId = "test_rest_api_id"; + + const spy = chai.spy.on(plugin.apigateway, "createBasePathMapping"); + + await plugin.createBasePathMapping(dc); + + expect(spy).to.have.been.called.with({ + basePath: "test_basepath", + domainName: "test_domain", + restApiId: "test_rest_api_id", + stage: "test", + }); + }); + + it("Creates basepath mapping for regional tls 1.2 REST api", async () => { + AWS.mock("ApiGatewayV2", "createApiMapping", (params, callback) => { + callback(null, params); + }); + const plugin = constructPlugin({ + basePath: "test_basepath", + domainName: "test_domain", + endpointType: "regional", + }); + plugin.initializeVariables(); + plugin.apigatewayV2 = new aws.ApiGatewayV2(); + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + dc.apiId = "test_rest_api_id"; + + const spy = chai.spy.on(plugin.apigatewayV2, "createApiMapping"); + + await plugin.createBasePathMapping(dc); + + expect(spy).to.have.been.called.with({ + ApiId: "test_rest_api_id", + ApiMappingKey: "test_basepath", + DomainName: "test_domain", + Stage: "test", + }); + }); + + it("Creates basepath mapping for regional HTTP/Websocket api", async () => { + AWS.mock("ApiGatewayV2", "createApiMapping", (params, callback) => { + callback(null, params); + }); + const plugin = constructPlugin({ + apiType: "http", + basePath: "test_basepath", + domainName: "test_domain", + endpointType: "regional", + }); + plugin.initializeVariables(); + plugin.apigatewayV2 = new aws.ApiGatewayV2(); + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + dc.apiId = "test_rest_api_id"; + + const spy = chai.spy.on(plugin.apigatewayV2, "createApiMapping"); + + await plugin.createBasePathMapping(dc); + expect(spy).to.have.been.called.with({ + ApiId: "test_rest_api_id", + ApiMappingKey: "test_basepath", + DomainName: "test_domain", + Stage: "$default", + }); + }); + + it("Updates basepath mapping for a edge REST api", async () => { AWS.mock("APIGateway", "updateBasePathMapping", (params, callback) => { callback(null, params); }); @@ -167,12 +284,16 @@ describe("Custom Domain Plugin", () => { domainName: "test_domain", }); plugin.initializeVariables(); + plugin.apigateway = new aws.APIGateway(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; - plugin.basePath = plugin.serverless.service.custom.customDomain.basePath; + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + dc.apiMapping = {ApiMappingKey: "old_basepath"}; + const spy = chai.spy.on(plugin.apigateway, "updateBasePathMapping"); - await plugin.updateBasePathMapping("old_basepath"); + await plugin.updateBasePathMapping(dc); expect(spy).to.have.been.called.with({ basePath: "old_basepath", domainName: "test_domain", @@ -210,17 +331,101 @@ describe("Custom Domain Plugin", () => { }); }); - it("Add Domain Name and HostedZoneId to stack output", () => { + it("Updates basepath mapping for regional HTTP/WS api", async () => { + AWS.mock("ApiGatewayV2", "updateApiMapping", (params, callback) => { + callback(null, params); + }); + const plugin = constructPlugin({ + apiType: "http", + basePath: "test_basepath", + domainName: "test_domain", + endpointType: "regional", + }); + plugin.initializeVariables(); + + plugin.apigatewayV2 = new aws.ApiGatewayV2(); + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + dc.apiId = "test_api_id"; + dc.apiMapping = {ApiMappingId: "test_mapping_id"}; + dc.domainInfo = new DomainInfo({ + DomainNameConfigurations: [{ + ApiGatewayDomainName: "fake_dist_name", + HostedZoneId: "fake_zone_id", + SecurityPolicy: "TLS_1_2", + }], + }); + + const spy = chai.spy.on(plugin.apigatewayV2, "updateApiMapping"); + + await plugin.updateBasePathMapping(dc); + expect(spy).to.have.been.called.with({ + ApiId: "test_api_id", + ApiMappingId: "test_mapping_id", + ApiMappingKey: dc.basePath, + DomainName: dc.givenDomainName, + Stage: "$default", + }); + }); + + it("Remove basepath mappings", async () => { + AWS.mock("CloudFormation", "describeStackResource", (params, callback) => { + callback(null, { + StackResourceDetail: + { + LogicalResourceId: "ApiGatewayRestApi", + PhysicalResourceId: "test_rest_api_id", + }, + }); + }); + AWS.mock("ApiGatewayV2", "getApiMappings", (params, callback) => { + callback(null, { + Items: [ + { ApiId: "test_rest_api_id", MappingKey: "test", ApiMappingId: "test_mapping_id", Stage: "test" }, + ], + }); + }); + AWS.mock("ApiGatewayV2", "deleteApiMapping", (params, callback) => { + callback(null, params); + }); + const plugin = constructPlugin({ + basePath: "test_basepath", domainName: "test_domain", + restApiId: "test_rest_api_id", }); - plugin.addOutputs(new DomainInfo({ + plugin.initializeVariables(); + + plugin.apigatewayV2 = new aws.ApiGatewayV2(); + + plugin.domains[0].apiMapping = {ApiMappingId: "test_mapping_id"}; + + const spy = chai.spy.on(plugin.apigatewayV2, "deleteApiMapping"); + + await plugin.removeBasePathMappings(); + expect(spy).to.have.been.called.with({ + ApiMappingId: "test_mapping_id", + DomainName: "test_domain", + }); + }); + + it("Add Distribution Domain Name, Domain Name, and HostedZoneId to stack output", () => { + const plugin = constructPlugin({ + domainName: "test_domain", + }); + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + dc.domainInfo = new DomainInfo({ distributionDomainName: "fake_dist_name", distributionHostedZoneId: "fake_zone_id", domainName: "fake_domain", - })); - const cfTemplat = plugin.serverless.service.provider.compiledCloudFormationTemplate.Outputs; - expect(cfTemplat).to.not.equal(undefined); + }); + + plugin.addOutputs(dc); + + const cfTemplate = plugin.serverless.service.provider.compiledCloudFormationTemplate.Outputs; + expect(cfTemplate).to.not.equal(undefined); }); it("(none) is added if basepath is an empty string", async () => { @@ -234,10 +439,14 @@ describe("Custom Domain Plugin", () => { }); plugin.initializeVariables(); plugin.apigateway = new aws.APIGateway(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + dc.apiId = "test_rest_api_id"; + const spy = chai.spy.on(plugin.apigateway, "createBasePathMapping"); - await plugin.createBasePathMapping("test_rest_api_id"); + await plugin.createBasePathMapping(dc); expect(spy).to.have.been.called.with({ basePath: "(none)", domainName: "test_domain", @@ -257,10 +466,14 @@ describe("Custom Domain Plugin", () => { }); plugin.initializeVariables(); plugin.apigateway = new aws.APIGateway(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + dc.apiId = "test_rest_api_id"; + const spy = chai.spy.on(plugin.apigateway, "createBasePathMapping"); - await plugin.createBasePathMapping("test_rest_api_id"); + await plugin.createBasePathMapping(dc); expect(spy).to.have.been.called.with({ basePath: "(none)", domainName: "test_domain", @@ -279,10 +492,14 @@ describe("Custom Domain Plugin", () => { }); plugin.initializeVariables(); plugin.apigateway = new aws.APIGateway(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + dc.apiId = "test_rest_api_id"; + const spy = chai.spy.on(plugin.apigateway, "createBasePathMapping"); - await plugin.createBasePathMapping("test_rest_api_id"); + await plugin.createBasePathMapping(dc); expect(spy).to.have.been.called.with({ basePath: "(none)", domainName: "test_domain", @@ -300,12 +517,15 @@ describe("Custom Domain Plugin", () => { domainName: "test_domain", }); plugin.initializeVariables(); - plugin.cloudformation = new aws.CloudFormation(); plugin.apigateway = new aws.APIGateway(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + dc.apiId = "test_rest_api_id"; + const spy = chai.spy.on(plugin.apigateway, "createBasePathMapping"); - await plugin.createBasePathMapping("test_rest_api_id"); + await plugin.createBasePathMapping(dc); expect(spy).to.have.been.called.with({ basePath: "(none)", domainName: "test_domain", @@ -331,7 +551,9 @@ describe("Custom Domain Plugin", () => { const plugin = constructPlugin(options); plugin.acm = new aws.ACM(); - const result = await plugin.getCertArn(); + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + const result = await plugin.getCertArn(dc); expect(result).to.equal("test_given_arn"); }); @@ -342,7 +564,9 @@ describe("Custom Domain Plugin", () => { const plugin = constructPlugin({ certificateName: "cert_name" }); plugin.acm = new aws.ACM(); - const result = await plugin.getCertArn(); + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + const result = await plugin.getCertArn(dc); expect(result).to.equal("test_given_cert_name"); }); @@ -355,12 +579,15 @@ describe("Custom Domain Plugin", () => { const plugin = constructPlugin({ domainName: "test_domain"}); plugin.initializeVariables(); plugin.apigateway = new aws.APIGateway(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; - const result = await plugin.createCustomDomain("fake_cert"); + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + dc.certificateArn = "fake_cert"; + + await plugin.createCustomDomain(dc); - expect(result.domainName).to.equal("foo"); - expect(result.securityPolicy).to.equal("TLS_1_2"); + expect(dc.domainInfo.domainName).to.equal("foo"); + expect(dc.domainInfo.securityPolicy).to.equal("TLS_1_2"); }); it("Create an HTTP domain name", async () => { @@ -368,15 +595,18 @@ describe("Custom Domain Plugin", () => { callback(null, { DomainName: "foo", DomainNameConfigurations: [{SecurityPolicy: "TLS_1_2"}]}); }); - const plugin = constructPlugin({ domainName: "test_domain", apiType: "http"}); + const plugin = constructPlugin({ domainName: "test_domain", apiType: "http", endpointType: "regional"}); plugin.initializeVariables(); plugin.apigatewayV2 = new aws.ApiGatewayV2(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; - const result = await plugin.createCustomDomain("fake_cert"); + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + dc.certificateArn = "fake_cert"; - expect(result.domainName).to.equal("foo"); - expect(result.securityPolicy).to.equal("TLS_1_2"); + await plugin.createCustomDomain(dc); + + expect(dc.domainInfo.domainName).to.equal("foo"); + expect(dc.domainInfo.securityPolicy).to.equal("TLS_1_2"); }); it("Create a domain name with specific TLS version", async () => { @@ -387,12 +617,15 @@ describe("Custom Domain Plugin", () => { const plugin = constructPlugin({ domainName: "test_domain", securityPolicy: "tls_1_2"}); plugin.initializeVariables(); plugin.apigateway = new aws.APIGateway(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; - const result = await plugin.createCustomDomain("fake_cert"); + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); - expect(result.domainName).to.equal("foo"); - expect(result.securityPolicy).to.equal("TLS_1_2"); + dc.certificateArn = "fake_cert"; + + await plugin.createCustomDomain(dc); + + expect(dc.domainInfo.domainName).to.equal("foo"); + expect(dc.domainInfo.securityPolicy).to.equal("TLS_1_2"); }); it("Create a new A Alias Record", async () => { @@ -404,19 +637,21 @@ describe("Custom Domain Plugin", () => { callback(null, params); }); - const plugin = constructPlugin({ basePath: "test_basepath" }); + const plugin = constructPlugin({ basePath: "test_basepath", domainName: "test_domain" }); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = "test_domain"; - const spy = chai.spy.on(plugin.route53, "changeResourceRecordSets"); - const domain = new DomainInfo( + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + dc.domainInfo = new DomainInfo( { distributionDomainName: "test_distribution_name", distributionHostedZoneId: "test_id", }, ); - await plugin.changeResourceRecordSet("UPSERT", domain); + const spy = chai.spy.on(plugin.route53, "changeResourceRecordSets"); + + await plugin.changeResourceRecordSet("UPSERT", dc); const expectedParams = { ChangeBatch: { @@ -458,7 +693,10 @@ describe("Custom Domain Plugin", () => { createRoute53Record: false, domainName: "test_domain", }); - const result = await plugin.changeResourceRecordSet("UPSERT", new DomainInfo({})); + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + const result = await plugin.changeResourceRecordSet("UPSERT", dc); expect(result).to.equal(undefined); }); @@ -469,11 +707,11 @@ describe("Custom Domain Plugin", () => { }); describe("Gets existing basepath mappings correctly", () => { - it("Returns undefined if no basepaths map to current REST api", async () => { - AWS.mock("APIGateway", "getBasePathMappings", (params, callback) => { + it("Returns undefined if no basepaths map to current api", async () => { + AWS.mock("ApiGatewayV2", "getApiMappings", (params, callback) => { callback(null, { - items: [ - { basePath: "(none)", restApiId: "test_rest_api_id_one", stage: "test" }, + Items: [ + { ApiId: "someother_api_id", MappingKey: "test", ApiMappingId: "test_rest_api_id_one", Stage: "test" }, ], }); }); @@ -481,11 +719,13 @@ describe("Custom Domain Plugin", () => { const plugin = constructPlugin({ domainName: "test_domain", }); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; - plugin.basePath = plugin.serverless.service.custom.customDomain.basePath; + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + dc.apiMapping = {ApiMappingId: "api_id"}; + plugin.initializeVariables(); - const result = await plugin.getBasePathMapping("test_rest_api_id_two"); + const result = await plugin.getBasePathMapping(dc); expect(result).to.equal(undefined); }); @@ -510,25 +750,32 @@ describe("Custom Domain Plugin", () => { expect(result).to.equal(undefined); }); - it("Returns current REST api", async () => { - AWS.mock("APIGateway", "getBasePathMappings", (params, callback) => { + it("Returns current api mapping", async () => { + AWS.mock("ApiGatewayV2", "getApiMappings", (params, callback) => { callback(null, { - items: [ - { basePath: "api", restApiId: "test_rest_api_id", stage: "test" }, + Items: [ + { ApiId: "test_rest_api_id", ApiMappingKey: "api", ApiMappingId: "fake_id", Stage: "test" }, ], }); }); const plugin = constructPlugin({ + apiType: Globals.apiTypes.rest, basePath: "api", domainName: "test_domain", }); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; - plugin.basePath = plugin.serverless.service.custom.customDomain.basePath; + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + dc.apiId = "test_rest_api_id"; + plugin.initializeVariables(); - const result = await plugin.getBasePathMapping("test_rest_api_id"); - expect(result).to.equal("api"); + const result = await plugin.getBasePathMapping(dc); + expect(result).to.eql({ + ApiId: "test_rest_api_id", + ApiMappingId: "fake_id", + ApiMappingKey: "api", + Stage: "test" }); }); it("Returns current HTTP api", async () => { @@ -559,8 +806,8 @@ describe("Custom Domain Plugin", () => { }); }); - describe("Gets Rest API correctly", () => { - it("Fetches restApiId correctly when no ApiGateway specified", async () => { + describe("Gets Rest API id correctly", () => { + it("Fetches REST API id correctly when no ApiGateway specified", async () => { AWS.mock("CloudFormation", "describeStacks", (params, callback) => { callback(null, { Stacks: [ @@ -590,57 +837,79 @@ describe("Custom Domain Plugin", () => { domainName: "test_domain", }); plugin.initializeVariables(); - plugin.cloudformation = new aws.CloudFormation(); - const result = await plugin.getApiId(); + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + const spy = chai.spy.on(plugin.cloudFormationWrapper.provider, "describeStackResource"); + + const result = await plugin.getApiId(dc); + expect(result).to.equal("test_rest_api_id"); + expect(spy).to.have.been.called.with({ + LogicalResourceId: "ApiGatewayRestApi", + StackName: "custom-stage-name", + }); + }); + + it("Gets HTTP API id correctly when no ApiGateway specified", async () => { + AWS.mock("CloudFormation", "describeStackResource", (params, callback) => { + callback(null, { + StackResourceDetail: + { + LogicalResourceId: "HttpApi", + PhysicalResourceId: "test_http_api_id", + }, + }); + }); + const plugin = constructPlugin({ + apiType: "http", + basePath: "test_basepath", + domainName: "test_domain", + endpointType: "regional", + }); + plugin.initializeVariables(); + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + const spy = chai.spy.on(plugin.cloudFormationWrapper.provider, "describeStackResource"); + + const result = await plugin.getApiId(dc); + expect(result).to.equal("test_http_api_id"); + expect(spy).to.have.been.called.with({ + LogicalResourceId: "HttpApi", + StackName: "custom-stage-name", + }); }); - // The tests below can be uncommited ater aws-sdk-mock is updated to new version that supports .remock() - - // it("Fetches correct HTTP apiId", async () => { - // AWS.mock("CloudFormation", "describeStackResource", (params, callback) => { - // callback(null, { - // StackResourceDetail: - // { - // LogicalResourceId: "HttpApi", - // PhysicalResourceId: "test_http_api_id", - // }, - // }); - // }); - // const plugin = constructPlugin({ - // apiType: "http", - // basePath: "test_basepath", - // domainName: "test_domain", - // }); - // plugin.initializeVariables(); - // plugin.cloudformation = new aws.CloudFormation(); - - // const result = await plugin.getApiId(); - // expect(result).to.equal("test_http_api_id"); - // }); - - // it("Fetches correct WebSocket apiId", async () => { - // AWS.mock("CloudFormation", "describeStackResource", (params, callback) => { - // callback(null, { - // StackResourceDetail: - // { - // LogicalResourceId: "WebsocketsApi", - // PhysicalResourceId: "test_ws_api_id", - // }, - // }); - // }); - // const plugin = constructPlugin({ - // apiType: "websocket", - // basePath: "test_basepath", - // domainName: "test_domain", - // }); - // plugin.initializeVariables(); - // plugin.cloudformation = new aws.CloudFormation(); - - // const result = await plugin.getApiId(); - // expect(result).to.equal("test_ws_api_id"); - // }); + it("Gets Websocket API id correctly when no ApiGateway specified", async () => { + AWS.mock("CloudFormation", "describeStackResource", (params, callback) => { + callback(null, { + StackResourceDetail: + { + LogicalResourceId: "WebsocketsApi", + PhysicalResourceId: "test_ws_api_id", + }, + }); + }); + const plugin = constructPlugin({ + apiType: "websocket", + basePath: "test_basepath", + domainName: "test_domain", + endpointType: "regional", + }); + plugin.initializeVariables(); + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + const spy = chai.spy.on(plugin.cloudFormationWrapper.provider, "describeStackResource"); + + const result = await plugin.getApiId(dc); + expect(result).to.equal("test_ws_api_id"); + expect(spy).to.have.been.called.with({ + LogicalResourceId: "WebsocketsApi", + StackName: "custom-stage-name", + }); + }); it("serverless.yml defines explicitly the apiGateway", async () => { AWS.mock("CloudFormation", "describeStackResource", (params, callback) => { @@ -657,14 +926,17 @@ describe("Custom Domain Plugin", () => { basePath: "test_basepath", domainName: "test_domain", }); - plugin.cloudformation = new aws.CloudFormation(); + plugin.serverless.service.provider.apiGateway.restApiId = "custom_test_rest_api_id"; - const result = await plugin.getApiId(); + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + + const result = await plugin.getApiId(dc); expect(result).to.equal("custom_test_rest_api_id"); }); afterEach(() => { + AWS.restore(); consoleOutput = []; }); }); @@ -680,11 +952,12 @@ describe("Custom Domain Plugin", () => { domainName: "test_domain", }); plugin.apigateway = new aws.APIGateway(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; - const result = await plugin.getDomainInfo(); + await plugin.getDomainInfo(); - expect(result.domainName).to.equal("test_domain"); + plugin.domains.forEach((domain) => { + expect(domain.domainInfo.domainName).to.equal("test_domain"); + }); }); it("Delete A Alias Record", async () => { @@ -701,15 +974,17 @@ describe("Custom Domain Plugin", () => { domainName: "test_domain", }); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); + const spy = chai.spy.on(plugin.route53, "changeResourceRecordSets"); - const domain = new DomainInfo({ + dc.domainInfo = new DomainInfo({ distributionDomainName: "test_distribution_name", distributionHostedZoneId: "test_id", }); - await plugin.changeResourceRecordSet("DELETE", domain); + await plugin.changeResourceRecordSet("DELETE", dc); const expectedParams = { ChangeBatch: { Changes: [ @@ -747,7 +1022,7 @@ describe("Custom Domain Plugin", () => { }); it("Delete the domain name", async () => { - AWS.mock("APIGateway", "deleteDomainName", (params, callback) => { + AWS.mock("ApiGatewayV2", "deleteDomainName", (params, callback) => { callback(null, {}); }); @@ -755,13 +1030,15 @@ describe("Custom Domain Plugin", () => { basePath: "test_basepath", domainName: "test_domain", }); - plugin.apigateway = new aws.APIGateway(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; - const spy = chai.spy.on(plugin.apigateway, "deleteDomainName"); + plugin.apigatewayV2 = new aws.ApiGatewayV2(); + + const dc: DomainConfig = new DomainConfig(plugin.serverless.service.custom.customDomain); - await plugin.deleteCustomDomain(); + const spy = chai.spy.on(plugin.apigatewayV2, "deleteDomainName"); + + await plugin.deleteCustomDomain(dc); expect(spy).to.be.called.with({ - domainName: "test_domain", + DomainName: "test_domain", }); }); @@ -773,11 +1050,12 @@ describe("Custom Domain Plugin", () => { describe("Hook Methods", () => { it("setupBasePathMapping", async () => { - AWS.mock("APIGateway", "getDomainName", (params, callback) => { - callback(null, { domainName: "fake_domain", distributionDomainName: "fake_dist_name" }); + AWS.mock("ApiGatewayV2", "getDomainName", (params, callback) => { + callback(null, {DomainName: "test_domain", + DomainNameConfigurations: [{ApiGatewayDomainName: "fake_dist_name"}]}); }); - AWS.mock("APIGateway", "getBasePathMappings", (params, callback) => { - callback(null, { items: [] }); + AWS.mock("ApiGatewayV2", "getApiMappings", (params, callback) => { + callback(null, { Items: [] }); }); AWS.mock("APIGateway", "createBasePathMapping", (params, callback) => { callback(null, params); @@ -809,20 +1087,20 @@ describe("Custom Domain Plugin", () => { const plugin = constructPlugin({ domainName: "test_domain"}); plugin.initializeVariables(); plugin.apigateway = new aws.APIGateway(); - plugin.cloudformation = new aws.CloudFormation(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; + plugin.apigatewayV2 = new aws.ApiGatewayV2(); + const spy = chai.spy.on(plugin, "createBasePathMapping"); - await plugin.setupBasePathMapping(); + await plugin.setupBasePathMappings(); expect(spy).to.be.called(); }); it("deleteDomain", async () => { - AWS.mock("APIGateway", "getDomainName", (params, callback) => { - callback(null, { distributionDomainName: "test_distribution", regionalHostedZoneId: "test_id" }); + AWS.mock("ApiGatewayV2", "getDomainName", (params, callback) => { + callback(null, {DomainName: "test_domain", DomainNameConfigurations: [{HostedZoneId: "test_id"}]}); }); - AWS.mock("APIGateway", "deleteDomainName", (params, callback) => { + AWS.mock("ApiGatewayV2", "deleteDomainName", (params, callback) => { callback(null, {}); }); AWS.mock("Route53", "listHostedZones", (params, callback) => { @@ -835,14 +1113,15 @@ describe("Custom Domain Plugin", () => { const plugin = constructPlugin({ domainName: "test_domain"}); plugin.apigateway = new aws.APIGateway(); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; - await plugin.deleteDomain(); - expect(consoleOutput[0]).to.equal(`Custom domain ${plugin.givenDomainName} was deleted.`); + plugin.initializeVariables(); + + await plugin.deleteDomains(); + expect(consoleOutput[0]).to.equal(`Custom domain ${plugin.domains[0].givenDomainName} was deleted.`); }); it("createDomain if one does not exist before", async () => { AWS.mock("ACM", "listCertificates", certTestData); - AWS.mock("APIGateway", "getDomainName", (params, callback) => { + AWS.mock("ApiGatewayV2", "getDomainName", (params, callback) => { callback({ code: "NotFoundException" }, {}); }); AWS.mock("APIGateway", "createDomainName", (params, callback) => { @@ -859,17 +1138,18 @@ describe("Custom Domain Plugin", () => { plugin.apigateway = new aws.APIGateway(); plugin.route53 = new aws.Route53(); plugin.acm = new aws.ACM(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; + plugin.initializeVariables(); - await plugin.createDomain(); - expect(consoleOutput[0]).to.equal(`Custom domain ${plugin.givenDomainName} was created. - New domains may take up to 40 minutes to be initialized.`); + await plugin.createDomains(); + + expect(consoleOutput[0]).to.equal(`Custom domain ${plugin.domains[0].givenDomainName} was created. + New domains may take up to 40 minutes to be initialized.`); }); it("Does not create domain if one existed before", async () => { AWS.mock("ACM", "listCertificates", certTestData); - AWS.mock("APIGateway", "getDomainName", (params, callback) => { - callback(null, { distributionDomainName: "foo", regionalHostedZoneId: "test_id" }); + AWS.mock("ApiGatewayV2", "getDomainName", (params, callback) => { + callback(null, {DomainName: "test_domain", DomainNameConfigurations: [{HostedZoneId: "test_id"}]}); }); AWS.mock("APIGateway", "createDomainName", (params, callback) => { callback(null, { distributionDomainName: "foo", regionalHostedZoneId: "test_id" }); @@ -885,9 +1165,9 @@ describe("Custom Domain Plugin", () => { plugin.apigateway = new aws.APIGateway(); plugin.route53 = new aws.Route53(); plugin.acm = new aws.ACM(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; - await plugin.createDomain(); - expect(consoleOutput[0]).to.equal(`Custom domain ${plugin.givenDomainName} already exists.`); + plugin.initializeVariables(); + await plugin.createDomains(); + expect(consoleOutput[0]).to.equal(`Custom domain test_domain already exists.`); }); afterEach(() => { @@ -909,11 +1189,10 @@ describe("Custom Domain Plugin", () => { }); }); - const plugin = constructPlugin({}); + const plugin = constructPlugin({domainName: "ccc.bbb.aaa.com"}); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = "ccc.bbb.aaa.com"; - - const result = await plugin.getRoute53HostedZoneId(); + plugin.initializeVariables(); + const result = await plugin.getRoute53HostedZoneId(plugin.domains[0]); expect(result).to.equal("test_id_2"); }); @@ -929,11 +1208,11 @@ describe("Custom Domain Plugin", () => { }); }); - const plugin = constructPlugin({}); + const plugin = constructPlugin({domainName: "test.ccc.bbb.aaa.com"}); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = "test.ccc.bbb.aaa.com"; + plugin.initializeVariables(); - const result = await plugin.getRoute53HostedZoneId(); + const result = await plugin.getRoute53HostedZoneId(plugin.domains[0]); expect(result).to.equal("test_id_1"); }); @@ -949,11 +1228,11 @@ describe("Custom Domain Plugin", () => { }); }); - const plugin = constructPlugin({}); + const plugin = constructPlugin({domainName: "test.ccc.bbb.aaa.com"}); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = "test.ccc.bbb.aaa.com"; + plugin.initializeVariables(); - const result = await plugin.getRoute53HostedZoneId(); + const result = await plugin.getRoute53HostedZoneId(plugin.domains[0]); expect(result).to.equal("test_id_2"); }); @@ -968,11 +1247,11 @@ describe("Custom Domain Plugin", () => { }); }); - const plugin = constructPlugin({}); + const plugin = constructPlugin({domainName: "bar.foo.bbb.fr"}); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = "bar.foo.bbb.fr"; + plugin.initializeVariables(); - const result = await plugin.getRoute53HostedZoneId(); + const result = await plugin.getRoute53HostedZoneId(plugin.domains[0]); expect(result).to.equal("test_id_1"); }); @@ -986,11 +1265,11 @@ describe("Custom Domain Plugin", () => { }); }); - const plugin = constructPlugin({}); + const plugin = constructPlugin({domainName: "test.a.aaa.com"}); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = "test.a.aaa.com"; + plugin.initializeVariables(); - const result = await plugin.getRoute53HostedZoneId(); + const result = await plugin.getRoute53HostedZoneId(plugin.domains[0]); expect(result).to.equal("test_id_0"); }); @@ -1006,11 +1285,11 @@ describe("Custom Domain Plugin", () => { }); }); - const plugin = constructPlugin({}); + const plugin = constructPlugin({domainName: "bar.foo.bbb.fr"}); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = "bar.foo.bbb.fr"; + plugin.initializeVariables(); - const result = await plugin.getRoute53HostedZoneId(); + const result = await plugin.getRoute53HostedZoneId(plugin.domains[0]); expect(result).to.equal("test_id_3"); }); @@ -1026,11 +1305,11 @@ describe("Custom Domain Plugin", () => { }); }); - const plugin = constructPlugin({}); + const plugin = constructPlugin({domainName: "bar.foo.bbb.fr"}); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = "bar.foo.bbb.fr"; + plugin.initializeVariables(); - const result = await plugin.getRoute53HostedZoneId(); + const result = await plugin.getRoute53HostedZoneId(plugin.domains[0]); expect(result).to.equal("test_id_3"); }); @@ -1045,11 +1324,11 @@ describe("Custom Domain Plugin", () => { }); }); - const plugin = constructPlugin({}); + const plugin = constructPlugin({domainName: "bar.foo.bbb.fr"}); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = "bar.foo.bbb.fr"; + plugin.initializeVariables(); - const result = await plugin.getRoute53HostedZoneId(); + const result = await plugin.getRoute53HostedZoneId(plugin.domains[0]); expect(result).to.equal("test_id_3"); }); @@ -1062,12 +1341,11 @@ describe("Custom Domain Plugin", () => { }); }); - const plugin = constructPlugin({}); + const plugin = constructPlugin({domainName: "aaa.com", hostedZonePrivate: true}); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = "aaa.com"; - plugin.hostedZonePrivate = true; + plugin.initializeVariables(); - const result = await plugin.getRoute53HostedZoneId(); + const result = await plugin.getRoute53HostedZoneId(plugin.domains[0]); expect(result).to.equal("test_id_0"); }); @@ -1080,11 +1358,11 @@ describe("Custom Domain Plugin", () => { }); }); - const plugin = constructPlugin({}); + const plugin = constructPlugin({domainName: "aaa.com"}); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = "aaa.com"; + plugin.initializeVariables(); - const result = await plugin.getRoute53HostedZoneId(); + const result = await plugin.getRoute53HostedZoneId(plugin.domains[0]); expect(result).to.equal("test_id_0"); }); @@ -1104,8 +1382,9 @@ describe("Custom Domain Plugin", () => { }; const plugin = constructPlugin(options); plugin.acm = new aws.ACM(); + plugin.initializeVariables(); - return plugin.getCertArn().then(() => { + return plugin.getCertArn(plugin.domains[0]).then(() => { throw new Error("Test has failed. getCertArn did not catch errors."); }).catch((err) => { const expectedErrorMessage = "Error: Could not find the certificate does_not_exist."; @@ -1120,9 +1399,9 @@ describe("Custom Domain Plugin", () => { const plugin = constructPlugin({ domainName: "test_domain"}); plugin.route53 = new aws.Route53(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; + plugin.initializeVariables(); - return plugin.getRoute53HostedZoneId().then(() => { + return plugin.getRoute53HostedZoneId(plugin.domains[0]).then(() => { throw new Error("Test has failed, getHostedZone did not catch errors."); }).catch((err) => { const expectedErrorMessage = "Error: Could not find hosted zone \"test_domain\""; @@ -1136,9 +1415,9 @@ describe("Custom Domain Plugin", () => { }); const plugin = constructPlugin({ domainName: "test_domain"}); plugin.apigateway = new aws.APIGateway(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; + plugin.initializeVariables(); - return plugin.domainSummary().then(() => { + return plugin.domainSummaries().then(() => { // check if distribution domain name is printed }).catch((err) => { const expectedErrorMessage = `Error: Unable to fetch information about test_domain`; @@ -1148,17 +1427,17 @@ describe("Custom Domain Plugin", () => { it("Should log if SLS_DEBUG is set", async () => { const plugin = constructPlugin({ domainName: "test_domain" }); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; + plugin.initializeVariables(); // set sls debug to true process.env.SLS_DEBUG = "True"; plugin.logIfDebug("test message"); - expect(consoleOutput).to.contain("test message"); + expect(consoleOutput[0]).to.contain("test message"); }); it("Should not log if SLS_DEBUG is not set", async () => { const plugin = constructPlugin({ domainName: "test_domain" }); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; + plugin.initializeVariables(); plugin.logIfDebug("test message"); expect(consoleOutput).to.not.contain("test message"); @@ -1173,19 +1452,18 @@ describe("Custom Domain Plugin", () => { describe("Summary Printing", () => { it("Prints Summary", async () => { - AWS.mock("APIGateway", "getDomainName", (params, callback) => { + AWS.mock("ApiGatewayV2", "getDomainName", (params, callback) => { callback(null, { domainName: params, distributionDomainName: "test_distributed_domain_name" }); }); const plugin = constructPlugin({domainName: "test_domain"}); - plugin.apigateway = new aws.APIGateway(); - plugin.givenDomainName = plugin.serverless.service.custom.customDomain.domainName; + plugin.apigatewayV2 = new aws.ApiGatewayV2(); + plugin.initializeVariables(); - await plugin.domainSummary(); + await plugin.domainSummaries(); expect(consoleOutput[0]).to.contain("Serverless Domain Manager Summary"); - expect(consoleOutput[1]).to.contain("Domain Name"); + expect(consoleOutput[1]).to.contain("Distribution Domain Name"); expect(consoleOutput[2]).to.contain("test_domain"); - expect(consoleOutput[3]).to.contain("Distribution Domain Name"); - expect(consoleOutput[4]).to.contain("test_distributed_domain_name"); + expect(consoleOutput[3]).to.contain("test_distributed_domain_name"); }); afterEach(() => { @@ -1203,7 +1481,10 @@ describe("Custom Domain Plugin", () => { const returnedCreds = plugin.apigateway.config.credentials; expect(returnedCreds.accessKeyId).to.equal(testCreds.accessKeyId); expect(returnedCreds.sessionToken).to.equal(testCreds.sessionToken); - expect(plugin.enabled).to.equal(true); + expect(plugin.domains).length.to.be.greaterThan(0); + for (const domain of plugin.domains) { + expect(domain.enabled).to.equal(true); + } }); it("Should enable the plugin when passing a true parameter with type boolean", () => { @@ -1214,7 +1495,10 @@ describe("Custom Domain Plugin", () => { const returnedCreds = plugin.apigateway.config.credentials; expect(returnedCreds.accessKeyId).to.equal(testCreds.accessKeyId); expect(returnedCreds.sessionToken).to.equal(testCreds.sessionToken); - expect(plugin.enabled).to.equal(true); + expect(plugin.domains).length.to.be.greaterThan(0); + for (const domain of plugin.domains) { + expect(domain.enabled).to.equal(true); + } }); it("Should enable the plugin when passing a true parameter with type string", () => { @@ -1225,7 +1509,10 @@ describe("Custom Domain Plugin", () => { const returnedCreds = plugin.apigateway.config.credentials; expect(returnedCreds.accessKeyId).to.equal(testCreds.accessKeyId); expect(returnedCreds.sessionToken).to.equal(testCreds.sessionToken); - expect(plugin.enabled).to.equal(true); + expect(plugin.domains).length.to.be.greaterThan(0); + for (const domain of plugin.domains) { + expect(domain.enabled).to.equal(true); + } }); it("Should disable the plugin when passing a false parameter with type boolean", () => { @@ -1233,7 +1520,7 @@ describe("Custom Domain Plugin", () => { plugin.initializeVariables(); - expect(plugin.enabled).to.equal(false); + expect(plugin.domains.length).to.equal(0); }); it("Should disable the plugin when passing a false parameter with type string", () => { @@ -1241,56 +1528,50 @@ describe("Custom Domain Plugin", () => { plugin.initializeVariables(); - expect(plugin.enabled).to.equal(false); + expect(plugin.domains.length).to.equal(0); }); it("createDomain should do nothing when domain manager is disabled", async () => { const plugin = constructPlugin({ enabled: false }); - const result = await plugin.hookWrapper(plugin.createDomain); + await plugin.hookWrapper(plugin.createDomains); - expect(plugin.enabled).to.equal(false); - expect(result).to.equal(undefined); + expect(plugin.domains.length).to.equal(0); }); it("deleteDomain should do nothing when domain manager is disabled", async () => { const plugin = constructPlugin({ enabled: false }); - const result = await plugin.hookWrapper(plugin.deleteDomain); + await plugin.hookWrapper(plugin.deleteDomains); - expect(plugin.enabled).to.equal(false); - expect(result).to.equal(undefined); + expect(plugin.domains.length).to.equal(0); }); it("setUpBasePathMapping should do nothing when domain manager is disabled", async () => { const plugin = constructPlugin({ enabled: false }); - const result = await plugin.hookWrapper(plugin.setupBasePathMapping); + await plugin.hookWrapper(plugin.setupBasePathMappings); - expect(plugin.enabled).to.equal(false); - expect(result).to.equal(undefined); + expect(plugin.domains.length).to.equal(0); }); it("removeBasePathMapping should do nothing when domain manager is disabled", async () => { const plugin = constructPlugin({ enabled: false }); - const result = await plugin.hookWrapper(plugin.removeBasePathMapping); + await plugin.hookWrapper(plugin.removeBasePathMappings); - expect(plugin.enabled).to.equal(false); - expect(result).to.equal(undefined); + expect(plugin.domains.length).to.equal(0); }); it("domainSummary should do nothing when domain manager is disabled", async () => { const plugin = constructPlugin({ enabled: false }); - const result = await plugin.hookWrapper(plugin.domainSummary); + await plugin.hookWrapper(plugin.domainSummaries); - expect(plugin.enabled).to.equal(false); - expect(result).to.equal(undefined); + expect(plugin.domains.length).to.equal(0); }); it("Should throw an Error when passing a parameter that is not boolean", () => { - const stringWithValueYes = "yes"; const plugin = constructPlugin({ enabled: 0 }); let errored = false; @@ -1354,4 +1635,202 @@ describe("Custom Domain Plugin", () => { consoleOutput = []; }); }); + + describe("AWS paged results", () => { + it("Should combine paged results into a list", async () => { + let callCount = 0; + const responses = [{ + Items: ["a", "b"], + NextToken: "1", + }, + { + Items: ["c", "d"], + NextToken: "2", + }, + { + Items: ["e"], + }, + { + Items: ["f"], // this call should never happen since its after the last request that included a token + }]; + AWS.mock("ApiGatewayV2", "getApiMappings", (params, callback) => { + callback(null, responses[callCount++]); + }); + + const plugin = constructPlugin({}); + const results = await getAWSPagedResults( + new aws.ApiGatewayV2(), + "getApiMappings", + "Items", + "NextToken", + "NextToken", + { DomainName: "example.com"}, + ); + expect(results).to.deep.equal([ "a", "b", "c", "d", "e" ]); + AWS.restore(); + }); + }); + + describe("autoDomain deploy", () => { + it("Should be disabled by default", () => { + const plugin = constructPlugin({ domainName: "test_domain" }); + plugin.initializeVariables(); + expect(plugin.serverless.service.custom.customDomain.autoDomain).to.equal(undefined); + }); + + it("createOrGetDomainForCfOutputs should call createDomain when autoDomain is true", async () => { + AWS.mock("ApiGatewayV2", "getDomainName", (params, callback) => { + callback(null, params); + }); + const plugin = constructPlugin({ + autoDomain: true, + basePath: "test_basepath", + createRoute53Record: false, + domainName: "test_domain", + restApiId: "test_rest_api_id", + }); + plugin.initializeVariables(); + + plugin.apigateway = new aws.APIGateway(); + plugin.apigatewayV2 = new aws.ApiGatewayV2(); + + plugin.domains[0].apiMapping = {ApiMappingId: "test_mapping_id"}; + + const spy = chai.spy.on(plugin.apigatewayV2, "getDomainName"); + + await plugin.createOrGetDomainForCfOutputs(); + + expect(plugin.serverless.service.custom.customDomain.autoDomain).to.equal(true); + expect(spy).to.have.been.called(); + }); + + it("createOrGetDomainForCfOutputs should not call createDomain when autoDomain is not true", async () => { + AWS.mock("ApiGatewayV2", "getDomainName", (params, callback) => { + callback(null, params); + }); + + const plugin = constructPlugin({ + autoDomain: false, + basePath: "test_basepath", + createRoute53Record: false, + domainName: "test_domain", + restApiId: "test_rest_api_id", + }); + plugin.initializeVariables(); + + plugin.apigateway = new aws.APIGateway(); + plugin.apigatewayV2 = new aws.ApiGatewayV2(); + + plugin.domains[0].apiMapping = {ApiMappingId: "test_mapping_id"}; + + const spy1 = chai.spy.on(plugin.apigateway, "createDomainName"); + const spy2 = chai.spy.on(plugin.apigatewayV2, "createDomainName"); + + await plugin.createOrGetDomainForCfOutputs(); + + expect(plugin.serverless.service.custom.customDomain.autoDomain).to.equal(false); + expect(spy1).to.have.not.been.called(); + expect(spy2).to.have.not.been.called(); + }); + + it("removeBasePathMapping should call deleteDomain when autoDomain is true", async () => { + AWS.mock("CloudFormation", "describeStackResource", (params, callback) => { + callback(null, { + StackResourceDetail: + { + LogicalResourceId: "ApiGatewayRestApi", + PhysicalResourceId: "test_rest_api_id", + }, + }); + }); + AWS.mock("ApiGatewayV2", "getApiMappings", (params, callback) => { + callback(null, { + Items: [ + { ApiId: "test_rest_api_id", MappingKey: "test", ApiMappingId: "test_mapping_id", Stage: "test" }, + ], + }); + }); + AWS.mock("ApiGatewayV2", "deleteApiMapping", (params, callback) => { + callback(null, params); + }); + AWS.mock("ApiGatewayV2", "deleteDomainName", (params, callback) => { + callback(null, params); + }); + AWS.mock("ApiGatewayV2", "getDomainName", (params, callback) => { + callback(null, params); + }); + + const plugin = constructPlugin({ + autoDomain: true, + basePath: "test_basepath", + createRoute53Record: false, + domainName: "test_domain", + restApiId: "test_rest_api_id", + }); + plugin.initializeVariables(); + + plugin.apigatewayV2 = new aws.ApiGatewayV2(); + + plugin.domains[0].apiMapping = {ApiMappingId: "test_mapping_id"}; + + const spy = chai.spy.on(plugin.apigatewayV2, "deleteDomainName"); + + await plugin.removeBasePathMappings(); + + expect(plugin.serverless.service.custom.customDomain.autoDomain).to.equal(true); + expect(spy).to.have.been.called.with({DomainName: "test_domain"}); + }); + + it("removeBasePathMapping should not call deleteDomain when autoDomain is not true", async () => { + AWS.mock("CloudFormation", "describeStackResource", (params, callback) => { + callback(null, { + StackResourceDetail: + { + LogicalResourceId: "ApiGatewayRestApi", + PhysicalResourceId: "test_rest_api_id", + }, + }); + }); + AWS.mock("ApiGatewayV2", "getApiMappings", (params, callback) => { + callback(null, { + Items: [ + { ApiId: "test_rest_api_id", MappingKey: "test", ApiMappingId: "test_mapping_id", Stage: "test" }, + ], + }); + }); + AWS.mock("ApiGatewayV2", "deleteApiMapping", (params, callback) => { + callback(null, params); + }); + AWS.mock("ApiGatewayV2", "deleteDomainName", (params, callback) => { + callback(null, params); + }); + AWS.mock("ApiGatewayV2", "getDomainName", (params, callback) => { + callback(null, params); + }); + + const plugin = constructPlugin({ + autoDomain: false, + basePath: "test_basepath", + createRoute53Record: false, + domainName: "test_domain", + restApiId: "test_rest_api_id", + }); + plugin.initializeVariables(); + + plugin.apigatewayV2 = new aws.ApiGatewayV2(); + + plugin.domains[0].apiMapping = {ApiMappingId: "test_mapping_id"}; + + const spy = chai.spy.on(plugin.apigatewayV2, "deleteDomainName"); + + await plugin.removeBasePathMappings(); + + expect(plugin.serverless.service.custom.customDomain.autoDomain).to.equal(false); + expect(spy).to.have.not.been.called(); + }); + + afterEach(() => { + consoleOutput = []; + }); + }); }); diff --git a/test/unit-tests/tslint.json b/test/unit-tests/tslint.json deleted file mode 100644 index f7bb7a71..00000000 --- a/test/unit-tests/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "tslint:recommended" -} diff --git a/tsconfig.json b/tsconfig.json index babfb254..10e94eea 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,16 +2,13 @@ "compilerOptions": { "module": "commonjs", "moduleResolution": "node", - "rootDir": ".", + "rootDir": "src", "target": "es6", "sourceMap": false, "outDir": "dist", "types": ["node"] }, "include": [ - "*.ts" - ], - "exclude": [ - "node_modules" + "src/**/*.ts" ] } diff --git a/tsconfig.tests.json b/tsconfig.tests.json new file mode 100644 index 00000000..f80adfec --- /dev/null +++ b/tsconfig.tests.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "rootDir": ".", + "target": "es6", + "sourceMap": false, + "outDir": "dist", + "types": ["mocha", "node"] + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ] +} diff --git a/tslint.json b/tslint.json index 78af2344..534cb941 100644 --- a/tslint.json +++ b/tslint.json @@ -1,3 +1,6 @@ { - "extends": "tslint:recommended" + "extends": "tslint:recommended", + "rules": { + "no-console": false + } }