diff --git a/CHANGELOG.md b/CHANGELOG.md index 201f2f34a..38487e1f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +# 1.32.0 (17.09.2018) +- [Update quick-start.md](https://github.com/serverless/serverless/pull/5290) +- [Backend state item generation and multi-region support](https://github.com/serverless/serverless/pull/5265) + +## Meta +- [Comparison since last release](https://github.com/serverless/serverless/compare/v1.31.0...v1.32.0) + + +# 1.31.0 (11.09.2018) +- [Add support for Cloudflare Workers](https://github.com/serverless/serverless/pull/5258) +- [docs: Fix mismatch in AWS Metrics](https://github.com/serverless/serverless/pull/5276) +- [Add new template for AWS Alexa Typescript](https://github.com/serverless/serverless/pull/5266) +- [Remove `/tmp/node-dependencies*`](https://github.com/serverless/serverless/pull/5079) +- [Adds FilterPolicy to SNS event](https://github.com/serverless/serverless/pull/5229) +- [Update API Gateway Default Request Templates](https://github.com/serverless/serverless/pull/5222) +- [Update serverless.yml.md](https://github.com/serverless/serverless/pull/5236) +- [Fix for #3069 - Failing to handle schedule event body params](https://github.com/serverless/serverless/pull/5268) +- [Remove redundant link to same docs page](https://github.com/serverless/serverless/pull/5243) + +## Meta +- [Comparison since last release](https://github.com/serverless/serverless/compare/v1.30.3...v1.31.0) + + # 1.30.3 (28.08.2018) - [Fix CORS race condition](https://github.com/serverless/serverless/pull/5256) @@ -22,6 +45,7 @@ ## Meta - [Comparison since last release](https://github.com/serverless/serverless/compare/v1.30.0...v1.30.1) + # 1.30.0 (09.08.2018) - [Added support for multiple access keys for multiple tenants](https://github.com/serverless/serverless/pull/5189) - [Fixed a publishing bug when having more than 100 resources](https://github.com/serverless/serverless/pull/5189) @@ -37,6 +61,7 @@ ## Meta - [Comparison since last release](https://github.com/serverless/serverless/compare/v1.29.2...v1.30.0) + # 1.29.2 (29.07.2018) - [Fixed a bug when using APIG lambda integration with Serverless Dashboard](https://github.com/serverless/serverless/pull/5174) - [Fixed a bug by transforming env var to string when setting num value](https://github.com/serverless/serverless/pull/5166) @@ -44,12 +69,14 @@ ## Meta - [Comparison since last release](https://github.com/serverless/serverless/compare/v1.29.1...v1.29.2) + # 1.29.1 (28.07.2018) - [Fixed a bug when using APIG root path with Serverless Dashboard](https://github.com/serverless/serverless/pull/5170) ## Meta - [Comparison since last release](https://github.com/serverless/serverless/compare/v1.29.0...v1.29.1) + # 1.29.0 (26.07.2018) - [Fixes issue with Node 10.7.0](https://github.com/serverless/serverless/issues/5133) - [Serverless Dashboard Updates: Subscriptions, Resources, Deploys and Refresh Tokens](https://github.com/serverless/serverless/pull/5127) @@ -59,6 +86,7 @@ ## Meta - [Comparison since last release](https://github.com/serverless/serverless/compare/v1.28.0...v1.29.0) + # 1.28.0 (04.07.2018) - [Add SQS event integration](https://github.com/serverless/serverless/pull/5074) - [Integration with the Serverless Dashboard](https://github.com/serverless/serverless/pull/5043) @@ -76,6 +104,7 @@ ## Meta - [Comparison since last release](https://github.com/serverless/serverless/compare/v1.27.0...v1.28.0) + # 1.27.0 (02.05.2018) - [Add maxAge option for CORS](https://github.com/serverless/serverless/pull/4639) - [Add fn integration](https://github.com/serverless/serverless/pull/4934) @@ -103,6 +132,7 @@ ## Meta - [Comparison since last release](https://github.com/serverless/serverless/compare/v1.26.0...v1.26.1) + # 1.26.0 (29.01.2018) - [AWS Go support](https://github.com/serverless/serverless/pull/4669) - [Support for using an existing ApiGateway and Resources](https://github.com/serverless/serverless/pull/4247) @@ -190,7 +220,6 @@ - [Fixed a bug with Kinesis events](https://github.com/serverless/serverless/pull/4084) - [Fixed a bug with packaging](https://github.com/serverless/serverless/pull/4189) - ## Meta - [Comparison since last release](https://github.com/serverless/serverless/compare/v1.21.1...v1.22.0) diff --git a/README.md b/README.md index 6b9dd40cd..5f12833f8 100644 --- a/README.md +++ b/README.md @@ -337,7 +337,9 @@ This table is generated from https://github.com/serverless/plugins/blob/master/p This table is generated from https://github.com/serverless/examples/blob/master/community-examples.json please make additions there --> | Project Name | Author | -| :----------- | :----: | +|:-------------|:------:| +| **[Serverless Pipeline](https://github.com/msfidelis/serverless-pipeline)**
Simple CI/CD Pipeline to Serverless Projects on AWS using Codepipeline, Codebuild and Terraform | [msfidelis](http://github.com/msfidelis) | +| **[Jwtauthorizr](https://github.com/serverlessbuch/jwtAuthorizr)**
Custom JWT Authorizer Lambda function for Amazon API Gateway with Bearer JWT | [serverlessbuch](http://github.com/serverlessbuch) | | **[AWS Demo Java Spring Cloud Function Serverless](https://github.com/mbsambangi/aws-java-spring-cloud-function-demo)**
If Java is your choice of programming language-Spring Cloud Function,Serverless Framework makes a great technology stack. It boosts developer productivity by decoupling from Vendor specific FaaS API, and deployment activities. | [mbsambangi](http://github.com/mbsambangi) | | **[Serverless Architecture Boilerplate](https://github.com/msfidelis/serverless-architecture-boilerplate)**
Boilerplate to organize and deploy big projects using Serverless and CloudFormation on AWS | [msfidelis](http://github.com/msfidelis) | | **[Bablebot](https://github.com/abiglobalhealth/babelbot)**
Lambda + API Gateway: Zero-to-chatbot in <10 lines of JS. Built-in integrations for Messenger, Telegram, Kik, Line, Twilio, Skype, and Wechat. Or roll your own! | [abiglobalhealth](http://github.com/abiglobalhealth) | @@ -403,6 +405,7 @@ This table is generated from https://github.com/serverless/examples/blob/master/ | **[AWS Cognito Custom User Pool Example](https://github.com/bsdkurt/aws-node-custom-user-pool)**
Example CloudFormation custom resource backed by a lambda using Cognito User Pools | [bsdkurt](http://github.com/bsdkurt) | | **[Serverless Lambda Protobuf Responses](https://github.com/theburningmonk/lambda-protobuf-demo)**
Demo using API Gateway and Lambda with Protocol Buffer | [theburningmonk](http://github.com/theburningmonk) | | **[Serverless Telegram Bot](https://github.com/jonatasbaldin/serverless-telegram-bot)**
This example demonstrates how to setup an echo Telegram Bot using the Serverless Framework ⚡🤖 | [jonatasbaldin](http://github.com/jonatasbaldin) | +| **[Serverless Line Bot](https://github.com/jiyeonseo/azure-line-bot-example)**
Echo Line bot using Azure Function with Node.js | [jiyeonseo](http://github.com/jiyeonseo) | | **[Serverless Dashboard For Atom Editor](https://github.com/horike37/serverless-dashboard-for-atom)**
Atom editor package which allows you to deploy and visualize your serverless services with Serverless Framework on your editor. | [horike37](http://github.com/horike37) | | **[Serverless Lambda Vpc Nat Redis](https://github.com/ittus/aws-lambda-vpc-nat-examples)**
Demo using API Gateway and Lambda with VPC and NAT to access Internet and AWS Resource | [ittus](http://github.com/ittus) | | **[Serverless Gitlab CI](https://github.com/bvincent1/serverless-gitlab-ci)**
Simple Gitlab CI template for automatic testing and deployments | [bvincent1](http://github.com/bvincent1) | diff --git a/RELEASE_CHECKLIST.md b/RELEASE_CHECKLIST.md index d3f0c9dcf..18fbdab2d 100644 --- a/RELEASE_CHECKLIST.md +++ b/RELEASE_CHECKLIST.md @@ -8,7 +8,7 @@ More info about our release process can be found in the [`RELEASE_PROCESS.md`](. - [ ] Look through all open issues and PRs (if any) of that milestone and close them / move them to another milestone if still open -- [ ] Look through all closed issues and PRs of that milestone to see what has changed. Run `./scripts/prs-since-last tag` or if you want to run against a specific tag `./scripts/prs-since-last tag v1.20.0` to get a list of all merged PR's since a specific tag +- [ ] Look through all closed issues and PRs of that milestone to see what has changed. Run `./scripts/prs-since-last-tag` or if you want to run against a specific tag `./scripts/prs-since-last-tag v1.20.0` to get a list of all merged PR's since a specific tag - [ ] Close milestone on GitHub - [ ] Create a new draft release in GitHub diff --git a/bin/serverless b/bin/serverless index 399da0dc3..baefb710a 100755 --- a/bin/serverless +++ b/bin/serverless @@ -40,23 +40,26 @@ const invocationId = uuid.v4(); serverless.invocationId = invocationId; - return serverless.init().then(() => serverless.run()).catch((e) => { - if (serverless.service.deployment && serverless.service.deployment.deploymentId) { - const deploymentData = { - tenant: serverless.service.deployment.tenant, - app: serverless.service.deployment.app, - serviceName: serverless.service.deployment.serviceName, - deploymentId: serverless.service.deployment.deploymentId, - accessKey: serverless.service.deployment.accessKey, - }; - deploymentData.status = 'Failed'; - return platform.updateDeployment(deploymentData) - .then(() => { - throw e; - }); - } - throw e; - }); + return serverless.init() + .then(() => serverless.run()) + .then(() => process.exit(0)) + .catch((e) => { + if (serverless.service.deployment && serverless.service.deployment.deploymentId) { + const deploymentData = { + tenant: serverless.service.deployment.tenant, + app: serverless.service.deployment.app, + serviceName: serverless.service.deployment.serviceName, + deploymentId: serverless.service.deployment.deploymentId, + accessKey: serverless.service.deployment.accessKey, + }; + deploymentData.status = 'Failed'; + return platform.updateDeployment(deploymentData) + .then(() => { + throw e; + }); + } + throw e; + }); }).catch(e => { process.exitCode = 1; logError(e); diff --git a/docker-compose.yml b/docker-compose.yml index 918dbb126..373d2631a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -22,7 +22,7 @@ services: aws-clojurescript-gradle: image: pgoudreau/docker-maven-node volumes: - - ./tmp/serverless-integration-test-aws-clojurescript-gradle:/app + - ./tmp/serverless-integration-test-aws-clojurescript-gradle:/app aws-nodejs: image: node:5.11.1 volumes: @@ -81,10 +81,19 @@ services: volumes: - ./tmp/serverless-integration-test-aws-go-dep:/app - ./tmp/serverless-integration-test-aws-go-dep:/go/src/app + aws-go-mod: + image: golang:1.11 + volumes: + - ./tmp/serverless-integration-test-aws-go-mod:/app + - ./tmp/serverless-integration-test-aws-go-mod:/go/src/app aws-nodejs-typescript: image: node:6.10.3 volumes: - ./tmp/serverless-integration-test-aws-nodejs-typescript:/app + aws-alexa-typescript: + image: node:6.10.3 + volumes: + - ./tmp/serverless-integration-test-aws-alexa-typescript:/app aws-nodejs-ecma-script: image: node:6.10.3 volumes: @@ -109,7 +118,3 @@ services: image: maven:3-jdk-8 volumes: - ./tmp/serverless-integration-test-spotinst-java8:/app - webtasks-nodejs: - image: node:6.10.3 - volumes: - - ./tmp/serverless-integration-test-webtasks-nodejs:/app diff --git a/docs/README.md b/docs/README.md index 3189bfba5..9df779283 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,7 +12,7 @@ menuItems: - {menuText: "- OpenWhisk", path: /framework/docs/providers/openwhisk/} - {menuText: "- Kubeless" , path: /framework/docs/providers/kubeless/} - {menuText: "- Spotinst" , path: /framework/docs/providers/spotinst/} - - {menuText: "- Webtasks" , path: /framework/docs/providers/webtasks/} + - {menuText: "- Cloudflare" , path: /framework/docs/providers/cloudflare/} --> @@ -40,7 +40,7 @@ Already using AWS or another cloud provider? Read on.
-
-
- - - -
-
- -
-
@@ -157,4 +142,19 @@ Already using AWS or another cloud provider? Read on.
+
+
+ + + +
+
+ +
+
diff --git a/docs/getting-started.md b/docs/getting-started.md index 2cd79a29e..a51225de9 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -11,7 +11,6 @@ menuItems: - {menuText: Google Functions Guide, path: /framework/docs/providers/google/guide/quick-start} - {menuText: Kubeless Guide, path: /framework/docs/providers/kubeless/guide/quick-start} - {menuText: Spotinst Guide, path: /framework/docs/providers/spotinst/guide/quick-start} - - {menuText: Webtasks Guide, path: /framework/docs/providers/webtasks/guide/quick-start} --> # Getting Started with Serverless @@ -92,16 +91,6 @@ Next up, it's time to choose where you'd like your serverless service to run. Spotinst
Quick Start Guide
-
-
- - - -
-
- Webtasks
Quick Start Guide
-
-
@@ -112,4 +101,14 @@ Next up, it's time to choose where you'd like your serverless service to run. Fn
Quick Start Guide
+
+
+ + + +
+
+ Cloudflare Workers
Quick Start Guide
+
+
diff --git a/docs/providers/README.md b/docs/providers/README.md index 9ea9f6efb..24c8d07a7 100644 --- a/docs/providers/README.md +++ b/docs/providers/README.md @@ -73,16 +73,6 @@ Under the hood, the serverless framework is deploying your code to a cloud provi Spotinst Docs -
-
- - - -
-
- Auth0 Webtasks Docs -
-
diff --git a/docs/providers/aws/cli-reference/create.md b/docs/providers/aws/cli-reference/create.md index 0ba45886a..391c1b9b1 100644 --- a/docs/providers/aws/cli-reference/create.md +++ b/docs/providers/aws/cli-reference/create.md @@ -52,6 +52,7 @@ Most commonly used templates: - aws-clojure-gradle - aws-nodejs - aws-nodejs-typescript +- aws-alexa-typescript - aws-nodejs-ecma-script - aws-python - aws-python3 @@ -64,6 +65,9 @@ Most commonly used templates: - aws-scala-sbt - aws-csharp - aws-fsharp +- aws-go +- aws-go-dep +- aws-go-mod - plugin ## Examples diff --git a/docs/providers/aws/cli-reference/deploy-function.md b/docs/providers/aws/cli-reference/deploy-function.md index 1b4486288..8b06da246 100644 --- a/docs/providers/aws/cli-reference/deploy-function.md +++ b/docs/providers/aws/cli-reference/deploy-function.md @@ -27,7 +27,7 @@ cycles and not production deployments - `--function` or `-f` The name of the function which should be deployed - `--stage` or `-s` The stage in your service that you want to deploy to. - `--region` or `-r` The region in that stage that you want to deploy to. -- `--update-config` or `-u` Pushes ONLY Lambda-level configuration changes e.g. timeout or memorySize +- `--update-config` or `-u` Pushes ONLY Lambda-level configuration changes e.g. handler, timeout or memorySize ## Examples diff --git a/docs/providers/aws/cli-reference/invoke-local.md b/docs/providers/aws/cli-reference/invoke-local.md index 20a618a98..0df47645b 100644 --- a/docs/providers/aws/cli-reference/invoke-local.md +++ b/docs/providers/aws/cli-reference/invoke-local.md @@ -28,6 +28,7 @@ serverless invoke local --function functionName - `--raw` Pass data as a raw string even if it is JSON. If not set, JSON data are parsed and passed as an object. - `--contextPath` or `-x`, The path to a json file holding input context to be passed to the invoked function. This path is relative to the root directory of the service. - `--context` or `-c`, String data to be passed as a context to your function. Same like with `--data`, context included in `--contextPath` will overwrite the context you passed with `--context` flag. +* `--env` or `-e` String representing an environment variable to set when invoking your function, in the form `=`. Can be repeated for more than one environment variable. ## Environment @@ -94,6 +95,16 @@ serverless invoke local --function functionName --contextPath lib/context.json ``` This example will pass the json context in the `lib/context.json` file (relative to the root of the service) while invoking the specified/deployed function. +### Local function invocation, setting environment variables + +```bash +serverless invoke local -f functionName -e VAR1=value1 + +# Or more than one variable + +serverless invoke local -f functionName -e VAR1=value1 -e VAR2=value2 +``` + ### Limitations Currently, `invoke local` only supports the NodeJs, Python & Java runtimes. diff --git a/docs/providers/aws/cli-reference/metrics.md b/docs/providers/aws/cli-reference/metrics.md index 6b048ec28..d4b57f2ea 100644 --- a/docs/providers/aws/cli-reference/metrics.md +++ b/docs/providers/aws/cli-reference/metrics.md @@ -23,7 +23,7 @@ serverless metrics - `--function` or `-f` The function you want to fetch the metrics for. - `--stage` or `-s` The stage you want to view the function metrics for. If not provided, the plugin will use the default stage listed in `serverless.yml`. If that doesn't exist either it'll just fetch the metrics from the `dev` stage. - `--region` or `-r` The region you want to view the function metrics for. If not provided, the plugin will use the default region listed in `serverless.yml`. If that doesn't exist either it'll just fetch the metrics from the `us-east-1` region. -- `--startTime` A specific unit in time to start fetching metrics from (ie: `2010-10-20`, `1469705761`, `30m` (30 minutes ago), `2h` (2 days ago) or `3d` (3 days ago)). Date formats should be written in ISO 8601. Defaults to 24h ago. +- `--startTime` A specific unit in time to start fetching metrics from (ie: `2010-10-20`, `1469705761`, `30m` (30 minutes ago), `2h` (2 hours ago) or `3d` (3 days ago)). Date formats should be written in ISO 8601. Defaults to 24h ago. - `--endTime` A specific unit in time to end fetching metrics from (ie: `2010-10-21` or `1469705761`). Date formats should be written in ISO 8601. Defaults to now. ## Examples diff --git a/docs/providers/aws/events/apigateway.md b/docs/providers/aws/events/apigateway.md index edf5fdbd0..5ab14febf 100644 --- a/docs/providers/aws/events/apigateway.md +++ b/docs/providers/aws/events/apigateway.md @@ -246,6 +246,31 @@ functions: maxAge: 86400 ``` +If you are using CloudFront or another CDN for your API Gateway, you may want to setup a `Cache-Control` header to allow for OPTIONS request to be cached to avoid the additional hop. + +To enable the `Cache-Control` header on preflight response, set the `cacheControl` property in the `cors` object: + +```yml +functions: + hello: + handler: handler.hello + events: + - http: + path: hello + method: get + cors: + origin: '*' + headers: + - Content-Type + - X-Amz-Date + - Authorization + - X-Api-Key + - X-Amz-Security-Token + - X-Amz-User-Agent + allowCredentials: false + cacheControl: 'max-age=600, s-maxage=600, proxy-revalidate' # Caches on browser and proxy for 10 minutes and doesnt allow proxy to serve out of date content +``` + If you want to use CORS with the lambda-proxy integration, remember to include the `Access-Control-Allow-*` headers in your headers object, like this: ```javascript @@ -602,7 +627,7 @@ Both templates give you access to the following properties you can access with t - principalId - stage - headers -- query +- queryStringParameters - path - identity - stageVariables diff --git a/docs/providers/aws/events/cognito-user-pool.md b/docs/providers/aws/events/cognito-user-pool.md index 981a38283..b7dadd597 100644 --- a/docs/providers/aws/events/cognito-user-pool.md +++ b/docs/providers/aws/events/cognito-user-pool.md @@ -109,7 +109,7 @@ functions: resources: Resources: - CognitoUserPoolMyUserPool: + MyUserPool: Type: AWS::Cognito::UserPool ``` diff --git a/docs/providers/aws/events/sns.md b/docs/providers/aws/events/sns.md index 2dd1b2d09..ccaf019cc 100644 --- a/docs/providers/aws/events/sns.md +++ b/docs/providers/aws/events/sns.md @@ -95,3 +95,20 @@ functions: topicName: aggregate displayName: Data aggregation pipeline ``` + +## Setting a filter policy + +This event definition creates an SNS topic which subscription uses a filter policy. The filter policy filters out messages that don't have attribute key `pet` with value `dog` or `cat`. + +```yml +functions: + pets: + handler: pets.handler + events: + - sns: + topicName: pets + filterPolicy: + pet: + - dog + - cat +``` diff --git a/docs/providers/aws/events/sqs.md b/docs/providers/aws/events/sqs.md index e66ab7498..f264d39c5 100644 --- a/docs/providers/aws/events/sqs.md +++ b/docs/providers/aws/events/sqs.md @@ -18,6 +18,8 @@ The ARN for the queue can be specified as a string, the reference to the ARN of **Note:** The `sqs` event will hook up your existing SQS Queue to a Lambda function. Serverless won't create a new queue for you. +**IMPORTANT:** AWS is [not supporting FIFO queue](https://docs.aws.amazon.com/lambda/latest/dg/with-sqs.html) to trigger Lambda function so your queue(s) **must be** a standard queue. + ```yml functions: compute: diff --git a/docs/providers/aws/examples/hello-world/csharp/README.md b/docs/providers/aws/examples/hello-world/csharp/README.md index f0a617e5e..499d24224 100644 --- a/docs/providers/aws/examples/hello-world/csharp/README.md +++ b/docs/providers/aws/examples/hello-world/csharp/README.md @@ -15,7 +15,7 @@ Make sure `serverless` is installed. [See installation guide](../../../guide/ins Once installed the Serverless CLI can be called with `serverless` or the shorthand `sls` command. -If `sls` command retuns an error in PowerShell, please user `serverless` command. +If `sls` command retuns an error in PowerShell, please use `serverless` command. ``` $ sls diff --git a/docs/providers/aws/guide/deploying.md b/docs/providers/aws/guide/deploying.md index fa05211eb..53b94e23c 100644 --- a/docs/providers/aws/guide/deploying.md +++ b/docs/providers/aws/guide/deploying.md @@ -68,6 +68,9 @@ The Serverless Framework translates all syntax in `serverless.yml` to a single A * You can specify your own S3 bucket which should be used to store all the deployment artifacts. The `deploymentBucket` config which is nested under `provider` lets you e.g. set the `name` or the `serverSideEncryption` method for this bucket +* You can specify your own S3 prefix which should be used to store all the deployment artifacts. + The `deploymentPrefix` config which is nested under `provider` lets you set the prefix under which the deployment artifacts will be stored. If not specified, defaults to `serverless`. + * You can make uploading to S3 faster by adding `--aws-s3-accelerate` Check out the [deploy command docs](../cli-reference/deploy.md) for all details and options. diff --git a/docs/providers/aws/guide/quick-start.md b/docs/providers/aws/guide/quick-start.md index 235f87a09..8c85ee4ce 100644 --- a/docs/providers/aws/guide/quick-start.md +++ b/docs/providers/aws/guide/quick-start.md @@ -20,7 +20,7 @@ layout: Doc Check out the following links for tutorial walkthroughs: -- [Build an Node.js REST API](/blog/serverless-express-rest-api/) +- [Build a Node.js REST API](/blog/serverless-express-rest-api/) - [Deploy a GraphQL endpoint](/blog/make-serverless-graphql-api-using-lambda-dynamodb/) Or follow the steps below for creating & deploying a simple service and learning some simple Serverless commands. diff --git a/docs/providers/aws/guide/serverless.yml.md b/docs/providers/aws/guide/serverless.yml.md index 1bef3bb86..75b8b5248 100644 --- a/docs/providers/aws/guide/serverless.yml.md +++ b/docs/providers/aws/guide/serverless.yml.md @@ -25,9 +25,9 @@ frameworkVersion: ">=1.0.0 <2.0.0" provider: name: aws - runtime: nodejs6.10 - stage: dev # Set the default stage used. Default is dev - region: us-east-1 # Overwrite the default region used. Default is us-east-1 + runtime: nodejs8.10 + stage: ${opt:stage, 'dev'} # Set the default stage used. Default is dev + region: ${opt:region, 'us-east-1'} # Overwrite the default region used. Default is us-east-1 stackName: custom-stack-name # Use a custom name for the CloudFormation stack apiName: custom-api-name # Use a custom name for the API Gateway API profile: production # The default profile to use with this service @@ -37,6 +37,7 @@ provider: deploymentBucket: name: com.serverless.${self:provider.region}.deploys # Deployment bucket name. Default is generated by the framework serverSideEncryption: AES256 # when using server-side encryption + deploymentPrefix: serverless # The S3 prefix under which deployed artifacts should be stored. Default is serverless role: arn:aws:iam::XXXXXX:role/role # Overwrite the default IAM role which is used for all functions cfnRole: arn:aws:iam::XXXXXX:role/role # ARN of an IAM role for CloudFormation service. If specified, CloudFormation uses the role's credentials versionFunctions: false # Optional function versioning diff --git a/docs/providers/aws/guide/services.md b/docs/providers/aws/guide/services.md index 75dd1bd99..0d20767c7 100644 --- a/docs/providers/aws/guide/services.md +++ b/docs/providers/aws/guide/services.md @@ -54,6 +54,7 @@ Here are the available runtimes for AWS Lambda: * aws-clojure-gradle * aws-nodejs * aws-nodejs-typescript +* aws-alexa-typescript * aws-nodejs-ecma-script * aws-python * aws-python3 @@ -106,6 +107,7 @@ provider: deploymentBucket: name: com.serverless.${self:provider.region}.deploys # Overwrite the default deployment bucket serverSideEncryption: AES256 # when using server-side encryption + deploymentPrefix: serverless # Overwrite the default S3 prefix under which deployed artifacts should be stored. Default is serverless versionFunctions: false # Optional function versioning stackTags: # Optional CF stack tags key: value diff --git a/docs/providers/aws/guide/variables.md b/docs/providers/aws/guide/variables.md index 5cb29d337..3e657900a 100644 --- a/docs/providers/aws/guide/variables.md +++ b/docs/providers/aws/guide/variables.md @@ -33,15 +33,15 @@ You can define your own variable syntax (regex) if it conflicts with CloudFormat ## Current variable sources: -- [environment variables](https://serverless.com/framework/docs/providers/aws/guide/variables#referencing-environment-variables) -- [CLI options](https://serverless.com/framework/docs/providers/aws/guide/variables#referencing-cli-options) -- [other properties defined in `serverless.yml`](https://serverless.com/framework/docs/providers/aws/guide/variables#reference-properties-in-serverlessyml) -- [external YAML/JSON files](https://serverless.com/framework/docs/providers/aws/guide/variables#reference-variables-in-other-files) -- [variables from S3](https://serverless.com/framework/docs/providers/aws/guide/variables#referencing-s3-objects) -- [variables from AWS SSM Parameter Store](https://serverless.com/framework/docs/providers/aws/guide/variables#reference-variables-using-the-ssm-parameter-store) -- [CloudFormation stack outputs](https://serverless.com/framework/docs/providers/aws/guide/variables#reference-cloudformation-outputs) -- [properties exported from Javascript files (sync or async)](https://serverless.com/framework/docs/providers/aws/guide/variables#reference-variables-in-javascript-files) -- [Pseudo Parameters Reference](https://serverless.com/framework/docs/providers/aws/guide/variables#referencing-Pseudo-Parameters-Reference) +- [environment variables](#referencing-environment-variables) +- [CLI options](#referencing-cli-options) +- [other properties defined in `serverless.yml`](#reference-properties-in-serverlessyml) +- [external YAML/JSON files](#reference-variables-in-other-files) +- [variables from S3](#referencing-s3-objects) +- [variables from AWS SSM Parameter Store](#reference-variables-using-the-ssm-parameter-store) +- [CloudFormation stack outputs](#reference-cloudformation-outputs) +- [properties exported from Javascript files (sync or async)](#reference-variables-in-javascript-files) +- [Pseudo Parameters Reference](#referencing-Pseudo-Parameters-Reference) ## Recursively reference properties diff --git a/docs/providers/cloudflare/README.md b/docs/providers/cloudflare/README.md new file mode 100644 index 000000000..5cdc83273 --- /dev/null +++ b/docs/providers/cloudflare/README.md @@ -0,0 +1,71 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/) + + +# Cloudflare Provider Documentation + +Welcome to the Serverless Cloudflare Workers documentation! + +If you have any questions, [search the forums](https://forum.serverless.com?utm_source=framework-docs) or [start your own thread](https://forum.serverless.com?utm_source=framework-docs) + + diff --git a/docs/providers/cloudflare/cli-reference/README.md b/docs/providers/cloudflare/cli-reference/README.md new file mode 100644 index 000000000..5e37d8038 --- /dev/null +++ b/docs/providers/cloudflare/cli-reference/README.md @@ -0,0 +1,15 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/cli-reference/) + + +# Serverless Cloudflare Workers CLI Reference + +Welcome to the Serverless Cloudflare Workers CLI Reference! Please select a section on the left to get started. + +If you have questions, join the [chat in gitter](https://gitter.im/serverless/serverless) or [post over on the forums](http://forum.serverless.com/). diff --git a/docs/providers/cloudflare/cli-reference/create.md b/docs/providers/cloudflare/cli-reference/create.md new file mode 100644 index 000000000..e5ce773db --- /dev/null +++ b/docs/providers/cloudflare/cli-reference/create.md @@ -0,0 +1,76 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/cli-reference/create) + + + +# Cloudflare Workers - Create +Creates a new Serverless service in the current working directory based on the provided template. + +**Create service in current working directory:** + +```bash +serverless create --template cloudflare-workers +``` + +Or for Enterprise Cloudflare accounts: + +```bash +serverless create --template cloudflare-workers-enterprise +``` + +**Create service in new folder:** + +```bash +serverless create --template cloudflare-workers --path my-service +``` + +Or for Enterprise Cloudflare accounts: + +```bash +serverless create --template cloudflare-workers-enterprise --path my-service +``` + +## Options +- `--template` or `-t` The name of one of the available templates. Required if --template-url and --template-path are not present. +- `--template-url` or `-u` The name of one of the available templates. Required if --template and --template-path are not present. +- `--template-path` The local path of your template. Required if --template and --template-url are not present. +- `--path` or `-p` The path where the service should be created. +- `--name` or `-n` the name of the service in `serverless.yml`. +## Provided lifecycle events +- `create:create` +## Available Templates for Cloudflare Workers +To see a list of available templates run `serverless create --help` +These are the current available templates for Cloudflare Workers: + +- cloudflare-workers +- cloudflare-workers-enterprise + +## Examples +### Creating a new service +```bash +serverless create --template cloudflare-workers --name my-special-service +``` + +This example will generate scaffolding for a service with `Cloudflare` as a provider. The scaffolding will be generated in the current working directory. + +### Creating a named service in a (new) directory +```bash +serverless create --template cloudflare-workers --path my-new-service +``` + +This example will generate scaffolding for a service with `Cloudflare` as a provider. The scaffolding will be generated in the `my-new-service` directory. This directory will be created if not present. Otherwise, Serverless will use the already present directory. +Additionally, Serverless will rename the service according to the path you provide. In this example, the service will be renamed to `my-new-service`. + +### Creating a new service using a local template +```bash +serverless create --template-path path/to/my/template/folder --path path/to/my/service --name my-new-service +``` +This will copy the `path/to/my/template/folder` folder into `path/to/my/service` and rename the service to `my-new-service`. diff --git a/docs/providers/cloudflare/cli-reference/deploy.md b/docs/providers/cloudflare/cli-reference/deploy.md new file mode 100644 index 000000000..6e9c3e5fb --- /dev/null +++ b/docs/providers/cloudflare/cli-reference/deploy.md @@ -0,0 +1,50 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/cli-reference/deploy) + + + +# Cloudflare Workers - Deploy +In order to be able to deploy any Cloudflare Workers, You will need to set your Global API key from Cloudflare as an environmental variable named `CLOUDFLARE_AUTH_KEY`, and your Cloudflare account email as an environmental variable named `CLOUDFLARE_AUTH_EMAIL`. You can get your Global API key from your [Cloudflare profile](https://dash.cloudflare.com/profile) page. You will also need to set `accountId` and `zoneId` in `serverless.yml` under `service.config`. The first part of the path when you open [Cloudflare dashboard](https://dash.cloudflare.com/) as a logged in user is your `accountId`, e.g. `dash.cloudflare.com/{accountId}`. And the `zoneId` can be found from the overview tab after selecting the desired zone from the [Cloudflare dashboard](https://dash.cloudflare.com/). + +Environmental variables are variables that live inside your terminal. + +For Mac and Linux users, you can set environmental variables like this: + +```bash +export CLOUDFLARE_AUTH_KEY=YOUR_API_KEY_HERE +export CLOUDFLARE_AUTH_EMAIL=YOUR_CLOUDFLARE_EMAIL +``` + +And for Windows (CMD) users, you can set environmental variables like this: + +```bash +set CLOUDFLARE_AUTH_KEY=YOUR_API_KEY_HERE +set CLOUDFLARE_AUTH_EMAIL=YOUR_CLOUDFLARE_EMAIL +``` + +You’ll need to redefine your environmental variables after each time you close your terminal. + +The `serverless deploy` command deploys your entire service via the Cloudflare Workers API. Run this command when you have made service changes (i.e., you edited `serverless.yml`). +Use `serverless deploy -f my-function` when you have made code changes and you want to quickly upload your updated code to Cloudflare. + +```bash +serverless deploy +``` + +This is the simplest deployment usage possible. With this command, Serverless will deploy your service to Cloudflare. + +## Options +- `--verbose` or `-v`: Shows all stack events during deployment, and display any Stack Output. +- `--function` or `-f`: Invokes `deploy function` (see above). Convenience shortcut + +## Provided lifecycle events +- `deploy:deploy` +- `deploy:function:deploy` diff --git a/docs/providers/cloudflare/cli-reference/invoke.md b/docs/providers/cloudflare/cli-reference/invoke.md new file mode 100644 index 000000000..3eae71090 --- /dev/null +++ b/docs/providers/cloudflare/cli-reference/invoke.md @@ -0,0 +1,65 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare-workers/cli-reference/invoke) + + + +# Cloudflare Workers - Invoke +Invokes a deployed function. It allows you to send an event to a deployed function, which can be useful for testing. Cloudflare Workers only support `GET` requests for now. The optional `headers` field allows you to specify headers that will be sent to your Worker along with your request. + +```bash +serverless invoke --function functionName +``` + +In the following example, you could run: + +```bash +serverless invoke --function helloWorld +``` + +```yml +# serverless.yml + ... +functions: + helloWorld: + # What the script will be called on Cloudflare + worker: hello + # The name of the script on your machine, omitting the .js file extension + script: helloWorld + events: + - http: + url: example.com/hello/user + # Defines the method used by serverless when the `invoke` command is used. Cloudflare Workers only support GET requests for now + method: GET + headers: + greeting: hi +``` + +## Options +* `--function` or `-f` The name of the function in your service that you want to invoke. Required. +* `--data` or `-d` String data to be passed as an event to your function. By default data is read from standard input. +* `--path` or `-p` The path to a json file with input data to be passed to the invoked function. This path is relative to the root directory of the service. + +## Provided lifecycle events +- `invoke:invoke` + +## Examples + +### Cloudflare Workers +```bash +serverless invoke --function functionName +``` + +This example will invoke your deployed function on the configured Cloudflare Workers API URL endpoint. This will output the result of the request in your terminal. + +#### Function invocation with data +```bash +serverless invoke --function functionName +``` \ No newline at end of file diff --git a/docs/providers/cloudflare/cli-reference/plugin-install.md b/docs/providers/cloudflare/cli-reference/plugin-install.md new file mode 100644 index 000000000..0bb19f137 --- /dev/null +++ b/docs/providers/cloudflare/cli-reference/plugin-install.md @@ -0,0 +1,42 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/cli-reference/plugin-install) + + +# Plugin Install + +Install a Serverless plugin and add it to the services `plugins` array. By default, a latest version is installed. +If you want a specific version, you can specify `@` as name option. + +**Note:** You might want to change the order of the plugin in the services `plugins` array. + +```bash +serverless plugin install --name pluginName +``` + +## Options +- `--name` or `-n` The plugins name. **Required**. + +## Provided lifecycle events +- `plugin:install:install` + +## Examples + +### Install the `serverless-webpack` plugin + +```bash +serverless plugin install --name serverless-webpack +``` + +### Install a specific version + +```bash +serverless plugin install --name serverless-webpack@3.0.0-rc.2 +``` diff --git a/docs/providers/cloudflare/cli-reference/plugin-list.md b/docs/providers/cloudflare/cli-reference/plugin-list.md new file mode 100644 index 000000000..c7b74d804 --- /dev/null +++ b/docs/providers/cloudflare/cli-reference/plugin-list.md @@ -0,0 +1,25 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/cli-reference/plugin-list) + + +# Plugin List + +List all available plugins on the terminal. Connected to the [Serverless plugin registry](https://github.com/serverless/plugins). + +```bash +serverless plugin list +``` + +## Options +- *None* + +## Provided lifecycle events +- `plugin:list:list` diff --git a/docs/providers/cloudflare/cli-reference/plugin-search.md b/docs/providers/cloudflare/cli-reference/plugin-search.md new file mode 100644 index 000000000..4f793f035 --- /dev/null +++ b/docs/providers/cloudflare/cli-reference/plugin-search.md @@ -0,0 +1,33 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/cli-reference/plugin-search) + + +# Plugin Search + +Search for a specific plugin based on a search query. Connected to the [Serverless plugin registry](https://github.com/serverless/plugins). + +```bash +serverless plugin search --query query +``` + +## Options +- `--query` or `-q` The query you want to use for your search. **Required**. + +## Provided lifecycle events +- `plugin:search:search` + +## Examples + +### Search for a `sqs` plugin + +```bash +serverless plugin search --query sqs +``` diff --git a/docs/providers/cloudflare/cli-reference/plugin-uninstall.md b/docs/providers/cloudflare/cli-reference/plugin-uninstall.md new file mode 100644 index 000000000..74852fb6b --- /dev/null +++ b/docs/providers/cloudflare/cli-reference/plugin-uninstall.md @@ -0,0 +1,33 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/cli-reference/plugin-uninstall) + + +# Plugin Uninstall + +Uninstall a Serverless plugin and remove it from the services `plugins` array. + +```bash +serverless plugin uninstall --name pluginName +``` + +## Options +- `--name` or `-n` The plugins name. **Required**. + +## Provided lifecycle events +- `plugin:uninstall:uninstall` + +## Examples + +### Remove the `serverless-webpack` plugin + +```bash +serverless plugin uninstall --name serverless-webpack +``` diff --git a/docs/providers/cloudflare/cli-reference/remove.md b/docs/providers/cloudflare/cli-reference/remove.md new file mode 100644 index 000000000..505bc0df1 --- /dev/null +++ b/docs/providers/cloudflare/cli-reference/remove.md @@ -0,0 +1,21 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/cli-reference/remove) + + +# Cloudflare Workers - Remove +The `serverless remove` command will remove the deployed service, defined in your current working directory, from the provider. + +```bash +serverless remove +``` +It will remove the Cloudflare Worker functions from the Cloudflare. +## Provided lifecycle events +- `remove:remove` diff --git a/docs/providers/cloudflare/events/README.md b/docs/providers/cloudflare/events/README.md new file mode 100644 index 000000000..09b25c7a8 --- /dev/null +++ b/docs/providers/cloudflare/events/README.md @@ -0,0 +1,18 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/events/) + + +# Serverless Cloudflare Workers Events + +Welcome to the Serverless Cloudflare Workers Events Glossary! + +Please select a section on the left to get started. + +If you have questions, join the [chat in gitter](https://gitter.im/serverless/serverless) or [post over on the forums](http://forum.serverless.com/) + diff --git a/docs/providers/cloudflare/events/http.md b/docs/providers/cloudflare/events/http.md new file mode 100644 index 000000000..0713feeae --- /dev/null +++ b/docs/providers/cloudflare/events/http.md @@ -0,0 +1,37 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/events/http) + + + +# Cloudflare Workers - HTTP Events +The only type of event that is supported in Cloudflare Workers is HTTP events, so defining events in your `serverless.yml` is optional. Defined events in your `serverless.yml` are only used by the `serverless invoke` command, which can be useful for testing your Functions. + +## Serverless Yml +When creating a service your serverless yml will define which endpoint is used for your function when you run the [`serverless invoke`](../cli-reference/invoke.md) command. + +```yml +# serverless.yml +... +functions: + helloWorld: + # What the script will be called on Cloudflare + worker: hello + # The name of the script on your machine, omitting the .js file extension + script: helloWorld + events: + - http: + url: example.com/hello/user + method: GET + headers: + greeting: hi +``` + +The events section in the yml above makes it so that the Function helloWorld will be used for request to the `example.com/hello/user` endpoint. This configuration would send a GET request with a header called `greeting` that has a value of `hi` to the `example.com/hello/user` endpoint when you run `serverless invoke -f helloWorld`. \ No newline at end of file diff --git a/docs/providers/cloudflare/guide/README.md b/docs/providers/cloudflare/guide/README.md new file mode 100644 index 000000000..bf10653c8 --- /dev/null +++ b/docs/providers/cloudflare/guide/README.md @@ -0,0 +1,17 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/guide/) + + +# Serverless Cloudflare Workers Guide + +Welcome to the Serverless Cloudflare Workers Guide! + +Get started with the **[Introduction to the Serverless framework](./intro.md)** + +If you have questions, join the [chat in gitter](https://gitter.im/serverless/serverless) or [post over on the forums](http://forum.serverless.com/) diff --git a/docs/providers/cloudflare/guide/debugging.md b/docs/providers/cloudflare/guide/debugging.md new file mode 100644 index 000000000..705ccbcdb --- /dev/null +++ b/docs/providers/cloudflare/guide/debugging.md @@ -0,0 +1,62 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/guide/debugging) + + +# Cloudflare Workers - Debugging +How can we debug errors in our Cloudflare Workers functions? + +Let's imagine that we have deployed the following code as a Cloudflare Worker function using Serverless: + +```javascript +addEventListener('fetch', event => { + event.respondWith(handleRequest(event.request)) + }) + async function handleRequest(request) { + const answer = request.headers.get("greeting") || "hello" + return new Response(answer + " world") + } + +``` +And its corresponding Serverless yml file: + +```yml +# serverless.yml +... +functions: + helloWorld: + # What the script will be called on Cloudflare + worker: hello + # The name of the script on your machine, omitting the .js file extension + script: helloWorld + events: + - http: + url: example.com/hello/user + # Defines the method used by serverless when the `invoke` command is used. Cloudflare Workers only support GET requests for now + method: GET + headers: + greeting: hi +``` + +Let's invoke correctly that function + +```bash +serverless invoke --function helloWorld + +# Output +hi world +``` + + +If we were to call the above function without any headers, you would get `hello world` back instead of `hi world`, so we know that our worker is properly reading the greeting header. + +## Cloudflare Workers Playground + +Cloudflare Workers also have a [Playground](https://cloudflareworkers.com/#) you can use to modify a Cloudflare Worker and see the results live on the same screen. The Cloudflare Workers Playground is another great way to debug your worker. diff --git a/docs/providers/cloudflare/guide/deploying.md b/docs/providers/cloudflare/guide/deploying.md new file mode 100644 index 000000000..74f8632d7 --- /dev/null +++ b/docs/providers/cloudflare/guide/deploying.md @@ -0,0 +1,115 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/guide/deploying) + + +# Cloudflare Workers - Deploying +The Serverless Framework was designed to provision your Cloudflare Workers Functions and Events. It does this via a couple of methods designed for different types of deployments. + +## prerequisites + +In order to deploy your Cloudflare Worker, you need to set your Cloudflare email as an environmental variable called `CLOUDFLARE_AUTH_EMAIL`, and your Cloudflare Global API Key as an environmental variable called `CLOUDFLARE_AUTH_KEY`. You will also need to set `accountId` and `zoneId` in `serverless.yml` under `service.config`. The first part of the path when you open [Cloudflare dashboard](https://dash.cloudflare.com/) as a logged in user is your `accountId`, e.g. `dash.cloudflare.com/{accountId}`. And the `zoneId` can be found from the overview tab after selecting the desired zone from the [Cloudflare dashboard](https://dash.cloudflare.com/). + +Environmental variables are variables that live inside your terminal. + +For Mac and Linux users, you can set environmental variables like this: + +```bash +export CLOUDFLARE_AUTH_KEY=YOUR_API_KEY_HERE +export CLOUDFLARE_AUTH_EMAIL=YOUR_CLOUDFLARE_EMAIL +``` + +And for Windows (CMD) users, you can set environmental variables like this: + +```bash +set CLOUDFLARE_AUTH_KEY=YOUR_API_KEY_HERE +set CLOUDFLARE_AUTH_EMAIL=YOUR_CLOUDFLARE_EMAIL +``` + +You’ll need to redefine your environmental variables after each time you close your terminal. + + + +## Deploy All +This is the main method for doing deployments with the Serverless Framework: + +```bash +serverless deploy +``` + +Use this method when you have updated your Function, Event or Resource configuration in `serverless.yml` and you want to deploy that change (or multiple changes at the same time) to your Cloudflare Worker. If you've made changes to any of your routes since last deploying, the Serverless Framework will update them on the server for you. + +### How It Works +The Serverless Framework reads in `serverless.yml` and uses it to provision your Functions. + +For each defined Function in your `serverless.yml` file, the Framework will create a Cloudflare Workers script. This means that only enterprise customers can declare more than one Function, but anyone can use [webpack](https://developers.cloudflare.com/workers/writing-workers/using-npm-modules/) to package their application into a single script. + +For example, let's take the following example `serverless.yml` file: + +```yml +# serverless.yml + +service: + name: hello-world + config: + accountId: CLOUDFLARE_ACCOUNT_ID + zoneId: CLOUDFLARE_ZONE_ID + workers: + hello: + routes: + - example.com/hello/* + foo_script: + routes: + - example.com/foo/* + +provider: + name: cloudflare + +plugins: + - serverless-cloudflare-workers + +functions: + helloWorld: + # What the script will be called on Cloudflare + worker: hello + # The name of the script on your machine, omitting the .js file extension + script: helloWorld + # Events are optional to declare and only affect the `serverless invoke` command + events: + - http: + url: example.com/hello/user + method: GET + headers: + greeting: hi + + + # Only Enterprise accounts would be allowed to add this second function + foo: + worker: foo_script + script: bar + events: + - http: + url: example.com/foo/bar + method: GET +``` + +After deploying that file, you’ll be able to hit the specified top-level routes of your zone, `example.com/hello/*` and `example.com/foo/*`, and any endpoints that resolve to these routes, like `example.com/hello/user` and `example.com/foo/bar`. + +## Deploy Function +This deployment method updates or deploys a single function. It performs the platform API call to deploy your package without the other resources. It is much faster than re-deploying your whole service each time. + +```bash +serverless deploy --function myFunction +``` + +If you've made changes to the routes corresponding to this Function since last deploying, the Serverless Framework will update them on the server for you. + +### Tips +Check out the [deploy command docs](../cli-reference/deploy.md) for all details and options. diff --git a/docs/providers/cloudflare/guide/events.md b/docs/providers/cloudflare/guide/events.md new file mode 100644 index 000000000..e011b2dc9 --- /dev/null +++ b/docs/providers/cloudflare/guide/events.md @@ -0,0 +1,40 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/guide/events) + + + +# Cloudflare Workers - Events +Simply put, events are the things that trigger your functions to run. Currently, they are optional to define and are only used by the `serverless invoke` command, which can be useful for testing your Functions. + +If you are using Cloudflare Workers as your provider, all `events` in the service are HTTP Events, because that is the only event that Cloudflare Workers currently support. + +```yml +# serverless.yml +… + +functions: + helloWorld: + # What the script will be called on Cloudflare + worker: hello + # The name of the script on your machine, omitting the .js file extension + script: helloWorld + events: + - http: + url: example.com/hello/user + # Defines the method used by serverless when the `invoke` command is used. Cloudflare Workers only support GET requests for now + method: GET + headers: + greeting: hi +``` + +Then [`serverless invoke -f helloWorld`](../cli-reference/invoke.md) will make a GET request to `example.com/hello/user` with a header called `greeting` that has a value of `hi`. + +[View the Cloudflare Workers events section for more information on HTTP events](../events). diff --git a/docs/providers/cloudflare/guide/functions.md b/docs/providers/cloudflare/guide/functions.md new file mode 100644 index 000000000..ab114991f --- /dev/null +++ b/docs/providers/cloudflare/guide/functions.md @@ -0,0 +1,119 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/guide/functions) + + +# Cloudflare Workers - Functions + +If you are using Cloudflare as a provider, all *functions* inside the service are Cloudflare Workers. + +## Configuration + +All of the Cloudflare Workers in your serverless service can be found in `serverless.yml` under the `functions` property. + +```yml +# serverless.yml + +service: + name: hello-world + config: + accountId: CLOUDFLARE_ACCOUNT_ID + zoneId: CLOUDFLARE_ZONE_ID + workers: + hello: + routes: + - example.com/hello/* + +provider: + name: cloudflare + +plugins: + - serverless-cloudflare-workers + +functions: + helloWorld: + # What the script will be called on Cloudflare + worker: hello + # The name of the script on your machine, omitting the .js file extension + script: helloWorld + # Events are only relevant to the `serverless invoke` command and don’t affect deployment in any way + events: + - http: + url: example.com/hello/user + method: GET + headers: + someKey: someValue +``` + +The `script` property points to the file containing your Cloudflare Worker. + +```javascript +// helloWorld.js + +addEventListener('fetch', event => { + event.respondWith(handleRequest(event.request)) + }) + + async function handleRequest(request) { + return new Response("Hello world") + } +``` + +If you have an Enterprise Cloudflare account, you can add multiple Cloudflare Workers to your project. + +```yml +# serverless.yml + +service: + name: hello-world + config: + accountId: CLOUDFLARE_ACCOUNT_ID + zoneId: CLOUDFLARE_ZONE_ID + workers: + hello: + routes: + - example.com/hello/* + foo_script: + routes: + - example.com/foo/* + +provider: + name: cloudflare + +plugins: + - serverless-cloudflare-workers + +functions: + helloWorld: + # What the script will be called on Cloudflare + worker: hello + # The name of the script on your machine, omitting the .js file extension + script: helloWorld + # Events are only relevant to the `serverless invoke` command and don’t affect deployment in any way + events: + - http: + url: example.com/hello/user + method: GET + headers: + someKey: someValue + + + # Only Enterprise accounts would be allowed to add this second function and its corresponding route above + foo: + worker: foo_script + script: bar + events: + - http: + url: example.com/foo/bar + method: GET +``` +The `script` property is what the Cloudflare Worker will be called on Cloudflare’s data centers. + +The `events` property is optional and is only relevant for using the `serverless invoke` command. Check out the [`events`](./events.md) guide for more information. diff --git a/docs/providers/cloudflare/guide/installation.md b/docs/providers/cloudflare/guide/installation.md new file mode 100644 index 000000000..1771fcf70 --- /dev/null +++ b/docs/providers/cloudflare/guide/installation.md @@ -0,0 +1,57 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/guide/installation) + + +# Cloudflare Workers - Installation + +## Installing Cloudflare Workers +Cloudflare Workers don’t actually require any installation to run. However, You will need to set your Global API key from Cloudflare as an environmental variable named `CLOUDFLARE_AUTH_KEY`, and your Cloudflare account email as an environmental variable named `CLOUDFLARE_AUTH_EMAIL`. You can get your Global API key from your [Cloudflare profile](https://dash.cloudflare.com/profile) page. + +Environmental variables are variables that live inside your terminal. + +For Mac and Linux users, you can set environmental variables like this: + +```bash +export CLOUDFLARE_AUTH_KEY=YOUR_API_KEY_HERE +export CLOUDFLARE_AUTH_EMAIL=YOUR_CLOUDFLARE_EMAIL +``` + +And for Windows (CMD) users, you can set environmental variables like this: + +```bash +set CLOUDFLARE_AUTH_KEY=YOUR_API_KEY_HERE +set CLOUDFLARE_AUTH_EMAIL=YOUR_CLOUDFLARE_EMAIL +``` + +You’ll need to redefine your environmental variables after each time you close your terminal. + +## Installing the Serverless Framework +Next, install the Serverless Framework via [npm](https://npmjs.org) which was already installed when you installed Node.js. + +Open up a terminal and type `npm install -g serverless` to install Serverless. + +```bash +npm install -g serverless +``` + +Once the installation process is done you can verify that Serverless is installed successfully by running the following command in your terminal: + +```bash +serverless +``` + +To see which version of serverless you have installed run: + +```bash +serverless --version +``` + +Remember, you need at least version 1.31.0 to use Cloudflare Workers with Serverless. diff --git a/docs/providers/cloudflare/guide/intro.md b/docs/providers/cloudflare/guide/intro.md new file mode 100644 index 000000000..827a8be38 --- /dev/null +++ b/docs/providers/cloudflare/guide/intro.md @@ -0,0 +1,109 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/guide/intro) + + + +# Cloudflare Workers - Introduction + +The Serverless Framework helps you develop and deploy serverless applications using [Cloudflare Workers](https://www.cloudflare.com/products/cloudflare-workers/). It's a CLI that offers structure, automation, and best practices out-of-the-box, allowing you to focus on building sophisticated, event-driven, serverless architectures, comprised of [Functions](#functions) and [Events](#events). It lets you manage your Worker routing in a flat configuration file that you can keep in alongside the rest of your code in version control, and the Serverless Framework will intelligently manage your routes as they change. + +The Serverless Framework is different than other application frameworks because: +* It manages your code as well as your infrastructure +* It supports multiple languages (Although Cloudflare Workers only supports Javascript for now) + +## Core Concepts +Here are the Serverless Framework's main concepts and how they pertain to Cloudflare Workers. + +### Functions +A Function is a Cloudflare Worker. It's an independent unit of deployment, like a microservice. It's merely code, deployed on Cloudflare’s 152+ PoPs (points of presence), that is most often written to perform a single job, such as: +* *Performing A/B Testing* +* *Custom routing based on user location, custom headers, etc.* +* *Hosting webhook endpoints* + +### Events +Anything that triggers a Cloudflare Worker Event to execute is regarded by the Framework as an **Event**. The only event that triggers a Cloudflare Worker is an HTTP request. Since the only event that can trigger a Worker is an HTTP request, declaring events is optional, and only used to declare specific endpoints that can be called by [`serverless invoke`](../cli-reference/invoke.md). This is useful for defining specific hooks into your application for testing. + +### Services +A **Service** is the Serverless Framework's unit of organization. You can think of it as a project file, though you can have multiple services for a single application. It's where you define your Functions and the routes they will live on, all in one file entitled `serverless.yml`. Non-Enterprise Cloudflare accounts can only deploy one function (that can be deployed to multiple routes), while Enterprise Cloudflare accounts can deploy multiple functions at once: + +```yml +# serverless.yml + +service: + name: hello-world + config: + accountId: CLOUDFLARE_ACCOUNT_ID + zoneId: CLOUDFLARE_ZONE_ID + workers: + hello: + routes: + - example.com/hello/* + foo_script: + routes: + - example.com/foo/* + +provider: + name: cloudflare + +plugins: + - serverless-cloudflare-workers + +functions: + helloWorld: + # What the script will be called on Cloudflare + worker: hello + # The name of the script on your machine, omitting the .js file extension + script: helloWorld + # Events are only relevant to the `serverless invoke` command and don’t affect deployment in any way + events: + - http: + url: example.com/hello/user + # Defines the method used by serverless when the `invoke` command is used. Cloudflare Workers only support GET requests for now + method: GET + headers: + someKey: someValue + + + # Only Enterprise accounts would be allowed to add this second function and its corresponding route above + foo: + worker: foo_script + script: bar + events: + - http: + url: example.com/foo/bar + method: GET +``` + +You get your `accountId` by grabbing it from the URL when using the [Cloudflare dashboard](https://dash.cloudflare.com), and your `zoneId` from the `overview` tab after selecting the desired zone from the [Cloudflare dashboard](https://dash.cloudflare.com). + +You will also need to set your Global API key from Cloudflare as an environmental variable named `CLOUDFLARE_AUTH_KEY`, and your Cloudflare account email as an environmental variable named `CLOUDFLARE_AUTH_EMAIL`. You can get your Global API key from your [Cloudflare profile](https://dash.cloudflare.com/profile) page. + +Environmental variables are variables that live inside your terminal. + +For Mac and Linux users, you can set environmental variables like this: + +```bash +export CLOUDFLARE_AUTH_KEY=YOUR_API_KEY_HERE +export CLOUDFLARE_AUTH_EMAIL=YOUR_CLOUDFLARE_EMAIL +``` + +And for Windows (CMD) users, you can set environmental variables like this: + +```bash +set CLOUDFLARE_AUTH_KEY=YOUR_API_KEY_HERE +set CLOUDFLARE_AUTH_EMAIL=YOUR_CLOUDFLARE_EMAIL +``` + +You’ll need to redefine your environmental variables after each time you close your terminal. + +If you’re not an enterprise customer and you want to execute different code on multiple routes with only one funciton, we recommend writing code based off of our [conditional routing](https://developers.cloudflare.com/workers/recipes/conditional-routing/) template to check your route and execute different code accordingly. You can also write workers in separate files and compile it into one worker with [webpack](https://developers.cloudflare.com/workers/writing-workers/using-npm-modules/). + +When you deploy with the Framework by running `serverless deploy`, everything in `serverless.yml` is deployed at once. diff --git a/docs/providers/cloudflare/guide/quick-start.md b/docs/providers/cloudflare/guide/quick-start.md new file mode 100644 index 000000000..e0dcb857c --- /dev/null +++ b/docs/providers/cloudflare/guide/quick-start.md @@ -0,0 +1,106 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/guide/quick-start) + + +# Cloudflare Workers - Quickstart + +## Pre-requisites +Node.js `v6.5.0` or later. +Serverless CLI `v1.31.0` or later. You can run `npm install -g serverless` to install it. + +## Create a new service +Create a new service using either the `cloudflare-workers` or `cloudflare-workers-enterprise` template, depending on your Cloudflare domain’s plan level, and specifying a unique name and an optional path for your service. + +```bash +# Create a new Serverless Service/Project +$ serverless create --template cloudflare-workers --path new-project +# Change into the newly created directory +$ cd new-project +# Install npm dependencies +$ npm install +``` + +Note: there are two templates for [Cloudflare Workers](https://www.cloudflare.com/products/cloudflare-workers/): `cloudflare-workers` and `cloudflare-workers-enterprise`. The enterprise template sets up a project that can natively deploy [multiple scripts](https://developers.cloudflare.com/workers/api/config-api-for-enterprise/), each with their own routes. It requires an enterprise Cloudflare account to use. + +The `cloudflare-workers` template still supports [conditional routing](https://developers.cloudflare.com/workers/recipes/conditional-routing/) and multiple scripts if you use a tool like [webpack](https://developers.cloudflare.com/workers/writing-workers/using-npm-modules/). + +## Deploy, test and diagnose your service + +You will need to set your Global API key from Cloudflare as an environmental variable named `CLOUDFLARE_AUTH_KEY`, and your Cloudflare account email as an environmental variable named `CLOUDFLARE_AUTH_EMAIL`. You can get your Global API key from your [Cloudflare profile](https://dash.cloudflare.com/profile) page. You will also need to set `accountId` and `zoneId` in `serverless.yml` under `service.config`. The first part of the path when you open [Cloudflare dashboard](https://dash.cloudflare.com/) as a logged in user is your `accountId`, e.g. `dash.cloudflare.com/{accountId}`. And the `zoneId` can be found from the overview tab after selecting the desired zone from the [Cloudflare dashboard](https://dash.cloudflare.com/). + +Environmental variables are variables that live inside your terminal. + +For Mac and Linux users, you can set environmental variables like this: + +```bash +export CLOUDFLARE_AUTH_KEY=YOUR_API_KEY_HERE +export CLOUDFLARE_AUTH_EMAIL=YOUR_CLOUDFLARE_EMAIL +``` + +And for Windows (CMD) users, you can set environmental variables like this: + +```bash +set CLOUDFLARE_AUTH_KEY=YOUR_API_KEY_HERE +set CLOUDFLARE_AUTH_EMAIL=YOUR_CLOUDFLARE_EMAIL +``` + +You’ll need to redefine your environmental variables after each time you close your terminal. + +1. **Deploy the Service** + +Use this when you have made changes to your Functions, Events or Resources in `serverless.yml` or you simply want to deploy all changes within your Service at the same time. If you've made changes to your routes since last deploying, the Serverless Framework will update them on the server for you. + +```bash +serverless deploy +``` + +2. **Deploy the Function** + +Use this to quickly upload and overwrite your function code, allowing you to develop faster. + +```bash +serverless deploy -f hello +``` + +3. **Invoke the Function** + +Invokes the Function and returns results. + +```bash +serverless invoke --function helloWorld + +Hello world +``` + +Note that for `invoke`, your Function must have the `events` field populated in order for the `serverless` tool to know exactly which route to request. Defining the `headers` field is optional. + +```yml +# serverless.yml +... +foo: + worker: foo_script + script: bar + events: + - http: + url: example.com/foo/bar + # Defines the method used by serverless when the `invoke` command is used. Cloudflare Workers only support GET requests for now + method: GET + headers: + someKey: someValue +``` + + +## Cleanup +If at any point, you no longer need your service, you can run the following command to remove the Functions, Events and Resources that were created. + +```bash +serverless remove +``` diff --git a/docs/providers/cloudflare/guide/services.md b/docs/providers/cloudflare/guide/services.md new file mode 100644 index 000000000..fdd2be9da --- /dev/null +++ b/docs/providers/cloudflare/guide/services.md @@ -0,0 +1,202 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/guide/services) + + +# Cloudflare Workers - Services + +A `service` is like a project. It's where you define your Cloudflare Workers and the `events` you test them with, all in a file called `serverless.yml`. + +To get started building your first Serverless Framework project, create a `service`. + +## Organization + +In the beginning of an application created by a team with an Enterprise Cloudflare account, and for the lifespan of an application made by a team with a Non-Enterprise Cloudflare account, we recommend you use a single Service to define all of the Functions and Events for that project. + +```bash +myService/ + serverless.yml # Contains all functions and infrastructure resources +``` + +However, as your application grows as an Enterprise Cloudflare user, you can break it out into multiple services. A lot of people organize their services by workflows or data models, and group the functions related to those workflows and data models together in the service. + +```bash +users/ + serverless.yml # Contains 4 functions that do Users CRUD operations and the Users database +posts/ + serverless.yml # Contains 4 functions that do Posts CRUD operations and the Posts database +comments/ + serverless.yml # Contains 4 functions that do Comments CRUD operations and the Comments database +``` + +This makes sense since related functions usually use common infrastructure resources, and you want to keep those functions and resources together as a single unit of deployment, for better organization and separation of concerns. + +## Creation + +To create a service, use the `create` command. You can also pass in a path to create a directory and auto-name your service: + +```bash +# Create service with cloudflare-workers template in the folder ./my-service +serverless create --template cloudflare-workers --path my-service +``` + +Here are the available runtimes for Cloudflare Workers: + +* cloudflare-workers +* cloudflare-workers-enterprise + +Check out the [create command docs](../cli-reference/create) for all the details and options. + +## Contents + +You'll see the following files in your working directory: + +- `serverless.yml` +- `helloWorld.js` + +### serverless.yml + +Each `service` configuration is managed in the `serverless.yml` file. The main responsibilities of this file are: + +- Declare a Serverless service +- Define one or more functions in the service + - Define the provider the service will be deployed to + - Define any custom plugins to be used + - Define events that trigger each function to execute (e.g. HTTP requests) + - Allow events listed in the `events` section to automatically create the resources required for the `serverless invoke` command + +You can see the name of the service, the provider configuration and the first function inside the `functions` definition. Any further service configuration will be done in this file. + +```yml +# serverless.yml + +service: + name: hello-world + config: + accountId: CLOUDFLARE_ACCOUNT_ID + zoneId: CLOUDFLARE_ZONE_ID + workers: + hello: + routes: + - example.com/hello/* + foo_script: + routes: + - example.com/foo/* + +provider: + name: cloudflare + +plugins: + - serverless-cloudflare-workers + +functions: + helloWorld: + # What the script will be called on Cloudflare + worker: hello + # The name of the script on your machine, omitting the .js file extension + script: helloWorld + # Events are only relevant to the `serverless invoke` command and don’t affect deployment in any way + events: + - http: + url: example.com/hello/user + method: GET + headers: + someKey: someValue + + + # Only Enterprise accounts would be allowed to add this second function and its corresponding route above + foo: + worker: foo_script + script: bar + events: + - http: + url: example.com/foo/bar + method: GET + +``` + +### helloWorld.js + +The `helloWorld.js` file contains a barebones Cloudflare Worker that returns ‘hello world’. + +## Deployment + +When you deploy a Service, all of the Functions, and Events in your `serverless.yml` are translated into calls to Cloudflare to create your Cloudflare Worker(s). + +To deploy a service, first `cd` into the relevant service directory: + +```bash +cd my-service +``` + +Then use the `deploy` command: + +```bash +serverless deploy +``` + +Check out the [deployment guide](./deploying.md) to learn more about deployments and how they work. Or, check out the [deploy command docs](../cli-reference/deploy.md) for all the details and options. + +## Removal + +To easily remove your Service from Cloudflare’s data centers, you can use the `remove` command. + +Run `serverless remove` to trigger the removal process. + +Serverless will start the removal and informs you about it's process on the console. A success message is printed once the whole service is removed. + +The removal process will only remove the service on your provider's infrastructure. The service directory will still remain on your local machine so you can still modify and (re)deploy it to another stage, region or provider later on. + +## Version Pinning + +The Serverless framework is usually installed globally via `npm install -g serverless`. This way you have the Serverless CLI available for all your services. + +Installing tools globally has the downside that the version can't be pinned inside package.json. This can lead to issues if you upgrade Serverless, but your colleagues or CI system don't. You can use a feature in your serverless.yml without worrying that your CI system will deploy with an old version of Serverless. + +### Pinning a Version + +To configure version pinning define a `frameworkVersion` property in your serverless.yaml. Whenever you run a Serverless command from the CLI it checks if your current Serverless version is matching the `frameworkVersion` range. The CLI uses [Semantic Versioning](http://semver.org/) so you can pin it to an exact version or provide a range. In general we recommend to pin to an exact version to ensure everybody in your team has the exact same setup and no unexpected problems happen. + +### Examples + +#### Exact Version + +```yml +# serverless.yml + +frameworkVersion: "=1.0.3" +``` + +#### Version Range + +```yml +# serverless.yml + +frameworkVersion: ">=1.0.0 <2.0.0" +``` + + +## Installing Serverless in an existing service + +If you already have a Serverless service, and would prefer to lock down the framework version using `package.json`, then you can install Serverless as follows: + +```bash +# from within a service +npm install serverless --save-dev +``` + +### Invoking Serverless locally + +To execute the locally installed Serverless executable you have to reference the binary out of the node modules directory. + +Example: +``` +node ./node_modules/serverless/bin/serverless deploy +``` diff --git a/docs/providers/cloudflare/guide/workflow.md b/docs/providers/cloudflare/guide/workflow.md new file mode 100644 index 000000000..c6dda1f8d --- /dev/null +++ b/docs/providers/cloudflare/guide/workflow.md @@ -0,0 +1,58 @@ + + + +### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/cloudflare/guide/workflow) + + + +# Cloudflare Workers - Workflow +Generally, Cloudflare Workers can be written locally, deployed with serverless, and tested with the [`serverless invoke`](../cli-reference/invoke.md) command. However, using the [Cloudflare Workers Playground](https://cloudflareworkers.com/#) can help you test and view your worker’s results live if you need more insight while developing your Cloudflare Worker. + +Below is a list of general tips for developing Cloudflare Workers with Serverless. + +### Development Workflow +Write your functions +Use `serverless deploy` only when you've made changes to `serverless.yml` and in CI/CD systems. +Use `serverless deploy -f myFunction` to rapidly deploy changes when you are working on a specific Cloudflare Workers Function. +Use `serverless invoke -f myFunction` to test your Cloudflare Workers Functions. +### Larger Projects +* For Non-Enterprise Cloudflare customers, combining multiple workers into one file or using [webpack](https://developers.cloudflare.com/workers/writing-workers/using-npm-modules/). +* Keep the Functions and Resources in your Serverless Services to a minimum. +## Cheat Sheet +A handy list of commands to use when developing with the Serverless Framework. + +##### Create A Service: +Creates a new Service: + +```bash +serverless create -p [SERVICE NAME] -t cloudflare-workers +``` + +##### Deploy All +Use this when you have made changes to your Functions, Events or Resources in `serverless.yml` or you simply want to deploy all changes within your Service at the same time. + +```bash +serverless deploy +``` + + +##### Deploy Function +Use this to quickly overwrite your Cloudflare Workers Functions, allowing you to develop faster if you have an Enterprise account that supports deploying multiple functions. + +```bash +serverless deploy -f [FUNCTION NAME] +``` + + +##### Invoke Function +Invokes a Cloudflare Workers Function. + +```bash +serverless invoke -f [FUNCTION NAME] +``` diff --git a/docs/providers/google/cli-reference/invoke-local.md b/docs/providers/google/cli-reference/invoke-local.md index 54ab11701..6d2e27c73 100644 --- a/docs/providers/google/cli-reference/invoke-local.md +++ b/docs/providers/google/cli-reference/invoke-local.md @@ -17,7 +17,7 @@ layout: Doc Invokes deployed function locally. It allows to send event data to the function, read logs and display other important information of the function invocation. ```bash -serverless invoke -f functionName +serverless invoke local -f functionName ``` ## Options @@ -28,6 +28,7 @@ serverless invoke -f functionName * `--raw` Pass data as a raw string even if it is JSON. If not set, JSON data are parsed and passed as an object. * `--contextPath` or `-x`, The path to a json file holding input context to be passed to the invoked function. This path is relative to the root directory of the service. * `--context` or `-c`, String data to be passed as a context to your function. Same like with `--data`, context included in `--contextPath` will overwrite the context you passed with `--context` flag. +* `--env` or `-e` String representing an environment variable to set when invoking your function, in the form `=`. Can be repeated for more than one environment variable. > Keep in mind that if you pass both `--path` and `--data`, the data included in the `--path` file will overwrite the data you passed with the `--data` flag. @@ -54,3 +55,13 @@ serverless invoke local -f functionName -p path/to/file.json serverless invoke local -f functionName -p path/to/file.yaml ``` + +### Local function invocation, setting environment variables + +```bash +serverless invoke local -f functionName -e VAR1=value1 + +# Or more than one variable + +serverless invoke local -f functionName -e VAR1=value1 -e VAR2=value2 +``` diff --git a/docs/providers/openwhisk/cli-reference/invoke-local.md b/docs/providers/openwhisk/cli-reference/invoke-local.md index cad243fe1..4bb1ab52d 100644 --- a/docs/providers/openwhisk/cli-reference/invoke-local.md +++ b/docs/providers/openwhisk/cli-reference/invoke-local.md @@ -25,6 +25,7 @@ __*Please note that only the JavaScript and Python runtimes are supported with t - `--function` or `-f` The name of the function in your service that you want to invoke locally. **Required**. - `--path` or `-p` The path to a json file holding input data to be passed to the invoked function. This path is relative to the root directory of the service. The json file should have event and context properties to hold your mocked event and context data. - `--data` or `-d` String data to be passed as an event to your function. Keep in mind that if you pass both `--path` and `--data`, the data included in the `--path` file will overwrite the data you passed with the `--data` flag. +* `--env` or `-e` String representing an environment variable to set when invoking your function, in the form `=`. Can be repeated for more than one environment variable. ## Examples @@ -60,6 +61,16 @@ serverless invoke local --function functionName --path lib/data.json This example will pass the json data in the `lib/data.json` file (relative to the root of the service) while invoking the specified/deployed function. +### Local function invocation, setting environment variables + +```bash +serverless invoke local -f functionName -e VAR1=value1 + +# Or more than one variable + +serverless invoke local -f functionName -e VAR1=value1 -e VAR2=value2 +``` + ### Limitations Currently, `invoke local` only supports the NodeJs and Python runtimes. diff --git a/docs/providers/openwhisk/guide/functions.md b/docs/providers/openwhisk/guide/functions.md index 2f0aacbda..ee922e444 100644 --- a/docs/providers/openwhisk/guide/functions.md +++ b/docs/providers/openwhisk/guide/functions.md @@ -156,11 +156,12 @@ functions: resources: packages: myPackage: + name: optionalCustomName parameters: hello: world ``` -*Explicit packages support the following properties: `parameters`, `annotations` and `shared`.* +*Explicit packages support the following properties: `name`, `parameters`, `annotations` and `shared`.* ## Binding Services (IBM Cloud Functions) diff --git a/docs/providers/webtasks/README.md b/docs/providers/webtasks/README.md deleted file mode 100755 index 930332cbf..000000000 --- a/docs/providers/webtasks/README.md +++ /dev/null @@ -1,37 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/) - - -# Webtasks Provider Documentation - -Welcome to the Serverless Webtasks documentation! - -If you have questions specific to the Webtasks provider, please join our [Slack](http://chat.webtask.io). - -For general Serverless Framework questions, [search the forums](https://forum.serverless.com?utm_source=framework-docs) or [start your own thread](https://forum.serverless.com?utm_source=framework-docs) - -#### Quick Start - -- Intro -- Quick Start - -#### CLI reference - -- Config Credentials -- Create -- Deploy -- Invoke -- Logs -- Info -- Remove - -#### Events - -- http event -- Schedule event diff --git a/docs/providers/webtasks/cli-reference/README.md b/docs/providers/webtasks/cli-reference/README.md deleted file mode 100755 index f8affe3dd..000000000 --- a/docs/providers/webtasks/cli-reference/README.md +++ /dev/null @@ -1,19 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/cli-reference/) - - -# Serverless Auth0 Webtasks CLI Reference - -Welcome to the Serverless Auth0 Webtasks CLI Reference! - -Please select a section on the left to get started. - -If you have questions specific to the Webtasks provider, please join our [Slack](http://chat.webtask.io). For general Serverless Framework questions, join the [chat in gitter](https://gitter.im/serverless/serverless) or [post over on the forums](http://forum.serverless.com/) - -**Note:** A local profile is required to use Auth0 Webtasks with the Serverless Framework. Follow the steps in the [Quick Start](../quick-start.md) to get setup in less than a minute. diff --git a/docs/providers/webtasks/cli-reference/config-credentials.md b/docs/providers/webtasks/cli-reference/config-credentials.md deleted file mode 100755 index 532e78dc6..000000000 --- a/docs/providers/webtasks/cli-reference/config-credentials.md +++ /dev/null @@ -1,21 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/cli-reference/config-credentials) - - -# Auth0 Webtasks - Config Credentials - -Before you are able to use the Auth0 Webtasks platform with the Serverless Framework, you will need to setup a local profile. Fortunately, this takes less than a minute. - -```bash -serverless config credentials --provider webtasks -``` - -You will be asked for a phone number or email. You'll immediately receive a verification code. Enter the verification code and your profile will be entirely setup and ready to use. \ No newline at end of file diff --git a/docs/providers/webtasks/cli-reference/create.md b/docs/providers/webtasks/cli-reference/create.md deleted file mode 100755 index 779f57738..000000000 --- a/docs/providers/webtasks/cli-reference/create.md +++ /dev/null @@ -1,71 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/cli-reference/create) - - -# Auth0 Webtasks - Create - -Creates a new service in the current working directory based on the specified Auth0 Webtasks template. - -**Create service in current working directory:** - -```bash -serverless create --template webtasks-nodejs -``` - -**Create service in new folder:** - -```bash -serverless create --template webtasks-nodejs --path my-service -``` - -## Options - -- `--template` or `-t` The name of one of the available templates. **Required if --template-url and --template-path are not present**. -- `--template-url` or `-u` The name of one of the available templates. **Required if --template and --template-path are not present**. -- `--template-path` The local path of your template. **Required if --template and --template-url are not present**. -- `--path` or `-p` The path where the service should be created. -- `--name` or `-n` the name of the service in `serverless.yml`. - -## Available Templates - -To see a list of available templates run `serverless create --help` - -The only template available for use with the Auth0 Webtasks platform is: - -- webtasks-nodejs - -## Examples - -### Creating a new service - -```bash -serverless create --template webtasks-nodejs --name my-special-service -``` - -This example will generate scaffolding for a service with `webtasks` as a provider. The scaffolding will be generated in the current working directory. - -### Creating a named service in a (new) directory - -```bash -serverless create --template webtasks-nodejs --path my-new-service -``` - -This example will generate scaffolding for a service with `webtasks` as a provider. The scaffolding will be generated in the `my-new-service` directory. This directory will be created if not present. Otherwise Serverless will use the already present directory. - -Additionally Serverless will rename the service according to the path you provide. In this example the service will be renamed to `my-new-service`. - -### Creating a new service using a local template - -```bash -serverless create --template-path path/to/my/template/folder --path path/to/my/service --name my-new-service -``` - -This will copy the `path/to/my/template/folder` folder into `path/to/my/service` and rename the service to `my-new-service`. diff --git a/docs/providers/webtasks/cli-reference/deploy.md b/docs/providers/webtasks/cli-reference/deploy.md deleted file mode 100755 index 9fec68fc6..000000000 --- a/docs/providers/webtasks/cli-reference/deploy.md +++ /dev/null @@ -1,45 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/cli-reference/deploy) - - -# Auth0 Webtasks - deploy - -The `serverless deploy` command deploys either your entire service or a single Function of your service to the Auth0 Webtasks platform. - -```bash -serverless deploy -``` - -## Options -- `--stage` or `-s` The stage in your service that you want to deploy to. The default stage is 'dev'. -- `--profile` or `-p` The Auth0 Webtasks profile to use when deploying your service. The 'serverless' profile is used by default. - -## Examples - -### Deploying an entire service - -```bash -serverless deploy -``` - -This example will deploy all of the Functions specified in the service to the Auth0 Webtasks platform. If a given function was previously deployed, it will be re-deployed with the current version of the code. - -All of the Functions will be deployed with the default 'dev' stage. Functions deployed to different stages are different webtasks on the Auth0 Webtasks platform and therefore have distinct URLs. - -### Deploying a single function - -```bash -serverless deploy function -f main -``` - -This example will deploy only the 'main' function to the Auth0 Webtasks platform. If the 'main' function was previously deployed, it will be re-deployed with the current version of the code. - -The 'main' Function will be deployed with the default 'dev' stage. \ No newline at end of file diff --git a/docs/providers/webtasks/cli-reference/info.md b/docs/providers/webtasks/cli-reference/info.md deleted file mode 100755 index e04d180c4..000000000 --- a/docs/providers/webtasks/cli-reference/info.md +++ /dev/null @@ -1,46 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/cli-reference/info) - - -# Auth0 Webtasks - Info - -Displays information about the deployed service. - -```bash -serverless info -``` - -## Options -- `--stage` or `-s` The stage in your service you want to display information about. The default stage is 'dev'. -- `--profile` or `-p` The Auth0 Webtasks profile to use when deploying your service. The 'serverless' profile is used by default. - -## Provided lifecycle events -- `info:info` - -## Examples - -### Getting info on a service - -```bash -serverless info -``` - -This example will display information about the deployed service for the default 'dev' stage. It will list the endpoints with the URL for each webtask. - -### Getting info on a given stage of the service - -```bash -serverless info --stage prod -``` - -This example will display information about the deployed service for the 'prod' stage. It will list the endpoints with the URL for each webtask. - -Functions deployed to different stages are different webtasks on the Auth0 Webtasks platform and therefore have distinct URLs. \ No newline at end of file diff --git a/docs/providers/webtasks/cli-reference/invoke.md b/docs/providers/webtasks/cli-reference/invoke.md deleted file mode 100755 index 293c4fa4c..000000000 --- a/docs/providers/webtasks/cli-reference/invoke.md +++ /dev/null @@ -1,63 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/cli-reference/invoke) - - -# Auth0 Webtasks - Invoke - -Invokes a deployed Function. It allows you to send event data to the Function and returns the response. - -```bash -serverless invoke --function functionName -``` - -## Options -- `--function` or `-f` The name of the function in your service that you want to invoke. **Required**. -- `--stage` or `-s` The stage in your service that you want to deploy to. The default stage is 'dev'. -- `--profile` or `-p` The Auth0 Webtasks profile to use when deploying your service. The 'serverless' profile is used by default. -- `--data` or `-d` String data to be passed as an event to your function. By default data is read from standard input. -- `--path` or `-p` The path to a JSON file with input data to be passed to the invoked function. This path is relative to the root directory of the service. - -## Provided lifecycle events -- `invoke:invoke` - -## Examples - -### Invoking a Function - -```bash -serverless invoke --function main -``` - -This example will invoke the 'main' function for the default 'dev' stage. The webtask will be invoked with an HTTP POST request by default. The command will return the HTTP status code and body of the response. - -### Invoking a Function with data - -```bash -serverless invoke --function main --data '{"message":"Serverless + Webtasks!"}' -``` - -This example will invoke the 'main' function for the default 'dev' stage. The webtask will be invoked with an HTTP POST and a request body that includes the JSON payload: `{"message":"Serverless + Webtasks!"}`. - -### Invoking a Function with specific HTTP method - -```bash -serverless invoke --function main --data '{"method":"GET", "body":{"message":"Serverless + Webtasks!"}}' -``` - -This example will invoke the 'main' function for the default 'dev' stage. The webtask will be invoked with an HTTP GET request and a request body that includes the JSON payload: `{"message":"Serverless + Webtasks!"}`. - -### Invoking a Function with a request query string - -```bash -serverless invoke --function main --data '{"query":{"message":"Serverless + Webtasks!"}}' -``` - -This example will invoke the 'main' function for the default 'dev' stage. The webtask will be invoked with an HTTP POST request and a request query string: `?message=Serverless%20%2B%20Webtasks!`. \ No newline at end of file diff --git a/docs/providers/webtasks/cli-reference/logs.md b/docs/providers/webtasks/cli-reference/logs.md deleted file mode 100755 index 1185cf3c4..000000000 --- a/docs/providers/webtasks/cli-reference/logs.md +++ /dev/null @@ -1,25 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/cli-reference/logs) - - -# Auth0 Webtasks - Logs - -The `serverless logs` command will allow you to connect to the streaming real-time logs from your profile on the Auth0 Webtasks platform. - -```bash -serverless logs -``` - -**Note:** The logs are streamed in real-time and not persisted. If none of your webtasks are currently executing, you will not see any log entries. - -## Options - -There are no options for this command. diff --git a/docs/providers/webtasks/cli-reference/remove.md b/docs/providers/webtasks/cli-reference/remove.md deleted file mode 100755 index 133bca784..000000000 --- a/docs/providers/webtasks/cli-reference/remove.md +++ /dev/null @@ -1,46 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/cli-reference/remove) - - -# Auth0 Webtasks - Remove - -The `serverless remove` command will remove the deployed service, defined in your current working directory. All of the Functions deployed as webtasks on the Auth0 Webtasks platform will be removed. - -```bash -serverless remove -``` - -## Options -- `--stage` or `-s` The stage in your service that you want to deploy to. The default stage is 'dev'. -- `--profile` or `-p` The Auth0 Webtasks profile to use when deploying your service. The 'serverless' profile is used by default. - -## Provided lifecycle events -- `remove:remove` - -## Examples - -### Removing the default 'dev' service - -```bash -serverless remove -``` - -This example will remove the deployed service for the default 'dev' stage. None of the endpoints for the Functions in the 'deve' stage of the service will be available afterwards. - -### Removing a given default stage of the service - -```bash -serverless info --stage prod -``` - -This example will remove the deployed service for the 'prod' stage. None of the endpoints for the Functions in the 'prod' stage of the service will be available afterwards. - -Functions deployed to different stages are different webtasks on the Auth0 Webtasks platform and therefore have distinct URLs. diff --git a/docs/providers/webtasks/events/README.md b/docs/providers/webtasks/events/README.md deleted file mode 100755 index a202cbafc..000000000 --- a/docs/providers/webtasks/events/README.md +++ /dev/null @@ -1,19 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/events/) - - -# Serverless Auth0 Webtasks Events - -Welcome to the Serverless Auth0 Webtasks Events Glossary. - -Please select a section on the left to get started. - -If you have questions specific to the Webtasks provider, please join our [Slack](http://chat.webtask.io). For general Serverless Framework questions, join the [chat in gitter](https://gitter.im/serverless/serverless) or [post over on the forums](http://forum.serverless.com/) - -**Note:** A local profile is required to use Auth0 Webtasks with the Serverless Framework. Follow the steps in the [Quick Start](../quick-start.md) to get setup in less than a minute. diff --git a/docs/providers/webtasks/events/http.md b/docs/providers/webtasks/events/http.md deleted file mode 100755 index 4d49fe7dc..000000000 --- a/docs/providers/webtasks/events/http.md +++ /dev/null @@ -1,23 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/events/apigateway) - - -# Http Event - -By default Functions with Auth0 Webtasks are configured to respond to HTTP events. The URL of the webtask is determined by name of the function. Also, any HTTP method can be used to invoke the webtask. Therefore, configuring a Function when using Auth0 webtasks for an HTTP event is as simple as specifing the handler file that contains your code. - -```yml -functions: - hello: - handler: handlerFile -``` - -**Note:** Auth0 Webtasks only supports a single handler per file. Therefore, you do not need to specify the `method` like with other Serverless providers. diff --git a/docs/providers/webtasks/events/schedule.md b/docs/providers/webtasks/events/schedule.md deleted file mode 100755 index 8a5ad75c7..000000000 --- a/docs/providers/webtasks/events/schedule.md +++ /dev/null @@ -1,37 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/events/schedule) - - -# Schedule - -The following config will attach a schedule event and causes the function `crawl` to be called every 2 hours. Auth0 Webtasks only support a single schedule per Function. - -You can either use the `rate` or `cron` syntax. - -```yml -functions: - crawl: - handler: crawl - events: - - schedule: rate(2 hours) -``` - -or with default cron syntax - -```yml -functions: - crawl: - handler: crawl - events: - - schedule: cron(0 0/2 * * *) -``` - -**Note:** Auth0 Webtasks supports the 5 field crontab format. [CronTab.guru](http://crontab.guru/) is a useful site for calculating cron schedules. \ No newline at end of file diff --git a/docs/providers/webtasks/guide/README.md b/docs/providers/webtasks/guide/README.md deleted file mode 100755 index a4a6d0838..000000000 --- a/docs/providers/webtasks/guide/README.md +++ /dev/null @@ -1,19 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/guide/) - - -# Serverless Auth0 Webtasks Guide - -Welcome to the Serverless Auth0 Webtasks Guide! - -Get started with the **[Introduction to the framework](./intro.md)** - -If you have questions specific to the Webtasks provider, please join our [Slack](http://chat.webtask.io). For general Serverless Framework questions, join the [chat in gitter](https://gitter.im/serverless/serverless) or [post over on the forums](http://forum.serverless.com/) - -**Note:** A local profile is required to use Auth0 Webtasks with the Serverless Framework. Follow the steps in the [Quick Start](../quick-start.md) to get setup in less than a minute. diff --git a/docs/providers/webtasks/guide/intro.md b/docs/providers/webtasks/guide/intro.md deleted file mode 100644 index 9a8b18cd0..000000000 --- a/docs/providers/webtasks/guide/intro.md +++ /dev/null @@ -1,66 +0,0 @@ - - - -### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/webtasks/guide/intro) - - -# Auth0 Webtasks - Introduction - -The Serverless Framework helps you develop and deploy serverless applications using Auth0 Webtasks. The Serverless CLI offers structure, automation and best practices out-of-the-box. And with Auth0 Webtasks it's simple and easy to deploy code in just seconds. - -**Note:** A local profile is required to use Auth0 Webtasks with the Serverless Framework. Follow the steps in the [Quick Start](quick-start.md) to get setup in less than a minute. - -## Core Concepts - -Here are the Framework's main concepts and how they pertain to Auth0 Webtasks... - -### Services - -A **Service** is the Framework's unit of organization. You can think of it as a project file, though you can have multiple services for a single application. - -The Auth0 Webtasks platform was designed to be simple and easy to use with minimal configuration. Therefore, services that uses Auth0 Webtasks are just a few lines of configuration in a single file, entitled `serverless.yml` (or `serverless.json` or `serverless.js`). It looks like this: - -```yml -# serverless.yml - -service: users - -provider: - name: webtasks - -functions: - user: - handler: handler - -plugins: - - '@webtask/serverless-webtasks' -``` - -### Functions - -A Function is an independent unit of deployment, like a microservice. It's merely code, deployed in the cloud, that is most often written to perform just a single job. When using Auth0 Webtasks, a Function is implemented as a webtask on the Auth0 Webtasks platform. - -You can perform multiple jobs in your code, but we don't recommend doing that without good reason. Separation of concerns is best and the Framework is designed to help you easily develop and deploy Functions, as well as manage lots of them. - -### Events - -By default, a webtask is configured to respond to HTTP events. The Auth0 Webtasks platform also supports scheduled events, so that your code can be invoked at a regular interval. - -### Plugins - -You can overwrite or extend the functionality of the Serverless Framework using **Plugins**. Every `serverless.yml` can contain a `plugins:` property, which features multiple plugins. - -In fact, the Auth0 Webtasks provider is itself a plugin and needs to be specified in the `serverless.yml` file. - -```yml -# serverless.yml - -plugins: - - '@webtask/serverless-webtasks' -``` diff --git a/docs/providers/webtasks/guide/quick-start.md b/docs/providers/webtasks/guide/quick-start.md deleted file mode 100644 index 5bcb980d7..000000000 --- a/docs/providers/webtasks/guide/quick-start.md +++ /dev/null @@ -1,50 +0,0 @@ - - -# Auth0 Webtasks - Quick Start - -This guide is designed to help you get started as quick as possible. - -## 1. Create a new service - -1. Create a new service with the [`webtasks-nodejs`](https://github.com/serverless/serverless/tree/master/lib/plugins/create/templates/webtasks-nodejs) template - -```bash -serverless create --template webtasks-nodejs --path my-service -``` - -2. Install the dependencies - -```bash -cd my-service -npm install -``` - -## 2. Set up the credentials - -Run the [config crendentials command](../cli-reference/config-credentials.md) to create a local profile. You will be asked for a phone number or email. You'll immediately receive a verification code. Enter the verification code and your profile will be entirely setup and ready to use. - -```bash -serverless config credentials --provider webtasks -``` - -## 4. Deploy - -Run the [deploy command](../cli-reference/deploy.md) - -```bash -serverless deploy -``` - -## 5. Invoke - -Run the [invoke command](../cli-reference/invoke.md) - -```bash -serverless invoke --function main -``` diff --git a/lib/classes/CLI.js b/lib/classes/CLI.js index 3d7f4b5ab..f4db30103 100644 --- a/lib/classes/CLI.js +++ b/lib/classes/CLI.js @@ -34,7 +34,33 @@ class CLI { inputArray = process.argv.slice(2); } - const argv = minimist(inputArray); + const toBase64Helper = (value, index) => { + if ((index % 2) !== 0) { + return new Buffer(value.toString()).toString('base64'); + } + return value; + }; + + const decodedArgsHelper = (arg) => { + if (_.isString(arg)) { + return new Buffer(arg, 'base64').toString(); + } + return arg; + }; + + // get all the commands + const valuesToIgnore = _.takeWhile(inputArray, (item) => !item.startsWith('-')); + // get all the options + const valuesToConvert = _.difference(inputArray, valuesToIgnore); + // encode all the options values to base64 + const valuesToB64 = _.map(valuesToConvert, toBase64Helper); + // concat commands with values on base64 + const valuesToParse = _.concat(valuesToIgnore, valuesToB64); + + const argvToParse = minimist(valuesToParse); + + // decode all values to utf8 strings + const argv = _.mapValues(argvToParse, decodedArgsHelper); const commands = [].concat(argv._); const options = _.omit(argv, ['_']); diff --git a/lib/classes/CLI.test.js b/lib/classes/CLI.test.js index 9925a75a1..112b8befa 100644 --- a/lib/classes/CLI.test.js +++ b/lib/classes/CLI.test.js @@ -362,6 +362,15 @@ describe('CLI', () => { expect(inputToBeProcessed).to.deep.equal(expectedObject); }); + it('should only return numbers like strings when numbers are given on options', () => { + cli = new CLI(serverless, ['-f', 'function1', '-k', 123]); + const inputToBeProcessed = cli.processInput(); + + const expectedObject = { commands: [], options: { f: 'function1', k: '123' } }; + + expect(inputToBeProcessed).to.deep.equal(expectedObject); + }); + it('should return commands and options when both are given', () => { cli = new CLI(serverless, ['deploy', 'functions', '-f', 'function1']); const inputToBeProcessed = cli.processInput(); diff --git a/lib/classes/PluginManager.js b/lib/classes/PluginManager.js index 2e10cf0b0..ac97772e4 100644 --- a/lib/classes/PluginManager.js +++ b/lib/classes/PluginManager.js @@ -475,13 +475,12 @@ class PluginManager { .concat(Object.keys(command.commands)); }); - const servicePath = this.serverless.config.servicePath || 'x'; - return getServerlessConfigFile(servicePath) + return getServerlessConfigFile(this.serverless.config.servicePath) .then((serverlessConfigFile) => { const serverlessConfigFileHash = crypto.createHash('sha256') .update(JSON.stringify(serverlessConfigFile)).digest('hex'); cacheFile.validationHash = serverlessConfigFileHash; - const cacheFilePath = getCacheFilePath(servicePath); + const cacheFilePath = getCacheFilePath(this.serverless.config.servicePath); return writeFile(cacheFilePath, cacheFile); }) .catch((e) => null); // eslint-disable-line diff --git a/lib/plugins/aws/deploy/lib/checkForChanges.js b/lib/plugins/aws/deploy/lib/checkForChanges.js index 0254de25c..ec8640875 100644 --- a/lib/plugins/aws/deploy/lib/checkForChanges.js +++ b/lib/plugins/aws/deploy/lib/checkForChanges.js @@ -27,7 +27,7 @@ module.exports = { const params = { Bucket: this.bucketName, - Prefix: `serverless/${service}/${this.provider.getStage()}`, + Prefix: `${this.provider.getDeploymentPrefix()}/${service}/${this.provider.getStage()}`, }; return this.provider.request('S3', diff --git a/lib/plugins/aws/deploy/lib/cleanupS3Bucket.js b/lib/plugins/aws/deploy/lib/cleanupS3Bucket.js index e54403609..4f2bbfb2d 100644 --- a/lib/plugins/aws/deploy/lib/cleanupS3Bucket.js +++ b/lib/plugins/aws/deploy/lib/cleanupS3Bucket.js @@ -10,18 +10,19 @@ module.exports = { const stacksToKeepCount = 5; const service = this.serverless.service.service; const stage = this.provider.getStage(); + const prefix = this.provider.getDeploymentPrefix(); return this.provider.request('S3', 'listObjectsV2', { Bucket: this.bucketName, - Prefix: `serverless/${service}/${stage}`, + Prefix: `${prefix}/${service}/${stage}`, }) .then((response) => { - const stacks = findAndGroupDeployments(response, service, stage); + const stacks = findAndGroupDeployments(response, prefix, service, stage); const stacksToKeep = _.takeRight(stacks, stacksToKeepCount); const stacksToRemove = _.pullAllWith(stacks, stacksToKeep, _.isEqual); - const objectsToRemove = getS3ObjectsFromStacks(stacksToRemove, service, stage); + const objectsToRemove = getS3ObjectsFromStacks(stacksToRemove, prefix, service, stage); if (objectsToRemove.length) { return BbPromise.resolve(objectsToRemove); diff --git a/lib/plugins/aws/deploy/lib/cleanupS3Bucket.test.js b/lib/plugins/aws/deploy/lib/cleanupS3Bucket.test.js index d15d6cd7a..84447eedc 100644 --- a/lib/plugins/aws/deploy/lib/cleanupS3Bucket.test.js +++ b/lib/plugins/aws/deploy/lib/cleanupS3Bucket.test.js @@ -29,7 +29,8 @@ describe('cleanupS3Bucket', () => { provider = new AwsProvider(serverless, options); serverless.setProvider('aws', provider); serverless.service.service = 'cleanupS3Bucket'; - s3Key = `serverless/${serverless.service.service}/${provider.getStage()}`; + const prefix = provider.getDeploymentPrefix(); + s3Key = `${prefix}/${serverless.service.service}/${provider.getStage()}`; awsDeploy = new AwsDeploy(serverless, options); awsDeploy.bucketName = 'deployment-bucket'; awsDeploy.serverless.cli = new serverless.classes.CLI(); diff --git a/lib/plugins/aws/deploy/lib/createDeployment.js b/lib/plugins/aws/deploy/lib/createDeployment.js index 943832404..1f4d981e2 100644 --- a/lib/plugins/aws/deploy/lib/createDeployment.js +++ b/lib/plugins/aws/deploy/lib/createDeployment.js @@ -1,11 +1,17 @@ 'use strict'; +const path = require('path'); +const fs = require('fs'); const platform = require('@serverless/platform-sdk'); const BbPromise = require('bluebird'); const getAccessKey = require('../../../../utils/getAccessKey'); module.exports = { createDeployment() { + const serverlessStateFilePath = path.join( + this.serverless.config.servicePath, '.serverless', 'serverless-state.json'); + const serverlessStateFileContent = JSON.parse(fs.readFileSync(serverlessStateFilePath, 'utf8')); + return getAccessKey(this.serverless.service.tenant).then(accessKey => { if (accessKey && this.serverless.service.app && this.serverless.service.tenant && @@ -15,6 +21,9 @@ module.exports = { app: this.serverless.service.app, accessKey, serviceName: this.serverless.service.service, + files: { + 'serverless-state.json': serverlessStateFileContent, + }, }; return platform.createDeployment(deploymentData) .then((res) => { diff --git a/lib/plugins/aws/deploy/lib/createStack.test.js b/lib/plugins/aws/deploy/lib/createStack.test.js index eff833e45..95d5375f8 100644 --- a/lib/plugins/aws/deploy/lib/createStack.test.js +++ b/lib/plugins/aws/deploy/lib/createStack.test.js @@ -50,6 +50,7 @@ describe('createStack', () => { const createStackStub = sandbox .stub(awsDeploy.provider, 'request').resolves(); sandbox.stub(awsDeploy, 'monitorStack').resolves(); + sandbox.stub(awsDeploy, 'createDeployment').resolves(); return awsDeploy.create().then(() => { expect(createStackStub.args[0][2].Tags) @@ -66,6 +67,7 @@ describe('createStack', () => { const createStackStub = sandbox .stub(awsDeploy.provider, 'request').resolves(); sandbox.stub(awsDeploy, 'monitorStack').resolves(); + sandbox.stub(awsDeploy, 'createDeployment').resolves(); return awsDeploy.create().then(() => { expect(createStackStub.args[0][2].RoleARN) @@ -80,6 +82,7 @@ describe('createStack', () => { const createStackStub = sinon .stub(awsDeploy.provider, 'request').resolves(); sinon.stub(awsDeploy, 'monitorStack').resolves(); + sinon.stub(awsDeploy, 'createDeployment').resolves(); return awsDeploy.create().then(() => { expect(createStackStub.args[0][2].NotificationARNs) diff --git a/lib/plugins/aws/deploy/lib/validateTemplate.test.js b/lib/plugins/aws/deploy/lib/validateTemplate.test.js index 8d504a45b..8d4e7c5b7 100644 --- a/lib/plugins/aws/deploy/lib/validateTemplate.test.js +++ b/lib/plugins/aws/deploy/lib/validateTemplate.test.js @@ -35,6 +35,7 @@ describe('validateTemplate', () => { }, }; validateTemplateStub = sinon.stub(awsDeploy.provider, 'request'); + sinon.stub(awsDeploy, 'createDeployment').resolves(); awsDeploy.serverless.cli = { log: sinon.spy(), }; @@ -42,6 +43,7 @@ describe('validateTemplate', () => { afterEach(() => { awsDeploy.provider.request.restore(); + awsDeploy.createDeployment.restore(); }); describe('#validateTemplate()', () => { diff --git a/lib/plugins/aws/deployFunction/index.js b/lib/plugins/aws/deployFunction/index.js index daef82b2e..db92c4939 100644 --- a/lib/plugins/aws/deployFunction/index.js +++ b/lib/plugins/aws/deployFunction/index.js @@ -129,6 +129,10 @@ class AwsDeployFunction { params.Description = functionObj.description; } + if ('handler' in functionObj && !_.isObject(functionObj.handler)) { + params.Handler = functionObj.handler; + } + if ('memorySize' in functionObj && !_.isObject(functionObj.memorySize)) { params.MemorySize = functionObj.memorySize; } else if ('memorySize' in providerObj && !_.isObject(providerObj.memorySize)) { diff --git a/lib/plugins/aws/deployFunction/index.test.js b/lib/plugins/aws/deployFunction/index.test.js index 6b61d129b..e68fcfe7c 100644 --- a/lib/plugins/aws/deployFunction/index.test.js +++ b/lib/plugins/aws/deployFunction/index.test.js @@ -218,6 +218,7 @@ describe('AwsDeployFunction', () => { options.functionObj = { awsKmsKeyArn: 'arn:aws:kms:us-east-1:123456789012', description: 'desc', + handler: 'my_handler', environment: { VARIABLE: 'value', }, @@ -245,6 +246,7 @@ describe('AwsDeployFunction', () => { DeadLetterConfig: { TargetArn: 'arn:aws:sqs:us-east-1:123456789012:dlq', }, + Handler: 'my_handler', Description: 'desc', Environment: { Variables: { @@ -291,6 +293,7 @@ describe('AwsDeployFunction', () => { options.functionObj = { name: 'first', description: 'change', + handler: 'my_handler', vpc: { securityGroupIds: ['xxxxx', { ref: 'myVPCRef', @@ -316,6 +319,7 @@ describe('AwsDeployFunction', () => { 'updateFunctionConfiguration', { FunctionName: 'first', + Handler: 'my_handler', Description: 'change', } )).to.be.equal(true); @@ -357,6 +361,7 @@ describe('AwsDeployFunction', () => { () => { options.functionObj = { name: 'first', + handler: 'my_handler', description: 'change', environment: { COUNTER: 6, @@ -372,6 +377,7 @@ describe('AwsDeployFunction', () => { 'updateFunctionConfiguration', { FunctionName: 'first', + Handler: 'my_handler', Description: 'change', Environment: { Variables: { @@ -386,6 +392,7 @@ describe('AwsDeployFunction', () => { it('should inherit provider-level config', () => { options.functionObj = { name: 'first', + handler: 'my_handler', description: 'change', }; @@ -408,6 +415,7 @@ describe('AwsDeployFunction', () => { 'updateFunctionConfiguration', { FunctionName: 'first', + Handler: 'my_handler', Description: 'change', VpcConfig: { SubnetIds: [1234, 12345], diff --git a/lib/plugins/aws/deployList/index.js b/lib/plugins/aws/deployList/index.js index 00a70f98b..81f651854 100644 --- a/lib/plugins/aws/deployList/index.js +++ b/lib/plugins/aws/deployList/index.js @@ -35,17 +35,18 @@ class AwsDeployList { listDeployments() { const service = this.serverless.service.service; const stage = this.provider.getStage(); + const prefix = this.provider.getDeploymentPrefix(); return this.provider.request('S3', 'listObjectsV2', { Bucket: this.bucketName, - Prefix: `serverless/${service}/${stage}`, + Prefix: `${prefix}/${service}/${stage}`, } ) .then((response) => { const directoryRegex = new RegExp('(.+)-(.+-.+-.+)'); - const deployments = findAndGroupDeployments(response, service, stage); + const deployments = findAndGroupDeployments(response, prefix, service, stage); if (deployments.length === 0) { this.serverless.cli.log('Couldn\'t find any existing deployments.'); diff --git a/lib/plugins/aws/deployList/index.test.js b/lib/plugins/aws/deployList/index.test.js index e6aea30bc..92ea6568b 100644 --- a/lib/plugins/aws/deployList/index.test.js +++ b/lib/plugins/aws/deployList/index.test.js @@ -21,7 +21,8 @@ describe('AwsDeployList', () => { provider = new AwsProvider(serverless, options); serverless.setProvider('aws', provider); serverless.service.service = 'listDeployments'; - s3Key = `serverless/${serverless.service.service}/${provider.getStage()}`; + const prefix = provider.getDeploymentPrefix(); + s3Key = `${prefix}/${serverless.service.service}/${provider.getStage()}`; awsDeployList = new AwsDeployList(serverless, options); awsDeployList.bucketName = 'deployment-bucket'; awsDeployList.serverless.cli = { diff --git a/lib/plugins/aws/invokeLocal/index.js b/lib/plugins/aws/invokeLocal/index.js index fe6e99e44..64a56ec49 100644 --- a/lib/plugins/aws/invokeLocal/index.js +++ b/lib/plugins/aws/invokeLocal/index.js @@ -249,7 +249,6 @@ class AwsInvokeLocal { } invokeLocalNodeJs(handlerPath, handlerName, event, customContext) { - this.serverless.cli.log('INVOKING INVOKE'); let lambda; let pathToHandler; let hasResponded = false; diff --git a/lib/plugins/aws/invokeLocal/invoke.py b/lib/plugins/aws/invokeLocal/invoke.py index 02ba1d69f..cd10e7910 100755 --- a/lib/plugins/aws/invokeLocal/invoke.py +++ b/lib/plugins/aws/invokeLocal/invoke.py @@ -2,7 +2,7 @@ import argparse import json import logging import sys -from time import time +from time import strftime, time from importlib import import_module class FakeLambdaContext(object): @@ -31,12 +31,23 @@ class FakeLambdaContext(object): @property def memory_limit_in_mb(self): - return 1024 + return '1024' @property def aws_request_id(self): return '1234567890' + @property + def log_group_name(self): + return '/aws/lambda/' + self.name + + @property + def log_stream_name(self): + return strftime('%Y/%m/%d') +'/[$' + self.version + ']58419525dade4d17a495dceeeed44708' + + @property + def log(self): + return sys.stdout.write logging.basicConfig() diff --git a/lib/plugins/aws/lib/cloudformationSchema.js b/lib/plugins/aws/lib/cloudformationSchema.js new file mode 100644 index 000000000..5e140de2e --- /dev/null +++ b/lib/plugins/aws/lib/cloudformationSchema.js @@ -0,0 +1,51 @@ +'use strict'; + +const YAML = require('js-yaml'); +const _ = require('lodash'); + +const functionNames = [ + 'And', + 'Base64', + 'Cidr', + 'Condition', + 'Equals', + 'FindInMap', + 'GetAtt', + 'GetAZs', + 'If', + 'ImportValue', + 'Join', + 'Not', + 'Or', + 'Ref', + 'Select', + 'Split', + 'Sub', +]; + +const yamlType = (name, kind) => { + const functionName = _.includes(['Ref', 'Condition'], name) ? name : `Fn::${name}`; + return new YAML.Type(`!${name}`, { + kind, + construct: data => { + if (name === 'GetAtt') { + // special GetAtt dot syntax + return { [functionName]: _.isString(data) ? _.split(data, '.', 2) : data }; + } + return { [functionName]: data }; + }, + }); +}; + +const createSchema = () => { + const types = _.flatten( + _.map(functionNames, functionName => + _.map(['mapping', 'scalar', 'sequence'], kind => yamlType(functionName, kind)) + ) + ); + return YAML.Schema.create(types); +}; + +module.exports = { + schema: createSchema(), +}; diff --git a/lib/plugins/aws/lib/cloudformationSchema.test.js b/lib/plugins/aws/lib/cloudformationSchema.test.js new file mode 100644 index 000000000..2ec7434f1 --- /dev/null +++ b/lib/plugins/aws/lib/cloudformationSchema.test.js @@ -0,0 +1,20 @@ +'use strict'; + +const expect = require('chai').expect; + +const cloudformationSchema = require('./cloudformationSchema'); + +describe('#cloudformationSchame()', () => { + describe('#schema()', () => { + it('should contain schema', () => { + expect(Object.keys(cloudformationSchema.schema)).to.be.eql([ + 'include', + 'implicit', + 'explicit', + 'compiledImplicit', + 'compiledExplicit', + 'compiledTypeMap', + ]); + }); + }); +}); diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.js index 4fe96e7f4..1f467b64e 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.js @@ -34,6 +34,11 @@ module.exports = { } } + // Allow Cache-Control header if set + if (_.has(config, 'cacheControl')) { + preflightHeaders['Cache-Control'] = `'${config.cacheControl}'`; + } + if (_.includes(config.methods, 'ANY')) { preflightHeaders['Access-Control-Allow-Methods'] = preflightHeaders['Access-Control-Allow-Methods'] diff --git a/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.test.js b/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.test.js index 128b0375e..6b45f83ff 100644 --- a/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.test.js +++ b/lib/plugins/aws/package/compile/events/apiGateway/lib/cors.test.js @@ -68,6 +68,7 @@ describe('#compileCors()', () => { methods: ['OPTIONS', 'PUT'], allowCredentials: false, maxAge: 86400, + cacheControl: 'max-age=600, s-maxage=600', }, 'users/create': { origins: ['*', 'http://example.com'], @@ -75,6 +76,7 @@ describe('#compileCors()', () => { methods: ['OPTIONS', 'POST'], allowCredentials: true, maxAge: 86400, + cacheControl: 'max-age=600, s-maxage=600', }, 'users/delete': { origins: ['*'], @@ -82,6 +84,7 @@ describe('#compileCors()', () => { methods: ['OPTIONS', 'DELETE'], allowCredentials: false, maxAge: 86400, + cacheControl: 'max-age=600, s-maxage=600', }, 'users/any': { origins: ['http://example.com'], @@ -127,6 +130,13 @@ describe('#compileCors()', () => { .ResponseParameters['method.response.header.Access-Control-Max-Age'] ).to.equal('\'86400\''); + expect( + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate + .Resources.ApiGatewayMethodUsersCreateOptions + .Properties.Integration.IntegrationResponses[0] + .ResponseParameters['method.response.header.Cache-Control'] + ).to.equal('\'max-age=600, s-maxage=600\''); + // users/update expect( awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate @@ -156,6 +166,13 @@ describe('#compileCors()', () => { .ResponseParameters['method.response.header.Access-Control-Max-Age'] ).to.equal('\'86400\''); + expect( + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate + .Resources.ApiGatewayMethodUsersUpdateOptions + .Properties.Integration.IntegrationResponses[0] + .ResponseParameters['method.response.header.Cache-Control'] + ).to.equal('\'max-age=600, s-maxage=600\''); + // users/delete expect( awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate @@ -192,6 +209,13 @@ describe('#compileCors()', () => { .ResponseParameters['method.response.header.Access-Control-Max-Age'] ).to.equal('\'86400\''); + expect( + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate + .Resources.ApiGatewayMethodUsersDeleteOptions + .Properties.Integration.IntegrationResponses[0] + .ResponseParameters['method.response.header.Cache-Control'] + ).to.equal('\'max-age=600, s-maxage=600\''); + // users/any expect( awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate diff --git a/lib/plugins/aws/package/compile/events/schedule/index.js b/lib/plugins/aws/package/compile/events/schedule/index.js index 5ec91bd46..42cd9f997 100644 --- a/lib/plugins/aws/package/compile/events/schedule/index.js +++ b/lib/plugins/aws/package/compile/events/schedule/index.js @@ -61,6 +61,20 @@ class AwsCompileScheduledEvents { } if (Input && typeof Input === 'object') { + if (_.has(Input, 'body') && typeof Input.body === 'string') { + try { + Input.body = JSON.parse(Input.body); + } catch (error) { + const errorMessage = [ + 'The body of the schedule event associated with', + ` ${functionName} was passed as a string`, + ' but it failed to parse to a JSON object.', + ' Please check the docs for more info.', + ].join(''); + throw new this.serverless.classes + .Error(errorMessage); + } + } Input = JSON.stringify(Input); } if (Input && typeof Input === 'string') { diff --git a/lib/plugins/aws/package/compile/events/schedule/index.test.js b/lib/plugins/aws/package/compile/events/schedule/index.test.js index bb3eb72a0..af6a7d0be 100644 --- a/lib/plugins/aws/package/compile/events/schedule/index.test.js +++ b/lib/plugins/aws/package/compile/events/schedule/index.test.js @@ -287,6 +287,46 @@ describe('AwsCompileScheduledEvents', () => { expect(() => awsCompileScheduledEvents.compileScheduledEvents()).to.throw(Error); }); + it('should not throw an error when Input body is a valid JSON string', () => { + awsCompileScheduledEvents.serverless.service.functions = { + first: { + events: [ + { + schedule: { + rate: 'rate(10 minutes)', + enabled: false, + input: { + body: '{ "functionId": "..." }', + }, + }, + }, + ], + }, + }; + + expect(() => awsCompileScheduledEvents.compileScheduledEvents()).not.to.throw(Error); + }); + + it('should throw an error when Input body is an invalid JSON string', () => { + awsCompileScheduledEvents.serverless.service.functions = { + first: { + events: [ + { + schedule: { + rate: 'rate(10 minutes)', + enabled: false, + input: { + body: 'an invalid input body', + }, + }, + }, + ], + }, + }; + + expect(() => awsCompileScheduledEvents.compileScheduledEvents()).to.throw(Error); + }); + it('should not create corresponding resources when scheduled events are not given', () => { awsCompileScheduledEvents.serverless.service.functions = { first: { diff --git a/lib/plugins/aws/package/compile/events/sns/index.js b/lib/plugins/aws/package/compile/events/sns/index.js index cde37bd2f..d07c343d9 100644 --- a/lib/plugins/aws/package/compile/events/sns/index.js +++ b/lib/plugins/aws/package/compile/events/sns/index.js @@ -105,10 +105,10 @@ class AwsCompileSNSEvents { 'Fn::GetAtt': [lambdaLogicalId, 'Arn'], }; - if (topicArn) { - const subscriptionLogicalId = this.provider.naming - .getLambdaSnsSubscriptionLogicalId(functionName, topicName); + const subscriptionLogicalId = this.provider.naming + .getLambdaSnsSubscriptionLogicalId(functionName, topicName); + if (topicArn) { _.merge(template.Resources, { [subscriptionLogicalId]: { Type: 'AWS::SNS::Subscription', @@ -116,6 +116,7 @@ class AwsCompileSNSEvents { TopicArn: topicArn, Protocol: 'lambda', Endpoint: endpoint, + FilterPolicy: event.sns.filterPolicy, }, }, }); @@ -134,6 +135,7 @@ class AwsCompileSNSEvents { ], ], }; + const topicLogicalId = this.provider.naming .getTopicLogicalId(topicName); @@ -142,21 +144,38 @@ class AwsCompileSNSEvents { Protocol: 'lambda', }; - if (topicLogicalId in template.Resources) { - template.Resources[topicLogicalId] - .Properties.Subscription.push(subscription); - } else { + if (!(topicLogicalId in template.Resources)) { _.merge(template.Resources, { [topicLogicalId]: { Type: 'AWS::SNS::Topic', Properties: { TopicName: topicName, DisplayName: displayName, - Subscription: [subscription], }, }, }); } + + if (event.sns.filterPolicy) { + _.merge(template.Resources, { + [subscriptionLogicalId]: { + Type: 'AWS::SNS::Subscription', + Properties: + _.merge(subscription, { + TopicArn: { + Ref: topicLogicalId, + }, + FilterPolicy: event.sns.filterPolicy, + }), + }, + }); + } else { + if (!template.Resources[topicLogicalId].Properties.Subscription) { + template.Resources[topicLogicalId].Properties.Subscription = []; + } + template.Resources[topicLogicalId] + .Properties.Subscription.push(subscription); + } } const lambdaPermissionLogicalId = this.provider.naming diff --git a/lib/plugins/aws/package/compile/events/sns/index.test.js b/lib/plugins/aws/package/compile/events/sns/index.test.js index edcbe67d0..504d34a96 100644 --- a/lib/plugins/aws/package/compile/events/sns/index.test.js +++ b/lib/plugins/aws/package/compile/events/sns/index.test.js @@ -44,6 +44,9 @@ describe('AwsCompileSNSEvents', () => { sns: { topicName: 'Topic 1', displayName: 'Display name for topic 1', + filterPolicy: { + pet: ['dog', 'cat'], + }, }, }, { @@ -67,6 +70,67 @@ describe('AwsCompileSNSEvents', () => { expect(awsCompileSNSEvents.serverless.service .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionTopic2SNS.Type ).to.equal('AWS::Lambda::Permission'); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources.FirstSnsSubscriptionTopic1.Type + ).to.equal('AWS::SNS::Subscription'); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate + .Resources.FirstSnsSubscriptionTopic1.Properties.FilterPolicy + ).to.eql({ pet: ['dog', 'cat'] }); + }); + + it('should create corresponding resources when topic is defined in resources', () => { + awsCompileSNSEvents.serverless.service.functions = { + first: { + events: [ + { + sns: { + topicName: 'Topic 1', + displayName: 'Display name for topic 1', + filterPolicy: { + pet: ['dog', 'cat'], + }, + }, + }, + { + sns: 'Topic 2', + }, + ], + }, + }; + + Object.assign(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources, { + SNSTopicTopic2: { + Type: 'AWS::SNS::Topic', + Properties: { + TopicName: 'Topic 2', + DisplayName: 'Display name for topic 2', + }, + }, + }); + + awsCompileSNSEvents.compileSNSEvents(); + + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources.SNSTopicTopic1.Type + ).to.equal('AWS::SNS::Topic'); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources.SNSTopicTopic2.Type + ).to.equal('AWS::SNS::Topic'); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionTopic1SNS.Type + ).to.equal('AWS::Lambda::Permission'); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionTopic2SNS.Type + ).to.equal('AWS::Lambda::Permission'); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources.FirstSnsSubscriptionTopic1.Type + ).to.equal('AWS::SNS::Subscription'); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate + .Resources.FirstSnsSubscriptionTopic1.Properties.FilterPolicy + ).to.eql({ pet: ['dog', 'cat'] }); }); it('should create single SNS topic when the same topic is referenced repeatedly', () => { @@ -94,10 +158,6 @@ describe('AwsCompileSNSEvents', () => { expect(awsCompileSNSEvents.serverless.service .provider.compiledCloudFormationTemplate.Resources.SNSTopicTopic1.Type ).to.equal('AWS::SNS::Topic'); - expect(awsCompileSNSEvents.serverless.service - .provider.compiledCloudFormationTemplate.Resources.SNSTopicTopic1 - .Properties.Subscription.length - ).to.equal(2); expect(awsCompileSNSEvents.serverless.service .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionTopic1SNS.Type ).to.equal('AWS::Lambda::Permission'); @@ -156,6 +216,10 @@ describe('AwsCompileSNSEvents', () => { expect(awsCompileSNSEvents.serverless.service .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionFooSNS.Type ).to.equal('AWS::Lambda::Permission'); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate + .Resources.FirstSnsSubscriptionFoo.Properties.FilterPolicy + ).to.equal(undefined); }); it('should create SNS topic when only arn is given as an object property', () => { @@ -184,6 +248,22 @@ describe('AwsCompileSNSEvents', () => { ).to.equal('AWS::Lambda::Permission'); }); + it('should throw an error when the arn an object and the value is not a string', () => { + awsCompileSNSEvents.serverless.service.functions = { + first: { + events: [ + { + sns: { + arn: 123, + }, + }, + ], + }, + }; + + expect(() => { awsCompileSNSEvents.compileSNSEvents(); }).to.throw(Error); + }); + it('should create SNS topic when arn and topicName are given as object properties', () => { awsCompileSNSEvents.serverless.service.functions = { first: { @@ -210,5 +290,39 @@ describe('AwsCompileSNSEvents', () => { .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionBarSNS.Type ).to.equal('AWS::Lambda::Permission'); }); + + it('should create SNS topic when arn, topicName, and filterPolicy are given as object', () => { + awsCompileSNSEvents.serverless.service.functions = { + first: { + events: [ + { + sns: { + topicName: 'bar', + arn: 'arn:aws:sns:region:accountid:bar', + filterPolicy: { + pet: ['dog', 'cat'], + }, + }, + }, + ], + }, + }; + + awsCompileSNSEvents.compileSNSEvents(); + + expect(Object.keys(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources) + ).to.have.length(2); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources.FirstSnsSubscriptionBar.Type + ).to.equal('AWS::SNS::Subscription'); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate + .Resources.FirstSnsSubscriptionBar.Properties.FilterPolicy + ).to.eql({ pet: ['dog', 'cat'] }); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionBarSNS.Type + ).to.equal('AWS::Lambda::Permission'); + }); }); }); diff --git a/lib/plugins/aws/package/lib/generateArtifactDirectoryName.js b/lib/plugins/aws/package/lib/generateArtifactDirectoryName.js index 8a3840754..795fd3081 100644 --- a/lib/plugins/aws/package/lib/generateArtifactDirectoryName.js +++ b/lib/plugins/aws/package/lib/generateArtifactDirectoryName.js @@ -7,8 +7,9 @@ module.exports = { const date = new Date(); const serviceStage = `${this.serverless.service.service}/${this.provider.getStage()}`; const dateString = `${date.getTime().toString()}-${date.toISOString()}`; + const prefix = this.provider.getDeploymentPrefix(); this.serverless.service.package - .artifactDirectoryName = `serverless/${serviceStage}/${dateString}`; + .artifactDirectoryName = `${prefix}/${serviceStage}/${dateString}`; return BbPromise.resolve(); }, diff --git a/lib/plugins/aws/provider/awsProvider.js b/lib/plugins/aws/provider/awsProvider.js index 440735642..53b49ee01 100644 --- a/lib/plugins/aws/provider/awsProvider.js +++ b/lib/plugins/aws/provider/awsProvider.js @@ -266,6 +266,7 @@ class AwsProvider { { providerError: _.assign({}, err, { retryable: false }) } )); } + return BbPromise.reject(Object.assign( new this.serverless.classes.Error(message, err.statusCode), { providerError: err } @@ -390,6 +391,10 @@ class AwsProvider { ).then((result) => result.StackResourceDetail.PhysicalResourceId); } + getDeploymentPrefix() { + return this.serverless.service.provider.deploymentPrefix || 'serverless'; + } + getStageSourceValue() { const values = this.getValues(this, [ ['options', 'stage'], diff --git a/lib/plugins/aws/provider/awsProvider.test.js b/lib/plugins/aws/provider/awsProvider.test.js index b518cc28d..cc31e3be6 100644 --- a/lib/plugins/aws/provider/awsProvider.test.js +++ b/lib/plugins/aws/provider/awsProvider.test.js @@ -911,6 +911,21 @@ describe('AwsProvider', () => { }); }); + describe('#getDeploymentPrefix()', () => { + it('should return custom deployment prefix if defined', () => { + serverless.service.provider.deploymentPrefix = 'providerPrefix'; + + expect(awsProvider.getDeploymentPrefix()) + .to.equal(serverless.service.provider.deploymentPrefix); + }); + + it('should use the default serverless if not defined', () => { + serverless.service.provider.deploymentPrefix = undefined; + + expect(awsProvider.getDeploymentPrefix()).to.equal('serverless'); + }); + }); + describe('#getStage()', () => { it('should prefer options over config or provider', () => { const newOptions = { diff --git a/lib/plugins/aws/remove/lib/bucket.js b/lib/plugins/aws/remove/lib/bucket.js index d9308d2c1..b67abf82e 100644 --- a/lib/plugins/aws/remove/lib/bucket.js +++ b/lib/plugins/aws/remove/lib/bucket.js @@ -18,7 +18,7 @@ module.exports = { return this.provider.request('S3', 'listObjectsV2', { Bucket: this.bucketName, - Prefix: `serverless/${serviceStage}`, + Prefix: `${this.provider.getDeploymentPrefix()}/${serviceStage}`, }).then((result) => { if (result) { result.Contents.forEach((object) => { diff --git a/lib/plugins/aws/remove/lib/bucket.test.js b/lib/plugins/aws/remove/lib/bucket.test.js index e4b8b77eb..8714e96fc 100644 --- a/lib/plugins/aws/remove/lib/bucket.test.js +++ b/lib/plugins/aws/remove/lib/bucket.test.js @@ -42,6 +42,9 @@ describe('emptyS3Bucket', () => { const listObjectsStub = sinon.stub(awsRemove.provider, 'request') .resolves(); + const stage = awsRemove.provider.getStage(); + const prefix = awsRemove.provider.getDeploymentPrefix(); + return awsRemove.listObjects().then(() => { expect(listObjectsStub.calledOnce).to.be.equal(true); expect(listObjectsStub.calledWithExactly( @@ -49,7 +52,7 @@ describe('emptyS3Bucket', () => { 'listObjectsV2', { Bucket: awsRemove.bucketName, - Prefix: `serverless/${serverless.service.service}/${awsRemove.provider.getStage()}`, + Prefix: `${prefix}/${serverless.service.service}/${stage}`, } )).to.be.equal(true); expect(awsRemove.objectsInBucket.length).to.equal(0); @@ -66,6 +69,9 @@ describe('emptyS3Bucket', () => { ], }); + const stage = awsRemove.provider.getStage(); + const prefix = awsRemove.provider.getDeploymentPrefix(); + return awsRemove.listObjects().then(() => { expect(listObjectsStub.calledOnce).to.be.equal(true); expect(listObjectsStub.calledWithExactly( @@ -73,7 +79,7 @@ describe('emptyS3Bucket', () => { 'listObjectsV2', { Bucket: awsRemove.bucketName, - Prefix: `serverless/${serverless.service.service}/${awsRemove.provider.getStage()}`, + Prefix: `${prefix}/${serverless.service.service}/${stage}`, } )).to.be.equal(true); expect(awsRemove.objectsInBucket[0]).to.deep.equal({ Key: 'object1' }); diff --git a/lib/plugins/aws/rollback/index.js b/lib/plugins/aws/rollback/index.js index 9a7ca5edc..296da4df1 100644 --- a/lib/plugins/aws/rollback/index.js +++ b/lib/plugins/aws/rollback/index.js @@ -47,7 +47,8 @@ class AwsRollback { const service = this.serverless.service; const serviceName = this.serverless.service.service; const stage = this.provider.getStage(); - const prefix = `serverless/${serviceName}/${stage}`; + const deploymentPrefix = this.provider.getDeploymentPrefix(); + const prefix = `${deploymentPrefix}/${serviceName}/${stage}`; return this.provider.request('S3', 'listObjectsV2', @@ -56,7 +57,7 @@ class AwsRollback { Prefix: prefix, }) .then((response) => { - const deployments = findAndGroupDeployments(response, serviceName, stage); + const deployments = findAndGroupDeployments(response, deploymentPrefix, serviceName, stage); if (deployments.length === 0) { const msg = 'Couldn\'t find any existing deployments.'; diff --git a/lib/plugins/aws/rollback/index.test.js b/lib/plugins/aws/rollback/index.test.js index edd096c5f..93549df5c 100644 --- a/lib/plugins/aws/rollback/index.test.js +++ b/lib/plugins/aws/rollback/index.test.js @@ -27,7 +27,8 @@ describe('AwsRollback', () => { spawnStub = sinon.stub(serverless.pluginManager, 'spawn'); awsRollback = new AwsRollback(serverless, options); awsRollback.serverless.cli = new serverless.classes.CLI(); - s3Key = `serverless/${serverless.service.service}/${provider.getStage()}`; + const prefix = provider.getDeploymentPrefix(); + s3Key = `${prefix}/${serverless.service.service}/${provider.getStage()}`; }); afterEach(() => { diff --git a/lib/plugins/aws/utils/findAndGroupDeployments.js b/lib/plugins/aws/utils/findAndGroupDeployments.js index 0dc9a570a..aef6e7d36 100644 --- a/lib/plugins/aws/utils/findAndGroupDeployments.js +++ b/lib/plugins/aws/utils/findAndGroupDeployments.js @@ -2,9 +2,9 @@ const _ = require('lodash'); -module.exports = (s3Response, service, stage) => { +module.exports = (s3Response, prefix, service, stage) => { if (s3Response.Contents.length) { - const regex = new RegExp(`serverless/${service}/${stage}/(.+-.+-.+-.+)/(.+)`); + const regex = new RegExp(`${prefix}/${service}/${stage}/(.+-.+-.+-.+)/(.+)`); const s3Objects = s3Response.Contents.filter((s3Object) => s3Object.Key.match(regex)); const names = s3Objects.map((s3Object) => { const match = s3Object.Key.match(regex); diff --git a/lib/plugins/aws/utils/findAndGroupDeployments.test.js b/lib/plugins/aws/utils/findAndGroupDeployments.test.js index 0977869b1..17406cf84 100644 --- a/lib/plugins/aws/utils/findAndGroupDeployments.test.js +++ b/lib/plugins/aws/utils/findAndGroupDeployments.test.js @@ -9,7 +9,7 @@ describe('#findAndGroupDeployments()', () => { Contents: [], }; - expect(findAndGroupDeployments(s3Response, 'test', 'dev')).to.deep.equal([]); + expect(findAndGroupDeployments(s3Response, 'serverless', 'test', 'dev')).to.deep.equal([]); }); it('should group stacks', () => { @@ -73,6 +73,7 @@ describe('#findAndGroupDeployments()', () => { ], ]; - expect(findAndGroupDeployments(s3Response, 'test', 'dev')).to.deep.equal(expected); + expect(findAndGroupDeployments(s3Response, 'serverless', 'test', 'dev')) + .to.deep.equal(expected); }); }); diff --git a/lib/plugins/aws/utils/getS3ObjectsFromStacks.js b/lib/plugins/aws/utils/getS3ObjectsFromStacks.js index 8ae79200a..1a98dc822 100644 --- a/lib/plugins/aws/utils/getS3ObjectsFromStacks.js +++ b/lib/plugins/aws/utils/getS3ObjectsFromStacks.js @@ -2,8 +2,8 @@ const _ = require('lodash'); -module.exports = (stacks, service, stage) => ( +module.exports = (stacks, prefix, service, stage) => ( _.flatten(stacks).map((entry) => ( - { Key: `serverless/${service}/${stage}/${entry.directory}/${entry.file}` }) + { Key: `${prefix}/${service}/${stage}/${entry.directory}/${entry.file}` }) ) ); diff --git a/lib/plugins/aws/utils/getS3ObjectsFromStacks.test.js b/lib/plugins/aws/utils/getS3ObjectsFromStacks.test.js index d5f9851a7..df6f4beda 100644 --- a/lib/plugins/aws/utils/getS3ObjectsFromStacks.test.js +++ b/lib/plugins/aws/utils/getS3ObjectsFromStacks.test.js @@ -5,7 +5,7 @@ const getS3ObjectsFromStacks = require('./getS3ObjectsFromStacks'); describe('#getS3ObjectsFromStacks()', () => { it('should return an empty result in case no stacks are provided', () => { - expect(getS3ObjectsFromStacks([], 'test', 'dev')).to.deep.equal([]); + expect(getS3ObjectsFromStacks([], 'serverless', 'test', 'dev')).to.deep.equal([]); }); it('should return an empty result in case no stacks are provided', () => { @@ -41,6 +41,6 @@ describe('#getS3ObjectsFromStacks()', () => { { Key: 'serverless/test/dev/1476779278222-2016-10-18T08:27:58.222Z/test.zip' }, ]; - expect(getS3ObjectsFromStacks(stacks, 'test', 'dev')).to.deep.equal(expected); + expect(getS3ObjectsFromStacks(stacks, 'serverless', 'test', 'dev')).to.deep.equal(expected); }); }); diff --git a/lib/plugins/create/create.js b/lib/plugins/create/create.js index 259d6b4bc..77ec7058c 100644 --- a/lib/plugins/create/create.js +++ b/lib/plugins/create/create.js @@ -4,6 +4,7 @@ const BbPromise = require('bluebird'); const path = require('path'); const fse = require('fs-extra'); const _ = require('lodash'); +const untildify = require('untildify'); const ServerlessError = require('../../classes/Error').ServerlessError; const userStats = require('../../utils/userStats'); @@ -18,6 +19,7 @@ const validTemplates = [ 'aws-clojurescript-gradle', 'aws-nodejs', 'aws-nodejs-typescript', + 'aws-alexa-typescript', 'aws-nodejs-ecma-script', 'aws-python', 'aws-python3', @@ -32,7 +34,10 @@ const validTemplates = [ 'aws-fsharp', 'aws-go', 'aws-go-dep', + 'aws-go-mod', 'azure-nodejs', + 'cloudflare-workers', + 'cloudflare-workers-enterprise', 'fn-nodejs', 'fn-go', 'google-nodejs', @@ -47,7 +52,6 @@ const validTemplates = [ 'spotinst-python', 'spotinst-ruby', 'spotinst-java8', - 'webtasks-nodejs', 'plugin', // this template is used to streamline the onboarding process @@ -128,12 +132,14 @@ class Create { }); } else if ('template-path' in this.options) { // Copying template from a local directory - const servicePath = this.options.path || path.join(process.cwd(), this.options.name); + const servicePath = this.options.path + ? untildify(this.options.path) + : path.join(process.cwd(), this.options.name); if (dirExistsSync(servicePath)) { const errorMessage = `A folder named "${servicePath}" already exists.`; throw new ServerlessError(errorMessage); } - copyDirContentsSync(this.options['template-path'], servicePath, { + copyDirContentsSync(untildify(this.options['template-path']), servicePath, { noLinks: true, }); if (this.options.name) { diff --git a/lib/plugins/create/create.test.js b/lib/plugins/create/create.test.js index 6534db0d0..9fc678d6c 100644 --- a/lib/plugins/create/create.test.js +++ b/lib/plugins/create/create.test.js @@ -185,6 +185,43 @@ describe('Create', () => { }); }); + it('should generate scaffolding for "aws-alexa-typescript" template', () => { + process.chdir(tmpDir); + create.options.template = 'aws-alexa-typescript'; + + return create.create().then(() => { + const dirContent = fs.readdirSync(tmpDir); + expect(dirContent).to.include('serverless.yml'); + expect(dirContent).to.include('handler.ts'); + expect(dirContent).to.include('tsconfig.json'); + expect(dirContent).to.include('package.json'); + expect(dirContent).to.include('webpack.config.js'); + expect(dirContent).to.include('.gitignore'); + }); + }); + it('should generate scaffolding for "aws-alexa-typescript" ' + + 'template and override service name if user passed', () => { + process.chdir(tmpDir); + create.options.template = 'aws-alexa-typescript'; + create.options.name = 'my-awesome-service'; + + return create.create().then(() => { + const dirContent = fs.readdirSync(tmpDir); + expect(dirContent).to.include('serverless.yml'); + expect(dirContent).to.include('handler.ts'); + expect(dirContent).to.include('tsconfig.json'); + expect(dirContent).to.include('package.json'); + expect(dirContent).to.include('webpack.config.js'); + expect(dirContent).to.include('.gitignore'); + + // check if the service was renamed + const serverlessYmlfileContent = fse + .readFileSync(path.join(tmpDir, 'serverless.yml')).toString(); + expect((/service:\n {2}name: my-awesome-service/) + .test(serverlessYmlfileContent)).to.equal(true); + }); + }); + it('should generate scaffolding for "aws-nodejs-ecma-script" template', () => { process.chdir(tmpDir); create.options.template = 'aws-nodejs-ecma-script'; @@ -599,19 +636,6 @@ describe('Create', () => { }); }); - it('should generate scaffolding for "webtasks-nodejs" template', () => { - process.chdir(tmpDir); - create.options.template = 'webtasks-nodejs'; - - return create.create().then(() => { - const dirContent = fs.readdirSync(tmpDir); - expect(dirContent).to.include('package.json'); - expect(dirContent).to.include('serverless.yml'); - expect(dirContent).to.include('handler.js'); - expect(dirContent).to.include('.gitignore'); - }); - }); - it('should generate scaffolding for "fn-nodejs" template', () => { process.chdir(tmpDir); create.options.template = 'fn-nodejs'; @@ -876,5 +900,22 @@ describe('Create', () => { expect(dirContent).to.include('.gitignore'); }); }); + + it('should generate scaffolding for "aws-go-mod" template', () => { + process.chdir(tmpDir); + create.options.template = 'aws-go-mod'; + + return create.create().then(() => { + const dirContent = walkDirSync(tmpDir) + .map(elem => elem.replace(path.join(tmpDir, path.sep), '')); + + expect(dirContent).to.include('serverless.yml'); + expect(dirContent).to.include(path.join('hello', 'main.go')); + expect(dirContent).to.include(path.join('world', 'main.go')); + expect(dirContent).to.include('gomod.sh'); + expect(dirContent).to.include('Makefile'); + expect(dirContent).to.include('.gitignore'); + }); + }); }); }); diff --git a/lib/plugins/create/templates/webtasks-nodejs/gitignore b/lib/plugins/create/templates/aws-alexa-typescript/gitignore similarity index 61% rename from lib/plugins/create/templates/webtasks-nodejs/gitignore rename to lib/plugins/create/templates/aws-alexa-typescript/gitignore index cd8399671..983749343 100644 --- a/lib/plugins/create/templates/webtasks-nodejs/gitignore +++ b/lib/plugins/create/templates/aws-alexa-typescript/gitignore @@ -1,5 +1,9 @@ # package directories node_modules +jspm_packages # Serverless directories .serverless + +# Webpack directories +.webpack \ No newline at end of file diff --git a/lib/plugins/create/templates/aws-alexa-typescript/handler.ts b/lib/plugins/create/templates/aws-alexa-typescript/handler.ts new file mode 100644 index 000000000..dc7cb2a77 --- /dev/null +++ b/lib/plugins/create/templates/aws-alexa-typescript/handler.ts @@ -0,0 +1,9 @@ +import * as Ask from 'ask-sdk'; + +export const alexa = Ask.SkillBuilders.custom() + .addRequestHandlers({ + canHandle: handlerInput => true, + handle: handlerInput => + handlerInput.responseBuilder.speak('Hello world!').getResponse() + }) + .lambda(); diff --git a/lib/plugins/create/templates/aws-alexa-typescript/package.json b/lib/plugins/create/templates/aws-alexa-typescript/package.json new file mode 100644 index 000000000..01a04b631 --- /dev/null +++ b/lib/plugins/create/templates/aws-alexa-typescript/package.json @@ -0,0 +1,24 @@ +{ + "name": "aws-alexa-typescript", + "version": "1.0.0", + "description": "Alexa example using Typescript", + "main": "handler.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "ask-sdk": "^2.0.7" + }, + "devDependencies": { + "@types/node": "^8.0.57", + "serverless-alexa-skills": "^0.1.0", + "serverless-webpack": "^5.1.1", + "source-map-support": "^0.5.6", + "ts-loader": "^4.2.0", + "typescript": "^2.9.2", + "webpack": "^4.5.0" + }, + "author": + "The serverless webpack authors (https://github.com/elastic-coders/serverless-webpack)", + "license": "MIT" +} diff --git a/lib/plugins/create/templates/aws-alexa-typescript/serverless.yml b/lib/plugins/create/templates/aws-alexa-typescript/serverless.yml new file mode 100644 index 000000000..3dde4cb45 --- /dev/null +++ b/lib/plugins/create/templates/aws-alexa-typescript/serverless.yml @@ -0,0 +1,48 @@ +service: + name: aws-alexa-typescript + +plugins: + - serverless-webpack + - serverless-alexa-skills + +provider: + name: aws + runtime: nodejs8.10 + +custom: + alexa: + # Step 1: Run `sls alexa auth` to authenticate + # Step 2: Run `sls alexa create --name "Serverless Alexa Typescript" --locale en-GB --type custom` to create a new skill + skills: + # Step 3: Paste the skill id returned by the create command here: + - id: amzn1.ask.skill.xxxx-xxxx-xxxx-xxxx-xxxx + manifest: + publishingInformation: + locales: + en-GB: + name: Serverless Alexa Typescript + apis: + custom: + endpoint: + # Step 4: Do your first deploy of your Serverless stack + # Step 5: Paste the ARN of your lambda here: + uri: arn:aws:lambda:[region]:[account-id]:function:[function-name] + # Step 6: Run `sls alexa update` to deploy the skill manifest + # Step 7: Run `sls alexa build` to build the skill interaction model + # Step 8: Enable the skill in the Alexa app to start testing. + manifestVersion: '1.0' + models: + en-GB: + interactionModel: + languageModel: + invocationName: serverless typescript + intents: + - name: HelloIntent + samples: + - 'hello' + +functions: + alexa: + handler: handler.alexa + events: + - alexaSkill: ${self:custom.alexa.skills.0.id} diff --git a/lib/plugins/create/templates/aws-alexa-typescript/source-map-install.js b/lib/plugins/create/templates/aws-alexa-typescript/source-map-install.js new file mode 100644 index 000000000..ef7457f72 --- /dev/null +++ b/lib/plugins/create/templates/aws-alexa-typescript/source-map-install.js @@ -0,0 +1 @@ +require('source-map-support').install(); diff --git a/lib/plugins/create/templates/aws-alexa-typescript/tsconfig.json b/lib/plugins/create/templates/aws-alexa-typescript/tsconfig.json new file mode 100644 index 000000000..20be6a1c6 --- /dev/null +++ b/lib/plugins/create/templates/aws-alexa-typescript/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "sourceMap": true, + "target": "es6", + "lib": [ + "esnext" + ], + "moduleResolution": "node" + }, + "exclude": [ + "node_modules" + ] +} diff --git a/lib/plugins/create/templates/aws-alexa-typescript/webpack.config.js b/lib/plugins/create/templates/aws-alexa-typescript/webpack.config.js new file mode 100644 index 000000000..482b98431 --- /dev/null +++ b/lib/plugins/create/templates/aws-alexa-typescript/webpack.config.js @@ -0,0 +1,29 @@ +const path = require('path'); +const slsw = require('serverless-webpack'); + +const entries = {}; + +Object.keys(slsw.lib.entries).forEach( + key => (entries[key] = ['./source-map-install.js', slsw.lib.entries[key]]) +); + +module.exports = { + mode: slsw.lib.webpack.isLocal ? 'development' : 'production', + entry: entries, + devtool: 'source-map', + resolve: { + extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'], + }, + output: { + libraryTarget: 'commonjs', + path: path.join(__dirname, '.webpack'), + filename: '[name].js', + }, + target: 'node', + module: { + rules: [ + // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader` + { test: /\.tsx?$/, loader: 'ts-loader' }, + ], + }, +}; diff --git a/lib/plugins/create/templates/aws-go-dep/Makefile b/lib/plugins/create/templates/aws-go-dep/Makefile index 4e281fb7d..e1a16281c 100644 --- a/lib/plugins/create/templates/aws-go-dep/Makefile +++ b/lib/plugins/create/templates/aws-go-dep/Makefile @@ -1,12 +1,12 @@ +.PHONY: build clean deploy + build: dep ensure -v env GOOS=linux go build -ldflags="-s -w" -o bin/hello hello/main.go env GOOS=linux go build -ldflags="-s -w" -o bin/world world/main.go -.PHONY: clean clean: rm -rf ./bin ./vendor Gopkg.lock -.PHONY: deploy deploy: clean build sls deploy --verbose diff --git a/lib/plugins/create/templates/aws-go-dep/gitignore b/lib/plugins/create/templates/aws-go-dep/gitignore index 99a966a94..eea931b34 100644 --- a/lib/plugins/create/templates/aws-go-dep/gitignore +++ b/lib/plugins/create/templates/aws-go-dep/gitignore @@ -5,4 +5,17 @@ bin # golang vendor (dependencies) directory -vendor \ No newline at end of file +vendor + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out diff --git a/lib/plugins/create/templates/aws-go-mod/Makefile b/lib/plugins/create/templates/aws-go-mod/Makefile new file mode 100644 index 000000000..e72595764 --- /dev/null +++ b/lib/plugins/create/templates/aws-go-mod/Makefile @@ -0,0 +1,16 @@ +.PHONY: build clean deploy gomodgen + +build: gomodgen + export GO111MODULE=on + env GOOS=linux go build -ldflags="-s -w" -o bin/hello hello/main.go + env GOOS=linux go build -ldflags="-s -w" -o bin/world world/main.go + +clean: + rm -rf ./bin ./vendor Gopkg.lock + +deploy: clean build + sls deploy --verbose + +gomodgen: + chmod u+x gomod.sh + ./gomod.sh diff --git a/lib/plugins/create/templates/aws-go-mod/gitignore b/lib/plugins/create/templates/aws-go-mod/gitignore new file mode 100644 index 000000000..eea931b34 --- /dev/null +++ b/lib/plugins/create/templates/aws-go-mod/gitignore @@ -0,0 +1,21 @@ +# Serverless directories +.serverless + +# golang output binary directory +bin + +# golang vendor (dependencies) directory +vendor + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out diff --git a/lib/plugins/create/templates/aws-go-mod/gomod.sh b/lib/plugins/create/templates/aws-go-mod/gomod.sh new file mode 100644 index 000000000..ef6bf56b4 --- /dev/null +++ b/lib/plugins/create/templates/aws-go-mod/gomod.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -eu + +touch go.mod + +PROJECT_NAME=$(basename $(pwd | xargs dirname)) +CURRENT_DIR=$(basename $(pwd)) + +CONTENT=$(cat <<-EOD +module github.com/${PROJECT_NAME}/${CURRENT_DIR} + +require github.com/aws/aws-lambda-go v1.6.0 +EOD) + +echo "$CONTENT" > go.mod diff --git a/lib/plugins/create/templates/aws-go-mod/hello/main.go b/lib/plugins/create/templates/aws-go-mod/hello/main.go new file mode 100644 index 000000000..2a4d5526f --- /dev/null +++ b/lib/plugins/create/templates/aws-go-mod/hello/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + + "github.com/aws/aws-lambda-go/events" + "github.com/aws/aws-lambda-go/lambda" +) + +// Response is of type APIGatewayProxyResponse since we're leveraging the +// AWS Lambda Proxy Request functionality (default behavior) +// +// https://serverless.com/framework/docs/providers/aws/events/apigateway/#lambda-proxy-integration +type Response events.APIGatewayProxyResponse + +// Handler is our lambda handler invoked by the `lambda.Start` function call +func Handler(ctx context.Context) (Response, error) { + var buf bytes.Buffer + + body, err := json.Marshal(map[string]interface{}{ + "message": "Go Serverless v1.0! Your function executed successfully!", + }) + if err != nil { + return Response{StatusCode: 404}, err + } + json.HTMLEscape(&buf, body) + + resp := Response{ + StatusCode: 200, + IsBase64Encoded: false, + Body: buf.String(), + Headers: map[string]string{ + "Content-Type": "application/json", + "X-MyCompany-Func-Reply": "hello-handler", + }, + } + + return resp, nil +} + +func main() { + lambda.Start(Handler) +} diff --git a/lib/plugins/create/templates/aws-go-mod/serverless.yml b/lib/plugins/create/templates/aws-go-mod/serverless.yml new file mode 100644 index 000000000..974b2bbfd --- /dev/null +++ b/lib/plugins/create/templates/aws-go-mod/serverless.yml @@ -0,0 +1,113 @@ +# Welcome to Serverless! +# +# This file is the main config file for your service. +# It's very minimal at this point and uses default values. +# You can always add more config options for more control. +# We've included some commented out config examples here. +# Just uncomment any of them to get that config option. +# +# For full config options, check the docs: +# docs.serverless.com +# +# Happy Coding! + +service: aws-go-mod # NOTE: update this with your service name + +# You can pin your service to only deploy with a specific Serverless version +# Check out our docs for more details +# frameworkVersion: "=X.X.X" +frameworkVersion: ">=1.28.0 <2.0.0" + +provider: + name: aws + runtime: go1.x + +# you can overwrite defaults here +# stage: dev +# region: us-east-1 + +# you can add statements to the Lambda function's IAM Role here +# iamRoleStatements: +# - Effect: "Allow" +# Action: +# - "s3:ListBucket" +# Resource: { "Fn::Join" : ["", ["arn:aws:s3:::", { "Ref" : "ServerlessDeploymentBucket" } ] ] } +# - Effect: "Allow" +# Action: +# - "s3:PutObject" +# Resource: +# Fn::Join: +# - "" +# - - "arn:aws:s3:::" +# - "Ref" : "ServerlessDeploymentBucket" +# - "/*" + +# you can define service wide environment variables here +# environment: +# variable1: value1 + +package: + exclude: + - ./** + include: + - ./bin/** + +functions: + hello: + handler: bin/hello + events: + - http: + path: hello + method: get + world: + handler: bin/world + events: + - http: + path: world + method: get + +# The following are a few example events you can configure +# NOTE: Please make sure to change your handler code to work with those events +# Check the event documentation for details +# events: +# events: +# - http: +# path: users/create +# method: get +# - s3: ${env:BUCKET} +# - schedule: rate(10 minutes) +# - sns: greeter-topic +# - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000 +# - alexaSkill: amzn1.ask.skill.xx-xx-xx-xx +# - alexaSmartHome: amzn1.ask.skill.xx-xx-xx-xx +# - iot: +# sql: "SELECT * FROM 'some_topic'" +# - cloudwatchEvent: +# event: +# source: +# - "aws.ec2" +# detail-type: +# - "EC2 Instance State-change Notification" +# detail: +# state: +# - pending +# - cloudwatchLog: '/aws/lambda/hello' +# - cognitoUserPool: +# pool: MyUserPool +# trigger: PreSignUp + +# Define function environment variables here +# environment: +# variable2: value2 + +# you can add CloudFormation resource templates here +#resources: +# Resources: +# NewResource: +# Type: AWS::S3::Bucket +# Properties: +# BucketName: my-new-bucket +# Outputs: +# NewOutput: +# Description: "Description for the output" +# Value: "Some output value" diff --git a/lib/plugins/create/templates/aws-go-mod/world/main.go b/lib/plugins/create/templates/aws-go-mod/world/main.go new file mode 100644 index 000000000..b49d1c4a1 --- /dev/null +++ b/lib/plugins/create/templates/aws-go-mod/world/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + + "github.com/aws/aws-lambda-go/events" + "github.com/aws/aws-lambda-go/lambda" +) + +// Response is of type APIGatewayProxyResponse since we're leveraging the +// AWS Lambda Proxy Request functionality (default behavior) +// +// https://serverless.com/framework/docs/providers/aws/events/apigateway/#lambda-proxy-integration +type Response events.APIGatewayProxyResponse + +// Handler is our lambda handler invoked by the `lambda.Start` function call +func Handler(ctx context.Context) (Response, error) { + var buf bytes.Buffer + + body, err := json.Marshal(map[string]interface{}{ + "message": "Okay so your other function also executed successfully!", + }) + if err != nil { + return Response{StatusCode: 404}, err + } + json.HTMLEscape(&buf, body) + + resp := Response{ + StatusCode: 200, + IsBase64Encoded: false, + Body: buf.String(), + Headers: map[string]string{ + "Content-Type": "application/json", + "X-MyCompany-Func-Reply": "world-handler", + }, + } + + return resp, nil +} + +func main() { + lambda.Start(Handler) +} diff --git a/lib/plugins/create/templates/aws-go/Makefile b/lib/plugins/create/templates/aws-go/Makefile index a9fb91a45..3623a7971 100644 --- a/lib/plugins/create/templates/aws-go/Makefile +++ b/lib/plugins/create/templates/aws-go/Makefile @@ -1,11 +1,11 @@ +.PHONY: build clean deploy + build: env GOOS=linux go build -ldflags="-s -w" -o bin/hello hello/main.go env GOOS=linux go build -ldflags="-s -w" -o bin/world world/main.go -.PHONY: clean clean: rm -rf ./bin -.PHONY: deploy deploy: clean build sls deploy --verbose diff --git a/lib/plugins/create/templates/aws-go/gitignore b/lib/plugins/create/templates/aws-go/gitignore index f5b4c36ad..2cd4e1acf 100644 --- a/lib/plugins/create/templates/aws-go/gitignore +++ b/lib/plugins/create/templates/aws-go/gitignore @@ -2,4 +2,17 @@ .serverless # golang output binary directory -bin \ No newline at end of file +bin + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out diff --git a/lib/plugins/create/templates/aws-nodejs-typescript/handler.ts b/lib/plugins/create/templates/aws-nodejs-typescript/handler.ts index 7dfcf29e0..20e1cbaa3 100644 --- a/lib/plugins/create/templates/aws-nodejs-typescript/handler.ts +++ b/lib/plugins/create/templates/aws-nodejs-typescript/handler.ts @@ -1,13 +1,11 @@ -import { APIGatewayEvent, Callback, Context, Handler } from 'aws-lambda'; +import { APIGatewayProxyHandler } from 'aws-lambda'; -export const hello: Handler = (event: APIGatewayEvent, context: Context, cb: Callback) => { - const response = { +export const hello: APIGatewayProxyHandler = async (event, context) => { + return { statusCode: 200, body: JSON.stringify({ message: 'Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!', input: event, }), }; - - cb(null, response); } diff --git a/lib/plugins/create/templates/cloudflare-workers-enterprise/.gitignore b/lib/plugins/create/templates/cloudflare-workers-enterprise/.gitignore new file mode 100644 index 000000000..9e5bccff8 --- /dev/null +++ b/lib/plugins/create/templates/cloudflare-workers-enterprise/.gitignore @@ -0,0 +1,3 @@ +# Serverless directories +.serverless +node_modules/ diff --git a/lib/plugins/create/templates/cloudflare-workers-enterprise/bar.js b/lib/plugins/create/templates/cloudflare-workers-enterprise/bar.js new file mode 100644 index 000000000..14359baea --- /dev/null +++ b/lib/plugins/create/templates/cloudflare-workers-enterprise/bar.js @@ -0,0 +1,7 @@ +addEventListener('fetch', event => { + event.respondWith(handleRequest(event.request)) + }) + + async function handleRequest(request) { + return new Response("Foo is not Bar") + } diff --git a/lib/plugins/create/templates/cloudflare-workers-enterprise/helloWorld.js b/lib/plugins/create/templates/cloudflare-workers-enterprise/helloWorld.js new file mode 100644 index 000000000..dbede8a62 --- /dev/null +++ b/lib/plugins/create/templates/cloudflare-workers-enterprise/helloWorld.js @@ -0,0 +1,7 @@ +addEventListener('fetch', event => { + event.respondWith(handleRequest(event.request)) + }) + + async function handleRequest(request) { + return new Response("Hello world") + } diff --git a/lib/plugins/create/templates/cloudflare-workers-enterprise/package.json b/lib/plugins/create/templates/cloudflare-workers-enterprise/package.json new file mode 100644 index 000000000..1785da86a --- /dev/null +++ b/lib/plugins/create/templates/cloudflare-workers-enterprise/package.json @@ -0,0 +1,14 @@ +{ + "name": "cloudflare-workers-enterprise", + "version": "1.0.0", + "description": "Cloudflare serverless deployment for enterprise customers", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "cloudflare", + "license": "MIT", + "devDependencies": { + "serverless-cloudflare-workers": "0.1.1" + } +} diff --git a/lib/plugins/create/templates/cloudflare-workers-enterprise/serverless.yml b/lib/plugins/create/templates/cloudflare-workers-enterprise/serverless.yml new file mode 100644 index 000000000..988a40d60 --- /dev/null +++ b/lib/plugins/create/templates/cloudflare-workers-enterprise/serverless.yml @@ -0,0 +1,41 @@ +service: + name: hello-world + +provider: + name: cloudflare + config: + accountId: CLOUDFLARE_ACCOUNT_ID + zoneId: CLOUDFLARE_ZONE_ID + workers: + hello: + routes: + - example.com/hello/* + foo_script: + routes: + - example.com/foo/* + +plugins: + - serverless-cloudflare-workers + +functions: + helloWorld: + worker: hello + script: helloWorld + events: + - http: + url: example.com/hello/user + method: GET + headers: + foo: bar + x-client-data: value + + foo: + worker: foo_script + script: bar + events: + - http: + url: example.com/foo/bar + method: GET + headers: + foo: bar + x-client-data: value diff --git a/lib/plugins/create/templates/cloudflare-workers/.gitignore b/lib/plugins/create/templates/cloudflare-workers/.gitignore new file mode 100644 index 000000000..9e5bccff8 --- /dev/null +++ b/lib/plugins/create/templates/cloudflare-workers/.gitignore @@ -0,0 +1,3 @@ +# Serverless directories +.serverless +node_modules/ diff --git a/lib/plugins/create/templates/cloudflare-workers/helloWorld.js b/lib/plugins/create/templates/cloudflare-workers/helloWorld.js new file mode 100644 index 000000000..dbede8a62 --- /dev/null +++ b/lib/plugins/create/templates/cloudflare-workers/helloWorld.js @@ -0,0 +1,7 @@ +addEventListener('fetch', event => { + event.respondWith(handleRequest(event.request)) + }) + + async function handleRequest(request) { + return new Response("Hello world") + } diff --git a/lib/plugins/create/templates/cloudflare-workers/package.json b/lib/plugins/create/templates/cloudflare-workers/package.json new file mode 100644 index 000000000..9e8bd054d --- /dev/null +++ b/lib/plugins/create/templates/cloudflare-workers/package.json @@ -0,0 +1,14 @@ +{ + "name": "cloudflare-workers", + "version": "1.0.0", + "description": "Cloudflare serverless deployment for self-serve customers", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "cloudflare", + "license": "MIT", + "devDependencies": { + "serverless-cloudflare-workers": "0.1.1" + } +} diff --git a/lib/plugins/create/templates/cloudflare-workers/serverless.yml b/lib/plugins/create/templates/cloudflare-workers/serverless.yml new file mode 100644 index 000000000..489c2782f --- /dev/null +++ b/lib/plugins/create/templates/cloudflare-workers/serverless.yml @@ -0,0 +1,27 @@ +service: + name: hello-world + +provider: + name: cloudflare + config: + accountId: CLOUDFLARE_ACCOUNT_ID + zoneId: CLOUDFLARE_ZONE_ID + workers: + hello: + routes: + - example.com/hello/* + +plugins: + - serverless-cloudflare-workers + +functions: + helloWorld: + worker: hello + script: helloWorld # there must be a file called helloWorld.js + events: + - http: + url: example.com/hello/user + method: GET + headers: + foo: bar + x-client-data: value diff --git a/lib/plugins/create/templates/webtasks-nodejs/handler.js b/lib/plugins/create/templates/webtasks-nodejs/handler.js deleted file mode 100644 index 48732afc6..000000000 --- a/lib/plugins/create/templates/webtasks-nodejs/handler.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -module.exports = (context, cb) => { - const message = 'Go Serverless & Webtasks! Your function executed successfully!'; - cb(null, { message }); -}; diff --git a/lib/plugins/create/templates/webtasks-nodejs/package.json b/lib/plugins/create/templates/webtasks-nodejs/package.json deleted file mode 100644 index f4eb188f3..000000000 --- a/lib/plugins/create/templates/webtasks-nodejs/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "webtasks-nodejs", - "version": "1.0.0", - "description": "Auth0 Webtasks NodeJS template for the Serverless Framework", - "main": "handler.js", - "keywords": [ - "serverless", - "webtasks" - ], - "devDependencies": { - "@webtask/serverless-webtasks": "^1.0.1" - } - } diff --git a/lib/plugins/create/templates/webtasks-nodejs/serverless.yml b/lib/plugins/create/templates/webtasks-nodejs/serverless.yml deleted file mode 100644 index 338686f6f..000000000 --- a/lib/plugins/create/templates/webtasks-nodejs/serverless.yml +++ /dev/null @@ -1,29 +0,0 @@ -# Welcome to Serverless! -# -# This file is the main config file for your service. -# It's very minimal at this point and uses default values. -# You can always add more config options for more control. -# We've included some commented out config examples here. -# Just uncomment any of them to get that config option. -# -# For full config options, check the docs: -# docs.serverless.com -# -# Happy Coding! - -service: - name: webtasks-nodejs # NOTE: update this with your service name - -provider: - name: webtasks - -# you can define service wide environment variables here -# environment: -# variable1: value1 - -functions: - main: - handler: handler - -plugins: - - '@webtask/serverless-webtasks' diff --git a/lib/plugins/info/info.js b/lib/plugins/info/info.js index 5d4499397..fab1c3633 100644 --- a/lib/plugins/info/info.js +++ b/lib/plugins/info/info.js @@ -2,11 +2,17 @@ const BbPromise = require('bluebird'); const userStats = require('../../utils/userStats'); +const validate = require('../lib/validate'); class Info { constructor(serverless) { this.serverless = serverless; + Object.assign( + this, + validate + ); + this.commands = { info: { usage: 'Display information about the service', @@ -31,6 +37,7 @@ class Info { }; this.hooks = { + 'before:info:info': () => BbPromise.bind(this).then(this.validate), 'after:info:info': () => BbPromise.bind(this).then(this.track), }; } diff --git a/lib/plugins/info/info.test.js b/lib/plugins/info/info.test.js index ebb27d7b9..eb3a4427b 100644 --- a/lib/plugins/info/info.test.js +++ b/lib/plugins/info/info.test.js @@ -3,6 +3,7 @@ const expect = require('chai').expect; const Info = require('./info'); const Serverless = require('../../Serverless'); +const sinon = require('sinon'); describe('Info', () => { let info; @@ -16,4 +17,21 @@ describe('Info', () => { describe('#constructor()', () => { it('should have commands', () => expect(info.commands).to.be.not.empty); }); + + describe('"before:info:info" hook', () => { + let validateStub; + + beforeEach(() => { + validateStub = sinon.stub(info, 'validate').resolves(); + }); + + afterEach(() => { + info.validate.restore(); + }); + + it('should run the validation', () => + expect(info.hooks['before:info:info']()) + .to.be.fulfilled.then(() => expect(validateStub).to.be.called) + ); + }); }); diff --git a/lib/plugins/invoke/invoke.js b/lib/plugins/invoke/invoke.js index 18f715735..4890bc896 100644 --- a/lib/plugins/invoke/invoke.js +++ b/lib/plugins/invoke/invoke.js @@ -5,8 +5,9 @@ const _ = require('lodash'); const userStats = require('../../utils/userStats'); class Invoke { - constructor(serverless) { + constructor(serverless, options) { this.serverless = serverless; + this.options = options || {}; this.commands = { invoke: { @@ -81,6 +82,10 @@ class Invoke { usage: 'Path to JSON or YAML file holding context data', shortcut: 'x', }, + env: { + usage: 'Override environment variables. e.g. --env VAR1=val1 --env VAR2=val2', + shortcut: 'e', + }, }, }, }, @@ -114,6 +119,14 @@ class Invoke { _.merge(process.env, defaultEnvVars); + // Turn zero or more --env options into an array + // ...then split --env NAME=value and put into process.env. + _.concat(this.options.env || []) + .forEach(itm => { + const splitItm = _.split(itm, '='); + process.env[splitItm[0]] = splitItm[1] || ''; + }); + return BbPromise.resolve(); } } diff --git a/lib/plugins/invoke/invoke.test.js b/lib/plugins/invoke/invoke.test.js index da707b70a..c4830bee6 100644 --- a/lib/plugins/invoke/invoke.test.js +++ b/lib/plugins/invoke/invoke.test.js @@ -41,6 +41,20 @@ describe('Invoke', () => { return expect(invoke.hooks['invoke:local:loadEnvVars']()).to.be.fulfilled .then(() => expect(process.env.IS_LOCAL).to.equal('true')); }); + + it('should accept a single env option', () => { + invoke.options = { env: 'NAME=value' }; + expect(invoke.hooks['invoke:local:loadEnvVars']()).to.be.fulfilled + .then(() => expect(process.env.NAME).to.equal('value')); + }); + + it('should accept multiple env options', () => { + invoke.options = { env: ['NAME1=val1', 'NAME2=val2'] }; + + expect(invoke.hooks['invoke:local:loadEnvVars']()).to.be.fulfilled + .then(() => expect(process.env.NAME1).to.equal('val1')) + .then(() => expect(process.env.NAME2).to.equal('val2')); + }); }); }); }); diff --git a/lib/plugins/lib/validate.js b/lib/plugins/lib/validate.js index 5d31d22be..11653caa2 100644 --- a/lib/plugins/lib/validate.js +++ b/lib/plugins/lib/validate.js @@ -5,7 +5,7 @@ const getServerlessConfigFile = require('../../utils/getServerlessConfigFile'); module.exports = { validate() { - return getServerlessConfigFile(process.cwd()).then((result) => { + return getServerlessConfigFile(this.serverless.config.servicePath).then((result) => { const isRunInService = !!result; if (!isRunInService) { diff --git a/lib/plugins/lib/validate.test.js b/lib/plugins/lib/validate.test.js index a88fb15f7..baad28f55 100644 --- a/lib/plugins/lib/validate.test.js +++ b/lib/plugins/lib/validate.test.js @@ -39,7 +39,8 @@ describe('#validate()', () => { return expect(serverlessPlugin.validate()).to.be.fulfilled.then(() => { expect(getServerlessConfigFileStub).to.have.been.calledOnce; - expect(getServerlessConfigFileStub).to.have.been.calledWithExactly(process.cwd()); + expect(getServerlessConfigFileStub).to.have.been + .calledWithExactly(serverless.config.servicePath); }); }); }); diff --git a/lib/plugins/package/lib/zipService.js b/lib/plugins/package/lib/zipService.js index 1fe7ebe4f..4c17a1b6f 100644 --- a/lib/plugins/package/lib/zipService.js +++ b/lib/plugins/package/lib/zipService.js @@ -222,6 +222,12 @@ function excludeNodeDevDependencies(servicePath) { return exAndIn; }) + .then(() => { + // cleanup + fs.unlinkSync(nodeDevDepFile); + fs.unlinkSync(nodeProdDepFile); + return exAndIn; + }) .catch(() => exAndIn); } catch (e) { // fail silently diff --git a/lib/plugins/platform/platform.js b/lib/plugins/platform/platform.js index 75d278572..22d1c99c3 100644 --- a/lib/plugins/platform/platform.js +++ b/lib/plugins/platform/platform.js @@ -4,10 +4,8 @@ const BbPromise = require('bluebird'); const path = require('path'); -const _ = require('lodash'); const fs = require('fs'); const fsExtra = require('../../utils/fs/fse'); -const crypto = require('crypto'); const platform = require('@serverless/platform-sdk'); const getAccessKey = require('../../utils/getAccessKey'); const userStats = require('../../utils/userStats'); @@ -34,286 +32,6 @@ class Platform { return null; } - getS3Type(s3Event) { - const splittedS3Event = s3Event.split(':'); - if (splittedS3Event[1] === 'ReducedRedundancyLostObject') { - return 'aws.s3.ReducedRedundancyLostObject'; - } else if (splittedS3Event[1] === 'ObjectCreated' || splittedS3Event[1] === 'ObjectRemoved') { - if (splittedS3Event[2] === '*') { - return `aws.s3.${splittedS3Event[1]}`; - } else if (typeof splittedS3Event[2] === 'string') { - return `aws.s3.${splittedS3Event[1]}.${splittedS3Event[2]}`; - } - } - return `aws.s3.${splittedS3Event[1]}`; - } - - getFunctionData(fn) { - const fnData = { - functionId: this.serverless.service.getFunction(fn).name, - details: { - runtime: this.serverless.service.functions[fn].runtime, - memory: this.serverless.service.functions[fn].memory, - timeout: this.serverless.service.functions[fn].timeout, - }, - package: { - handler: this.serverless.service.functions[fn].handler, - name: this.serverless.service.functions[fn].name, - arn: `arn:aws:lambda:${this.serverless.service.provider.region}:${ - this.data.service.provider.accountId}:function:${ - this.serverless.service.getFunction(fn).name}`, - }, - }; - return fnData; - } - - getServiceData() { - const serviceData = { - name: this.serverless.service.service, - stage: this.serverless.processedInput.options.stage - || this.serverless.service.provider.stage, - provider: { - name: this.serverless.service.provider.name, - region: this.serverless.service.provider.region, - stage: this.serverless.service.provider.stage, - accountId: this.serverless.service.provider.accountId, - }, - pluginsData: this.serverless.service.pluginsData, - readme: this.getReadme(), - }; - if (this.serverless.service.serviceObject.description) { - serviceData.description = this.serverless.service.serviceObject.description; - } - if (this.serverless.service.serviceObject.license) { - serviceData.license = this.serverless.service.serviceObject.license; - } - if (this.serverless.service.serviceObject.bugs) { - serviceData.bugs = this.serverless.service.serviceObject.bugs; - } - if (this.serverless.service.serviceObject.repository) { - serviceData.repository = this.serverless.service.serviceObject.repository; - } - if (this.serverless.service.serviceObject.homepage) { - serviceData.homepage = this.serverless.service.serviceObject.homepage; - } - return serviceData; - } - - getScheduledSubscription(event, fn) { - const provider = this.data.service.provider; - const subscription = { - functionId: this.serverless.service.getFunction(fn).name, - type: 'aws.cloudwatch.scheduled', - details: { - function: this.serverless.service.getFunction(fn).name, - source: 'AWS::CloudWatch::Scheduled', - }, - provider, - permissions: { - type: 'aws IAM', - action: 'lambda:InvokeFunction', - sourceAccount: 'Amazon', - }, - }; - if (typeof event === 'string') { - subscription.details.rate = event; - subscription.details.name = null; - subscription.details.description = null; - } else if (typeof event === 'object') { - subscription.details.rate = event.rate; - subscription.details.name = event.name; - subscription.details.description = event.description; - } - subscription.event = event; - return subscription; - } - - getS3Subscription(event, fn) { - const provider = this.data.service.provider; - const subscription = { - functionId: this.serverless.service.getFunction(fn).name, - details: { - function: this.serverless.service.getFunction(fn).name, - }, - provider, - permissions: { - type: 'aws IAM', - action: 'lambda:InvokeFunction', - sourceAccount: 'Amazon', - }, - }; - if (typeof event === 'string') { - subscription.type = 'aws.s3.ObjectCreated'; - subscription.details.source = `AWS::S3::${event}`; - subscription.details.bucket = event; - subscription.details.event = 's3:ObjectCreated:*'; - subscription.details.rules = null; - subscription.permissions.sourceArn = `arn:aws:s3:::${event}`; - } else if (typeof event === 'object') { - subscription.type = this.getS3Type(event.event); - subscription.details.source = `AWS::S3::${event.bucket}`; - subscription.details.bucket = event.bucket; - subscription.details.event = event.event; - subscription.details.rules = event.rules || null; - subscription.permissions.sourceArn = `arn:aws:s3:::${event.bucket}`; - } - subscription.event = event; - return subscription; - } - - getSnsSubscription(event, fn) { - // todo existing topic arn - const provider = this.data.service.provider; - const subscription = { - functionId: this.serverless.service.getFunction(fn).name, - type: 'aws.sns', - details: { - function: this.serverless.service.getFunction(fn).name, - }, - provider, - permissions: { - type: 'aws IAM', - action: 'lambda:InvokeFunction', - sourceAccount: 'Amazon', - }, - }; - - if (typeof event === 'string') { - subscription.details.source = `AWS::SNS::${event}`; - subscription.details.topic = event; - subscription.permissions.sourceArn = `arn:aws:sns:${this.provider.getRegion() - }:${provider.accountId}:${event}`; - } else if (typeof event === 'object') { - subscription.details.source = `AWS::SNS::${event.topicName}`; - subscription.details.topic = event.topicName; - subscription.details.displayName = event.displayName; - subscription.permissions.sourceArn = `arn:aws:sns:${this.provider.getRegion() - }:${provider.accountId}:${event.topicName}`; - } - subscription.event = event; - return subscription; - } - - getEGSubscription(event, fn) { - const subscription = { - functionId: this.serverless.service.getFunction(fn).name, - type: event.eventType, - details: { - function: this.serverless.service.getFunction(fn).name, - type: event.type, - app: this.data.app, - service: this.data.service.name, - stage: this.serverless.service.provider.stage, - path: event.path || '/', - }, - provider: { - name: 'Serverless', - tenant: this.data.tenant, - }, - properties: { - name: event.eventType, - service: this.data.service.name, - stage: this.serverless.service.provider.stage, - }, - }; - - if (event.type === 'sync') { - subscription.details.source = 'Sls::EventGateway::http'; - } else if (event.type === 'async') { - subscription.details.source = 'sls/eventgateway/com'; - } - if (event.eventType === 'http.request') { - subscription.details.method = event.method; - } - if (typeof event.cors === 'boolean' || typeof event.cors === 'object') { - subscription.details.cors = event.cors; - } else { - subscription.details.cors = true; - } - subscription.event = event; - return subscription; - } - - getApigSubscription(event, fn) { - const apiId = this.serverless.service.deployment.apiId; - const provider = this.data.service.provider; - const subscription = { - functionId: this.serverless.service.getFunction(fn).name, - type: 'aws.apigateway.http', - details: { - function: this.serverless.service.getFunction(fn).name, - type: 'http', - source: 'AWS::APIGateway::http', - apiId, - }, - provider, - permissions: { - type: 'aws IAM', - action: 'lambda:InvokeFunction', - sourceAccount: 'Amazon', - }, - }; - - if (typeof event === 'string') { - subscription.details.method = event.split(' ')[0]; - subscription.details.path = event.split(' ')[1]; - subscription.permissions.sourceArn = this.provider - .getMethodArn(provider.accountId, apiId, event.split(' ')[0], event.split(' ')[1]); - subscription.details.cors = false; - subscription.details.lambdaProxy = true; - } else if (typeof event === 'object') { - subscription.details.method = event.method; - subscription.details.path = event.path; - subscription.permissions.sourceArn = this.provider - .getMethodArn(provider.accountId, apiId, event.method, event.path); - if (typeof event.cors === 'boolean' || typeof event.cors === 'object') { - subscription.details.cors = true; - } else { - subscription.details.cors = false; - } - if (event.integration === 'AWS') { - subscription.details.lambdaProxy = false; - } else { - subscription.details.lambdaProxy = true; - } - } - subscription.event = event; - - // the aws package plugin strips trailing and leading slashes per CF needs. - if (subscription.details.path === '') subscription.details.path = '/'; - if (subscription.event.path === '') subscription.event.path = '/'; - - // in case of AWS integration, the aws package plugin adds - // request/response objects that we need to stringify - if (!subscription.details.lambdaProxy) { - subscription.event.request = JSON.stringify(subscription.event.request); - subscription.event.response = JSON.stringify(subscription.event.response); - } - - return subscription; - } - - getResources() { - const frameworkResources = this.serverless.service.provider - .compiledCloudFormationTemplate.Resources; - const resources = []; - - _.forEach(frameworkResources, (value, key) => { - const physicalId = _.find(this.cfResources, r => r.LogicalResourceId === key) - .PhysicalResourceId; - const resource = { - resourceId: key.toLowerCase(), - id: physicalId, - name: key, - type: value.Type, - properties: JSON.stringify(value.Properties), - provider: this.serverless.service.provider.name, - }; - resources.push(resource); - }); - return resources; - } - publishService() { if (!this.serverless.service.deployment || !this.serverless.service.deployment.deploymentId) { return BbPromise.resolve(); @@ -324,91 +42,24 @@ class Platform { this.cfResources = resources; }).then(() => this.provider.getAccountId()) .then(accountId => { - const service = this.serverless.service; - - this.data = { - app: this.serverless.service.app, - tenant: this.serverless.service.tenant, + const deploymentData = { + tenant: this.serverless.service.deployment.tenant, + app: this.serverless.service.deployment.app, + serviceName: this.serverless.service.deployment.serviceName, accessKey: this.serverless.service.deployment.accessKey, - version: '0.1.0', - service: this.getServiceData(), - functions: [], - subscriptions: [], - resources: this.getResources(), + deploymentId: this.serverless.service.deployment.deploymentId, + status: 'success', + computedData: { + readme: this.getReadme(), + accountId, + apiId: this.serverless.service.deployment.apiId, + physicalIds: this.cfResources.map(r => ({ + logicalId: r.LogicalResourceId, + physicalId: r.PhysicalResourceId, + })), + }, }; - this.data.service.provider.accountId = accountId; - - Object.keys(service.functions).forEach(fn => { - const fnData = this.getFunctionData(fn); - this.data.functions.push(fnData); - this.serverless.service.getAllEventsInFunction(fn).forEach(event => { - let subscription = { - functionId: this.serverless.service.getFunction(fn).name, - details: {}, - provider: this.data.service.provider, - permissions: {}, - }; - - if (Object.keys(event)[0] === 'eventgateway') { - subscription = this.getEGSubscription(event.eventgateway, fn); - } else if (Object.keys(event)[0] === 'http') { - subscription = this.getApigSubscription(event.http, fn); - } else if (Object.keys(event)[0] === 'stream') { - if (typeof event.stream === 'string') { - const streamType = event.stream.split(':')[2]; - subscription.type = `aws.${streamType}`; - } else if (typeof event.stream === 'object') { - if (event.stream.type === 'dynamodb') { - subscription.type = 'aws.dynamodb'; - } else if (event.stream.type === 'kinesis') { - subscription.type = 'aws.kinesis'; - } - } - subscription.event = event.stream; - if (typeof event.stream === 'object') { - subscription.event.arn = JSON.stringify(event.stream.arn); - } - } else if (Object.keys(event)[0] === 's3') { - subscription = this.getS3Subscription(event.s3, fn); - } else if (Object.keys(event)[0] === 'schedule') { - subscription = this.getScheduledSubscription(event.schedule, fn); - } else if (Object.keys(event)[0] === 'sns') { - subscription = this.getSnsSubscription(event.sns, fn); - } else if (Object.keys(event)[0] === 'alexaSkill') { - subscription.type = 'aws.alexa.skill'; - subscription.event = event.alexaSkill; - } else if (Object.keys(event)[0] === 'iot') { - subscription.type = 'aws.iot'; - subscription.event = event.iot; - } else if (Object.keys(event)[0] === 'cloudwatchEvent') { - subscription.type = 'aws.cloudwatch'; - subscription.event = event.cloudwatchEvent; - } else if (Object.keys(event)[0] === 'cloudwatchLog') { - subscription.type = 'aws.cloudwatch.log'; - subscription.event = event.cloudwatchLog; - } else if (Object.keys(event)[0] === 'cognitoUserPool') { - subscription.type = 'aws.cognito'; - subscription.event = event.cognitoUserPool; - } else if (Object.keys(event)[0] === 'alexaSmartHome') { - subscription.type = 'aws.alexa.home'; - subscription.event = event.alexaSmartHome; - } - - subscription.subscriptionId = crypto.createHash('md5') - .update(JSON.stringify(subscription)).digest('hex'); - - // dashboard currently does not support sqs - if (Object.keys(event)[0] !== 'sqs') { - this.data.subscriptions.push(subscription); - } - }); - }); - - const deploymentData = this.serverless.service.deployment; - deploymentData.status = 'Success'; - deploymentData.state = this.data; - return platform.updateDeployment(deploymentData) .then(() => { const trackingData = { @@ -419,7 +70,7 @@ class Platform { const serviceUrlData = { tenant: deploymentData.tenant, app: deploymentData.app, - name: deploymentData.state.service.name, + name: deploymentData.serviceName, }; const serviceUrl = platform.getServiceUrl(serviceUrlData); this.serverless.cli @@ -438,6 +89,8 @@ class Platform { name: this.serverless.service.service, tenant: this.serverless.service.tenant, app: this.serverless.service.app, + provider: this.serverless.service.provider.name, + region: this.serverless.service.provider.region, accessKey, }; return platform.archiveService(data) diff --git a/lib/plugins/print/print.js b/lib/plugins/print/print.js index 9c146bdbc..93ca74199 100644 --- a/lib/plugins/print/print.js +++ b/lib/plugins/print/print.js @@ -94,7 +94,7 @@ class Print { // the codebase. Avoiding that, this method must read the serverless.yml file itself, adorn it // as the Service class would and then populate it, reversing the adornments thereafter in // preparation for printing the service for the user. - return getServerlessConfigFile(process.cwd()) + return getServerlessConfigFile(this.serverless.config.servicePath) .then((svc) => { const service = svc; this.adorn(service); diff --git a/lib/utils/autocomplete.js b/lib/utils/autocomplete.js index 6b744aa8f..531de8bb9 100644 --- a/lib/utils/autocomplete.js +++ b/lib/utils/autocomplete.js @@ -40,27 +40,22 @@ const cacheFileValid = (serverlessConfigFile, validationHash) => { }; const autocomplete = () => { - let servicePath = process.cwd(); + const servicePath = process.cwd(); return getServerlessConfigFile(servicePath) - .then((serverlessConfigFile) => { - if (!serverlessConfigFile) { - servicePath = 'x'; - } - return getCacheFile(servicePath) - .then((cacheFile) => { - if (!cacheFile || !cacheFileValid(serverlessConfigFile, cacheFile.validationHash)) { - const serverless = new Serverless(); - return serverless.init().then(() => getCacheFile(servicePath)); - } - return cacheFile; - }) - .then((cacheFile) => { - if (!cacheFile || !cacheFileValid(serverlessConfigFile, cacheFile.validationHash)) { - return; - } - return getSuggestions(cacheFile.commands); // eslint-disable-line consistent-return - }); - }); + .then((serverlessConfigFile) => getCacheFile(servicePath) + .then((cacheFile) => { + if (!cacheFile || !cacheFileValid(serverlessConfigFile, cacheFile.validationHash)) { + const serverless = new Serverless(); + return serverless.init().then(() => getCacheFile(servicePath)); + } + return cacheFile; + }) + .then((cacheFile) => { + if (!cacheFile || !cacheFileValid(serverlessConfigFile, cacheFile.validationHash)) { + return; + } + return getSuggestions(cacheFile.commands); // eslint-disable-line consistent-return + })); }; module.exports = autocomplete; diff --git a/lib/utils/fs/parse.js b/lib/utils/fs/parse.js index f2dd20a0a..3987ff546 100644 --- a/lib/utils/fs/parse.js +++ b/lib/utils/fs/parse.js @@ -2,13 +2,37 @@ const jc = require('json-cycle'); const YAML = require('js-yaml'); +const _ = require('lodash'); +const cloudFormationSchema = require('../../plugins/aws/lib/cloudformationSchema'); + +const loadYaml = (contents, options) => { + let data; + let error; + try { + data = YAML.load(contents.toString(), options || {}); + } catch (exception) { + error = exception; + } + return { data, error }; +}; function parse(filePath, contents) { // Auto-parse JSON if (filePath.endsWith('.json')) { return jc.parse(contents); } else if (filePath.endsWith('.yml') || filePath.endsWith('.yaml')) { - return YAML.load(contents.toString(), { filename: filePath }); + const options = { + filename: filePath, + }; + let result = loadYaml(contents.toString(), options); + if (result.error && result.error.name === 'YAMLException') { + _.merge(options, { schema: cloudFormationSchema.schema }); + result = loadYaml(contents.toString(), options); + } + if (result.error) { + throw result.error; + } + return result.data; } return contents.toString().trim(); } diff --git a/lib/utils/fs/parse.test.js b/lib/utils/fs/parse.test.js index ee61ef94c..8473e925e 100644 --- a/lib/utils/fs/parse.test.js +++ b/lib/utils/fs/parse.test.js @@ -8,6 +8,82 @@ chai.use(require('chai-as-promised')); chai.use(require('sinon-chai')); const expect = require('chai').expect; +const shortHandOptions = [ + { + name: 'Ref', + yaml: 'Item: !Ref OtherItem', + json: { Item: { Ref: 'OtherItem' } }, + }, + { + name: 'GetAtt, dot syntax', + yaml: 'Item: !GetAtt MyResource.Arn', + json: { Item: { 'Fn::GetAtt': ['MyResource', 'Arn'] } }, + }, + { + name: 'GetAtt, array syntax', + yaml: 'Item: !GetAtt\n- MyResource\n- Arn', + json: { Item: { 'Fn::GetAtt': ['MyResource', 'Arn'] } }, + }, + { + name: 'Base64', + yaml: 'Item: !Base64 valueToEncode', + json: { Item: { 'Fn::Base64': 'valueToEncode' } }, + }, + { + name: 'Sub, without mapping', + yaml: 'Item: !Sub "My.${AWS::Region}"', + json: { Item: { 'Fn::Sub': 'My.${AWS::Region}' } }, + }, + { + name: 'Sub, with mapping', + yaml: 'Item: !Sub\n- www.${Domain}\n- { Domain: "serverless.com" }', + json: { + Item: { + 'Fn::Sub': [ + 'www.${Domain}', + { + Domain: 'serverless.com', + }, + ], + }, + }, + }, + { + name: 'Join, oneliner', + yaml: 'Item: !Join ["", ["arn:aws:s3::", { Ref: MyBucket }]]', + json: { + Item: { + 'Fn::Join': [ + '', + [ + 'arn:aws:s3::', + { + Ref: 'MyBucket', + }, + ], + ], + }, + }, + }, + { + name: 'Join, multiline', + yaml: 'Item: !Join\n- ""\n- - "arn:aws:s3::"\n - !Ref MyBucket', + json: { + Item: { + 'Fn::Join': [ + '', + [ + 'arn:aws:s3::', + { + Ref: 'MyBucket', + }, + ], + ], + }, + }, + }, +]; + describe('#parse()', () => { it('should reconstitute circular references', () => { const tmpFilePath = 'anything.json'; @@ -17,4 +93,54 @@ describe('#parse()', () => { expect(obj).to.equal(obj.foo); }); + + it('should return contents of a non json or yaml file as a string', () => { + const tmpFilePath = 'anything.txt'; + const fileContents = 'serverless'; + + const obj = parse(tmpFilePath, fileContents); + + expect(obj).to.equal('serverless'); + }); + + shortHandOptions.forEach(shortHandOption => { + it(`should convert shorthand syntax "${shortHandOption.name}"`, () => { + const tmpFilePath = 'anything.yml'; + const fileContents = shortHandOption.yaml; + const obj = parse(tmpFilePath, fileContents); + expect(obj).to.eql(shortHandOption.json); + }); + }); + + + it('should parse YAML without shorthand syntax', () => { + const tmpFilePath = 'anything.yml'; + const fileContents = 'Item:\n Fn::Join:\n - ""\n - - "arn:aws:s3::"\n - !Ref MyBucket'; + const obj = parse(tmpFilePath, fileContents); + expect(obj).to.eql({ + Item: { + 'Fn::Join': [ + '', + [ + 'arn:aws:s3::', + { + Ref: 'MyBucket', + }, + ], + ], + }, + }); + }); + + it('should throw error with invalid shorthand syntax', () => { + const tmpFilePath = 'anything.yml'; + const fileContents = 'Item:\n !Invalid\n- ""\n- - "arn:aws:s3::"\n - !Ref MyBucket'; + let obj; + try { + obj = parse(tmpFilePath, fileContents); + } catch (exception) { + expect(exception.name).to.be.equal('YAMLException'); + } + expect(obj).to.be.equal(undefined); + }); }); diff --git a/lib/utils/getCacheFilePath.js b/lib/utils/getCacheFilePath.js index 523c7b428..adf6d5d25 100644 --- a/lib/utils/getCacheFilePath.js +++ b/lib/utils/getCacheFilePath.js @@ -4,7 +4,8 @@ const homedir = require('os').homedir(); const path = require('path'); const crypto = require('crypto'); -const getCacheFilePath = function (servicePath) { +const getCacheFilePath = function (srvcPath) { + const servicePath = srvcPath || process.cwd(); const servicePathHash = crypto.createHash('sha256').update(servicePath).digest('hex'); return path.join(homedir, '.serverless', 'cache', servicePathHash, 'autocomplete.json'); }; diff --git a/lib/utils/getServerlessConfigFile.js b/lib/utils/getServerlessConfigFile.js index a85a1b67b..5b201ace1 100644 --- a/lib/utils/getServerlessConfigFile.js +++ b/lib/utils/getServerlessConfigFile.js @@ -6,7 +6,8 @@ const path = require('path'); const fileExists = require('./fs/fileExists'); const readFile = require('./fs/readFile'); -const getServerlessConfigFile = _.memoize((servicePath) => { +const getServerlessConfigFile = _.memoize((srvcPath) => { + const servicePath = srvcPath || process.cwd(); const jsonPath = path.join(servicePath, 'serverless.json'); const ymlPath = path.join(servicePath, 'serverless.yml'); const yamlPath = path.join(servicePath, 'serverless.yaml'); diff --git a/lib/utils/getServerlessConfigFile.test.js b/lib/utils/getServerlessConfigFile.test.js index 2d6c0fa48..40794ad23 100644 --- a/lib/utils/getServerlessConfigFile.test.js +++ b/lib/utils/getServerlessConfigFile.test.js @@ -73,4 +73,21 @@ describe('#getServerlessConfigFile()', () => { return expect(getServerlessConfigFile(tmpDirPath)) .to.be.rejectedWith('serverless.js must export plain object'); }); + + it('should look in the current working directory if servicePath is undefined', () => { + const serverlessFilePath = path.join(tmpDirPath, 'serverless.yml'); + + writeFileSync(serverlessFilePath, 'service: my-yml-service'); + const cwd = process.cwd(); + process.chdir(tmpDirPath); + return expect(getServerlessConfigFile()).to.be.fulfilled + .then(result => result) + .catch((ex) => { + process.chdir(cwd); + throw ex; + }) + .then((result) => { + expect(result).to.deep.equal({ service: 'my-yml-service' }); + }); + }); }); diff --git a/package-lock.json b/package-lock.json index e9f03bd3e..ae2700051 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,33 +1,41 @@ { "name": "serverless", - "version": "1.30.3", + "version": "1.32.0", "lockfileVersion": 1, "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.0.0-beta.56", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.56.tgz", - "integrity": "sha512-OBeGs8UXWpKl0oK2T5nUXNl2yu8RKxqL/7aUnMtKDXCU6VUrNP3npdrPivBA11HPB15TVI49nWf2lntTzoUuAg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", "dev": true, "requires": { - "@babel/highlight": "7.0.0-beta.56" + "@babel/highlight": "^7.0.0" } }, "@babel/highlight": { - "version": "7.0.0-beta.56", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.56.tgz", - "integrity": "sha512-q4TfI+jJISul6vVpZJktzH4tupwRiVk6KXRhB8PHqJ7erl966I6ePDXl9mAbE8jMM7YswhnnB0j1SYP7LBVyhg==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", "dev": true, "requires": { "chalk": "^2.0.0", "esutils": "^2.0.2", - "js-tokens": "^3.0.0" + "js-tokens": "^4.0.0" + }, + "dependencies": { + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + } } }, "@serverless/platform-sdk": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@serverless/platform-sdk/-/platform-sdk-0.2.1.tgz", - "integrity": "sha512-Iq9t67LNSVXUiw/r66NS6EhIwQvc67Hd1D+1buGkBFz0T2TA5dOPvP1cmInDO4L2pxeWoZ4tLCsksz1XKHfDaw==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@serverless/platform-sdk/-/platform-sdk-0.3.0.tgz", + "integrity": "sha512-Gw0y/HTy/+fA78DYABloFBBvz4g1iupuKBFeTP5+TSl7pDfhGHOiqjEKWPnqQHmvJ0ON3KnmV+3z8RcFw3vOAQ==", "requires": { "babel-polyfill": "^6.26.0", "body-parser": "^1.18.3", @@ -64,18 +72,27 @@ } }, "acorn": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", - "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", "dev": true }, "acorn-globals": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.1.0.tgz", - "integrity": "sha512-KjZwU26uG3u6eZcfGbTULzFcsoz6pegNKtHPksZPOUsiKo5bUmiBPa38FuHZ/Eun+XYh/JCCkS9AS3Lu4McQOQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz", + "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==", "dev": true, "requires": { - "acorn": "^5.0.0" + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.1.tgz", + "integrity": "sha512-SiwgrRuRD2D1R6qjwwoopKcCTkmmIWjy1M15Wv+Nk/7VUsBad4P8GOPft2t6coDZG0TuR5dq9o1v0g8wo7F6+A==", + "dev": true + } } }, "acorn-jsx": { @@ -95,6 +112,12 @@ } } }, + "acorn-walk": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.0.1.tgz", + "integrity": "sha512-PqVQ8c6a3kyqdsUZlC7nljp3FFuxipBRHKu+7C1h8QygBFlzTaDX5HD383jej3Peed+1aDG8HwkfB1Z1HMNPkw==", + "dev": true + }, "agent-base": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", @@ -121,22 +144,12 @@ "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", "dev": true }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "dev": true, - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - } - }, "amdefine": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true + "dev": true, + "optional": true }, "ansi": { "version": "0.3.1", @@ -223,6 +236,253 @@ "normalize-path": "^2.1.1" }, "dependencies": { + "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 + }, + "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 + }, + "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" + } + } + } + }, + "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": { + "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" + } + }, + "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": { + "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-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": { + "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-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" + } + }, + "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 + } + } + }, + "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" + } + } + } + }, + "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" + } + } + } + }, + "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" + } + }, + "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" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -253,12 +513,12 @@ } }, "append-transform": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", - "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", + "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", "dev": true, "requires": { - "default-require-extensions": "^2.0.0" + "default-require-extensions": "^1.0.0" } }, "archiver": { @@ -318,10 +578,13 @@ } }, "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 + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } }, "arr-flatten": { "version": "1.1.0", @@ -360,9 +623,9 @@ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" }, "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", "dev": true }, "array.prototype.find": { @@ -437,9 +700,9 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "atob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", + "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 }, "autolinker": { @@ -449,9 +712,9 @@ "dev": true }, "aws-sdk": { - "version": "2.289.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.289.0.tgz", - "integrity": "sha512-MboTnvLtEjG0CECsI2OHQx7q9DghiKtQgDFsbpPOuQhS9khVHS2RkN+eanExbN9W5yo7IGdHlOcrUfSTErRN5A==", + "version": "2.317.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.317.0.tgz", + "integrity": "sha512-X2Cd1Gb9Cf9WVgGOiBSW4TK6q5Mb6AYiGmEA9XikCgur4H8E4TgmgWbBWJnTzxssugclVLVoWQfw3RshNKJksg==", "requires": { "buffer": "4.9.1", "events": "1.1.1", @@ -466,7 +729,7 @@ "dependencies": { "buffer": { "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", "requires": { "base64-js": "^1.0.2", @@ -606,9 +869,9 @@ } }, "babel-jest": { - "version": "23.4.2", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.4.2.tgz", - "integrity": "sha512-wg1LJ2tzsafXqPFVgAsYsMCVD5U7kwJZAvbZIxVm27iOewsQw1BR7VZifDlMTEWVo3wasoPPyMdKXWCsfFPr3Q==", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-23.6.0.tgz", + "integrity": "sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew==", "dev": true, "requires": { "babel-plugin-istanbul": "^4.1.6", @@ -833,6 +1096,12 @@ "kind-of": "^6.0.2" } }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -866,9 +1135,9 @@ } }, "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz", + "integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg==" }, "body-parser": { "version": "1.18.3", @@ -940,32 +1209,14 @@ } }, "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "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" - } - } + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" } }, "browser-process-hrtime": { @@ -1007,9 +1258,9 @@ } }, "buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.0.tgz", - "integrity": "sha512-nUJyfChH7PMJy75eRDCCKtszSEFokUNXC1hNVSe+o+VdcgvDPLs20k3v8UXI8ruRYAJiYtyRea8mYyqPxoHWDw==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" @@ -1070,6 +1321,14 @@ "to-object-path": "^0.3.0", "union-value": "^1.0.0", "unset-value": "^1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } } }, "caller-id": { @@ -1111,9 +1370,9 @@ } }, "capture-stack-trace": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==" }, "caseless": { "version": "0.12.0", @@ -1132,17 +1391,6 @@ "url-to-options": "^1.0.1" } }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, "chai": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", @@ -1180,9 +1428,9 @@ "dev": true }, "ci-info": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz", - "integrity": "sha512-SK/846h/Rcy8q9Z9CAwGBLfCJ6EkjJWdpelWDufQpqVDYq2Wnnv8zlSO6AMQap02jvhVruKKpEtQOufo3pFhLg==" + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.5.1.tgz", + "integrity": "sha512-fKFIKXaYiL1exImwJ0AhR/6jxFPSKQBk2ayV5NiNoruUs2+rxC2kNw0EG+1Z9dugZRdCrppskQ8DN2cyaUM1Hw==" }, "circular-json": { "version": "0.3.3", @@ -1210,6 +1458,12 @@ "requires": { "is-descriptor": "^0.1.0" } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true } } }, @@ -1232,23 +1486,46 @@ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" }, "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, - "optional": true, "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0", + "wrap-ansi": "^2.0.0" }, "dependencies": { - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "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", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, - "optional": true + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "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" + } } } }, @@ -1280,17 +1557,17 @@ } }, "color-convert": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", - "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "requires": { - "color-name": "1.1.1" + "color-name": "1.1.3" } }, "color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "combined-stream": { "version": "1.0.6", @@ -1308,12 +1585,6 @@ "graceful-readlink": ">= 1.0.0" } }, - "compare-versions": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.3.0.tgz", - "integrity": "sha512-MAAAIOdi2s4Gl6rZ76PNcUa9IOYB+5ICdT41o5uMRf09aEu/F9RK+qhe8RjXNPwcTjGV7KU7h2P/fljThFVqyQ==", - "dev": true - }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", @@ -1347,9 +1618,9 @@ } }, "config-chain": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz", - "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", "requires": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -1385,10 +1656,13 @@ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, "convert-source-map": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", - "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", - "dev": true + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } }, "cookie": { "version": "0.3.1", @@ -1491,9 +1765,9 @@ "dev": true }, "cssstyle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.0.0.tgz", - "integrity": "sha512-Bpuh47j2mRMY60X90mXaJAEtJwxvA2roZzbgwAXYhMbmwmakdRr4Cq9L5SkleKJNLOKqHIa2YWyOXDX3VgggSQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.1.1.tgz", + "integrity": "sha512-364AI1l/M5TYcFH83JnOH/pSqgaNnKmYgKrm0didZMGKWjQB60dymwWy1rKUgL3J1ffdq9xVi2yGLHdSjjSNog==", "dev": true, "requires": { "cssom": "0.3.x" @@ -1524,21 +1798,26 @@ } }, "data-urls": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.0.0.tgz", - "integrity": "sha512-ai40PPQR0Fn1lD2PPie79CibnlMN2AYiDhwFX/rZHVsxbs5kNJSjegqXIprhouGXlRdEnfybva7kqRGnB6mypA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.0.1.tgz", + "integrity": "sha512-0HdcMZzK6ubMUnsMmQmG0AcLQPvbvb47R0+7CCZQCYgcd8OUWG91CG7sM6GoXgjz+WLl4ArFzHtBMy/QqSF4eg==", "dev": true, "requires": { - "abab": "^1.0.4", - "whatwg-mimetype": "^2.0.0", - "whatwg-url": "^6.4.0" + "abab": "^2.0.0", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^7.0.0" }, "dependencies": { - "abab": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", - "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=", - "dev": true + "whatwg-url": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", + "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } } } }, @@ -1678,22 +1957,32 @@ "dev": true }, "default-require-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", - "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", + "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", "dev": true, "requires": { - "strip-bom": "^3.0.0" + "strip-bom": "^2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + } } }, "define-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", - "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { - "foreach": "^2.0.5", - "object-keys": "^1.0.8" + "object-keys": "^1.0.12" } }, "define-property": { @@ -1735,6 +2024,12 @@ "kind-of": "^6.0.2" } }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -1937,9 +2232,9 @@ } }, "es5-ext": { - "version": "0.10.45", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz", - "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==", + "version": "0.10.46", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.46.tgz", + "integrity": "sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw==", "dev": true, "requires": { "es6-iterator": "~2.0.3", @@ -1973,9 +2268,9 @@ } }, "es6-promise": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", - "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==" + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.5.tgz", + "integrity": "sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==" }, "es6-promisify": { "version": "5.0.0", @@ -2377,38 +2672,12 @@ "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=" }, "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "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": { - "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" - } - } + "is-posix-bracket": "^0.1.0" } }, "expand-range": { @@ -2418,51 +2687,18 @@ "dev": true, "requires": { "fill-range": "^2.1.0" - }, - "dependencies": { - "fill-range": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", - "dev": true, - "requires": { - "is-number": "^2.1.0", - "isobject": "^2.0.0", - "randomatic": "^3.0.0", - "repeat-element": "^1.1.2", - "repeat-string": "^1.5.2" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "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" - } - } } }, "expect": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-23.4.0.tgz", - "integrity": "sha1-baTsyZwUcSU+cogziYOtHrrbYMM=", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-23.6.0.tgz", + "integrity": "sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w==", "dev": true, "requires": { "ansi-styles": "^3.2.0", - "jest-diff": "^23.2.0", + "jest-diff": "^23.6.0", "jest-get-type": "^22.1.0", - "jest-matcher-utils": "^23.2.0", + "jest-matcher-utils": "^23.6.0", "jest-message-util": "^23.4.0", "jest-regex-util": "^23.3.0" } @@ -2609,74 +2845,12 @@ } }, "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "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" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } + "is-extglob": "^1.0.0" } }, "extsprintf": { @@ -2790,26 +2964,16 @@ } }, "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", "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" - } - } + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" } }, "finalhandler": { @@ -2870,12 +3034,6 @@ "for-in": "^1.0.1" } }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -3495,10 +3653,13 @@ } }, "generate-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", - "dev": true + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dev": true, + "requires": { + "is-property": "^1.0.2" + } }, "generate-object-property": { "version": "1.2.0", @@ -3549,9 +3710,9 @@ } }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3679,24 +3840,24 @@ "dev": true }, "handlebars": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", - "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.12.tgz", + "integrity": "sha512-RhmTekP+FZL+XNhwS1Wf+bTTZpdLougwt5pcgA1tuz6Jcx0fpH/7z0qd71RKnZHBCxIRBHfBOnio4gViPemNzA==", "dev": true, "requires": { - "async": "^1.4.0", + "async": "^2.5.0", "optimist": "^0.6.1", - "source-map": "^0.4.4", - "uglify-js": "^2.6" + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" }, "dependencies": { - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", + "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", "dev": true, "requires": { - "amdefine": ">=0.0.4" + "lodash": "^4.17.10" } } } @@ -3708,12 +3869,12 @@ "dev": true }, "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", + "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", "dev": true, "requires": { - "ajv": "^5.1.0", + "ajv": "^5.3.0", "har-schema": "^2.0.0" } }, @@ -3772,6 +3933,14 @@ "get-value": "^2.0.6", "has-values": "^1.0.0", "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } } }, "has-values": { @@ -3784,6 +3953,26 @@ "kind-of": "^4.0.0" }, "dependencies": { + "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", @@ -3883,12 +4072,17 @@ }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" } } }, @@ -4084,11 +4278,11 @@ "dev": true }, "is-ci": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.1.0.tgz", - "integrity": "sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", "requires": { - "ci-info": "^1.0.0" + "ci-info": "^1.5.0" } }, "is-data-descriptor": { @@ -4211,9 +4405,9 @@ "dev": true }, "is-my-json-valid": { - "version": "2.17.2", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", - "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.19.0.tgz", + "integrity": "sha512-mG0f/unGX1HZ5ep4uhRaPOS8EkAY8/j6mDRMJrutq4CqhoJWYp7qAlonIPy3TV7p3ju4TK9fo/PbnoksWmsp5Q==", "dev": true, "requires": { "generate-function": "^2.0.0", @@ -4234,9 +4428,9 @@ "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=" }, "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "dev": true, "requires": { "kind-of": "^3.0.2" @@ -4282,6 +4476,14 @@ "dev": true, "requires": { "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } } }, "is-posix-bracket": { @@ -4377,10 +4579,13 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "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" + } }, "isomorphic-fetch": { "version": "2.2.1", @@ -4462,20 +4667,19 @@ } }, "istanbul-api": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.1.tgz", - "integrity": "sha512-duj6AlLcsWNwUpfyfHt0nWIeRiZpuShnP40YTxOGQgtaN8fd6JYSxsvxUphTDy8V5MfDXo4s/xVCIIvVCO808g==", + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.3.7.tgz", + "integrity": "sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA==", "dev": true, "requires": { "async": "^2.1.4", - "compare-versions": "^3.1.0", "fileset": "^2.0.2", - "istanbul-lib-coverage": "^1.2.0", - "istanbul-lib-hook": "^1.2.0", - "istanbul-lib-instrument": "^1.10.1", - "istanbul-lib-report": "^1.1.4", - "istanbul-lib-source-maps": "^1.2.4", - "istanbul-reports": "^1.3.0", + "istanbul-lib-coverage": "^1.2.1", + "istanbul-lib-hook": "^1.2.2", + "istanbul-lib-instrument": "^1.10.2", + "istanbul-lib-report": "^1.1.5", + "istanbul-lib-source-maps": "^1.2.6", + "istanbul-reports": "^1.5.1", "js-yaml": "^3.7.0", "mkdirp": "^0.5.1", "once": "^1.4.0" @@ -4493,24 +4697,24 @@ } }, "istanbul-lib-coverage": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz", - "integrity": "sha512-GvgM/uXRwm+gLlvkWHTjDAvwynZkL9ns15calTrmhGgowlwJBbWMYzWbKqE2DT6JDP1AFXKa+Zi0EkqNCUqY0A==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz", + "integrity": "sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ==", "dev": true }, "istanbul-lib-hook": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.1.tgz", - "integrity": "sha512-eLAMkPG9FU0v5L02lIkcj/2/Zlz9OuluaXikdr5iStk8FDbSwAixTK9TkYxbF0eNnzAJTwM2fkV2A1tpsIp4Jg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz", + "integrity": "sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw==", "dev": true, "requires": { - "append-transform": "^1.0.0" + "append-transform": "^0.4.0" } }, "istanbul-lib-instrument": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz", - "integrity": "sha512-1dYuzkOCbuR5GRJqySuZdsmsNKPL3PTuyPevQfoCXJePT9C8y1ga75neU+Tuy9+yS3G/dgx8wgOmp2KLpgdoeQ==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz", + "integrity": "sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A==", "dev": true, "requires": { "babel-generator": "^6.18.0", @@ -4518,17 +4722,17 @@ "babel-traverse": "^6.18.0", "babel-types": "^6.18.0", "babylon": "^6.18.0", - "istanbul-lib-coverage": "^1.2.0", + "istanbul-lib-coverage": "^1.2.1", "semver": "^5.3.0" } }, "istanbul-lib-report": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.4.tgz", - "integrity": "sha512-Azqvq5tT0U09nrncK3q82e/Zjkxa4tkFZv7E6VcqP0QCPn6oNljDPfrZEC/umNXds2t7b8sRJfs6Kmpzt8m2kA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz", + "integrity": "sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw==", "dev": true, "requires": { - "istanbul-lib-coverage": "^1.2.0", + "istanbul-lib-coverage": "^1.2.1", "mkdirp": "^0.5.1", "path-parse": "^1.0.5", "supports-color": "^3.1.2" @@ -4552,27 +4756,33 @@ } }, "istanbul-lib-source-maps": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.5.tgz", - "integrity": "sha512-8O2T/3VhrQHn0XcJbP1/GN7kXMiRAlPi+fj3uEHrjBD8Oz7Py0prSC25C09NuAZS6bgW1NNKAvCSHZXB0irSGA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz", + "integrity": "sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg==", "dev": true, "requires": { "debug": "^3.1.0", - "istanbul-lib-coverage": "^1.2.0", + "istanbul-lib-coverage": "^1.2.1", "mkdirp": "^0.5.1", "rimraf": "^2.6.1", "source-map": "^0.5.3" }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, + "ms": { + "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 + }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -4582,9 +4792,9 @@ } }, "istanbul-reports": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.3.0.tgz", - "integrity": "sha512-y2Z2IMqE1gefWUaVjrBm0mSKvUkaBy9Vqz8iwr/r40Y9hBbIteH5wqHG/9DLTfJ9xUnUT2j7A3+VVJ6EaYBllA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.5.1.tgz", + "integrity": "sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw==", "dev": true, "requires": { "handlebars": "^4.0.3" @@ -4609,9 +4819,9 @@ } }, "jest-cli": { - "version": "23.4.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-23.4.2.tgz", - "integrity": "sha512-vaDzy0wRWrgSfz4ZImCqD2gtZqCSoEWp60y3USvGDxA2b4K0rGj2voru6a5scJFjDx5GCiNWKpz2E8IdWDVjdw==", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-23.6.0.tgz", + "integrity": "sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ==", "dev": true, "requires": { "ansi-escapes": "^3.0.0", @@ -4626,18 +4836,18 @@ "istanbul-lib-instrument": "^1.10.1", "istanbul-lib-source-maps": "^1.2.4", "jest-changed-files": "^23.4.2", - "jest-config": "^23.4.2", + "jest-config": "^23.6.0", "jest-environment-jsdom": "^23.4.0", "jest-get-type": "^22.1.0", - "jest-haste-map": "^23.4.1", + "jest-haste-map": "^23.6.0", "jest-message-util": "^23.4.0", "jest-regex-util": "^23.3.0", - "jest-resolve-dependencies": "^23.4.2", - "jest-runner": "^23.4.2", - "jest-runtime": "^23.4.2", - "jest-snapshot": "^23.4.2", + "jest-resolve-dependencies": "^23.6.0", + "jest-runner": "^23.6.0", + "jest-runtime": "^23.6.0", + "jest-snapshot": "^23.6.0", "jest-util": "^23.4.0", - "jest-validate": "^23.4.0", + "jest-validate": "^23.6.0", "jest-watcher": "^23.4.0", "jest-worker": "^23.2.0", "micromatch": "^2.3.11", @@ -4664,42 +4874,6 @@ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "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", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "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" - } - }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -4708,60 +4882,41 @@ "requires": { "ansi-regex": "^3.0.0" } - }, - "yargs": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", - "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - } } } }, "jest-config": { - "version": "23.4.2", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-23.4.2.tgz", - "integrity": "sha512-CDJGO4H+7P+T6khaSHEjTxqVaIlmQMEFAyJFOVrAQeM+Xn12iZ+YY8Pluk1RDxi8Jqj9DoE09PHQzASCGePGtg==", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-23.6.0.tgz", + "integrity": "sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ==", "dev": true, "requires": { "babel-core": "^6.0.0", - "babel-jest": "^23.4.2", + "babel-jest": "^23.6.0", "chalk": "^2.0.1", "glob": "^7.1.1", "jest-environment-jsdom": "^23.4.0", "jest-environment-node": "^23.4.0", "jest-get-type": "^22.1.0", - "jest-jasmine2": "^23.4.2", + "jest-jasmine2": "^23.6.0", "jest-regex-util": "^23.3.0", - "jest-resolve": "^23.4.1", + "jest-resolve": "^23.6.0", "jest-util": "^23.4.0", - "jest-validate": "^23.4.0", - "pretty-format": "^23.2.0" + "jest-validate": "^23.6.0", + "micromatch": "^2.3.11", + "pretty-format": "^23.6.0" } }, "jest-diff": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-23.2.0.tgz", - "integrity": "sha1-nyz0tR4Sx5FVAgCrwWtHEwrxBio=", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-23.6.0.tgz", + "integrity": "sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g==", "dev": true, "requires": { "chalk": "^2.0.1", "diff": "^3.2.0", "jest-get-type": "^22.1.0", - "pretty-format": "^23.2.0" + "pretty-format": "^23.6.0" } }, "jest-docblock": { @@ -4774,13 +4929,13 @@ } }, "jest-each": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-23.4.0.tgz", - "integrity": "sha1-L6nt2J2qGk7cn/m/YGKja3E0UUM=", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-23.6.0.tgz", + "integrity": "sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg==", "dev": true, "requires": { "chalk": "^2.0.1", - "pretty-format": "^23.2.0" + "pretty-format": "^23.6.0" } }, "jest-environment-jsdom": { @@ -4811,13 +4966,14 @@ "dev": true }, "jest-haste-map": { - "version": "23.4.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-23.4.1.tgz", - "integrity": "sha512-PGQxOEGAfRbTyJkmZeOKkVSs+KVeWgG625p89KUuq+sIIchY5P8iPIIc+Hw2tJJPBzahU3qopw1kF/qyhDdNBw==", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-23.6.0.tgz", + "integrity": "sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg==", "dev": true, "requires": { "fb-watchman": "^2.0.0", "graceful-fs": "^4.1.11", + "invariant": "^2.2.4", "jest-docblock": "^23.2.0", "jest-serializer": "^23.0.1", "jest-worker": "^23.2.0", @@ -4826,43 +4982,43 @@ } }, "jest-jasmine2": { - "version": "23.4.2", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-23.4.2.tgz", - "integrity": "sha512-MUoqn41XHMQe5u8QvRTH2HahpBNzImnnjS3pV/T7LvrCM6f2zfGdi1Pm+bRbFMLJROqR8VlK8HmsenL2WjrUIQ==", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-23.6.0.tgz", + "integrity": "sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ==", "dev": true, "requires": { "babel-traverse": "^6.0.0", "chalk": "^2.0.1", "co": "^4.6.0", - "expect": "^23.4.0", + "expect": "^23.6.0", "is-generator-fn": "^1.0.0", - "jest-diff": "^23.2.0", - "jest-each": "^23.4.0", - "jest-matcher-utils": "^23.2.0", + "jest-diff": "^23.6.0", + "jest-each": "^23.6.0", + "jest-matcher-utils": "^23.6.0", "jest-message-util": "^23.4.0", - "jest-snapshot": "^23.4.2", + "jest-snapshot": "^23.6.0", "jest-util": "^23.4.0", - "pretty-format": "^23.2.0" + "pretty-format": "^23.6.0" } }, "jest-leak-detector": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-23.2.0.tgz", - "integrity": "sha1-wonZYdxjjxQ1fU75bgQx7MGqN30=", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-23.6.0.tgz", + "integrity": "sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg==", "dev": true, "requires": { - "pretty-format": "^23.2.0" + "pretty-format": "^23.6.0" } }, "jest-matcher-utils": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-23.2.0.tgz", - "integrity": "sha1-TUmB8jIT6Tnjzt8j3DTHR7WuGRM=", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz", + "integrity": "sha512-rosyCHQfBcol4NsckTn01cdelzWLU9Cq7aaigDf8VwwpIRvWE/9zLgX2bON+FkEW69/0UuYslUe22SOdEf2nog==", "dev": true, "requires": { "chalk": "^2.0.1", "jest-get-type": "^22.1.0", - "pretty-format": "^23.2.0" + "pretty-format": "^23.6.0" } }, "jest-message-util": { @@ -4891,9 +5047,9 @@ "dev": true }, "jest-resolve": { - "version": "23.4.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-23.4.1.tgz", - "integrity": "sha512-VNk4YRNR5gsHhNS0Lp46/DzTT11e+ecbUC61ikE593cKbtdrhrMO+zXkOJaE8YDD5sHxH9W6OfssNn4FkZBzZQ==", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-23.6.0.tgz", + "integrity": "sha512-XyoRxNtO7YGpQDmtQCmZjum1MljDqUCob7XlZ6jy9gsMugHdN2hY4+Acz9Qvjz2mSsOnPSH7skBmDYCHXVZqkA==", "dev": true, "requires": { "browser-resolve": "^1.11.3", @@ -4902,30 +5058,30 @@ } }, "jest-resolve-dependencies": { - "version": "23.4.2", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-23.4.2.tgz", - "integrity": "sha512-JUrU1/1mQAf0eKwKT4+RRnaqcw0UcRzRE38vyO+YnqoXUVidf646iuaKE+NG7E6Gb0+EVPOJ6TgqkaTPdQz78A==", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-23.6.0.tgz", + "integrity": "sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA==", "dev": true, "requires": { "jest-regex-util": "^23.3.0", - "jest-snapshot": "^23.4.2" + "jest-snapshot": "^23.6.0" } }, "jest-runner": { - "version": "23.4.2", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-23.4.2.tgz", - "integrity": "sha512-o+aEdDE7/Gyp8fLYEEf5B8aOUguz76AYcAMl5pueucey2Q50O8uUIXJ7zvt8O6OEJDztR3Kb+osMoh8MVIqgTw==", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-23.6.0.tgz", + "integrity": "sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA==", "dev": true, "requires": { "exit": "^0.1.2", "graceful-fs": "^4.1.11", - "jest-config": "^23.4.2", + "jest-config": "^23.6.0", "jest-docblock": "^23.2.0", - "jest-haste-map": "^23.4.1", - "jest-jasmine2": "^23.4.2", - "jest-leak-detector": "^23.2.0", + "jest-haste-map": "^23.6.0", + "jest-jasmine2": "^23.6.0", + "jest-leak-detector": "^23.6.0", "jest-message-util": "^23.4.0", - "jest-runtime": "^23.4.2", + "jest-runtime": "^23.6.0", "jest-util": "^23.4.0", "jest-worker": "^23.2.0", "source-map-support": "^0.5.6", @@ -4933,9 +5089,9 @@ } }, "jest-runtime": { - "version": "23.4.2", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-23.4.2.tgz", - "integrity": "sha512-qaUDOi7tcdDe3MH5g5ycEslTpx0voPZvzIYbKjvWxCzCL2JEemLM+7IEe0BeLi2v5wvb/uh3dkb2wQI67uPtCw==", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-23.6.0.tgz", + "integrity": "sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw==", "dev": true, "requires": { "babel-core": "^6.0.0", @@ -4945,93 +5101,20 @@ "exit": "^0.1.2", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.1.11", - "jest-config": "^23.4.2", - "jest-haste-map": "^23.4.1", + "jest-config": "^23.6.0", + "jest-haste-map": "^23.6.0", "jest-message-util": "^23.4.0", "jest-regex-util": "^23.3.0", - "jest-resolve": "^23.4.1", - "jest-snapshot": "^23.4.2", + "jest-resolve": "^23.6.0", + "jest-snapshot": "^23.6.0", "jest-util": "^23.4.0", - "jest-validate": "^23.4.0", + "jest-validate": "^23.6.0", "micromatch": "^2.3.11", "realpath-native": "^1.0.0", "slash": "^1.0.0", "strip-bom": "3.0.0", "write-file-atomic": "^2.1.0", "yargs": "^11.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "cliui": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", - "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", - "dev": true, - "requires": { - "string-width": "^2.1.1", - "strip-ansi": "^4.0.0", - "wrap-ansi": "^2.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "^2.0.0" - } - }, - "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", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "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" - } - }, - "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" - } - }, - "yargs": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", - "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", - "dev": true, - "requires": { - "cliui": "^4.0.0", - "decamelize": "^1.1.1", - "find-up": "^2.1.0", - "get-caller-file": "^1.0.1", - "os-locale": "^2.0.0", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^2.0.0", - "which-module": "^2.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^9.0.2" - } - } } }, "jest-serializer": { @@ -5041,20 +5124,20 @@ "dev": true }, "jest-snapshot": { - "version": "23.4.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-23.4.2.tgz", - "integrity": "sha512-rCBxIURDlVEW1gJgJSpo8l2F2gFwp9U7Yb3CmcABUpmQ8NASpb6LJkEvtcQifAYSi22OL44TSuanq1G6x1GJwg==", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-23.6.0.tgz", + "integrity": "sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg==", "dev": true, "requires": { "babel-types": "^6.0.0", "chalk": "^2.0.1", - "jest-diff": "^23.2.0", - "jest-matcher-utils": "^23.2.0", + "jest-diff": "^23.6.0", + "jest-matcher-utils": "^23.6.0", "jest-message-util": "^23.4.0", - "jest-resolve": "^23.4.1", + "jest-resolve": "^23.6.0", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "pretty-format": "^23.2.0", + "pretty-format": "^23.6.0", "semver": "^5.5.0" } }, @@ -5083,15 +5166,15 @@ } }, "jest-validate": { - "version": "23.4.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-23.4.0.tgz", - "integrity": "sha1-2W7t4B7wOskJwAnpyORVGX1IwgE=", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-23.6.0.tgz", + "integrity": "sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A==", "dev": true, "requires": { "chalk": "^2.0.1", "jest-get-type": "^22.1.0", "leven": "^2.1.0", - "pretty-format": "^23.2.0" + "pretty-format": "^23.6.0" } }, "jest-watcher": { @@ -5236,9 +5319,9 @@ }, "dependencies": { "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", + "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==" } } }, @@ -5388,9 +5471,9 @@ } }, "kleur": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-2.0.1.tgz", - "integrity": "sha512-Zq/jyANIJ2uX8UZjWlqLwbyhcxSXJtT/Y89lClyeZd3l++3ztL1I5SSCYrbcbwSunTjC88N3WuMk0kRDQD6gzA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-2.0.2.tgz", + "integrity": "sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ==", "dev": true }, "latest-version": { @@ -5402,11 +5485,13 @@ } }, "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", + "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", "dev": true, - "optional": true + "requires": { + "set-getter": "^0.1.0" + } }, "lazystream": { "version": "1.0.0", @@ -5482,15 +5567,6 @@ "requires": { "is-extendable": "^0.1.0" } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } } } }, @@ -5537,9 +5613,9 @@ } }, "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" }, "lodash.cond": { "version": "4.5.2", @@ -5608,12 +5684,6 @@ "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", "dev": true }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", - "dev": true - }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -5704,9 +5774,9 @@ }, "dependencies": { "commander": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", - "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", + "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", "dev": true }, "find-up": { @@ -5755,17 +5825,6 @@ "remarkable": "^1.7.1", "repeat-string": "^1.6.1", "strip-color": "^0.1.0" - }, - "dependencies": { - "lazy-cache": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", - "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", - "dev": true, - "requires": { - "set-getter": "^0.1.0" - } - } } }, "math-random": { @@ -5832,52 +5891,6 @@ "object.omit": "^2.0.0", "parse-glob": "^3.0.4", "regex-cache": "^0.4.2" - }, - "dependencies": { - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1" - } - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", - "dev": true - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "dev": true, - "requires": { - "expand-range": "^1.8.1", - "preserve": "^0.2.0", - "repeat-element": "^1.1.2" - } - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "dev": true, - "requires": { - "is-posix-bracket": "^0.1.0" - } - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "dev": true, - "requires": { - "is-extglob": "^1.0.0" - } - } } }, "mime": { @@ -5886,16 +5899,16 @@ "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" }, "mime-db": { - "version": "1.35.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", - "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" }, "mime-types": { - "version": "2.1.19", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", - "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", "requires": { - "mime-db": "~1.35.0" + "mime-db": "~1.36.0" } }, "mimic-fn": { @@ -5986,6 +5999,29 @@ "requires": { "ms": "2.0.0" } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "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" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } } } }, @@ -6051,6 +6087,18 @@ "to-regex": "^3.0.1" }, "dependencies": { + "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 + }, + "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 + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -6177,15 +6225,15 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "nwsapi": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.8.tgz", - "integrity": "sha512-7RZ+qbFGiVc6v14Y8DSZjPN1wZPOaMbiiP4tzf5eNuyOITAeOIA3cMhjuKUypVIqBgCSg1KaSyAv8Ocq/0ZJ1A==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.0.9.tgz", + "integrity": "sha512-nlWFSCTYQcHk/6A9FFnfhKc14c3aFhfdNBXgo8Qgi9QTBu/qg3Ww+Uiz9wMzXd1T8GFxPc2QIHB6Qtf2XFryFQ==", "dev": true }, "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, "object-assign": { @@ -6233,6 +6281,14 @@ "dev": true, "requires": { "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } } }, "object.assign": { @@ -6274,6 +6330,14 @@ "dev": true, "requires": { "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } } }, "on-finished": { @@ -6294,7 +6358,7 @@ }, "onetime": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=" }, "opn": { @@ -6485,9 +6549,9 @@ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, "path-loader": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-loader/-/path-loader-1.0.6.tgz", - "integrity": "sha512-vAtndQsgWS0s2JOjT+NWtJyP5Gc940SlQQ55j0+qSj/SJQ4dmt/L8gLeW9wJF0rM32qEts+3NDvKjs6TUxwFtg==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/path-loader/-/path-loader-1.0.9.tgz", + "integrity": "sha512-pD37gArtr+/72Tst9oJoDB9k7gB9A09Efj7yyBi5HDUqaxqULXBWW8Rnw2TfNF+3sN7QZv0ZNdW1Qx2pFGW5Jg==", "requires": { "native-promise-only": "^0.8.1", "superagent": "^3.8.3" @@ -6598,9 +6662,9 @@ "dev": true }, "pretty-format": { - "version": "23.2.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.2.0.tgz", - "integrity": "sha1-OwqqY8AYpTWDNzwcs6XZbMXoMBc=", + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", + "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", "dev": true, "requires": { "ansi-regex": "^3.0.0", @@ -6694,6 +6758,12 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, + "psl": { + "version": "1.1.29", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==", + "dev": true + }, "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", @@ -6840,9 +6910,9 @@ } }, "realpath-native": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.0.1.tgz", - "integrity": "sha512-W14EcXuqUvKP8dkWkD7B95iMy77lpMnlFXbbk409bQtNCbeu0kvRE5reo+yIZ3JXxg6frbGsz2DLQ39lrCB40g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.0.2.tgz", + "integrity": "sha512-+S3zTvVt9yTntFrBpm7TQmQ3tzpCrnA1a/y+3cUHAc9ZR6aIjG0WNLR+Rj79QpJktY+VeW/TQtFlQ1bzsehI8g==", "dev": true, "requires": { "util.promisify": "^1.0.0" @@ -6926,9 +6996,9 @@ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" }, "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "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": { @@ -6952,33 +7022,39 @@ "integrity": "sha1-gdgax663LX9cSUKt8ml6MiBojY4=" }, "request": { - "version": "2.87.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", - "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "dev": true, "requires": { "aws-sign2": "~0.7.0", - "aws4": "^1.6.0", + "aws4": "^1.8.0", "caseless": "~0.12.0", - "combined-stream": "~1.0.5", - "extend": "~3.0.1", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", "forever-agent": "~0.6.1", - "form-data": "~2.3.1", - "har-validator": "~5.0.3", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.17", - "oauth-sign": "~0.8.2", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", "performance-now": "^2.1.0", - "qs": "~6.5.1", - "safe-buffer": "^5.1.1", - "tough-cookie": "~2.3.3", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", "tunnel-agent": "^0.6.0", - "uuid": "^3.1.0" + "uuid": "^3.3.2" }, "dependencies": { + "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 + }, "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", @@ -7082,16 +7158,6 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "dev": true, - "optional": true, - "requires": { - "align-text": "^0.1.1" - } - }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", @@ -7167,6 +7233,253 @@ "watch": "~0.18.0" }, "dependencies": { + "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 + }, + "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 + }, + "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" + } + } + } + }, + "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": { + "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" + } + }, + "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": { + "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-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": { + "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-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" + } + }, + "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 + } + } + }, + "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" + } + } + } + }, + "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" + } + } + } + }, + "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" + } + }, + "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" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -7210,9 +7523,9 @@ } }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==" }, "semver-diff": { "version": "2.1.0", @@ -7475,6 +7788,12 @@ "kind-of": "^6.0.2" } }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -7511,9 +7830,9 @@ } }, "source-map-support": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.6.tgz", - "integrity": "sha512-N4KXEz7jcKqPf2b2vZF11lQIz9W5ZMuUcIOGj243lduidkf2fjkVKJS9vNxVWn3u/uxX38AcE8U9nnH9FPcq+g==", + "version": "0.5.9", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", + "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -7561,9 +7880,9 @@ } }, "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz", + "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==", "dev": true }, "split-string": { @@ -7749,19 +8068,24 @@ }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" } } }, "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "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" } @@ -7905,45 +8229,16 @@ } }, "test-exclude": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.1.tgz", - "integrity": "sha512-qpqlP/8Zl+sosLxBcVKl9vYy26T9NPalxSzzCP/OY6K7j938ui2oKgo+kRZYfxAeIpLqpbVnsHq1tyV70E4lWQ==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.2.3.tgz", + "integrity": "sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA==", "dev": true, "requires": { "arrify": "^1.0.1", - "micromatch": "^3.1.8", + "micromatch": "^2.3.11", "object-assign": "^4.1.0", "read-pkg-up": "^1.0.1", "require-main-filename": "^1.0.1" - }, - "dependencies": { - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "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" - } - } } }, "text-table": { @@ -8044,6 +8339,17 @@ "requires": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" + }, + "dependencies": { + "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" + } + } } }, "toml": { @@ -8053,11 +8359,12 @@ "dev": true }, "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "dev": true, "requires": { + "psl": "^1.1.24", "punycode": "^1.4.1" }, "dependencies": { @@ -8145,37 +8452,29 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "version": "3.4.9", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", + "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", "dev": true, "optional": true, "requires": { - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" + "commander": "~2.17.1", + "source-map": "~0.6.1" }, "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", "dev": true, "optional": true } } }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true, - "optional": true - }, "unbzip2-stream": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.2.5.tgz", - "integrity": "sha512-izD3jxT8xkzwtXRUZjtmRwKnZoeECrfZ8ra/ketwOcusbZEp4mjULMnJOCfTDZBgGQAAY1AJ/IgxcwkavcX9Og==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.0.tgz", + "integrity": "sha512-kE2WkurNnPUMcryNioS68DDbhoPB8Qxsd8btHSj+sd5Pjh2GsjmeHLzMSqV9HHziAo8FzVxVCJl9ZYhk7yY1pA==", "requires": { "buffer": "^3.0.1", "through": "^2.3.6" @@ -8188,7 +8487,7 @@ }, "buffer": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", "requires": { "base64-js": "0.0.8", @@ -8295,9 +8594,20 @@ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true } } }, + "untildify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", + "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==" + }, "unzip-response": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", @@ -8478,31 +8788,23 @@ "dev": true }, "whatwg-encoding": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz", - "integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.4.tgz", + "integrity": "sha512-vM9KWN6MP2mIHZ86ytcyIv7e8Cj3KTfO2nd2c8PFDqcI4bxFmQp83ibq4wadq7rL9l9sZV6o9B0LTt8ygGAAXg==", "dev": true, "requires": { - "iconv-lite": "0.4.19" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", - "dev": true - } + "iconv-lite": "0.4.23" } }, "whatwg-fetch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", - "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" }, "whatwg-mimetype": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz", - "integrity": "sha512-FKxhYLytBQiUKjkYteN71fAUA3g6KpNXoho1isLiLSB3N1G4F35Q5vUxWfKFhBwi5IWF27VE6WxhrnnC+m0Mew==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.2.0.tgz", + "integrity": "sha512-5YSO1nMd5D1hY3WzAQV3PzZL83W3YeyR1yW9PcH26Weh1t+Vzh9B6XkDh7aXm83HBZ4nSMvkjvN2H2ySWIvBgw==", "dev": true }, "whatwg-url": { @@ -8567,13 +8869,6 @@ } } }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "dev": true, - "optional": true - }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -8670,24 +8965,64 @@ "integrity": "sha1-0A88+ddztyQUCa6SpnQNHbGfSeY=" }, "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "version": "11.1.0", + "resolved": "http://registry.npmjs.org/yargs/-/yargs-11.1.0.tgz", + "integrity": "sha512-NwW69J42EsCSanF8kyn5upxvjp5ds+t3+udGBeTbFnERA+lF541DDpMawzo4z6W/QrzNM18D+BPMiOBibnFV5A==", "dev": true, - "optional": true, "requires": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" + "cliui": "^4.0.0", + "decamelize": "^1.1.1", + "find-up": "^2.1.0", + "get-caller-file": "^1.0.1", + "os-locale": "^2.0.0", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^2.0.0", + "which-module": "^2.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^9.0.2" }, "dependencies": { - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, - "optional": true + "requires": { + "locate-path": "^2.0.0" + } + }, + "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", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "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" + } + }, + "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" + } } } }, diff --git a/package.json b/package.json index 55644635a..351e9cc82 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "serverless", - "version": "1.30.3", + "version": "1.32.0", "engines": { "node": ">=4.0" }, @@ -92,7 +92,7 @@ "sinon-chai": "^2.9.0" }, "dependencies": { - "@serverless/platform-sdk": "^0.2.1", + "@serverless/platform-sdk": "^0.3.0", "archiver": "^1.1.0", "async": "^1.5.2", "aws-sdk": "^2.228.0", @@ -124,6 +124,7 @@ "semver": "^5.0.3", "semver-regex": "^1.0.0", "tabtab": "^2.2.2", + "untildify": "^3.0.3", "update-notifier": "^2.2.0", "uuid": "^2.0.2", "write-file-atomic": "^2.1.0", diff --git a/tests/templates/integration-test-template b/tests/templates/integration-test-template index 4bbd065d8..b12937bf8 100755 --- a/tests/templates/integration-test-template +++ b/tests/templates/integration-test-template @@ -37,7 +37,7 @@ serverless deploy -v echo "Invoking Service" serverless invoke --function hello -if [ $template == "aws-go" ] || [ $template == "aws-go-dep" ] +if [ $template == "aws-go" ] || [ $template == "aws-go-dep" ] || [ $template == "aws-go-mod" ] then serverless invoke --function world fi diff --git a/tests/templates/test_all_templates b/tests/templates/test_all_templates index 1eb18f9a2..858b4ca71 100755 --- a/tests/templates/test_all_templates +++ b/tests/templates/test_all_templates @@ -14,6 +14,7 @@ integration-test aws-csharp './build.sh' integration-test aws-fsharp './build.sh' integration-test aws-go 'cd /go/src/app && make build' integration-test aws-go-dep 'cd /go/src/app && make build' +integration-test aws-go-mod 'cd /go/src/app && make build' integration-test aws-groovy-gradle ./gradlew build integration-test aws-java-gradle ./gradlew build integration-test aws-java-maven mvn package @@ -25,10 +26,10 @@ integration-test aws-kotlin-jvm-gradle integration-test aws-kotlin-jvm-maven integration-test aws-kotlin-nodejs-gradle integration-test aws-nodejs-typescript +integration-test aws-alexa-typescript integration-test aws-nodejs-ecma-script integration-test google-nodejs integration-test spotinst-nodejs integration-test spotinst-python integration-test spotinst-ruby integration-test spotinst-java8 mvn package -integration-test webtasks-nodejs