├── .dockerignore ├── .gitignore ├── Dockerfile ├── Dockerfile.arm ├── Dockerfile.x86 ├── README.md ├── build.yml ├── buildspecs ├── build.sh ├── export.sh ├── publish.sh └── publish.yml ├── package-lock.json ├── package.json ├── release.yml ├── src ├── aws-helpers.ts ├── config │ ├── mysql.ts │ └── postgres.ts ├── dynamodb-item.ts ├── local-item.ts ├── mysql-item.ts ├── postgresdb-item.ts ├── server-helpers.ts └── server.ts └── tsconfig.json /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | built 3 | buildspecs 4 | cdk 5 | .gitignore 6 | .dockerignore -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | built/ 3 | docker-compose.yml -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/bitnami/node:15 2 | COPY --from=public.ecr.aws/tinystacks/secret-env-vars-wrapper:latest-x86 /opt /opt 3 | COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.3.2-x86_64 /lambda-adapter /opt/extensions/lambda-adapter 4 | 5 | # Create app directory 6 | WORKDIR /usr/src/app 7 | 8 | # Install app dependencies 9 | # A wildcard is used to ensure both package.json AND package-lock.json are copied 10 | # where available (npm@5+) 11 | COPY package*.json ./ 12 | COPY tsconfig.json ./ 13 | COPY src ./src 14 | RUN npm install 15 | RUN npm run build 16 | 17 | # Bundle app source 18 | COPY . . 19 | 20 | EXPOSE 8000 21 | CMD [ "/opt/tinystacks-secret-env-vars-wrapper", "node", "built/server.js" ] -------------------------------------------------------------------------------- /Dockerfile.arm: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/bitnami/node:15 2 | COPY --from=public.ecr.aws/tinystacks/secret-env-vars-wrapper:latest-arm /opt /opt 3 | COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.3.2 /lambda-adapter /opt/extensions/lambda-adapter 4 | 5 | # Create app directory 6 | WORKDIR /usr/src/app 7 | 8 | # Install app dependencies 9 | # A wildcard is used to ensure both package.json AND package-lock.json are copied 10 | # where available (npm@5+) 11 | COPY package*.json ./ 12 | COPY tsconfig.json ./ 13 | COPY src ./src 14 | RUN npm install 15 | RUN npm run build 16 | 17 | # Bundle app source 18 | COPY . . 19 | 20 | EXPOSE 8000 21 | CMD [ "/opt/tinystacks-secret-env-vars-wrapper", "node", "built/server.js" ] 22 | -------------------------------------------------------------------------------- /Dockerfile.x86: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/bitnami/node:15 2 | COPY --from=public.ecr.aws/tinystacks/secret-env-vars-wrapper:latest-x86 /opt /opt 3 | COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.3.2-x86_64 /lambda-adapter /opt/extensions/lambda-adapter 4 | 5 | # Create app directory 6 | WORKDIR /usr/src/app 7 | 8 | # Install app dependencies 9 | # A wildcard is used to ensure both package.json AND package-lock.json are copied 10 | # where available (npm@5+) 11 | COPY package*.json ./ 12 | COPY tsconfig.json ./ 13 | COPY src ./src 14 | RUN npm install 15 | RUN npm run build 16 | 17 | # Bundle app source 18 | COPY . . 19 | 20 | EXPOSE 8000 21 | CMD [ "/opt/tinystacks-secret-env-vars-wrapper", "node", "built/server.js" ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## AWS Docker Templates - Express 2 | 3 | The AWS Docker Templates for Express from TinyStacks enable launching an [Express Node.js](https://expressjs.com/) application as a Docker container using an AWS CodePipeline pipeline. The template includes its own small Express application, enabling developers to start a new Express project immediately. Developers can also take the AWS CodePipeline-specific files in this template and use them to ship an existing Express application as a Docker image on AWS. 4 | 5 | ## License 6 | 7 | This sample code is made available under a modified MIT license. See the LICENSE file. 8 | 9 | ## Outline 10 | 11 | - [Prerequisites](#prerequisites) 12 | - [Overview](#overview) 13 | - [Sample Application](#sample-application) 14 | - [Dockerfile](#dockerfile) 15 | - [Build Template](#build-template) 16 | - [Release Template](#release-template) 17 | - [Getting Started](#getting-started) 18 | - [Existing Project](#existing-project) 19 | - [Known Limitations](#known-limitations) 20 | 21 | ## Prerequisites 22 | 23 | If you wish to build and test the Express server (both as a standalone server and hosted inside of a Docker container) before publishing on AWS, you should have [Node.js](https://nodejs.org/en/download/), [Express](https://expressjs.com/en/starter/installing.html), and [Docker](https://docs.docker.com/get-docker/) installed locally. 24 | 25 | If you wish to run just the Docker container locally, you will only need Docker. 26 | 27 | This document also assumes that you have access to an AWS account. If you do not have one, [create one before getting started](https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/). 28 | 29 | If executed locally, the use of AWS DynamoDB and Amazon Cognito in the Express application will require that you have valid credentials for AWS saved on your local computer. We recommend configuring your credentials locally as a login profile and using the `AWS_PROFILE` environment variable to designate which set of credentials to use. For other options on setting AWS credentials, see [Setting Credentials in Node.js](https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html). 30 | 31 | Further prerequisites for running these templates on AWS are provided below. 32 | 33 | ## Overview 34 | 35 | The sample contains the following files: 36 | 37 | * A sample Express application, defined in the `src` directory. 38 | * A Dockerfile that builds the Express file as a Docker image. 39 | * A `build.yml` file for AWS CodeBuild that builds the image and pushes it to Amazon Elastic Container Registry (ECR). 40 | * A `release.yml` file for AWS CodeBuild that deploys the image stored in ECR to a Amazon Elastic Container Service (ECS) cluster. 41 | 42 | Users can use the `build.yml` and `release.yml` YAML files to create an AWS CodePipeline pipeline that compiles the latest application into a Docker image, which is then stored in an Amazon Elastic Container Registry (ECR) registry that is accessible to the user. The Express application itself is deployed onto AWS as a Docker container using Amazon Elastic Container Service (Amazon ECS) onto one of the user's available ECS clusters. 43 | 44 | ### Sample Application 45 | 46 | The sample application is a simple CRUD (Create/Read/Update/Delete) application that can store data either in memory or in an AWS DynamoDB database table. It is written as an Express application using TypeScript. When this application runs, it presents a set of REST API endpoints that other applications can call to store data. 47 | 48 | The application's data type, Item, contains two data fields: title and content. 49 | 50 | ```typescript 51 | type Item = { 52 | title: string; 53 | content: string; 54 | }; 55 | ``` 56 | 57 | The file `src/server.ts` declares the API's available endpoints. There are three sets of endpoints defined, each with slightly different functionality. 58 | 59 | | Endpoint Type | Description | 60 | | ------------- | ------------- | 61 | | `/local-item` | Stores the Item in memory. | 62 | | `/dynamodb-item` | Stores the item in an AWS DynamoDB table. | 63 | | `/postgres-item` | Stores the item in a Postgres table. | 64 | | `/authenticated-dynamodb-item` | Like `/dynamodb-item`, but requires that the API user be logged in with an Amazon Cognity Identity. All records saved with this API are saved with the user's Cognito ID. When performing read and update operations with this API, users can only access the records that they created. | 65 | 66 | The server uses the same endpoint for all CRUD operations, distinguishing between them with HTTP verbs: 67 | 68 | | Endpoint Type | Description | 69 | | ------------- | ------------- | 70 | | PUT | Create | 71 | | GET | Read | 72 | | POST | Update | 73 | | DELETE | Delete | 74 | 75 | #### Running The Express Server Directly 76 | 77 | To test out the sample application directly before you package it into a Dockerfile, clone this project locally, then run the following command on the command line in the root of this project: 78 | 79 | ``` 80 | npm install 81 | npm run build 82 | node built/server.js 83 | ``` 84 | 85 | To test that the server is running, test its `/ping` endpoint from the command line: 86 | 87 | ``` 88 | curl http://127.0.0.1/ping 89 | ``` 90 | 91 | If the server is running, this call will return an HTTP 200 (OK) result code. 92 | 93 | By default the server starts on port 8000. To bind to other ports, open the file `src/server.ts` and edit this line as needed: 94 | 95 | ```typescript 96 | const PORT = 8000; 97 | ``` 98 | 99 | #### Adding an Item in Memory 100 | 101 | To add an item in memory, call the `/local-item` endpoint with an HTTP PUT verb. This can be done on Unix/MacOS systems using cUrl: 102 | 103 | ``` 104 | curl -H "Content-Type: application/json" -X PUT -d '{"title":"my title", "content" : "my content"}' "http://127.0.0.1/item" 105 | ``` 106 | 107 | On Windows Powershell, use Invoke-WebRequest: 108 | 109 | ```powershell 110 | $item = @{ 111 | title="my title" 112 | content="my content" 113 | } 114 | $json = $item |convertto-json 115 | $response = Invoke-WebRequest 'http://127.0.0.1/local-item' -Method Put -Body $json -ContentType 'application/json' -UseBasicParsing 116 | ``` 117 | 118 | The return result will be the same item but with a UUID that serves as its index key into the in-memory dictionary where the entry is stored. 119 | 120 | #### Adding an Item to a DynamoDB Table 121 | 122 | The sample application can store items as full JSON files in a DynamoDB table. The name of the table used is retrieved from the environment variable `TABLE_NAME`. 123 | 124 | To write to DynamoDB, the application must be running in a context in which it has been granted permissions to access the DynamoDB table. 125 | 126 | ### Dockerfile 127 | 128 | The Dockerfile bundles the Express app (your app or the included sample app) onto a new Docker container image and runs the Express server. 129 | 130 | The Docker image itself derives from [Bitnami's Node.js image](https://gallery.ecr.aws/bitnami/node), which is made freely available on the [Amazon ECR Public Gallery](https://gallery.ecr.aws/) and is based on minideb, a minimalist Linux distribution. The Dockerfile uses the Node Package Manager (NPM) to install the Node.js packages required for the Express application as defined in the package-lock.json file. It then copies over the application's files and runs the Express server (as defined in the `src/server.ts` file) on port 8000 of the container. 131 | 132 | If you have Docker installed, you can build and try out the sample application locally. Open a command prompt to the directory containing the Dockerfile and run the following command: 133 | 134 | ``` 135 | docker build -t tinystacks/express-crud-app:latest . 136 | ``` 137 | 138 | Once built, run the Docker command locally, mapping port 8080 on your host machine to port 8000 on the container: 139 | 140 | ``` 141 | docker run -p 8080:8000 -d tinystacks/express-crud-app:latest 142 | ``` 143 | 144 | To test that the server is running, test its `/ping` endpoint from the command line. This time, you will change the port to 8080 to test that it's running from the running Docker container: 145 | 146 | ``` 147 | curl http://127.0.0.1:8080/ping 148 | ``` 149 | 150 | If the server is running, this call will return an HTTP 200 (OK) result code. 151 | 152 | ### Build Template 153 | 154 | The `build.yml` file is an AWS CodeBuild file that builds your Dockerfile and publishes the output to an Amazon ECR registry. 155 | 156 | To publish to Amazon ECR, the build script first needs to obtain login credentials to the cluster. It does this using a combination of the AWS CLI command `aws ecr get-login-password` and the docker login command. After authentication, the script then builds your Docker image, names it, and tags it with the name `latest` to mark it as the most recent build. Finally, it performs a `docker push`, publishing the new Docker image to your Amazon ECR Docker repository. 157 | 158 | ```yml 159 | version: 0.2 160 | phases: 161 | build: 162 | commands: 163 | - aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $ECR_ENDPOINT 164 | - docker build -t builtimage . 165 | - docker tag builtimage:latest $ECR_IMAGE_URL:latest 166 | - docker push $ECR_IMAGE_URL:latest 167 | ``` 168 | 169 | To run this in AWS CodeBuild, your build pipeline needs to define the following environment variables: 170 | 171 | * **ECR_ENDPOINT**: The name of the Amazon ECR repository to publish to. This variable takes the format: **.dkr.ecr.**.amazonaws.com 172 | * **ECR_IMAGE_URL**: The name of the Amazon ECR repository plus the name of the container you are publishing. This should take the format: **.dkr.ecr.**.amazonaws.com/aws-docker-express 173 | 174 | The variable `AWS_REGION` is a default global variable that will default to the same AWS region in which your build pipeline is defined. If you need to publish to an Amazon ECR repository in another region, modify this script to use a custom environment variable specifying the correct region. For more information on environment variables, see [Environment variables in build environments](https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-env-vars.html) on the AWS Web site. 175 | 176 | ### Release Template 177 | 178 | The `release.yml` file is another AWS CodeBuild file that takes the build output from the `build.yml` files (a Docker container image in an Amazon ECR repository) and runs it within an Amazon ECS cluster to which the pipeline has access. 179 | 180 | After logging in to the ECR repository using the `docker login` command, the script pulls down the image that was compiled and changes its tag from the name of the previous build to the name of the new build. Once the container's label has been updated, the script updates a defined service in Amazon ECS that pulls its image from our published Docker container. 181 | 182 | ```yaml 183 | version: 0.2 184 | phases: 185 | build: 186 | commands: 187 | - aws ecr get-login-password | docker login --username AWS --password-stdin $ECR_ENDPOINT 188 | - docker pull $ECR_IMAGE_URL:$PREVIOUS_STAGE_NAME 189 | - docker tag $ECR_IMAGE_URL:$PREVIOUS_STAGE_NAME $ECR_IMAGE_URL:$STAGE_NAME 190 | - docker push $ECR_IMAGE_URL:$STAGE_NAME 191 | - aws ecs update-service --service $SERVICE_NAME --cluster $CLUSTER_ARN --force-new-deployment 192 | ``` 193 | 194 | In addition to the variables discussed for `build.yml`, `release.yml` requires several environment variables defined in order to run: 195 | 196 | * **PREVIOUS_STAGE_NAME**: The previous build number or build stage name. This should be the previous Docker image tag name generated by the previous build. 197 | * **STAGE_NAME**: The current build number or build stage name you wish to use (e.g., `latest`). 198 | * **SERVICE_NAME**: The name of the Amazon ECS service to run. You will need to define this service yourself once you have the URI to your published container. 199 | * **CLUSTER_ARN**: The name of the cluster within your Amazon ECS service to which the release script will deploy the container. This should be the name of a custer that is running one or more instances of the service referenced by `SERVICE_NAME`. 200 | 201 | ## Getting Started 202 | 203 | ### Existing Project 204 | 205 | If you already have an existing Express application, you can use the core files included in this sample to run them on a Docker container in AWS. 206 | 207 | If your project is already Dockerized (i.e., it has its own Dockerfile), then simply copy over the `build.yml` and `release.yml` files into the root of your existing project. 208 | 209 | If your project is not Dockerized, you will also need to copy over the Dockerfile included in this sample. You may need to change the path to your application's source and to its configuration files (the `package*.json` and `tsconfig.json` files) in the Dockerfile itself to reflect your project's file paths: 210 | 211 | ```Dockerfile 212 | COPY package*.json ./ 213 | COPY tsconfig.json ./ 214 | COPY src ./src 215 | ``` 216 | 217 | If your application uses a different port than port 8000, you will also need to update the `EXPOSE` line in the Dockerfile to use a different port: 218 | 219 | ```Dockerfile 220 | EXPOSE 8000 221 | ``` 222 | 223 | ## Known Limitations 224 | 225 | The application was written for demonstration purposes and not for production use. 226 | -------------------------------------------------------------------------------- /build.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | phases: 3 | build: 4 | commands: 5 | - docker login -u AWS -p $(aws ecr get-login-password --region $AWS_REGION) $ECR_ENDPOINT 6 | - docker build -t builtimage . 7 | - docker tag builtimage:latest $ECR_IMAGE_URL:latest 8 | - docker tag builtimage:latest $ECR_IMAGE_URL:$(git rev-parse HEAD) 9 | - docker push $ECR_IMAGE_URL:latest 10 | - docker push $ECR_IMAGE_URL:$(git rev-parse HEAD) 11 | -------------------------------------------------------------------------------- /buildspecs/build.sh: -------------------------------------------------------------------------------- 1 | version=$(cat version); 2 | appName=$(cat name); 3 | arch_type=${1:-x86} 4 | debug=$2 5 | 6 | platform=linux/x86_64 7 | if [[ $arch_type == arm* ]]; 8 | then platform=linux/arm64 9 | fi 10 | if [[ $debug == y ]]; 11 | then 12 | echo "running $arch_type docker build in debug mode" 13 | docker build -f Dockerfile.$arch_type --progress=plain --no-cache --build-arg CACHEBUST="$(date)" --build-arg ARCH="$arch_type" --platform "$platform" -t "$appName:latest-$arch_type" .; 14 | else 15 | echo "running $arch_type docker build" 16 | docker build -f Dockerfile.$arch_type --build-arg ARCH="$arch_type" --platform "$platform" -t "$appName:latest-$arch_type" .; 17 | fi -------------------------------------------------------------------------------- /buildspecs/export.sh: -------------------------------------------------------------------------------- 1 | x86AppName="wrapper-x86" 2 | sudo rm -f ~/Downloads/$x86AppName.tar 3 | sudo rm -rf ~/Downloads/$x86AppName 4 | docker build --no-cache --platform "linux/x86_64" -t "$x86AppName:latest-x86" . 5 | docker container rm $x86AppName 2> /dev/null || true 6 | docker create --name $x86AppName "$x86AppName:latest-x86" 7 | docker export $x86AppName > ~/Downloads/$x86AppName.tar 8 | 9 | armAppName="wrapper-arm" 10 | sudo rm -f ~/Downloads/$armAppName.tar 11 | sudo rm -rf ~/Downloads/$armAppName 12 | docker build --no-cache --build-arg ARCH="arm" --platform "linux/arm64" -t "$armAppName:latest-arm" . 13 | docker container rm $armAppName 2> /dev/null || true 14 | docker create --name $armAppName "$armAppName:latest-arm" 15 | docker export $armAppName > ~/Downloads/$armAppName.tar 16 | -------------------------------------------------------------------------------- /buildspecs/publish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | arch_type=$1 4 | debug=$2 5 | 6 | if [[ -z "$arch_type" ]]; 7 | then 8 | echo "No architecture type specified!" 9 | echo "exiting..." 10 | exit 1 11 | fi 12 | 13 | region="${AWS_REGION:-us-east-1}"; 14 | echo "getting caller identity" 15 | callerIdentity=$(aws sts get-caller-identity); 16 | accountId=$(jq -r .Account <<< $callerIdentity); 17 | ## TODO: use this once our custom alias is approved 18 | # ecrEndpoint="public.ecr.aws/tinystacks/"; 19 | ecrEndpoint="public.ecr.aws/m7b0o7h1"; 20 | echo "getting version" 21 | version=$(jq -r .version ./package.json); 22 | echo "getting name" 23 | appName=$(jq -r .name ./package.json); 24 | echo "getting commit sha" 25 | commitSha=$(git rev-parse HEAD); 26 | ecrImageUrl="${ecrEndpoint}/${appName}" 27 | 28 | echo "logging in to docker and ecr-public" 29 | # docker login -u AWS -p $(aws ecr get-login-password --region $region) $ecrEndpoint; 30 | aws ecr-public get-login-password --region $region | docker login --username AWS --password-stdin public.ecr.aws 31 | 32 | # # We don't need to do this for our public ECR but if we want to test in out own accounts we may want to reintroduce this 33 | # # Create the ECR repo if it doesn't exist yet 34 | # echo "creating ecr repo if it doesn't exist" 35 | # aws ecr create-repository --repository-name $appName 2> /dev/null 36 | 37 | platform=linux/x86_64 38 | if [[ $arch_type == arm* ]]; 39 | then platform=linux/arm64 40 | fi 41 | if [[ $debug == y ]]; 42 | then 43 | echo "running $arch_type docker build in debug mode" 44 | docker build --progress=plain --no-cache --build-arg CACHEBUST="$(date)" --build-arg ARCH="$arch_type" --platform "$platform" -t "$appName:latest-$arch_type" . || exit 1 45 | else 46 | echo "running $arch_type docker build" 47 | docker build --build-arg ARCH="$arch_type" --platform "$platform" -t "$appName:latest-$arch_type" . || exit 1 48 | fi 49 | 50 | echo "tagging $arch_type docker images" 51 | docker image tag "$appName:latest-$arch_type" "$ecrImageUrl:latest-$arch_type" 52 | docker image tag "$appName:latest-$arch_type" "$ecrImageUrl:$version-$arch_type" 53 | docker image tag "$appName:latest-$arch_type" "$ecrImageUrl:$commitSha-$arch_type" 54 | 55 | echo "pushing docker images" 56 | docker push $ecrImageUrl --all-tags; 57 | -------------------------------------------------------------------------------- /buildspecs/publish.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | phases: 3 | build: 4 | commands: 5 | - machine_arch_type=$(uname -m) 6 | - arch_type=${ARCH:-$machine_arch_type} 7 | - bash buildspecs/publish.sh $arch_type -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express_crud_app", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "express_crud_app", 9 | "version": "1.0.0", 10 | "dependencies": { 11 | "@types/mysql": "^2.15.21", 12 | "@types/pg": "^8.6.1", 13 | "aws-sdk": "^2.822.0", 14 | "express": "^4.16.1", 15 | "mysql": "^2.18.1", 16 | "mysql2": "^2.3.3", 17 | "pg": "^8.7.1", 18 | "typescript": "^4.2.3", 19 | "uuid": "^3.3.2" 20 | }, 21 | "devDependencies": { 22 | "@types/express": "^4.17.11", 23 | "@types/uuid": "^8.3.0" 24 | } 25 | }, 26 | "node_modules/@types/body-parser": { 27 | "version": "1.19.0", 28 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", 29 | "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", 30 | "dev": true, 31 | "dependencies": { 32 | "@types/connect": "*", 33 | "@types/node": "*" 34 | } 35 | }, 36 | "node_modules/@types/connect": { 37 | "version": "3.4.34", 38 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", 39 | "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", 40 | "dev": true, 41 | "dependencies": { 42 | "@types/node": "*" 43 | } 44 | }, 45 | "node_modules/@types/express": { 46 | "version": "4.17.11", 47 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz", 48 | "integrity": "sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==", 49 | "dev": true, 50 | "dependencies": { 51 | "@types/body-parser": "*", 52 | "@types/express-serve-static-core": "^4.17.18", 53 | "@types/qs": "*", 54 | "@types/serve-static": "*" 55 | } 56 | }, 57 | "node_modules/@types/express-serve-static-core": { 58 | "version": "4.17.19", 59 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz", 60 | "integrity": "sha512-DJOSHzX7pCiSElWaGR8kCprwibCB/3yW6vcT8VG3P0SJjnv19gnWG/AZMfM60Xj/YJIp/YCaDHyvzsFVeniARA==", 61 | "dev": true, 62 | "dependencies": { 63 | "@types/node": "*", 64 | "@types/qs": "*", 65 | "@types/range-parser": "*" 66 | } 67 | }, 68 | "node_modules/@types/mime": { 69 | "version": "1.3.2", 70 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", 71 | "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", 72 | "dev": true 73 | }, 74 | "node_modules/@types/mysql": { 75 | "version": "2.15.21", 76 | "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.21.tgz", 77 | "integrity": "sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg==", 78 | "dependencies": { 79 | "@types/node": "*" 80 | } 81 | }, 82 | "node_modules/@types/node": { 83 | "version": "14.14.35", 84 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.35.tgz", 85 | "integrity": "sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==" 86 | }, 87 | "node_modules/@types/pg": { 88 | "version": "8.6.1", 89 | "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz", 90 | "integrity": "sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==", 91 | "dependencies": { 92 | "@types/node": "*", 93 | "pg-protocol": "*", 94 | "pg-types": "^2.2.0" 95 | } 96 | }, 97 | "node_modules/@types/qs": { 98 | "version": "6.9.6", 99 | "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", 100 | "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==", 101 | "dev": true 102 | }, 103 | "node_modules/@types/range-parser": { 104 | "version": "1.2.3", 105 | "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", 106 | "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", 107 | "dev": true 108 | }, 109 | "node_modules/@types/serve-static": { 110 | "version": "1.13.9", 111 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", 112 | "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==", 113 | "dev": true, 114 | "dependencies": { 115 | "@types/mime": "^1", 116 | "@types/node": "*" 117 | } 118 | }, 119 | "node_modules/@types/uuid": { 120 | "version": "8.3.0", 121 | "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", 122 | "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", 123 | "dev": true 124 | }, 125 | "node_modules/accepts": { 126 | "version": "1.3.7", 127 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 128 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 129 | "dependencies": { 130 | "mime-types": "~2.1.24", 131 | "negotiator": "0.6.2" 132 | }, 133 | "engines": { 134 | "node": ">= 0.6" 135 | } 136 | }, 137 | "node_modules/array-flatten": { 138 | "version": "1.1.1", 139 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 140 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 141 | }, 142 | "node_modules/aws-sdk": { 143 | "version": "2.865.0", 144 | "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.865.0.tgz", 145 | "integrity": "sha512-JUaUlGjnJY4Nnd/xnWt8rPmTwebVvA26XfnUM3tyAPtSClwniANkaRq4UdHI0uU3R+V4N2Cuohy8XSLOzBG/4A==", 146 | "dependencies": { 147 | "buffer": "4.9.2", 148 | "events": "1.1.1", 149 | "ieee754": "1.1.13", 150 | "jmespath": "0.15.0", 151 | "querystring": "0.2.0", 152 | "sax": "1.2.1", 153 | "url": "0.10.3", 154 | "uuid": "3.3.2", 155 | "xml2js": "0.4.19" 156 | }, 157 | "engines": { 158 | "node": ">= 0.8.0" 159 | } 160 | }, 161 | "node_modules/base64-js": { 162 | "version": "1.5.1", 163 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 164 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 165 | "funding": [ 166 | { 167 | "type": "github", 168 | "url": "https://github.com/sponsors/feross" 169 | }, 170 | { 171 | "type": "patreon", 172 | "url": "https://www.patreon.com/feross" 173 | }, 174 | { 175 | "type": "consulting", 176 | "url": "https://feross.org/support" 177 | } 178 | ] 179 | }, 180 | "node_modules/bignumber.js": { 181 | "version": "9.0.0", 182 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", 183 | "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", 184 | "engines": { 185 | "node": "*" 186 | } 187 | }, 188 | "node_modules/body-parser": { 189 | "version": "1.19.0", 190 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", 191 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 192 | "dependencies": { 193 | "bytes": "3.1.0", 194 | "content-type": "~1.0.4", 195 | "debug": "2.6.9", 196 | "depd": "~1.1.2", 197 | "http-errors": "1.7.2", 198 | "iconv-lite": "0.4.24", 199 | "on-finished": "~2.3.0", 200 | "qs": "6.7.0", 201 | "raw-body": "2.4.0", 202 | "type-is": "~1.6.17" 203 | }, 204 | "engines": { 205 | "node": ">= 0.8" 206 | } 207 | }, 208 | "node_modules/buffer": { 209 | "version": "4.9.2", 210 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", 211 | "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", 212 | "dependencies": { 213 | "base64-js": "^1.0.2", 214 | "ieee754": "^1.1.4", 215 | "isarray": "^1.0.0" 216 | } 217 | }, 218 | "node_modules/buffer-writer": { 219 | "version": "2.0.0", 220 | "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", 221 | "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", 222 | "engines": { 223 | "node": ">=4" 224 | } 225 | }, 226 | "node_modules/bytes": { 227 | "version": "3.1.0", 228 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 229 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", 230 | "engines": { 231 | "node": ">= 0.8" 232 | } 233 | }, 234 | "node_modules/content-disposition": { 235 | "version": "0.5.3", 236 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 237 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 238 | "dependencies": { 239 | "safe-buffer": "5.1.2" 240 | }, 241 | "engines": { 242 | "node": ">= 0.6" 243 | } 244 | }, 245 | "node_modules/content-type": { 246 | "version": "1.0.4", 247 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 248 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", 249 | "engines": { 250 | "node": ">= 0.6" 251 | } 252 | }, 253 | "node_modules/cookie": { 254 | "version": "0.4.0", 255 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", 256 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", 257 | "engines": { 258 | "node": ">= 0.6" 259 | } 260 | }, 261 | "node_modules/cookie-signature": { 262 | "version": "1.0.6", 263 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 264 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 265 | }, 266 | "node_modules/core-util-is": { 267 | "version": "1.0.3", 268 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 269 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" 270 | }, 271 | "node_modules/debug": { 272 | "version": "2.6.9", 273 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 274 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 275 | "dependencies": { 276 | "ms": "2.0.0" 277 | } 278 | }, 279 | "node_modules/denque": { 280 | "version": "2.0.1", 281 | "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", 282 | "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==", 283 | "engines": { 284 | "node": ">=0.10" 285 | } 286 | }, 287 | "node_modules/depd": { 288 | "version": "1.1.2", 289 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 290 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", 291 | "engines": { 292 | "node": ">= 0.6" 293 | } 294 | }, 295 | "node_modules/destroy": { 296 | "version": "1.0.4", 297 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 298 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 299 | }, 300 | "node_modules/ee-first": { 301 | "version": "1.1.1", 302 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 303 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 304 | }, 305 | "node_modules/encodeurl": { 306 | "version": "1.0.2", 307 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 308 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", 309 | "engines": { 310 | "node": ">= 0.8" 311 | } 312 | }, 313 | "node_modules/escape-html": { 314 | "version": "1.0.3", 315 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 316 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 317 | }, 318 | "node_modules/etag": { 319 | "version": "1.8.1", 320 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 321 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", 322 | "engines": { 323 | "node": ">= 0.6" 324 | } 325 | }, 326 | "node_modules/events": { 327 | "version": "1.1.1", 328 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", 329 | "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", 330 | "engines": { 331 | "node": ">=0.4.x" 332 | } 333 | }, 334 | "node_modules/express": { 335 | "version": "4.17.1", 336 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", 337 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", 338 | "dependencies": { 339 | "accepts": "~1.3.7", 340 | "array-flatten": "1.1.1", 341 | "body-parser": "1.19.0", 342 | "content-disposition": "0.5.3", 343 | "content-type": "~1.0.4", 344 | "cookie": "0.4.0", 345 | "cookie-signature": "1.0.6", 346 | "debug": "2.6.9", 347 | "depd": "~1.1.2", 348 | "encodeurl": "~1.0.2", 349 | "escape-html": "~1.0.3", 350 | "etag": "~1.8.1", 351 | "finalhandler": "~1.1.2", 352 | "fresh": "0.5.2", 353 | "merge-descriptors": "1.0.1", 354 | "methods": "~1.1.2", 355 | "on-finished": "~2.3.0", 356 | "parseurl": "~1.3.3", 357 | "path-to-regexp": "0.1.7", 358 | "proxy-addr": "~2.0.5", 359 | "qs": "6.7.0", 360 | "range-parser": "~1.2.1", 361 | "safe-buffer": "5.1.2", 362 | "send": "0.17.1", 363 | "serve-static": "1.14.1", 364 | "setprototypeof": "1.1.1", 365 | "statuses": "~1.5.0", 366 | "type-is": "~1.6.18", 367 | "utils-merge": "1.0.1", 368 | "vary": "~1.1.2" 369 | }, 370 | "engines": { 371 | "node": ">= 0.10.0" 372 | } 373 | }, 374 | "node_modules/finalhandler": { 375 | "version": "1.1.2", 376 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 377 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 378 | "dependencies": { 379 | "debug": "2.6.9", 380 | "encodeurl": "~1.0.2", 381 | "escape-html": "~1.0.3", 382 | "on-finished": "~2.3.0", 383 | "parseurl": "~1.3.3", 384 | "statuses": "~1.5.0", 385 | "unpipe": "~1.0.0" 386 | }, 387 | "engines": { 388 | "node": ">= 0.8" 389 | } 390 | }, 391 | "node_modules/forwarded": { 392 | "version": "0.1.2", 393 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 394 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", 395 | "engines": { 396 | "node": ">= 0.6" 397 | } 398 | }, 399 | "node_modules/fresh": { 400 | "version": "0.5.2", 401 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 402 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", 403 | "engines": { 404 | "node": ">= 0.6" 405 | } 406 | }, 407 | "node_modules/generate-function": { 408 | "version": "2.3.1", 409 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", 410 | "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", 411 | "dependencies": { 412 | "is-property": "^1.0.2" 413 | } 414 | }, 415 | "node_modules/http-errors": { 416 | "version": "1.7.2", 417 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 418 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 419 | "dependencies": { 420 | "depd": "~1.1.2", 421 | "inherits": "2.0.3", 422 | "setprototypeof": "1.1.1", 423 | "statuses": ">= 1.5.0 < 2", 424 | "toidentifier": "1.0.0" 425 | }, 426 | "engines": { 427 | "node": ">= 0.6" 428 | } 429 | }, 430 | "node_modules/iconv-lite": { 431 | "version": "0.4.24", 432 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 433 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 434 | "dependencies": { 435 | "safer-buffer": ">= 2.1.2 < 3" 436 | }, 437 | "engines": { 438 | "node": ">=0.10.0" 439 | } 440 | }, 441 | "node_modules/ieee754": { 442 | "version": "1.1.13", 443 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", 444 | "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" 445 | }, 446 | "node_modules/inherits": { 447 | "version": "2.0.3", 448 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 449 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 450 | }, 451 | "node_modules/ipaddr.js": { 452 | "version": "1.9.1", 453 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 454 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 455 | "engines": { 456 | "node": ">= 0.10" 457 | } 458 | }, 459 | "node_modules/is-property": { 460 | "version": "1.0.2", 461 | "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", 462 | "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" 463 | }, 464 | "node_modules/isarray": { 465 | "version": "1.0.0", 466 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 467 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 468 | }, 469 | "node_modules/jmespath": { 470 | "version": "0.15.0", 471 | "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", 472 | "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", 473 | "engines": { 474 | "node": ">= 0.6.0" 475 | } 476 | }, 477 | "node_modules/long": { 478 | "version": "4.0.0", 479 | "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", 480 | "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" 481 | }, 482 | "node_modules/lru-cache": { 483 | "version": "6.0.0", 484 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 485 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 486 | "dependencies": { 487 | "yallist": "^4.0.0" 488 | }, 489 | "engines": { 490 | "node": ">=10" 491 | } 492 | }, 493 | "node_modules/media-typer": { 494 | "version": "0.3.0", 495 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 496 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", 497 | "engines": { 498 | "node": ">= 0.6" 499 | } 500 | }, 501 | "node_modules/merge-descriptors": { 502 | "version": "1.0.1", 503 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 504 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 505 | }, 506 | "node_modules/methods": { 507 | "version": "1.1.2", 508 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 509 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", 510 | "engines": { 511 | "node": ">= 0.6" 512 | } 513 | }, 514 | "node_modules/mime": { 515 | "version": "1.6.0", 516 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 517 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 518 | "bin": { 519 | "mime": "cli.js" 520 | }, 521 | "engines": { 522 | "node": ">=4" 523 | } 524 | }, 525 | "node_modules/mime-db": { 526 | "version": "1.46.0", 527 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", 528 | "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==", 529 | "engines": { 530 | "node": ">= 0.6" 531 | } 532 | }, 533 | "node_modules/mime-types": { 534 | "version": "2.1.29", 535 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", 536 | "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", 537 | "dependencies": { 538 | "mime-db": "1.46.0" 539 | }, 540 | "engines": { 541 | "node": ">= 0.6" 542 | } 543 | }, 544 | "node_modules/ms": { 545 | "version": "2.0.0", 546 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 547 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 548 | }, 549 | "node_modules/mysql": { 550 | "version": "2.18.1", 551 | "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", 552 | "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", 553 | "dependencies": { 554 | "bignumber.js": "9.0.0", 555 | "readable-stream": "2.3.7", 556 | "safe-buffer": "5.1.2", 557 | "sqlstring": "2.3.1" 558 | }, 559 | "engines": { 560 | "node": ">= 0.6" 561 | } 562 | }, 563 | "node_modules/mysql/node_modules/readable-stream": { 564 | "version": "2.3.7", 565 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 566 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 567 | "dependencies": { 568 | "core-util-is": "~1.0.0", 569 | "inherits": "~2.0.3", 570 | "isarray": "~1.0.0", 571 | "process-nextick-args": "~2.0.0", 572 | "safe-buffer": "~5.1.1", 573 | "string_decoder": "~1.1.1", 574 | "util-deprecate": "~1.0.1" 575 | } 576 | }, 577 | "node_modules/mysql/node_modules/string_decoder": { 578 | "version": "1.1.1", 579 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 580 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 581 | "dependencies": { 582 | "safe-buffer": "~5.1.0" 583 | } 584 | }, 585 | "node_modules/mysql2": { 586 | "version": "2.3.3", 587 | "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz", 588 | "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", 589 | "dependencies": { 590 | "denque": "^2.0.1", 591 | "generate-function": "^2.3.1", 592 | "iconv-lite": "^0.6.3", 593 | "long": "^4.0.0", 594 | "lru-cache": "^6.0.0", 595 | "named-placeholders": "^1.1.2", 596 | "seq-queue": "^0.0.5", 597 | "sqlstring": "^2.3.2" 598 | }, 599 | "engines": { 600 | "node": ">= 8.0" 601 | } 602 | }, 603 | "node_modules/mysql2/node_modules/iconv-lite": { 604 | "version": "0.6.3", 605 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 606 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 607 | "dependencies": { 608 | "safer-buffer": ">= 2.1.2 < 3.0.0" 609 | }, 610 | "engines": { 611 | "node": ">=0.10.0" 612 | } 613 | }, 614 | "node_modules/mysql2/node_modules/sqlstring": { 615 | "version": "2.3.3", 616 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", 617 | "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", 618 | "engines": { 619 | "node": ">= 0.6" 620 | } 621 | }, 622 | "node_modules/named-placeholders": { 623 | "version": "1.1.2", 624 | "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", 625 | "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", 626 | "dependencies": { 627 | "lru-cache": "^4.1.3" 628 | }, 629 | "engines": { 630 | "node": ">=6.0.0" 631 | } 632 | }, 633 | "node_modules/named-placeholders/node_modules/lru-cache": { 634 | "version": "4.1.5", 635 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", 636 | "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", 637 | "dependencies": { 638 | "pseudomap": "^1.0.2", 639 | "yallist": "^2.1.2" 640 | } 641 | }, 642 | "node_modules/named-placeholders/node_modules/yallist": { 643 | "version": "2.1.2", 644 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 645 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" 646 | }, 647 | "node_modules/negotiator": { 648 | "version": "0.6.2", 649 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 650 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", 651 | "engines": { 652 | "node": ">= 0.6" 653 | } 654 | }, 655 | "node_modules/on-finished": { 656 | "version": "2.3.0", 657 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 658 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 659 | "dependencies": { 660 | "ee-first": "1.1.1" 661 | }, 662 | "engines": { 663 | "node": ">= 0.8" 664 | } 665 | }, 666 | "node_modules/packet-reader": { 667 | "version": "1.0.0", 668 | "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", 669 | "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" 670 | }, 671 | "node_modules/parseurl": { 672 | "version": "1.3.3", 673 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 674 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 675 | "engines": { 676 | "node": ">= 0.8" 677 | } 678 | }, 679 | "node_modules/path-to-regexp": { 680 | "version": "0.1.7", 681 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 682 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 683 | }, 684 | "node_modules/pg": { 685 | "version": "8.7.1", 686 | "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz", 687 | "integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==", 688 | "dependencies": { 689 | "buffer-writer": "2.0.0", 690 | "packet-reader": "1.0.0", 691 | "pg-connection-string": "^2.5.0", 692 | "pg-pool": "^3.4.1", 693 | "pg-protocol": "^1.5.0", 694 | "pg-types": "^2.1.0", 695 | "pgpass": "1.x" 696 | }, 697 | "engines": { 698 | "node": ">= 8.0.0" 699 | }, 700 | "peerDependencies": { 701 | "pg-native": ">=2.0.0" 702 | }, 703 | "peerDependenciesMeta": { 704 | "pg-native": { 705 | "optional": true 706 | } 707 | } 708 | }, 709 | "node_modules/pg-connection-string": { 710 | "version": "2.5.0", 711 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", 712 | "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" 713 | }, 714 | "node_modules/pg-int8": { 715 | "version": "1.0.1", 716 | "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", 717 | "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", 718 | "engines": { 719 | "node": ">=4.0.0" 720 | } 721 | }, 722 | "node_modules/pg-pool": { 723 | "version": "3.4.1", 724 | "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz", 725 | "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==", 726 | "peerDependencies": { 727 | "pg": ">=8.0" 728 | } 729 | }, 730 | "node_modules/pg-protocol": { 731 | "version": "1.5.0", 732 | "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", 733 | "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" 734 | }, 735 | "node_modules/pg-types": { 736 | "version": "2.2.0", 737 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", 738 | "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", 739 | "dependencies": { 740 | "pg-int8": "1.0.1", 741 | "postgres-array": "~2.0.0", 742 | "postgres-bytea": "~1.0.0", 743 | "postgres-date": "~1.0.4", 744 | "postgres-interval": "^1.1.0" 745 | }, 746 | "engines": { 747 | "node": ">=4" 748 | } 749 | }, 750 | "node_modules/pgpass": { 751 | "version": "1.0.4", 752 | "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", 753 | "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", 754 | "dependencies": { 755 | "split2": "^3.1.1" 756 | } 757 | }, 758 | "node_modules/postgres-array": { 759 | "version": "2.0.0", 760 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", 761 | "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", 762 | "engines": { 763 | "node": ">=4" 764 | } 765 | }, 766 | "node_modules/postgres-bytea": { 767 | "version": "1.0.0", 768 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", 769 | "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=", 770 | "engines": { 771 | "node": ">=0.10.0" 772 | } 773 | }, 774 | "node_modules/postgres-date": { 775 | "version": "1.0.7", 776 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", 777 | "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", 778 | "engines": { 779 | "node": ">=0.10.0" 780 | } 781 | }, 782 | "node_modules/postgres-interval": { 783 | "version": "1.2.0", 784 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", 785 | "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", 786 | "dependencies": { 787 | "xtend": "^4.0.0" 788 | }, 789 | "engines": { 790 | "node": ">=0.10.0" 791 | } 792 | }, 793 | "node_modules/process-nextick-args": { 794 | "version": "2.0.1", 795 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 796 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 797 | }, 798 | "node_modules/proxy-addr": { 799 | "version": "2.0.6", 800 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", 801 | "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", 802 | "dependencies": { 803 | "forwarded": "~0.1.2", 804 | "ipaddr.js": "1.9.1" 805 | }, 806 | "engines": { 807 | "node": ">= 0.10" 808 | } 809 | }, 810 | "node_modules/pseudomap": { 811 | "version": "1.0.2", 812 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 813 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" 814 | }, 815 | "node_modules/punycode": { 816 | "version": "1.3.2", 817 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 818 | "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" 819 | }, 820 | "node_modules/qs": { 821 | "version": "6.7.0", 822 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", 823 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", 824 | "engines": { 825 | "node": ">=0.6" 826 | } 827 | }, 828 | "node_modules/querystring": { 829 | "version": "0.2.0", 830 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 831 | "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", 832 | "engines": { 833 | "node": ">=0.4.x" 834 | } 835 | }, 836 | "node_modules/range-parser": { 837 | "version": "1.2.1", 838 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 839 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 840 | "engines": { 841 | "node": ">= 0.6" 842 | } 843 | }, 844 | "node_modules/raw-body": { 845 | "version": "2.4.0", 846 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", 847 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 848 | "dependencies": { 849 | "bytes": "3.1.0", 850 | "http-errors": "1.7.2", 851 | "iconv-lite": "0.4.24", 852 | "unpipe": "1.0.0" 853 | }, 854 | "engines": { 855 | "node": ">= 0.8" 856 | } 857 | }, 858 | "node_modules/readable-stream": { 859 | "version": "3.6.0", 860 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 861 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 862 | "dependencies": { 863 | "inherits": "^2.0.3", 864 | "string_decoder": "^1.1.1", 865 | "util-deprecate": "^1.0.1" 866 | }, 867 | "engines": { 868 | "node": ">= 6" 869 | } 870 | }, 871 | "node_modules/safe-buffer": { 872 | "version": "5.1.2", 873 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 874 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 875 | }, 876 | "node_modules/safer-buffer": { 877 | "version": "2.1.2", 878 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 879 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 880 | }, 881 | "node_modules/sax": { 882 | "version": "1.2.1", 883 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", 884 | "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" 885 | }, 886 | "node_modules/send": { 887 | "version": "0.17.1", 888 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", 889 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", 890 | "dependencies": { 891 | "debug": "2.6.9", 892 | "depd": "~1.1.2", 893 | "destroy": "~1.0.4", 894 | "encodeurl": "~1.0.2", 895 | "escape-html": "~1.0.3", 896 | "etag": "~1.8.1", 897 | "fresh": "0.5.2", 898 | "http-errors": "~1.7.2", 899 | "mime": "1.6.0", 900 | "ms": "2.1.1", 901 | "on-finished": "~2.3.0", 902 | "range-parser": "~1.2.1", 903 | "statuses": "~1.5.0" 904 | }, 905 | "engines": { 906 | "node": ">= 0.8.0" 907 | } 908 | }, 909 | "node_modules/send/node_modules/ms": { 910 | "version": "2.1.1", 911 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 912 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 913 | }, 914 | "node_modules/seq-queue": { 915 | "version": "0.0.5", 916 | "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", 917 | "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" 918 | }, 919 | "node_modules/serve-static": { 920 | "version": "1.14.1", 921 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", 922 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", 923 | "dependencies": { 924 | "encodeurl": "~1.0.2", 925 | "escape-html": "~1.0.3", 926 | "parseurl": "~1.3.3", 927 | "send": "0.17.1" 928 | }, 929 | "engines": { 930 | "node": ">= 0.8.0" 931 | } 932 | }, 933 | "node_modules/setprototypeof": { 934 | "version": "1.1.1", 935 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 936 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 937 | }, 938 | "node_modules/split2": { 939 | "version": "3.2.2", 940 | "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", 941 | "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", 942 | "dependencies": { 943 | "readable-stream": "^3.0.0" 944 | } 945 | }, 946 | "node_modules/sqlstring": { 947 | "version": "2.3.1", 948 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", 949 | "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=", 950 | "engines": { 951 | "node": ">= 0.6" 952 | } 953 | }, 954 | "node_modules/statuses": { 955 | "version": "1.5.0", 956 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 957 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", 958 | "engines": { 959 | "node": ">= 0.6" 960 | } 961 | }, 962 | "node_modules/string_decoder": { 963 | "version": "1.3.0", 964 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 965 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 966 | "dependencies": { 967 | "safe-buffer": "~5.2.0" 968 | } 969 | }, 970 | "node_modules/string_decoder/node_modules/safe-buffer": { 971 | "version": "5.2.1", 972 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 973 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 974 | "funding": [ 975 | { 976 | "type": "github", 977 | "url": "https://github.com/sponsors/feross" 978 | }, 979 | { 980 | "type": "patreon", 981 | "url": "https://www.patreon.com/feross" 982 | }, 983 | { 984 | "type": "consulting", 985 | "url": "https://feross.org/support" 986 | } 987 | ] 988 | }, 989 | "node_modules/toidentifier": { 990 | "version": "1.0.0", 991 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 992 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", 993 | "engines": { 994 | "node": ">=0.6" 995 | } 996 | }, 997 | "node_modules/type-is": { 998 | "version": "1.6.18", 999 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 1000 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 1001 | "dependencies": { 1002 | "media-typer": "0.3.0", 1003 | "mime-types": "~2.1.24" 1004 | }, 1005 | "engines": { 1006 | "node": ">= 0.6" 1007 | } 1008 | }, 1009 | "node_modules/typescript": { 1010 | "version": "4.2.3", 1011 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", 1012 | "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", 1013 | "bin": { 1014 | "tsc": "bin/tsc", 1015 | "tsserver": "bin/tsserver" 1016 | }, 1017 | "engines": { 1018 | "node": ">=4.2.0" 1019 | } 1020 | }, 1021 | "node_modules/unpipe": { 1022 | "version": "1.0.0", 1023 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1024 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", 1025 | "engines": { 1026 | "node": ">= 0.8" 1027 | } 1028 | }, 1029 | "node_modules/url": { 1030 | "version": "0.10.3", 1031 | "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", 1032 | "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", 1033 | "dependencies": { 1034 | "punycode": "1.3.2", 1035 | "querystring": "0.2.0" 1036 | } 1037 | }, 1038 | "node_modules/util-deprecate": { 1039 | "version": "1.0.2", 1040 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1041 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1042 | }, 1043 | "node_modules/utils-merge": { 1044 | "version": "1.0.1", 1045 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1046 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", 1047 | "engines": { 1048 | "node": ">= 0.4.0" 1049 | } 1050 | }, 1051 | "node_modules/uuid": { 1052 | "version": "3.3.2", 1053 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 1054 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", 1055 | "bin": { 1056 | "uuid": "bin/uuid" 1057 | } 1058 | }, 1059 | "node_modules/vary": { 1060 | "version": "1.1.2", 1061 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1062 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", 1063 | "engines": { 1064 | "node": ">= 0.8" 1065 | } 1066 | }, 1067 | "node_modules/xml2js": { 1068 | "version": "0.4.19", 1069 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", 1070 | "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", 1071 | "dependencies": { 1072 | "sax": ">=0.6.0", 1073 | "xmlbuilder": "~9.0.1" 1074 | } 1075 | }, 1076 | "node_modules/xmlbuilder": { 1077 | "version": "9.0.7", 1078 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", 1079 | "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", 1080 | "engines": { 1081 | "node": ">=4.0" 1082 | } 1083 | }, 1084 | "node_modules/xtend": { 1085 | "version": "4.0.2", 1086 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1087 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 1088 | "engines": { 1089 | "node": ">=0.4" 1090 | } 1091 | }, 1092 | "node_modules/yallist": { 1093 | "version": "4.0.0", 1094 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1095 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 1096 | } 1097 | }, 1098 | "dependencies": { 1099 | "@types/body-parser": { 1100 | "version": "1.19.0", 1101 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", 1102 | "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", 1103 | "dev": true, 1104 | "requires": { 1105 | "@types/connect": "*", 1106 | "@types/node": "*" 1107 | } 1108 | }, 1109 | "@types/connect": { 1110 | "version": "3.4.34", 1111 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", 1112 | "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", 1113 | "dev": true, 1114 | "requires": { 1115 | "@types/node": "*" 1116 | } 1117 | }, 1118 | "@types/express": { 1119 | "version": "4.17.11", 1120 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz", 1121 | "integrity": "sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==", 1122 | "dev": true, 1123 | "requires": { 1124 | "@types/body-parser": "*", 1125 | "@types/express-serve-static-core": "^4.17.18", 1126 | "@types/qs": "*", 1127 | "@types/serve-static": "*" 1128 | } 1129 | }, 1130 | "@types/express-serve-static-core": { 1131 | "version": "4.17.19", 1132 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz", 1133 | "integrity": "sha512-DJOSHzX7pCiSElWaGR8kCprwibCB/3yW6vcT8VG3P0SJjnv19gnWG/AZMfM60Xj/YJIp/YCaDHyvzsFVeniARA==", 1134 | "dev": true, 1135 | "requires": { 1136 | "@types/node": "*", 1137 | "@types/qs": "*", 1138 | "@types/range-parser": "*" 1139 | } 1140 | }, 1141 | "@types/mime": { 1142 | "version": "1.3.2", 1143 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", 1144 | "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", 1145 | "dev": true 1146 | }, 1147 | "@types/mysql": { 1148 | "version": "2.15.21", 1149 | "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.21.tgz", 1150 | "integrity": "sha512-NPotx5CVful7yB+qZbWtXL2fA4e7aEHkihHLjklc6ID8aq7bhguHgeIoC1EmSNTAuCgI6ZXrjt2ZSaXnYX0EUg==", 1151 | "requires": { 1152 | "@types/node": "*" 1153 | } 1154 | }, 1155 | "@types/node": { 1156 | "version": "14.14.35", 1157 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.35.tgz", 1158 | "integrity": "sha512-Lt+wj8NVPx0zUmUwumiVXapmaLUcAk3yPuHCFVXras9k5VT9TdhJqKqGVUQCD60OTMCl0qxJ57OiTL0Mic3Iag==" 1159 | }, 1160 | "@types/pg": { 1161 | "version": "8.6.1", 1162 | "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz", 1163 | "integrity": "sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==", 1164 | "requires": { 1165 | "@types/node": "*", 1166 | "pg-protocol": "*", 1167 | "pg-types": "^2.2.0" 1168 | } 1169 | }, 1170 | "@types/qs": { 1171 | "version": "6.9.6", 1172 | "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", 1173 | "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==", 1174 | "dev": true 1175 | }, 1176 | "@types/range-parser": { 1177 | "version": "1.2.3", 1178 | "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", 1179 | "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", 1180 | "dev": true 1181 | }, 1182 | "@types/serve-static": { 1183 | "version": "1.13.9", 1184 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", 1185 | "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==", 1186 | "dev": true, 1187 | "requires": { 1188 | "@types/mime": "^1", 1189 | "@types/node": "*" 1190 | } 1191 | }, 1192 | "@types/uuid": { 1193 | "version": "8.3.0", 1194 | "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", 1195 | "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", 1196 | "dev": true 1197 | }, 1198 | "accepts": { 1199 | "version": "1.3.7", 1200 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 1201 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 1202 | "requires": { 1203 | "mime-types": "~2.1.24", 1204 | "negotiator": "0.6.2" 1205 | } 1206 | }, 1207 | "array-flatten": { 1208 | "version": "1.1.1", 1209 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 1210 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 1211 | }, 1212 | "aws-sdk": { 1213 | "version": "2.865.0", 1214 | "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.865.0.tgz", 1215 | "integrity": "sha512-JUaUlGjnJY4Nnd/xnWt8rPmTwebVvA26XfnUM3tyAPtSClwniANkaRq4UdHI0uU3R+V4N2Cuohy8XSLOzBG/4A==", 1216 | "requires": { 1217 | "buffer": "4.9.2", 1218 | "events": "1.1.1", 1219 | "ieee754": "1.1.13", 1220 | "jmespath": "0.15.0", 1221 | "querystring": "0.2.0", 1222 | "sax": "1.2.1", 1223 | "url": "0.10.3", 1224 | "uuid": "3.3.2", 1225 | "xml2js": "0.4.19" 1226 | } 1227 | }, 1228 | "base64-js": { 1229 | "version": "1.5.1", 1230 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 1231 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" 1232 | }, 1233 | "bignumber.js": { 1234 | "version": "9.0.0", 1235 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", 1236 | "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" 1237 | }, 1238 | "body-parser": { 1239 | "version": "1.19.0", 1240 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", 1241 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 1242 | "requires": { 1243 | "bytes": "3.1.0", 1244 | "content-type": "~1.0.4", 1245 | "debug": "2.6.9", 1246 | "depd": "~1.1.2", 1247 | "http-errors": "1.7.2", 1248 | "iconv-lite": "0.4.24", 1249 | "on-finished": "~2.3.0", 1250 | "qs": "6.7.0", 1251 | "raw-body": "2.4.0", 1252 | "type-is": "~1.6.17" 1253 | } 1254 | }, 1255 | "buffer": { 1256 | "version": "4.9.2", 1257 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", 1258 | "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", 1259 | "requires": { 1260 | "base64-js": "^1.0.2", 1261 | "ieee754": "^1.1.4", 1262 | "isarray": "^1.0.0" 1263 | } 1264 | }, 1265 | "buffer-writer": { 1266 | "version": "2.0.0", 1267 | "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", 1268 | "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" 1269 | }, 1270 | "bytes": { 1271 | "version": "3.1.0", 1272 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 1273 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 1274 | }, 1275 | "content-disposition": { 1276 | "version": "0.5.3", 1277 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 1278 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 1279 | "requires": { 1280 | "safe-buffer": "5.1.2" 1281 | } 1282 | }, 1283 | "content-type": { 1284 | "version": "1.0.4", 1285 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 1286 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 1287 | }, 1288 | "cookie": { 1289 | "version": "0.4.0", 1290 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", 1291 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 1292 | }, 1293 | "cookie-signature": { 1294 | "version": "1.0.6", 1295 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 1296 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 1297 | }, 1298 | "core-util-is": { 1299 | "version": "1.0.3", 1300 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", 1301 | "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" 1302 | }, 1303 | "debug": { 1304 | "version": "2.6.9", 1305 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 1306 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 1307 | "requires": { 1308 | "ms": "2.0.0" 1309 | } 1310 | }, 1311 | "denque": { 1312 | "version": "2.0.1", 1313 | "resolved": "https://registry.npmjs.org/denque/-/denque-2.0.1.tgz", 1314 | "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==" 1315 | }, 1316 | "depd": { 1317 | "version": "1.1.2", 1318 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 1319 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 1320 | }, 1321 | "destroy": { 1322 | "version": "1.0.4", 1323 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 1324 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 1325 | }, 1326 | "ee-first": { 1327 | "version": "1.1.1", 1328 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 1329 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 1330 | }, 1331 | "encodeurl": { 1332 | "version": "1.0.2", 1333 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 1334 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 1335 | }, 1336 | "escape-html": { 1337 | "version": "1.0.3", 1338 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 1339 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 1340 | }, 1341 | "etag": { 1342 | "version": "1.8.1", 1343 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 1344 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 1345 | }, 1346 | "events": { 1347 | "version": "1.1.1", 1348 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", 1349 | "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" 1350 | }, 1351 | "express": { 1352 | "version": "4.17.1", 1353 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", 1354 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", 1355 | "requires": { 1356 | "accepts": "~1.3.7", 1357 | "array-flatten": "1.1.1", 1358 | "body-parser": "1.19.0", 1359 | "content-disposition": "0.5.3", 1360 | "content-type": "~1.0.4", 1361 | "cookie": "0.4.0", 1362 | "cookie-signature": "1.0.6", 1363 | "debug": "2.6.9", 1364 | "depd": "~1.1.2", 1365 | "encodeurl": "~1.0.2", 1366 | "escape-html": "~1.0.3", 1367 | "etag": "~1.8.1", 1368 | "finalhandler": "~1.1.2", 1369 | "fresh": "0.5.2", 1370 | "merge-descriptors": "1.0.1", 1371 | "methods": "~1.1.2", 1372 | "on-finished": "~2.3.0", 1373 | "parseurl": "~1.3.3", 1374 | "path-to-regexp": "0.1.7", 1375 | "proxy-addr": "~2.0.5", 1376 | "qs": "6.7.0", 1377 | "range-parser": "~1.2.1", 1378 | "safe-buffer": "5.1.2", 1379 | "send": "0.17.1", 1380 | "serve-static": "1.14.1", 1381 | "setprototypeof": "1.1.1", 1382 | "statuses": "~1.5.0", 1383 | "type-is": "~1.6.18", 1384 | "utils-merge": "1.0.1", 1385 | "vary": "~1.1.2" 1386 | } 1387 | }, 1388 | "finalhandler": { 1389 | "version": "1.1.2", 1390 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 1391 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 1392 | "requires": { 1393 | "debug": "2.6.9", 1394 | "encodeurl": "~1.0.2", 1395 | "escape-html": "~1.0.3", 1396 | "on-finished": "~2.3.0", 1397 | "parseurl": "~1.3.3", 1398 | "statuses": "~1.5.0", 1399 | "unpipe": "~1.0.0" 1400 | } 1401 | }, 1402 | "forwarded": { 1403 | "version": "0.1.2", 1404 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 1405 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 1406 | }, 1407 | "fresh": { 1408 | "version": "0.5.2", 1409 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 1410 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 1411 | }, 1412 | "generate-function": { 1413 | "version": "2.3.1", 1414 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", 1415 | "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", 1416 | "requires": { 1417 | "is-property": "^1.0.2" 1418 | } 1419 | }, 1420 | "http-errors": { 1421 | "version": "1.7.2", 1422 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 1423 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 1424 | "requires": { 1425 | "depd": "~1.1.2", 1426 | "inherits": "2.0.3", 1427 | "setprototypeof": "1.1.1", 1428 | "statuses": ">= 1.5.0 < 2", 1429 | "toidentifier": "1.0.0" 1430 | } 1431 | }, 1432 | "iconv-lite": { 1433 | "version": "0.4.24", 1434 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 1435 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 1436 | "requires": { 1437 | "safer-buffer": ">= 2.1.2 < 3" 1438 | } 1439 | }, 1440 | "ieee754": { 1441 | "version": "1.1.13", 1442 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", 1443 | "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" 1444 | }, 1445 | "inherits": { 1446 | "version": "2.0.3", 1447 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1448 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 1449 | }, 1450 | "ipaddr.js": { 1451 | "version": "1.9.1", 1452 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 1453 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 1454 | }, 1455 | "is-property": { 1456 | "version": "1.0.2", 1457 | "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", 1458 | "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" 1459 | }, 1460 | "isarray": { 1461 | "version": "1.0.0", 1462 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1463 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 1464 | }, 1465 | "jmespath": { 1466 | "version": "0.15.0", 1467 | "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", 1468 | "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" 1469 | }, 1470 | "long": { 1471 | "version": "4.0.0", 1472 | "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", 1473 | "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" 1474 | }, 1475 | "lru-cache": { 1476 | "version": "6.0.0", 1477 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 1478 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 1479 | "requires": { 1480 | "yallist": "^4.0.0" 1481 | } 1482 | }, 1483 | "media-typer": { 1484 | "version": "0.3.0", 1485 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 1486 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 1487 | }, 1488 | "merge-descriptors": { 1489 | "version": "1.0.1", 1490 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 1491 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 1492 | }, 1493 | "methods": { 1494 | "version": "1.1.2", 1495 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 1496 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 1497 | }, 1498 | "mime": { 1499 | "version": "1.6.0", 1500 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 1501 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 1502 | }, 1503 | "mime-db": { 1504 | "version": "1.46.0", 1505 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz", 1506 | "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==" 1507 | }, 1508 | "mime-types": { 1509 | "version": "2.1.29", 1510 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz", 1511 | "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==", 1512 | "requires": { 1513 | "mime-db": "1.46.0" 1514 | } 1515 | }, 1516 | "ms": { 1517 | "version": "2.0.0", 1518 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1519 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 1520 | }, 1521 | "mysql": { 1522 | "version": "2.18.1", 1523 | "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", 1524 | "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", 1525 | "requires": { 1526 | "bignumber.js": "9.0.0", 1527 | "readable-stream": "2.3.7", 1528 | "safe-buffer": "5.1.2", 1529 | "sqlstring": "2.3.1" 1530 | }, 1531 | "dependencies": { 1532 | "readable-stream": { 1533 | "version": "2.3.7", 1534 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", 1535 | "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", 1536 | "requires": { 1537 | "core-util-is": "~1.0.0", 1538 | "inherits": "~2.0.3", 1539 | "isarray": "~1.0.0", 1540 | "process-nextick-args": "~2.0.0", 1541 | "safe-buffer": "~5.1.1", 1542 | "string_decoder": "~1.1.1", 1543 | "util-deprecate": "~1.0.1" 1544 | } 1545 | }, 1546 | "string_decoder": { 1547 | "version": "1.1.1", 1548 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1549 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1550 | "requires": { 1551 | "safe-buffer": "~5.1.0" 1552 | } 1553 | } 1554 | } 1555 | }, 1556 | "mysql2": { 1557 | "version": "2.3.3", 1558 | "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-2.3.3.tgz", 1559 | "integrity": "sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA==", 1560 | "requires": { 1561 | "denque": "^2.0.1", 1562 | "generate-function": "^2.3.1", 1563 | "iconv-lite": "^0.6.3", 1564 | "long": "^4.0.0", 1565 | "lru-cache": "^6.0.0", 1566 | "named-placeholders": "^1.1.2", 1567 | "seq-queue": "^0.0.5", 1568 | "sqlstring": "^2.3.2" 1569 | }, 1570 | "dependencies": { 1571 | "iconv-lite": { 1572 | "version": "0.6.3", 1573 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", 1574 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", 1575 | "requires": { 1576 | "safer-buffer": ">= 2.1.2 < 3.0.0" 1577 | } 1578 | }, 1579 | "sqlstring": { 1580 | "version": "2.3.3", 1581 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", 1582 | "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" 1583 | } 1584 | } 1585 | }, 1586 | "named-placeholders": { 1587 | "version": "1.1.2", 1588 | "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.2.tgz", 1589 | "integrity": "sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA==", 1590 | "requires": { 1591 | "lru-cache": "^4.1.3" 1592 | }, 1593 | "dependencies": { 1594 | "lru-cache": { 1595 | "version": "4.1.5", 1596 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", 1597 | "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", 1598 | "requires": { 1599 | "pseudomap": "^1.0.2", 1600 | "yallist": "^2.1.2" 1601 | } 1602 | }, 1603 | "yallist": { 1604 | "version": "2.1.2", 1605 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 1606 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" 1607 | } 1608 | } 1609 | }, 1610 | "negotiator": { 1611 | "version": "0.6.2", 1612 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 1613 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 1614 | }, 1615 | "on-finished": { 1616 | "version": "2.3.0", 1617 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 1618 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 1619 | "requires": { 1620 | "ee-first": "1.1.1" 1621 | } 1622 | }, 1623 | "packet-reader": { 1624 | "version": "1.0.0", 1625 | "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", 1626 | "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" 1627 | }, 1628 | "parseurl": { 1629 | "version": "1.3.3", 1630 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 1631 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 1632 | }, 1633 | "path-to-regexp": { 1634 | "version": "0.1.7", 1635 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 1636 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 1637 | }, 1638 | "pg": { 1639 | "version": "8.7.1", 1640 | "resolved": "https://registry.npmjs.org/pg/-/pg-8.7.1.tgz", 1641 | "integrity": "sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA==", 1642 | "requires": { 1643 | "buffer-writer": "2.0.0", 1644 | "packet-reader": "1.0.0", 1645 | "pg-connection-string": "^2.5.0", 1646 | "pg-pool": "^3.4.1", 1647 | "pg-protocol": "^1.5.0", 1648 | "pg-types": "^2.1.0", 1649 | "pgpass": "1.x" 1650 | } 1651 | }, 1652 | "pg-connection-string": { 1653 | "version": "2.5.0", 1654 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", 1655 | "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" 1656 | }, 1657 | "pg-int8": { 1658 | "version": "1.0.1", 1659 | "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", 1660 | "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" 1661 | }, 1662 | "pg-pool": { 1663 | "version": "3.4.1", 1664 | "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz", 1665 | "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==", 1666 | "requires": {} 1667 | }, 1668 | "pg-protocol": { 1669 | "version": "1.5.0", 1670 | "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", 1671 | "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" 1672 | }, 1673 | "pg-types": { 1674 | "version": "2.2.0", 1675 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", 1676 | "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", 1677 | "requires": { 1678 | "pg-int8": "1.0.1", 1679 | "postgres-array": "~2.0.0", 1680 | "postgres-bytea": "~1.0.0", 1681 | "postgres-date": "~1.0.4", 1682 | "postgres-interval": "^1.1.0" 1683 | } 1684 | }, 1685 | "pgpass": { 1686 | "version": "1.0.4", 1687 | "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.4.tgz", 1688 | "integrity": "sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==", 1689 | "requires": { 1690 | "split2": "^3.1.1" 1691 | } 1692 | }, 1693 | "postgres-array": { 1694 | "version": "2.0.0", 1695 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", 1696 | "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" 1697 | }, 1698 | "postgres-bytea": { 1699 | "version": "1.0.0", 1700 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", 1701 | "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" 1702 | }, 1703 | "postgres-date": { 1704 | "version": "1.0.7", 1705 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", 1706 | "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" 1707 | }, 1708 | "postgres-interval": { 1709 | "version": "1.2.0", 1710 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", 1711 | "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", 1712 | "requires": { 1713 | "xtend": "^4.0.0" 1714 | } 1715 | }, 1716 | "process-nextick-args": { 1717 | "version": "2.0.1", 1718 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 1719 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 1720 | }, 1721 | "proxy-addr": { 1722 | "version": "2.0.6", 1723 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", 1724 | "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", 1725 | "requires": { 1726 | "forwarded": "~0.1.2", 1727 | "ipaddr.js": "1.9.1" 1728 | } 1729 | }, 1730 | "pseudomap": { 1731 | "version": "1.0.2", 1732 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 1733 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" 1734 | }, 1735 | "punycode": { 1736 | "version": "1.3.2", 1737 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 1738 | "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" 1739 | }, 1740 | "qs": { 1741 | "version": "6.7.0", 1742 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", 1743 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" 1744 | }, 1745 | "querystring": { 1746 | "version": "0.2.0", 1747 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 1748 | "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" 1749 | }, 1750 | "range-parser": { 1751 | "version": "1.2.1", 1752 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 1753 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 1754 | }, 1755 | "raw-body": { 1756 | "version": "2.4.0", 1757 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", 1758 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 1759 | "requires": { 1760 | "bytes": "3.1.0", 1761 | "http-errors": "1.7.2", 1762 | "iconv-lite": "0.4.24", 1763 | "unpipe": "1.0.0" 1764 | } 1765 | }, 1766 | "readable-stream": { 1767 | "version": "3.6.0", 1768 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 1769 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 1770 | "requires": { 1771 | "inherits": "^2.0.3", 1772 | "string_decoder": "^1.1.1", 1773 | "util-deprecate": "^1.0.1" 1774 | } 1775 | }, 1776 | "safe-buffer": { 1777 | "version": "5.1.2", 1778 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1779 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1780 | }, 1781 | "safer-buffer": { 1782 | "version": "2.1.2", 1783 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1784 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1785 | }, 1786 | "sax": { 1787 | "version": "1.2.1", 1788 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", 1789 | "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" 1790 | }, 1791 | "send": { 1792 | "version": "0.17.1", 1793 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", 1794 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", 1795 | "requires": { 1796 | "debug": "2.6.9", 1797 | "depd": "~1.1.2", 1798 | "destroy": "~1.0.4", 1799 | "encodeurl": "~1.0.2", 1800 | "escape-html": "~1.0.3", 1801 | "etag": "~1.8.1", 1802 | "fresh": "0.5.2", 1803 | "http-errors": "~1.7.2", 1804 | "mime": "1.6.0", 1805 | "ms": "2.1.1", 1806 | "on-finished": "~2.3.0", 1807 | "range-parser": "~1.2.1", 1808 | "statuses": "~1.5.0" 1809 | }, 1810 | "dependencies": { 1811 | "ms": { 1812 | "version": "2.1.1", 1813 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 1814 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 1815 | } 1816 | } 1817 | }, 1818 | "seq-queue": { 1819 | "version": "0.0.5", 1820 | "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", 1821 | "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" 1822 | }, 1823 | "serve-static": { 1824 | "version": "1.14.1", 1825 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", 1826 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", 1827 | "requires": { 1828 | "encodeurl": "~1.0.2", 1829 | "escape-html": "~1.0.3", 1830 | "parseurl": "~1.3.3", 1831 | "send": "0.17.1" 1832 | } 1833 | }, 1834 | "setprototypeof": { 1835 | "version": "1.1.1", 1836 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 1837 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 1838 | }, 1839 | "split2": { 1840 | "version": "3.2.2", 1841 | "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", 1842 | "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", 1843 | "requires": { 1844 | "readable-stream": "^3.0.0" 1845 | } 1846 | }, 1847 | "sqlstring": { 1848 | "version": "2.3.1", 1849 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", 1850 | "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" 1851 | }, 1852 | "statuses": { 1853 | "version": "1.5.0", 1854 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 1855 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 1856 | }, 1857 | "string_decoder": { 1858 | "version": "1.3.0", 1859 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 1860 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 1861 | "requires": { 1862 | "safe-buffer": "~5.2.0" 1863 | }, 1864 | "dependencies": { 1865 | "safe-buffer": { 1866 | "version": "5.2.1", 1867 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 1868 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 1869 | } 1870 | } 1871 | }, 1872 | "toidentifier": { 1873 | "version": "1.0.0", 1874 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 1875 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 1876 | }, 1877 | "type-is": { 1878 | "version": "1.6.18", 1879 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 1880 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 1881 | "requires": { 1882 | "media-typer": "0.3.0", 1883 | "mime-types": "~2.1.24" 1884 | } 1885 | }, 1886 | "typescript": { 1887 | "version": "4.2.3", 1888 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", 1889 | "integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==" 1890 | }, 1891 | "unpipe": { 1892 | "version": "1.0.0", 1893 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1894 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 1895 | }, 1896 | "url": { 1897 | "version": "0.10.3", 1898 | "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", 1899 | "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", 1900 | "requires": { 1901 | "punycode": "1.3.2", 1902 | "querystring": "0.2.0" 1903 | } 1904 | }, 1905 | "util-deprecate": { 1906 | "version": "1.0.2", 1907 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1908 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1909 | }, 1910 | "utils-merge": { 1911 | "version": "1.0.1", 1912 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1913 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 1914 | }, 1915 | "uuid": { 1916 | "version": "3.3.2", 1917 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 1918 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 1919 | }, 1920 | "vary": { 1921 | "version": "1.1.2", 1922 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1923 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 1924 | }, 1925 | "xml2js": { 1926 | "version": "0.4.19", 1927 | "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", 1928 | "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", 1929 | "requires": { 1930 | "sax": ">=0.6.0", 1931 | "xmlbuilder": "~9.0.1" 1932 | } 1933 | }, 1934 | "xmlbuilder": { 1935 | "version": "9.0.7", 1936 | "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", 1937 | "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" 1938 | }, 1939 | "xtend": { 1940 | "version": "4.0.2", 1941 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1942 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" 1943 | }, 1944 | "yallist": { 1945 | "version": "4.0.0", 1946 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1947 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 1948 | } 1949 | } 1950 | } 1951 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-docker-templates-express", 3 | "version": "1.0.0", 4 | "description": "Node.js + express on Docker", 5 | "author": "tinystacks - about@tinystacks.com", 6 | "main": "server.js", 7 | "scripts": { 8 | "start": "node built/server.js", 9 | "build": "tsc" 10 | }, 11 | "dependencies": { 12 | "@types/pg": "^8.6.1", 13 | "aws-sdk": "^2.822.0", 14 | "express": "^4.16.1", 15 | "mysql2": "^2.3.3", 16 | "pg": "^8.7.1", 17 | "typescript": "^4.2.3", 18 | "uuid": "^3.3.2" 19 | }, 20 | "devDependencies": { 21 | "@types/express": "^4.17.11", 22 | "@types/uuid": "^8.3.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /release.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | phases: 3 | build: 4 | commands: 5 | - docker login -u AWS -p $(aws ecr get-login-password --region $AWS_REGION) $ECR_ENDPOINT 6 | - docker pull $ECR_IMAGE_URL:$PREVIOUS_STAGE_NAME 7 | - docker tag $ECR_IMAGE_URL:$PREVIOUS_STAGE_NAME $ECR_IMAGE_URL:$STAGE_NAME 8 | - docker push $ECR_IMAGE_URL:$STAGE_NAME 9 | - | 10 | if [ ! -z "$REGIONAL_ECR_ENDPOINT" -a ! -z "$REGIONAL_ECR_IMAGE_URL" ]; 11 | then 12 | docker login -u AWS -p $(aws ecr get-login-password --region $STAGE_REGION) $REGIONAL_ECR_ENDPOINT 13 | docker tag $ECR_IMAGE_URL:$PREVIOUS_STAGE_NAME $REGIONAL_ECR_IMAGE_URL:$STAGE_NAME 14 | docker push $REGIONAL_ECR_IMAGE_URL:$STAGE_NAME 15 | fi 16 | post_build: 17 | on-failure: CONTINUE 18 | commands: 19 | - region="${STAGE_REGION:-$AWS_REGION}" 20 | - | 21 | if [ ! -z "$LAMBDA_FUNCTION_NAME" -a "$LAMBDA_FUNCTION_NAME" != "placeholder" ]; 22 | then 23 | imageUrl="${REGIONAL_ECR_IMAGE_URL:-$ECR_IMAGE_URL}" 24 | aws lambda update-function-code --function-name "$LAMBDA_FUNCTION_NAME" --image-uri "$imageUrl:$STAGE_NAME" --region $region 25 | imageSha=$(docker images --no-trunc --quiet $imageUrl:$PREVIOUS_STAGE_NAME); 26 | aws lambda tag-resource --resource "$LAMBDA_FUNCTION_ARN" --tags "IMAGE_SHA=$imageSha" --region $region 27 | else 28 | echo 'Not a serverless stage' 29 | if [ -z "$SERVICE_NAME" ] || [ "$SERVICE_NAME" == "placeholder" ]; 30 | then 31 | echo 'Service is not ready yet. Repository tagged correctly, exiting now'; 32 | else 33 | TASK_ARN=$(aws ecs describe-services --cluster $CLUSTER_ARN --services $SERVICE_NAME | jq -r '.services[].taskDefinition') 34 | TASK_DEFINITION=$(aws ecs describe-task-definition --task-definition "$TASK_ARN" | jq -r '.taskDefinition') 35 | CONTAINER_DEFINITIONS=$(jq -r '.containerDefinitions' <<< $TASK_DEFINITION) 36 | COMMIT_SHA=$ECR_IMAGE_URL:$(git rev-parse HEAD) 37 | CONTAINER_INDEX=$(echo $CONTAINER_DEFINITIONS | jq --arg IMAGE_URL "$ECR_IMAGE_URL" 'map(.image | contains($IMAGE_URL)) | index(true)' ) 38 | NEW_TASK_DEFINTIION=$(echo $TASK_DEFINITION | jq --arg IMAGE "$COMMIT_SHA" --arg INDEX "$CONTAINER_INDEX" '.containerDefinitions[$INDEX | tonumber].image = $IMAGE| del(.revision) | del(.status) | del(.statusString) | del(.registeredAt) | del(.taskDefinitionArn) | del(.compatibilities) | del(.requiresAttributes) | del(.registeredBy)' ) 39 | NEW_DEF_ARN=$(aws ecs register-task-definition --cli-input-json "$NEW_TASK_DEFINTIION" | jq -r '.taskDefinition.taskDefinitionArn') 40 | aws ecs update-service --service $SERVICE_NAME --cluster $CLUSTER_ARN --task-definition "$NEW_DEF_ARN" --force-new-deployment 41 | fi 42 | fi 43 | -------------------------------------------------------------------------------- /src/aws-helpers.ts: -------------------------------------------------------------------------------- 1 | 2 | import * as AWS from "aws-sdk"; 3 | import { Request } from "express"; 4 | 5 | const ddbClient = new AWS.DynamoDB.DocumentClient(); 6 | const cognito = new AWS.CognitoIdentityServiceProvider(); 7 | 8 | export function getUserData(req: Request) { 9 | const jwtToken = req.header('authorization').split(' '); 10 | var auth_params = { 11 | AccessToken: jwtToken[1] 12 | }; 13 | 14 | return cognito.getUser(auth_params).promise().then(function (data) { 15 | const userAttr = new Map(data.UserAttributes.map(i => [i.Name, i.Value])); 16 | return userAttr.get('sub'); 17 | }).catch(function (err) { 18 | console.log(err); 19 | throw err; 20 | }); 21 | } 22 | 23 | export function createItem(userId: string, itemId: string, title: string, content: string) { 24 | const params = { 25 | TableName: process.env.TABLE_NAME, // [ProjectName] 26 | // Item contains the following attributes: 27 | // - userId: authenticated user id from Cognito Identity pool 28 | // - itemId: a unique uuid for the item 29 | // - title: title of Item 30 | // - content: content of Item 31 | // - createdAt: current timestamp 32 | Item: { 33 | userId: userId, 34 | itemId: itemId, 35 | title: title, 36 | content: content, 37 | createdAt: Date.now() 38 | } 39 | }; 40 | 41 | return ddbClient.put(params).promise(); 42 | } 43 | 44 | export function updateItem(userId: string, itemId: string, title: string, content: string) { 45 | const params = { 46 | TableName: process.env.TABLE_NAME, 47 | Key: { 48 | "userId": userId, 49 | "itemId": itemId 50 | }, 51 | UpdateExpression: "set info.title = :t, info.content=:c", 52 | ExpressionAttributeValues: { 53 | ":t": title, 54 | ":c": content, 55 | } 56 | }; 57 | return ddbClient.update(params).promise(); 58 | } 59 | export function deleteItem(userId: string, itemId: string) { 60 | return ddbClient.delete({ 61 | TableName: process.env.TABLE_NAME, 62 | Key: { 63 | "userId": userId, 64 | "itemId": itemId, 65 | } 66 | }).promise(); 67 | } 68 | 69 | export function listItems(userId: string) { 70 | const params = { 71 | TableName: process.env.TABLE_NAME, 72 | KeyConditionExpression: "userId = :userId", 73 | ExpressionAttributeValues: { 74 | ":userId": userId 75 | } 76 | }; 77 | 78 | return ddbClient.query(params).promise(); 79 | } 80 | 81 | export function getItem(userId: string, itemId: string) { 82 | return ddbClient.get({ 83 | TableName: process.env.TABLE_NAME, 84 | Key: { 85 | "userId": userId, 86 | "itemId": itemId, 87 | } 88 | }).promise(); 89 | } -------------------------------------------------------------------------------- /src/config/mysql.ts: -------------------------------------------------------------------------------- 1 | import * as mysql from 'mysql2'; 2 | 3 | const basePool = mysql.createPool({ 4 | host: process.env.MYSQL_HOST || '0.0.0.0', 5 | port: parseInt(process.env.MYSQL_PORT || '3306'), 6 | user: process.env.MYSQL_USERNAME || 'mysql', 7 | password: process.env.MYSQL_PASSWORD || 'mysql', 8 | database: process.env.MYSQL_DATABASE || 'mysql', 9 | }); 10 | 11 | export const pool = basePool.promise(); 12 | -------------------------------------------------------------------------------- /src/config/postgres.ts: -------------------------------------------------------------------------------- 1 | import { Pool } from 'pg'; 2 | 3 | export const pool = new Pool({ 4 | host: process.env.PG_HOST || '0.0.0.0', 5 | port: parseInt(process.env.PG_PORT || '5432'), 6 | user: process.env.PG_USERNAME || 'postgres', 7 | password: process.env.PG_PASSWORD || 'postgres', 8 | database: process.env.PG_DATABASE || 'postgres', 9 | }); -------------------------------------------------------------------------------- /src/dynamodb-item.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import { createItem, getItem, listItems } from "./aws-helpers"; 3 | import { addHeadersToResponse } from "./server-helpers"; 4 | import * as uuid from "uuid"; 5 | 6 | export async function getDynamoDbItem(req: Request, res: Response) { 7 | addHeadersToResponse(res); 8 | let promise; 9 | const body = req.body; 10 | if (!!req.body) { 11 | promise = getItem("SYSTEM", body.itemId); 12 | } else { 13 | promise = listItems("SYSTEM"); 14 | } 15 | 16 | promise.then(function (data: any) { 17 | res.status(200).send(data); 18 | }) 19 | .catch(function (err) { 20 | console.log(err); 21 | res.status(500).send(); 22 | }); 23 | } 24 | 25 | export async function putDynamoDbItem(req: Request, res: Response) { 26 | const body = req.body; 27 | addHeadersToResponse(res); 28 | createItem("SYSTEM", uuid.v4(), body.title, body.content) 29 | .then(function(data) { 30 | res.status(200).send(); 31 | }) 32 | .catch(function(err) { 33 | console.log(err); 34 | res.status(500).send(); 35 | }); 36 | } 37 | 38 | export async function updateDynamoDbItem(req: Request, res: Response) { 39 | const body = req.body; 40 | addHeadersToResponse(res); 41 | createItem("SYSTEM", body.itemId, body.title, body.content) 42 | .then(function(data) { 43 | res.status(200).send(); 44 | }) 45 | .catch(function(err) { 46 | console.log(err); 47 | res.status(500).send(); 48 | }); 49 | } 50 | 51 | export async function deleteDynamoDbItem(req: Request, res: Response) { 52 | const body = req.body; 53 | addHeadersToResponse(res); 54 | createItem("SYSTEM", uuid.v4(), body.title, body.content) 55 | .then(function(data) { 56 | res.status(200).send(); 57 | }) 58 | .catch(function(err) { 59 | console.log(err); 60 | res.status(500).send(); 61 | }); 62 | } -------------------------------------------------------------------------------- /src/local-item.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from "express"; 2 | import * as uuid from "uuid"; 3 | import { addHeadersToResponse } from "./server-helpers"; 4 | 5 | type Item = { 6 | title: string; 7 | content: string; 8 | }; 9 | 10 | const items = new Map(); 11 | 12 | export function getItem(req: Request, res: Response) { 13 | addHeadersToResponse(res); 14 | if (req.query.itemId) { 15 | const toReturn = items.get(req.query.itemId); 16 | toReturn.itemId = req.query.itemId; 17 | return res.status(200).json(toReturn); 18 | } else { 19 | res.status(400).json("No itemId provided"); 20 | } 21 | } 22 | 23 | // return the list of all items 24 | export function listItems(req: Request, res: Response) { 25 | addHeadersToResponse(res); 26 | const reducedItems: ({ itemId: string } & Item)[] = []; 27 | items.forEach((value: Item, key: string) => { 28 | reducedItems.push({ itemId: key, ...value }); 29 | }) 30 | res.status(200).send(reducedItems); 31 | } 32 | 33 | export function putItem(req: Request, res: Response) { 34 | addHeadersToResponse(res); 35 | const body = req.body; 36 | const id = uuid.v4(); 37 | items.set(id, { 38 | title: body.title, 39 | content: body.content 40 | }); 41 | res.status(200).send({ 42 | id: id, 43 | title: body.title, 44 | content: body.content, 45 | }); 46 | } 47 | 48 | export function updateItem(req: Request, res: Response) { 49 | addHeadersToResponse(res); 50 | const body: any = req.body; 51 | const id = req.params.id; 52 | if (!body || !id) { 53 | res.status(500).send(); 54 | } else { 55 | items.set(id, { 56 | title: body.title, 57 | content: body.content 58 | }); 59 | res.status(200).send(); 60 | } 61 | } 62 | 63 | export function deleteItem(req: Request, res: Response) { 64 | addHeadersToResponse(res); 65 | const body: any = req.body; 66 | const id = req.params.id; 67 | if (!body || !body.id) { 68 | res.status(500).send(); 69 | } else { 70 | items.delete(body.id); 71 | res.status(200).send(); 72 | } 73 | } -------------------------------------------------------------------------------- /src/mysql-item.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | import { addHeadersToResponse } from './server-helpers'; 3 | import { pool } from './config/mysql'; 4 | 5 | /** 6 | * Get All or a single item 7 | * 8 | * @verb GET 9 | * @route [/postgresql-item/:id or /postgresql-item/] 10 | * 11 | * @param req.params.id 12 | * @returns an array of Items or a single Item 13 | */ 14 | export async function getMysqlItem(req: Request, res: Response) { 15 | addHeadersToResponse(res); 16 | 17 | try { 18 | const client = await pool.getConnection(); 19 | await client.query('CREATE TABLE IF NOT EXISTS "items" ("id" SERIAL PRIMARY KEY,"title" varchar(30),"content" varchar(30));'); 20 | let queryResult; 21 | if (!req.params.id) { 22 | const toRet = await client.query('SELECT * from items'); 23 | queryResult = toRet[1]; 24 | } else { 25 | const toRet = await client.query('SELECT * from items WHERE id = $1', [req.params.id]); 26 | queryResult = toRet[1]; 27 | } 28 | client.release(); 29 | return res.status(200).json(queryResult); 30 | } catch (error) { 31 | return res.status(500).json('Error on getPostgresDbItem' + error); 32 | } 33 | } 34 | 35 | /** 36 | * Create a new Item 37 | * 38 | * @verb PUT 39 | * @route [/postgresql-item/] 40 | * 41 | * @body The body wihch contains the values, in JSON format 42 | * @returns the body to create the Item 43 | */ 44 | export async function createMysqlItem(req: Request, res: Response) { 45 | addHeadersToResponse(res); 46 | 47 | try { 48 | const client = await pool.getConnection(); 49 | await client.query('CREATE TABLE IF NOT EXISTS "items" ("id" SERIAL PRIMARY KEY,"title" varchar(30),"content" varchar(30));'); 50 | await client.query('INSERT INTO items (title, content) VALUES ($1,$2)', [req.body.title, req.body.content]); 51 | await client.release(); 52 | return res.status(201).json(req.body); 53 | } catch (error) { 54 | return res.status(500).json(error); 55 | } 56 | } 57 | 58 | /** 59 | * Update an existing Item 60 | * 61 | * @verb POST 62 | * @route [/postgresql-item/:id] 63 | * 64 | * @body The body wihch contains the updated values, in JSON format 65 | * @param req.params.id 66 | * @returns the id of the Updated Item 67 | */ 68 | export async function updateMysqlItem(req: Request, res: Response) { 69 | addHeadersToResponse(res); 70 | 71 | try { 72 | const client = await pool.getConnection(); 73 | await client.query('CREATE TABLE IF NOT EXISTS "items" ("id" SERIAL PRIMARY KEY,"title" varchar(30),"content" varchar(30));'); 74 | await client.query(`UPDATE items SET title = $1 WHERE id = $2`, [req.body.title, req.params.id]); 75 | client.release(); 76 | return res.status(200).json('Updated id ' + req.params.id); 77 | } catch (error) { 78 | return res.status(500).json('Error on deletePostgresDbItem' + error); 79 | } 80 | } 81 | 82 | /** 83 | * Delete an existing Item 84 | * 85 | * @verb DELETE 86 | * @route [/postgresql-item/:id] 87 | * 88 | * @param req.params.id 89 | * @returns the id of the Deleted Item 90 | */ 91 | export async function deleteMysqlItem(req: Request, res: Response) { 92 | addHeadersToResponse(res); 93 | 94 | try { 95 | console.log(req.params.id); 96 | const client = await pool.getConnection(); 97 | await client.query('CREATE TABLE IF NOT EXISTS "items" ("id" SERIAL PRIMARY KEY,"title" varchar(30),"content" varchar(30));'); 98 | await client.query('DELETE from items WHERE id = $1', [req.params.id]); 99 | client.release(); 100 | return res.status(200).json('Removed id ' + req.params.id); 101 | } catch (error) { 102 | return res.status(500).json('Error on deletePostgresDbItem' + error); 103 | } 104 | } -------------------------------------------------------------------------------- /src/postgresdb-item.ts: -------------------------------------------------------------------------------- 1 | import { Request, Response } from 'express'; 2 | import { addHeadersToResponse } from './server-helpers'; 3 | import { pool } from './config/postgres'; 4 | 5 | /** 6 | * Get All or a single item 7 | * 8 | * @verb GET 9 | * @route [/postgresql-item/:id or /postgresql-item/] 10 | * 11 | * @param req.params.id 12 | * @returns an array of Items or a single Item 13 | */ 14 | export async function getPostgresDbItem(req: Request, res: Response) { 15 | addHeadersToResponse(res); 16 | 17 | try { 18 | const client = await pool.connect(); 19 | await client.query('CREATE TABLE IF NOT EXISTS "items" ("id" SERIAL PRIMARY KEY,"title" varchar(30),"content" varchar(30));'); 20 | let queryResult; 21 | if (!req.params.id) { 22 | const toRet = await client.query('SELECT * from items'); 23 | queryResult = toRet.rows; 24 | } else { 25 | const toRet = await client.query('SELECT * from items WHERE id = $1', [req.params.id]); 26 | queryResult = toRet.rows[0]; 27 | } 28 | client.release(); 29 | return res.status(200).json(queryResult); 30 | } catch (error) { 31 | return res.status(500).json('Error on getPostgresDbItem' + error); 32 | } 33 | } 34 | 35 | /** 36 | * Create a new Item 37 | * 38 | * @verb PUT 39 | * @route [/postgresql-item/] 40 | * 41 | * @body The body wihch contains the values, in JSON format 42 | * @returns the body to create the Item 43 | */ 44 | export async function createPostgresDbItem(req: Request, res: Response) { 45 | addHeadersToResponse(res); 46 | 47 | try { 48 | const client = await pool.connect(); 49 | await client.query('CREATE TABLE IF NOT EXISTS "items" ("id" SERIAL PRIMARY KEY,"title" varchar(30),"content" varchar(30));'); 50 | await client.query('INSERT INTO items (title, content) VALUES ($1,$2)', [req.body.title, req.body.content]); 51 | await client.release(); 52 | return res.status(201).json(req.body); 53 | } catch (error) { 54 | return res.status(500).json(error); 55 | } 56 | } 57 | 58 | /** 59 | * Update an existing Item 60 | * 61 | * @verb POST 62 | * @route [/postgresql-item/:id] 63 | * 64 | * @body The body wihch contains the updated values, in JSON format 65 | * @param req.params.id 66 | * @returns the id of the Updated Item 67 | */ 68 | export async function updatePostgresItem(req: Request, res: Response) { 69 | addHeadersToResponse(res); 70 | 71 | try { 72 | const client = await pool.connect(); 73 | await client.query('CREATE TABLE IF NOT EXISTS "items" ("id" SERIAL PRIMARY KEY,"title" varchar(30),"content" varchar(30));'); 74 | await client.query(`UPDATE items SET title = $1 WHERE id = $2`, [req.body.title, req.params.id]); 75 | client.release(); 76 | return res.status(200).json('Updated id ' + req.params.id); 77 | } catch (error) { 78 | return res.status(500).json('Error on deletePostgresDbItem' + error); 79 | } 80 | } 81 | 82 | /** 83 | * Delete an existing Item 84 | * 85 | * @verb DELETE 86 | * @route [/postgresql-item/:id] 87 | * 88 | * @param req.params.id 89 | * @returns the id of the Deleted Item 90 | */ 91 | export async function deletePostgresItem(req: Request, res: Response) { 92 | addHeadersToResponse(res); 93 | 94 | try { 95 | console.log(req.params.id); 96 | const client = await pool.connect(); 97 | await client.query('CREATE TABLE IF NOT EXISTS "items" ("id" SERIAL PRIMARY KEY,"title" varchar(30),"content" varchar(30));'); 98 | await client.query('DELETE from items WHERE id = $1', [req.params.id]); 99 | client.release(); 100 | return res.status(200).json('Removed id ' + req.params.id); 101 | } catch (error) { 102 | return res.status(500).json('Error on deletePostgresDbItem' + error); 103 | } 104 | } -------------------------------------------------------------------------------- /src/server-helpers.ts: -------------------------------------------------------------------------------- 1 | import { Response } from "express"; 2 | 3 | export function addHeadersToResponse(res: Response) { 4 | res.setHeader("Access-Control-Allow-Origin", "*"); 5 | res.setHeader("Access-Control-Allow-Credentials", "true"); 6 | } -------------------------------------------------------------------------------- /src/server.ts: -------------------------------------------------------------------------------- 1 | import * as express from "express"; 2 | import { json } from "body-parser"; 3 | 4 | import { deleteDynamoDbItem, getDynamoDbItem, putDynamoDbItem, updateDynamoDbItem } from "./dynamodb-item"; 5 | import { deletePostgresItem, getPostgresDbItem, createPostgresDbItem, updatePostgresItem } from "./postgresdb-item"; 6 | import { deleteItem, getItem, putItem, updateItem, listItems } from "./local-item"; 7 | import { createMysqlItem, deleteMysqlItem, getMysqlItem, updateMysqlItem } from "./mysql-item"; 8 | 9 | 10 | // Constants 11 | const PORT = 8000; 12 | const HOST = '0.0.0.0'; 13 | 14 | // App handlers 15 | const app = express(); 16 | const parser = json(); 17 | 18 | app.get("/", (req:any, res:any) => { 19 | res.status(200).send("hello world!"); 20 | }); 21 | 22 | app.get("/ping", (req:any, res:any) => { 23 | res.status(200).send("pong"); 24 | }); 25 | 26 | app.get("/healthy", (req:any, res:any) => { 27 | res.status(200).send("healthy"); 28 | }); 29 | 30 | app.get("/env-var", (req:any, res:any) => { 31 | res.status(200).send(process.env.TEST_ENV_VAR); 32 | }); 33 | 34 | 35 | app.get('/local-item/:id', parser, getItem); 36 | app.get('/local-item', parser, listItems); 37 | app.post('/local-item', parser, putItem); 38 | app.put('/local-item/:id', parser, updateItem); 39 | app.delete('/local-item', parser, deleteItem); 40 | 41 | app.put('/dynamodb-item', parser, putDynamoDbItem); 42 | app.post('/dynamodb-item', parser, updateDynamoDbItem); 43 | app.get('/dynamodb-item', parser, getDynamoDbItem); 44 | app.delete('/dynamodb-item', parser, deleteDynamoDbItem); 45 | 46 | app.get('/postgres-item/:id', parser, getPostgresDbItem); 47 | app.get('/postgres-item', parser, getPostgresDbItem); 48 | app.post('/postgres-item', parser, createPostgresDbItem); 49 | app.put('/postgres-item/:id', parser, updatePostgresItem); 50 | app.delete('/postgres-item/:id', parser, deletePostgresItem); 51 | 52 | app.get('/mysql-item/:id', parser, getMysqlItem); 53 | app.get('/mysql-item', parser, getMysqlItem); 54 | app.post('/mysql-item', parser, createMysqlItem); 55 | app.put('/mysql-item/:id', parser, updateMysqlItem); 56 | app.delete('/mysql-item/:id', parser, deleteMysqlItem); 57 | 58 | app.listen(PORT, HOST); 59 | console.log(`Running on http://${HOST}:${PORT}`); 60 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "ES2017", 5 | "noImplicitAny": true, 6 | "preserveConstEnums": true, 7 | "outDir": "./built", 8 | "sourceMap": true, 9 | }, 10 | "include": ["src/**/*"], 11 | "exclude": ["node_modules", "**/*.spec.ts"] 12 | } --------------------------------------------------------------------------------