├── .editorconfig ├── .eslintignore ├── .gitignore ├── Jenkinsfile ├── README.md ├── build └── functions.groovy ├── cfn ├── deployment │ └── s3bucket.cfn.yaml └── lambda │ └── lambda.cfn.yaml ├── package-lock.json ├── package.json ├── src └── handler.ts ├── test └── handler.spec.ts ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### IntelliJ IDEA ### 2 | .idea 3 | *.iws 4 | *.iml 5 | *.ipr 6 | 7 | # Build dir 8 | dist 9 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | /** 2 | * CREDENTIALS: 3 | * - ADD Jenkins global credentials -> add PRIV_AWS_ACCESS (aws key / assigned to admin user) 4 | * - ADD ssh key for Jenkins user (jenkins / github) 5 | * CREATE FOLDER (name of folder will be used as an environment eg dev/test/prod) 6 | * - inside FOLDER create pipeline project that will points to this Jenkinsfile 7 | */ 8 | 9 | def functions 10 | 11 | pipeline { 12 | agent any 13 | 14 | options { 15 | timeout(time: 15, unit: "MINUTES") 16 | withAWS(region: "${params.AWS_REGION}") 17 | withCredentials([[$class : "AmazonWebServicesCredentialsBinding", 18 | credentialsId : "${params.CREDENTIAL_ID}", 19 | accessKeyVariable: 'AWS_ACCESS_KEY_ID', 20 | secretKeyVariable: 'AWS_SECRET_ACCESS_KEY']]) 21 | } 22 | 23 | parameters { 24 | choice(name: 'CREDENTIAL_ID', choices: 'PRIV_AWS_ACCESS', description: 'Supply name of AWS_KEY (Stored on Jenkins)') 25 | choice(name: 'AWS_REGION', choices: 'eu-west-1\neu-west-2', description: 'Pick up region where app should be deployed (Ireland / London)') 26 | } 27 | 28 | stages { 29 | stage('Load functions') { 30 | steps { 31 | script { 32 | functions = load(pwd() + '/build/functions.groovy') 33 | } 34 | } 35 | } 36 | 37 | stage('Setup s3 deployment bucket') { 38 | steps { 39 | script { 40 | functions.validateTemplates() 41 | functions.updateDeploymentBucket() 42 | functions.uploadTemplates() 43 | } 44 | } 45 | } 46 | 47 | stage('Test and build deployment package') { 48 | steps { 49 | script { 50 | // clean up old dist files 51 | sh 'rm -fr dist/*' 52 | sh 'node -v' 53 | sh 'npm run build' 54 | sh 'npm prune --production' 55 | sh 'zip -q -r dist/lambda.zip node_modules dist' 56 | } 57 | } 58 | } 59 | 60 | stage('Copy deployment package to S3 and update lambda') { 61 | steps { 62 | script { 63 | functions.uploadLambdaCode() 64 | functions.updateLambda() 65 | } 66 | } 67 | } 68 | 69 | stage('Test deployed lambda') { 70 | steps { 71 | script { 72 | functions.callAWSLambda() 73 | } 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # What is this? 2 | 3 | Here you can find template for AWS Lambda written in TS. 4 | 5 | To build project you need to type: 6 | `npm run all` 7 | Build process consists of: 8 | - linting project (TSLint) 9 | - running tests 10 | - generating js files (tsc) 11 | - trimming node_modules to production only 12 | - creating zip file with lambda code and dependencies (zip is stored in dist directory) 13 | 14 | When you have zip file, you can create your lambda function. It can be done by AWS Web Console. 15 | Navigate to lambda functions, then click `Create Function`, pickup name for you function, and click `Create`. 16 | 17 | AWS should redirect you to lambda configuration page. Now to deploy your lambda you need to do the following steps: 18 | - navigate to section `Function code`, and change `code entry type` to `upload a .zip file`. 19 | - upload generated lambda.zip 20 | - set `Runtime` to `Node.js 8.10` 21 | - change handler to `dist/handler.handler` 22 | 23 | That's all :) now you can enjoy playing with lambda written in TypeScript 24 | 25 | # There is another way to do that! 26 | As you can see this project contains Jenkinsfile so you can easily build and deploy this lambda automatically! 27 | 28 | (If you don't have remote jenkins you can spin up your local copy you can find project [here](https://github.com/mslosarz/aws-jenkins)) 29 | 30 | What needs to be done: 31 | 1. create folder in your existing Jenkins e.g. dev/test/prod (it's very important because folder is used to distinguish environment) 32 | 2. Inside folder create the pipeline job (with the name you want), and configure it to use jenkinsfile from this project 33 | 3. Run build! 34 | 35 | 36 | # How to get rid of all created resources? 37 | 38 | To clean up AWS resources you need to navigate AWS Console / cloudformation and delete two stacks `-ts-lambda` and `-deployment-bucket`. 39 | S3 Bucket [will not be deleted automatically](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-deletionpolicy.html) so you need to remove it manual :( 40 | 41 | -------------------------------------------------------------------------------- /build/functions.groovy: -------------------------------------------------------------------------------- 1 | // Environment name will be taken from the ROOT folder 2 | def env() { 3 | return env.JOB_NAME.tokenize('/').get(0).toLowerCase() 4 | } 5 | 6 | def validateTemplates() { 7 | def templates = findFiles(glob: 'cfn/**') 8 | for (template in templates) { 9 | cfnValidate(file: template.getPath()) 10 | } 11 | } 12 | 13 | def updateDeploymentBucket() { 14 | def envName = env() 15 | cfnUpdate(stack: "${envName}-deployment-bucket", 16 | file: 'cfn/deployment/s3bucket.cfn.yaml', 17 | params: ['BucketName': envName], 18 | timeoutInMinutes: 10, 19 | tags: ['Environment=' + envName], 20 | pollInterval: 10000) 21 | } 22 | 23 | def getDeploymentBucketName() { 24 | return cfnDescribe(stack: "${env()}-deployment-bucket").BucketName 25 | } 26 | 27 | def getDeploymentPath() { 28 | return "artifacts/${env()}/${env.JOB_BASE_NAME}/${env.BUILD_NUMBER}" 29 | } 30 | 31 | def uploadTemplates() { 32 | s3Upload(file: 'cfn', bucket: getDeploymentBucketName(), path: "${getDeploymentPath()}/cfn") 33 | } 34 | 35 | def uploadLambdaCode() { 36 | s3Upload(file: 'dist/lambda.zip', bucket: getDeploymentBucketName(), path: "${getDeploymentPath()}/lambda.zip") 37 | } 38 | 39 | def updateLambda() { 40 | def envName = env() 41 | cfnUpdate(stack: "${envName}-ts-lambda", 42 | file: 'cfn/lambda/lambda.cfn.yaml', 43 | params: [ 44 | 'Environment' : envName, 45 | 'DeploymentBucket': getDeploymentBucketName(), 46 | 'LambdaZipPath' : "${getDeploymentPath()}/lambda.zip" 47 | ], 48 | timeoutInMinutes: 10, 49 | tags: ['Environment=' + envName], 50 | pollInterval: 10000) 51 | } 52 | 53 | def getLambdaName() { 54 | return cfnDescribe(stack: "${env()}-ts-lambda").TypescriptLambda 55 | } 56 | 57 | def callAWSLambda() { 58 | def result = invokeLambda( 59 | functionName: getLambdaName(), 60 | payloadAsString: '{}', 61 | returnValueAsString: true 62 | ) 63 | echo "-------------------------------------------------" 64 | echo "Execution Result:" 65 | echo result 66 | echo "-------------------------------------------------" 67 | } 68 | 69 | return this 70 | -------------------------------------------------------------------------------- /cfn/deployment/s3bucket.cfn.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: '2010-09-09' 2 | Description: DeploymentBucket 3 | Parameters: 4 | BucketName: 5 | Type: String 6 | Description: Deployment bucket name 7 | Resources: 8 | Bucket: 9 | Type: AWS::S3::Bucket 10 | Properties: 11 | BucketName: !Sub '${AWS::AccountId}-template-${AWS::Region}-s3-deployment-bucket' 12 | BucketEncryption: 13 | ServerSideEncryptionConfiguration: 14 | - ServerSideEncryptionByDefault: 15 | SSEAlgorithm: AES256 16 | 17 | Outputs: 18 | BucketName: 19 | Value: !Ref Bucket 20 | -------------------------------------------------------------------------------- /cfn/lambda/lambda.cfn.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: Template for typescript lambda 3 | Parameters: 4 | Environment: 5 | Type: String 6 | Description: Environment name 7 | DeploymentBucket: 8 | Type: String 9 | Description: Deployment bucket name 10 | LambdaZipPath: 11 | Type: String 12 | Description: Path to zip file with lambda code (including build number etc) 13 | 14 | Resources: 15 | TypescriptLambda: 16 | Type: AWS::Lambda::Function 17 | Properties: 18 | FunctionName: !Sub ${Environment}-${AWS::Region}-typescript-lambda 19 | Description: Sample lambda written in typescript 20 | Runtime: nodejs8.10 21 | Code: 22 | S3Bucket: !Ref DeploymentBucket 23 | S3Key: !Ref LambdaZipPath 24 | Handler: dist/handler.handler 25 | MemorySize: 128 26 | Role: !GetAtt LambdaExecutionRole.Arn 27 | Timeout: 10 28 | 29 | LambdaLogGroup: 30 | Type: AWS::Logs::LogGroup 31 | Properties: 32 | LogGroupName: !Sub /aws/lambda/${TypescriptLambda} 33 | RetentionInDays: 3 34 | 35 | LambdaExecutionRole: 36 | Type: AWS::IAM::Role 37 | Properties: 38 | AssumeRolePolicyDocument: 39 | Version: 2012-10-17 40 | Statement: 41 | - Effect: Allow 42 | Principal: 43 | Service: lambda.amazonaws.com 44 | Action: 45 | - sts:AssumeRole 46 | ManagedPolicyArns: 47 | - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 48 | 49 | Outputs: 50 | TypescriptLambda: 51 | Value: !Ref TypescriptLambda 52 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "template", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@sinonjs/commons": { 8 | "version": "1.3.0", 9 | "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.3.0.tgz", 10 | "integrity": "sha512-j4ZwhaHmwsCb4DlDOIWnI5YyKDNMoNThsmwEpfHx6a1EpsGZ9qYLxP++LMlmBRjtGptGHFsGItJ768snllFWpA==", 11 | "dev": true, 12 | "requires": { 13 | "type-detect": "4.0.8" 14 | } 15 | }, 16 | "@sinonjs/formatio": { 17 | "version": "3.1.0", 18 | "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-3.1.0.tgz", 19 | "integrity": "sha512-ZAR2bPHOl4Xg6eklUGpsdiIJ4+J1SNag1DHHrG/73Uz/nVwXqjgUtRPLoS+aVyieN9cSbc0E4LsU984tWcDyNg==", 20 | "dev": true, 21 | "requires": { 22 | "@sinonjs/samsam": "^2 || ^3" 23 | } 24 | }, 25 | "@sinonjs/samsam": { 26 | "version": "3.1.1", 27 | "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-3.1.1.tgz", 28 | "integrity": "sha512-ILlwvQUwAiaVBzr3qz8oT1moM7AIUHqUc2UmEjQcH9lLe+E+BZPwUMuc9FFojMswRK4r96x5zDTTrowMLw/vuA==", 29 | "dev": true, 30 | "requires": { 31 | "@sinonjs/commons": "^1.0.2", 32 | "array-from": "^2.1.1", 33 | "lodash": "^4.17.11" 34 | } 35 | }, 36 | "@types/aws-lambda": { 37 | "version": "8.10.19", 38 | "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.19.tgz", 39 | "integrity": "sha512-dEhQow/1awGGIf/unEpb97vsTtnQ3qRPAhSmZZcXKzs4nOVbIuWo5LCCzOYdSIkGkkoFXVvc8pBaSVKRYIFUBA==", 40 | "dev": true 41 | }, 42 | "@types/chai": { 43 | "version": "4.1.7", 44 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", 45 | "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", 46 | "dev": true 47 | }, 48 | "@types/mocha": { 49 | "version": "5.2.6", 50 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.6.tgz", 51 | "integrity": "sha512-1axi39YdtBI7z957vdqXI4Ac25e7YihYQtJa+Clnxg1zTJEaIRbndt71O3sP4GAMgiAm0pY26/b9BrY4MR/PMw==", 52 | "dev": true 53 | }, 54 | "@types/moment": { 55 | "version": "2.13.0", 56 | "resolved": "https://registry.npmjs.org/@types/moment/-/moment-2.13.0.tgz", 57 | "integrity": "sha1-YE69GJvDvDShVIaJQE5hoqSqyJY=", 58 | "dev": true, 59 | "requires": { 60 | "moment": "*" 61 | } 62 | }, 63 | "@types/node": { 64 | "version": "11.9.3", 65 | "resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.3.tgz", 66 | "integrity": "sha512-DMiqG51GwES/c4ScBY0u5bDlH44+oY8AeYHjY1SGCWidD7h08o1dfHue/TGK7REmif2KiJzaUskO+Q0eaeZ2fQ==", 67 | "dev": true 68 | }, 69 | "@types/sinon": { 70 | "version": "7.0.6", 71 | "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-7.0.6.tgz", 72 | "integrity": "sha512-ldQl2p7kyCXHhr//5sQCu9jWgSiDbYuCD5dUp53r/z8T8jmgKpANpy4vqjbdho9P2ldFaQC/gpW31hch+oQ0IQ==", 73 | "dev": true 74 | }, 75 | "@types/sinon-chai": { 76 | "version": "3.2.2", 77 | "resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-3.2.2.tgz", 78 | "integrity": "sha512-5zSs2AslzyPZdOsbm2NRtuSNAI2aTWzNKOHa/GRecKo7a5efYD7qGcPxMZXQDayVXT2Vnd5waXxBvV31eCZqiA==", 79 | "dev": true, 80 | "requires": { 81 | "@types/chai": "*", 82 | "@types/sinon": "*" 83 | } 84 | }, 85 | "ansi-styles": { 86 | "version": "3.2.1", 87 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 88 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 89 | "dev": true, 90 | "requires": { 91 | "color-convert": "^1.9.0" 92 | } 93 | }, 94 | "arg": { 95 | "version": "4.1.0", 96 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.0.tgz", 97 | "integrity": "sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg==", 98 | "dev": true 99 | }, 100 | "argparse": { 101 | "version": "1.0.10", 102 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 103 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 104 | "dev": true, 105 | "requires": { 106 | "sprintf-js": "~1.0.2" 107 | } 108 | }, 109 | "array-from": { 110 | "version": "2.1.1", 111 | "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", 112 | "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", 113 | "dev": true 114 | }, 115 | "assertion-error": { 116 | "version": "1.1.0", 117 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 118 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 119 | "dev": true 120 | }, 121 | "babel-code-frame": { 122 | "version": "6.26.0", 123 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 124 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 125 | "dev": true, 126 | "requires": { 127 | "chalk": "^1.1.3", 128 | "esutils": "^2.0.2", 129 | "js-tokens": "^3.0.2" 130 | }, 131 | "dependencies": { 132 | "ansi-regex": { 133 | "version": "2.1.1", 134 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 135 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 136 | "dev": true 137 | }, 138 | "ansi-styles": { 139 | "version": "2.2.1", 140 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 141 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 142 | "dev": true 143 | }, 144 | "chalk": { 145 | "version": "1.1.3", 146 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 147 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 148 | "dev": true, 149 | "requires": { 150 | "ansi-styles": "^2.2.1", 151 | "escape-string-regexp": "^1.0.2", 152 | "has-ansi": "^2.0.0", 153 | "strip-ansi": "^3.0.0", 154 | "supports-color": "^2.0.0" 155 | } 156 | }, 157 | "js-tokens": { 158 | "version": "3.0.2", 159 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 160 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 161 | "dev": true 162 | }, 163 | "strip-ansi": { 164 | "version": "3.0.1", 165 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 166 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 167 | "dev": true, 168 | "requires": { 169 | "ansi-regex": "^2.0.0" 170 | } 171 | }, 172 | "supports-color": { 173 | "version": "2.0.0", 174 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 175 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 176 | "dev": true 177 | } 178 | } 179 | }, 180 | "balanced-match": { 181 | "version": "1.0.0", 182 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 183 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 184 | "dev": true 185 | }, 186 | "brace-expansion": { 187 | "version": "1.1.11", 188 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 189 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 190 | "dev": true, 191 | "requires": { 192 | "balanced-match": "^1.0.0", 193 | "concat-map": "0.0.1" 194 | } 195 | }, 196 | "browser-stdout": { 197 | "version": "1.3.1", 198 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 199 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 200 | "dev": true 201 | }, 202 | "buffer-from": { 203 | "version": "1.1.1", 204 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 205 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 206 | "dev": true 207 | }, 208 | "builtin-modules": { 209 | "version": "1.1.1", 210 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 211 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 212 | "dev": true 213 | }, 214 | "chai": { 215 | "version": "4.2.0", 216 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", 217 | "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", 218 | "dev": true, 219 | "requires": { 220 | "assertion-error": "^1.1.0", 221 | "check-error": "^1.0.2", 222 | "deep-eql": "^3.0.1", 223 | "get-func-name": "^2.0.0", 224 | "pathval": "^1.1.0", 225 | "type-detect": "^4.0.5" 226 | } 227 | }, 228 | "chalk": { 229 | "version": "2.4.2", 230 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 231 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 232 | "dev": true, 233 | "requires": { 234 | "ansi-styles": "^3.2.1", 235 | "escape-string-regexp": "^1.0.5", 236 | "supports-color": "^5.3.0" 237 | } 238 | }, 239 | "check-error": { 240 | "version": "1.0.2", 241 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 242 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 243 | "dev": true 244 | }, 245 | "color-convert": { 246 | "version": "1.9.3", 247 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 248 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 249 | "dev": true, 250 | "requires": { 251 | "color-name": "1.1.3" 252 | } 253 | }, 254 | "color-name": { 255 | "version": "1.1.3", 256 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 257 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 258 | "dev": true 259 | }, 260 | "commander": { 261 | "version": "2.19.0", 262 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", 263 | "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", 264 | "dev": true 265 | }, 266 | "concat-map": { 267 | "version": "0.0.1", 268 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 269 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 270 | "dev": true 271 | }, 272 | "debug": { 273 | "version": "3.1.0", 274 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 275 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 276 | "dev": true, 277 | "requires": { 278 | "ms": "2.0.0" 279 | } 280 | }, 281 | "deep-eql": { 282 | "version": "3.0.1", 283 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 284 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 285 | "dev": true, 286 | "requires": { 287 | "type-detect": "^4.0.0" 288 | } 289 | }, 290 | "diff": { 291 | "version": "3.5.0", 292 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 293 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 294 | "dev": true 295 | }, 296 | "doctrine": { 297 | "version": "0.7.2", 298 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz", 299 | "integrity": "sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=", 300 | "dev": true, 301 | "requires": { 302 | "esutils": "^1.1.6", 303 | "isarray": "0.0.1" 304 | }, 305 | "dependencies": { 306 | "esutils": { 307 | "version": "1.1.6", 308 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz", 309 | "integrity": "sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=", 310 | "dev": true 311 | } 312 | } 313 | }, 314 | "escape-string-regexp": { 315 | "version": "1.0.5", 316 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 317 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 318 | "dev": true 319 | }, 320 | "esprima": { 321 | "version": "4.0.1", 322 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 323 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 324 | "dev": true 325 | }, 326 | "esutils": { 327 | "version": "2.0.2", 328 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 329 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 330 | "dev": true 331 | }, 332 | "fs.realpath": { 333 | "version": "1.0.0", 334 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 335 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 336 | "dev": true 337 | }, 338 | "get-func-name": { 339 | "version": "2.0.0", 340 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 341 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 342 | "dev": true 343 | }, 344 | "glob": { 345 | "version": "7.1.3", 346 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 347 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 348 | "dev": true, 349 | "requires": { 350 | "fs.realpath": "^1.0.0", 351 | "inflight": "^1.0.4", 352 | "inherits": "2", 353 | "minimatch": "^3.0.4", 354 | "once": "^1.3.0", 355 | "path-is-absolute": "^1.0.0" 356 | } 357 | }, 358 | "growl": { 359 | "version": "1.10.5", 360 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 361 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 362 | "dev": true 363 | }, 364 | "has-ansi": { 365 | "version": "2.0.0", 366 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 367 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 368 | "dev": true, 369 | "requires": { 370 | "ansi-regex": "^2.0.0" 371 | }, 372 | "dependencies": { 373 | "ansi-regex": { 374 | "version": "2.1.1", 375 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 376 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 377 | "dev": true 378 | } 379 | } 380 | }, 381 | "has-flag": { 382 | "version": "3.0.0", 383 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 384 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 385 | "dev": true 386 | }, 387 | "he": { 388 | "version": "1.1.1", 389 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 390 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 391 | "dev": true 392 | }, 393 | "inflight": { 394 | "version": "1.0.6", 395 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 396 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 397 | "dev": true, 398 | "requires": { 399 | "once": "^1.3.0", 400 | "wrappy": "1" 401 | } 402 | }, 403 | "inherits": { 404 | "version": "2.0.3", 405 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 406 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 407 | "dev": true 408 | }, 409 | "isarray": { 410 | "version": "0.0.1", 411 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 412 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 413 | "dev": true 414 | }, 415 | "js-yaml": { 416 | "version": "3.12.1", 417 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz", 418 | "integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==", 419 | "dev": true, 420 | "requires": { 421 | "argparse": "^1.0.7", 422 | "esprima": "^4.0.0" 423 | } 424 | }, 425 | "just-extend": { 426 | "version": "4.0.2", 427 | "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.0.2.tgz", 428 | "integrity": "sha512-FrLwOgm+iXrPV+5zDU6Jqu4gCRXbWEQg2O3SKONsWE4w7AXFRkryS53bpWdaL9cNol+AmR3AEYz6kn+o0fCPnw==", 429 | "dev": true 430 | }, 431 | "lodash": { 432 | "version": "4.17.11", 433 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 434 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", 435 | "dev": true 436 | }, 437 | "lolex": { 438 | "version": "3.1.0", 439 | "resolved": "https://registry.npmjs.org/lolex/-/lolex-3.1.0.tgz", 440 | "integrity": "sha512-zFo5MgCJ0rZ7gQg69S4pqBsLURbFw11X68C18OcJjJQbqaXm2NoTrGl1IMM3TIz0/BnN1tIs2tzmmqvCsOMMjw==", 441 | "dev": true 442 | }, 443 | "make-error": { 444 | "version": "1.3.5", 445 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", 446 | "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", 447 | "dev": true 448 | }, 449 | "minimatch": { 450 | "version": "3.0.4", 451 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 452 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 453 | "dev": true, 454 | "requires": { 455 | "brace-expansion": "^1.1.7" 456 | } 457 | }, 458 | "minimist": { 459 | "version": "0.0.8", 460 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 461 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 462 | "dev": true 463 | }, 464 | "mkdirp": { 465 | "version": "0.5.1", 466 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 467 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 468 | "dev": true, 469 | "requires": { 470 | "minimist": "0.0.8" 471 | } 472 | }, 473 | "mocha": { 474 | "version": "5.2.0", 475 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", 476 | "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", 477 | "dev": true, 478 | "requires": { 479 | "browser-stdout": "1.3.1", 480 | "commander": "2.15.1", 481 | "debug": "3.1.0", 482 | "diff": "3.5.0", 483 | "escape-string-regexp": "1.0.5", 484 | "glob": "7.1.2", 485 | "growl": "1.10.5", 486 | "he": "1.1.1", 487 | "minimatch": "3.0.4", 488 | "mkdirp": "0.5.1", 489 | "supports-color": "5.4.0" 490 | }, 491 | "dependencies": { 492 | "commander": { 493 | "version": "2.15.1", 494 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", 495 | "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", 496 | "dev": true 497 | }, 498 | "glob": { 499 | "version": "7.1.2", 500 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 501 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 502 | "dev": true, 503 | "requires": { 504 | "fs.realpath": "^1.0.0", 505 | "inflight": "^1.0.4", 506 | "inherits": "2", 507 | "minimatch": "^3.0.4", 508 | "once": "^1.3.0", 509 | "path-is-absolute": "^1.0.0" 510 | } 511 | }, 512 | "supports-color": { 513 | "version": "5.4.0", 514 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", 515 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", 516 | "dev": true, 517 | "requires": { 518 | "has-flag": "^3.0.0" 519 | } 520 | } 521 | } 522 | }, 523 | "moment": { 524 | "version": "2.24.0", 525 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", 526 | "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" 527 | }, 528 | "ms": { 529 | "version": "2.0.0", 530 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 531 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 532 | "dev": true 533 | }, 534 | "nise": { 535 | "version": "1.4.8", 536 | "resolved": "https://registry.npmjs.org/nise/-/nise-1.4.8.tgz", 537 | "integrity": "sha512-kGASVhuL4tlAV0tvA34yJYZIVihrUt/5bDwpp4tTluigxUr2bBlJeDXmivb6NuEdFkqvdv/Ybb9dm16PSKUhtw==", 538 | "dev": true, 539 | "requires": { 540 | "@sinonjs/formatio": "^3.1.0", 541 | "just-extend": "^4.0.2", 542 | "lolex": "^2.3.2", 543 | "path-to-regexp": "^1.7.0", 544 | "text-encoding": "^0.6.4" 545 | }, 546 | "dependencies": { 547 | "lolex": { 548 | "version": "2.7.5", 549 | "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.7.5.tgz", 550 | "integrity": "sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q==", 551 | "dev": true 552 | } 553 | } 554 | }, 555 | "once": { 556 | "version": "1.4.0", 557 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 558 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 559 | "dev": true, 560 | "requires": { 561 | "wrappy": "1" 562 | } 563 | }, 564 | "path-is-absolute": { 565 | "version": "1.0.1", 566 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 567 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 568 | "dev": true 569 | }, 570 | "path-parse": { 571 | "version": "1.0.6", 572 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 573 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 574 | "dev": true 575 | }, 576 | "path-to-regexp": { 577 | "version": "1.7.0", 578 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", 579 | "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", 580 | "dev": true, 581 | "requires": { 582 | "isarray": "0.0.1" 583 | } 584 | }, 585 | "pathval": { 586 | "version": "1.1.0", 587 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", 588 | "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", 589 | "dev": true 590 | }, 591 | "resolve": { 592 | "version": "1.10.0", 593 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", 594 | "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", 595 | "dev": true, 596 | "requires": { 597 | "path-parse": "^1.0.6" 598 | } 599 | }, 600 | "semver": { 601 | "version": "5.6.0", 602 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", 603 | "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", 604 | "dev": true 605 | }, 606 | "sinon": { 607 | "version": "7.2.3", 608 | "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.2.3.tgz", 609 | "integrity": "sha512-i6j7sqcLEqTYqUcMV327waI745VASvYuSuQMCjbAwlpAeuCgKZ3LtrjDxAbu+GjNQR0FEDpywtwGCIh8GicNyg==", 610 | "dev": true, 611 | "requires": { 612 | "@sinonjs/commons": "^1.3.0", 613 | "@sinonjs/formatio": "^3.1.0", 614 | "@sinonjs/samsam": "^3.0.2", 615 | "diff": "^3.5.0", 616 | "lolex": "^3.0.0", 617 | "nise": "^1.4.8", 618 | "supports-color": "^5.5.0" 619 | } 620 | }, 621 | "sinon-chai": { 622 | "version": "3.3.0", 623 | "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.3.0.tgz", 624 | "integrity": "sha512-r2JhDY7gbbmh5z3Q62pNbrjxZdOAjpsqW/8yxAZRSqLZqowmfGZPGUZPFf3UX36NLis0cv8VEM5IJh9HgkSOAA==", 625 | "dev": true 626 | }, 627 | "source-map": { 628 | "version": "0.6.1", 629 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 630 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 631 | "dev": true 632 | }, 633 | "source-map-support": { 634 | "version": "0.5.10", 635 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.10.tgz", 636 | "integrity": "sha512-YfQ3tQFTK/yzlGJuX8pTwa4tifQj4QS2Mj7UegOu8jAz59MqIiMGPXxQhVQiIMNzayuUSF/jEuVnfFF5JqybmQ==", 637 | "dev": true, 638 | "requires": { 639 | "buffer-from": "^1.0.0", 640 | "source-map": "^0.6.0" 641 | } 642 | }, 643 | "sprintf-js": { 644 | "version": "1.0.3", 645 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 646 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 647 | "dev": true 648 | }, 649 | "supports-color": { 650 | "version": "5.5.0", 651 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 652 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 653 | "dev": true, 654 | "requires": { 655 | "has-flag": "^3.0.0" 656 | } 657 | }, 658 | "text-encoding": { 659 | "version": "0.6.4", 660 | "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", 661 | "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", 662 | "dev": true 663 | }, 664 | "ts-node": { 665 | "version": "8.0.2", 666 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.0.2.tgz", 667 | "integrity": "sha512-MosTrinKmaAcWgO8tqMjMJB22h+sp3Rd1i4fdoWY4mhBDekOwIAKI/bzmRi7IcbCmjquccYg2gcF6NBkLgr0Tw==", 668 | "dev": true, 669 | "requires": { 670 | "arg": "^4.1.0", 671 | "diff": "^3.1.0", 672 | "make-error": "^1.1.1", 673 | "source-map-support": "^0.5.6", 674 | "yn": "^3.0.0" 675 | } 676 | }, 677 | "tslib": { 678 | "version": "1.9.3", 679 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", 680 | "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", 681 | "dev": true 682 | }, 683 | "tslint": { 684 | "version": "5.12.1", 685 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.12.1.tgz", 686 | "integrity": "sha512-sfodBHOucFg6egff8d1BvuofoOQ/nOeYNfbp7LDlKBcLNrL3lmS5zoiDGyOMdT7YsEXAwWpTdAHwOGOc8eRZAw==", 687 | "dev": true, 688 | "requires": { 689 | "babel-code-frame": "^6.22.0", 690 | "builtin-modules": "^1.1.1", 691 | "chalk": "^2.3.0", 692 | "commander": "^2.12.1", 693 | "diff": "^3.2.0", 694 | "glob": "^7.1.1", 695 | "js-yaml": "^3.7.0", 696 | "minimatch": "^3.0.4", 697 | "resolve": "^1.3.2", 698 | "semver": "^5.3.0", 699 | "tslib": "^1.8.0", 700 | "tsutils": "^2.27.2" 701 | } 702 | }, 703 | "tslint-config-standard": { 704 | "version": "8.0.1", 705 | "resolved": "https://registry.npmjs.org/tslint-config-standard/-/tslint-config-standard-8.0.1.tgz", 706 | "integrity": "sha512-OWG+NblgjQlVuUS/Dmq3ax2v5QDZwRx4L0kEuDi7qFY9UI6RJhhNfoCV1qI4el8Fw1c5a5BTrjQJP0/jhGXY/Q==", 707 | "dev": true, 708 | "requires": { 709 | "tslint-eslint-rules": "^5.3.1" 710 | } 711 | }, 712 | "tslint-eslint-rules": { 713 | "version": "5.4.0", 714 | "resolved": "https://registry.npmjs.org/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz", 715 | "integrity": "sha512-WlSXE+J2vY/VPgIcqQuijMQiel+UtmXS+4nvK4ZzlDiqBfXse8FAvkNnTcYhnQyOTW5KFM+uRRGXxYhFpuBc6w==", 716 | "dev": true, 717 | "requires": { 718 | "doctrine": "0.7.2", 719 | "tslib": "1.9.0", 720 | "tsutils": "^3.0.0" 721 | }, 722 | "dependencies": { 723 | "tslib": { 724 | "version": "1.9.0", 725 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", 726 | "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", 727 | "dev": true 728 | }, 729 | "tsutils": { 730 | "version": "3.8.0", 731 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.8.0.tgz", 732 | "integrity": "sha512-XQdPhgcoTbCD8baXC38PQ0vpTZ8T3YrE+vR66YIj/xvDt1//8iAhafpIT/4DmvzzC1QFapEImERu48Pa01dIUA==", 733 | "dev": true, 734 | "requires": { 735 | "tslib": "^1.8.1" 736 | } 737 | } 738 | } 739 | }, 740 | "tslint-microsoft-contrib": { 741 | "version": "6.0.0", 742 | "resolved": "https://registry.npmjs.org/tslint-microsoft-contrib/-/tslint-microsoft-contrib-6.0.0.tgz", 743 | "integrity": "sha512-R//efwn+34IUjTJeYgNDAJdzG0jyLWIehygPt/PHuZAieTolFVS56FgeFW7DOLap9ghXzMiFPTmDgm54qaL7QA==", 744 | "dev": true, 745 | "requires": { 746 | "tsutils": "^2.27.2 <2.29.0" 747 | }, 748 | "dependencies": { 749 | "tsutils": { 750 | "version": "2.28.0", 751 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.28.0.tgz", 752 | "integrity": "sha512-bh5nAtW0tuhvOJnx1GLRn5ScraRLICGyJV5wJhtRWOLsxW70Kk5tZtpK3O/hW6LDnqKS9mlUMPZj9fEMJ0gxqA==", 753 | "dev": true, 754 | "requires": { 755 | "tslib": "^1.8.1" 756 | } 757 | } 758 | } 759 | }, 760 | "tsutils": { 761 | "version": "2.29.0", 762 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 763 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 764 | "dev": true, 765 | "requires": { 766 | "tslib": "^1.8.1" 767 | } 768 | }, 769 | "type-detect": { 770 | "version": "4.0.8", 771 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 772 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 773 | "dev": true 774 | }, 775 | "typescript": { 776 | "version": "3.3.3", 777 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3.tgz", 778 | "integrity": "sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A==", 779 | "dev": true 780 | }, 781 | "wrappy": { 782 | "version": "1.0.2", 783 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 784 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 785 | "dev": true 786 | }, 787 | "yn": { 788 | "version": "3.0.0", 789 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.0.0.tgz", 790 | "integrity": "sha512-+Wo/p5VRfxUgBUGy2j/6KX2mj9AYJWOHuhMjMcbBFc3y54o9/4buK1ksBvuiK01C3kby8DH9lSmJdSxw+4G/2Q==", 791 | "dev": true 792 | } 793 | } 794 | } 795 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "template", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "lint": "tslint --project tsconfig.json", 8 | "pretest": "npm run lint", 9 | "test": "mocha -r ts-node/register test/**/*.spec.ts", 10 | "pre:build": "npm cit", 11 | "all": "npm run build && npm prune --production && rm -f dist/lambda.zip && zip -q -r dist/lambda.zip node_modules dist && npm ci", 12 | "build": "npm run pre:build && tsc", 13 | "start": "node ./index.js" 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "ISC", 18 | "devDependencies": { 19 | "@types/aws-lambda": "^8.10.19", 20 | "@types/chai": "^4.1.7", 21 | "@types/mocha": "^5.2.6", 22 | "@types/node": "^11.9.3", 23 | "@types/sinon": "^7.0.6", 24 | "@types/sinon-chai": "^3.2.2", 25 | "@types/moment": "^2.13.0", 26 | "sinon-chai": "^3.3.0", 27 | "chai": "^4.2.0", 28 | "mocha": "^5.2.0", 29 | "sinon": "^7.2.3", 30 | "ts-node": "^8.0.2", 31 | "tslint": "^5.12.1", 32 | "tslint-config-standard": "^8.0.1", 33 | "tslint-microsoft-contrib": "^6.0.0", 34 | "typescript": "^3.3.3" 35 | }, 36 | "dependencies": { 37 | "moment": "^2.24.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/handler.ts: -------------------------------------------------------------------------------- 1 | import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda' 2 | import moment from 'moment' 3 | 4 | export const handler = async (event: APIGatewayProxyEvent): Promise => { 5 | return { 6 | statusCode: 200, 7 | body: moment.utc().toISOString() 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/handler.spec.ts: -------------------------------------------------------------------------------- 1 | import { handler } from '../src/handler' 2 | import { expect } from 'chai' 3 | import * as sinon from 'sinon' 4 | import 'mocha' 5 | import moment from 'moment' 6 | 7 | describe('handler', () => { 8 | const dummyEvent = { 9 | headers: {}, 10 | body: null, 11 | multiValueHeaders: {}, 12 | httpMethod: 'GET', 13 | isBase64Encoded: false, 14 | path: 'xx', 15 | pathParameters: null, 16 | queryStringParameters: null, 17 | multiValueQueryStringParameters: null, 18 | stageVariables: null, 19 | requestContext: { 20 | accountId: '', 21 | apiId: '', 22 | connectedAt: 100, 23 | httpMethod: 'GET', 24 | identity: { 25 | accessKey: null, 26 | accountId: null, 27 | apiKey: null, 28 | apiKeyId: null, 29 | caller: null, 30 | cognitoAuthenticationProvider: null, 31 | cognitoAuthenticationType: null, 32 | cognitoIdentityId: null, 33 | cognitoIdentityPoolId: null, 34 | sourceIp: '10.10.10.10', 35 | user: null, 36 | userAgent: null, 37 | userArn: null 38 | }, 39 | path: 'xx', 40 | stage: 'test', 41 | requestId: 'id', 42 | requestTimeEpoch: 123, 43 | resourceId: 'a', 44 | resourcePath: 'xxx' 45 | }, 46 | resource: '' 47 | } 48 | 49 | before(function () { 50 | this.clock = sinon.useFakeTimers(new Date(2012, 1, 10).getTime()) 51 | }) 52 | 53 | after(function () { 54 | this.clock.restore() 55 | }) 56 | 57 | it('should return 200 always!', async () => { 58 | const result = await handler(dummyEvent) 59 | expect(result).to.be.deep.equal({statusCode: 200, body: moment().utc().toISOString()}) 60 | }) 61 | 62 | }) 63 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "outDir": "dist", 6 | "strict": true, 7 | "baseUrl": "./", 8 | "typeRoots": [ 9 | "node_modules/@types" 10 | ], 11 | "types": [ 12 | "node" 13 | ], 14 | "esModuleInterop": true, 15 | "inlineSourceMap": true 16 | }, 17 | "include": [ 18 | "src" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint-config-standard" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "no-implicit-dependencies": false 9 | }, 10 | "rulesDirectory": [] 11 | } 12 | --------------------------------------------------------------------------------