├── .github └── workflows │ └── licensing.yml ├── .gitignore ├── LICENSE ├── README.md ├── doc └── dependency_decisions.yml ├── index.js ├── package-lock.json ├── package.json ├── sample.env ├── scripts ├── seed-database.sh └── travel_db.sql └── tests.http /.github/workflows/licensing.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Verify dependency licenses 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | pull_request: 9 | types: 10 | - opened 11 | - reopened 12 | - synchronize 13 | 14 | jobs: 15 | licensing: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v2 19 | with: 20 | fetch-depth: 0 21 | - run: sudo gem install license_finder 22 | - run: npm install 23 | - run: license_finder -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # database-js-starter 2 | 3 | A sample Node.js Express API built using the [PlanetScale serverless driver for JavaScript](https://planetscale.com/blog/introducing-the-planetscale-serverless-driver-for-javascript). It contains sample API endpoints that can be used to map to various operations on your PlanetScale database: 4 | 5 | | API Method | SQL Action | 6 | |---|---| 7 | |`GET`| `SELECT`| 8 | |`POST`| `INSERT`| 9 | |`PUT`| `UPDATE`| 10 | |`DELETE`| `DELETE`| 11 | 12 | The main goal of this sample is to be used to gain an understanding of how to use the serverless driver in your own code. 13 | 14 | For an in-depth explanation of how to use this repo, check the [associated article](https://planetscale.com/docs/tutorials/planetscale-serverless-driver-node-example) on the PlanetScale docs site. 15 | 16 | ## Set up the database 17 | 18 | Before you can start the project, you should set up a database that can be used with the project. Create a database on PlanetScale named `travel_db`. Once the database has initialized, run the following command to create the necessary structures for the database and insert the sample dataset: 19 | 20 | ```bash 21 | cd scripts 22 | ./seed-database.sh 23 | ``` 24 | 25 | ## Start the API 26 | 27 | To use the project, clone the repository down to your workstation and run the following commands: 28 | 29 | ```bash 30 | npm install 31 | npm start 32 | ``` 33 | 34 | You should receive a message stating that the API is running. 35 | 36 | ## Test the API 37 | 38 | The `tests.http` file can be used to test the various endpoints. It is designed to be used with the [VS Code Rest Client plugin](https://marketplace.visualstudio.com/items?itemName=humao.rest-client), although it can also be used as a reference in testing with alternate tools. 39 | 40 | ## Further reading 41 | 42 | To learn more about the PlanetScale serverless driver for JavaScript, review the following articles: 43 | 44 | - [Introducing the PlanetScale serverless driver for JavaScript](https://planetscale.com/blog/introducing-the-planetscale-serverless-driver-for-javascript) 45 | - [The PlanetScale serverless driver for JavaScript documentation](https://planetscale.com/docs/tutorials/planetscale-serverless-driver) 46 | -------------------------------------------------------------------------------- /doc/dependency_decisions.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - - :permit 3 | - Simplified BSD 4 | - :who: 5 | :why: 6 | :versions: [] 7 | :when: 2022-08-16 20:30:58.418297000 Z 8 | - - :permit 9 | - MIT 10 | - :who: 11 | :why: 12 | :versions: [] 13 | :when: 2022-08-16 20:31:02.867792000 Z 14 | - - :permit 15 | - Apache 2.0 16 | - :who: 17 | :why: 18 | :versions: [] 19 | :when: 2022-08-16 20:31:06.913373000 Z 20 | - - :permit 21 | - CC0-1.0 22 | - :who: 23 | :why: 24 | :versions: [] 25 | :when: 2022-08-17 14:31:22.527535000 Z 26 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import { connect } from '@planetscale/database' 2 | import dotenv from 'dotenv' 3 | import express from 'express' 4 | 5 | dotenv.config() 6 | const app = express() 7 | app.use(express.json()) 8 | 9 | const config = { 10 | host: process.env.DATABASE_HOST, 11 | username: process.env.DATABASE_USERNAME, 12 | password: process.env.DATABASE_PASSWORD, 13 | } 14 | const conn = await connect(config) 15 | 16 | app.get('/', async (req, res) => { 17 | const results = await conn.execute("SELECT * FROM hotels") 18 | console.log(results) 19 | res.json(results.rows) 20 | }) 21 | 22 | app.post('/', async (req, res) => { 23 | const query = "INSERT INTO hotels (`name`, `address`, `stars`) VALUES (:name, :address, :stars)" 24 | const params = { 25 | name: req.body.name, 26 | address: req.body.address, 27 | stars: req.body.stars 28 | } 29 | const results = await conn.execute(query, params) 30 | console.log(results) 31 | res.json({ 32 | id: results.insertId, 33 | name: req.body.name, 34 | address: req.body.address, 35 | stars: req.body.stars 36 | }) 37 | }) 38 | 39 | app.put('/:id', async (req, res) => { 40 | const query = "UPDATE hotels set `name`=:name, `address`=:address, `stars`=:stars WHERE `id`=:id" 41 | const params = { 42 | id: req.params.id, 43 | name: req.body.name, 44 | address: req.body.address, 45 | stars: req.body.stars 46 | } 47 | const results = await conn.execute(query, params) 48 | console.log(results) 49 | res.status(200).send() 50 | }) 51 | 52 | app.delete("/:id", async (req, res) => { 53 | const query = "DELETE FROM hotels WHERE `id`=:id" 54 | const params = { 55 | id: req.params.id, 56 | name: req.body.name, 57 | address: req.body.address, 58 | stars: req.body.stars 59 | } 60 | const results = await conn.execute(query, params) 61 | console.log(results) 62 | res.status(200).send() 63 | }) 64 | 65 | const port = process.env.PORT || 3000 66 | 67 | app.listen(port, () => { 68 | console.log(`API running on http://localhost:${port}`) 69 | }) 70 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "database-js-starter", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "database-js-starter", 9 | "version": "1.0.0", 10 | "license": "CC0-1.0", 11 | "dependencies": { 12 | "@planetscale/database": "^0.5.0", 13 | "dotenv": "^16.0.1", 14 | "express": "^4.18.1" 15 | } 16 | }, 17 | "node_modules/@planetscale/database": { 18 | "version": "0.5.0", 19 | "resolved": "https://registry.npmjs.org/@planetscale/database/-/database-0.5.0.tgz", 20 | "integrity": "sha512-6DexUnNup44ciLNwnJFhM5DH1xTR5ILa8y5DiMOUkUcjZ0bcyraLH4kVuJkJQg2yI9vQXItwVk6Z+TfykCx2Aw==", 21 | "engines": { 22 | "node": ">=16" 23 | } 24 | }, 25 | "node_modules/accepts": { 26 | "version": "1.3.8", 27 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 28 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 29 | "dependencies": { 30 | "mime-types": "~2.1.34", 31 | "negotiator": "0.6.3" 32 | }, 33 | "engines": { 34 | "node": ">= 0.6" 35 | } 36 | }, 37 | "node_modules/array-flatten": { 38 | "version": "1.1.1", 39 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 40 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 41 | }, 42 | "node_modules/body-parser": { 43 | "version": "1.20.0", 44 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", 45 | "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", 46 | "dependencies": { 47 | "bytes": "3.1.2", 48 | "content-type": "~1.0.4", 49 | "debug": "2.6.9", 50 | "depd": "2.0.0", 51 | "destroy": "1.2.0", 52 | "http-errors": "2.0.0", 53 | "iconv-lite": "0.4.24", 54 | "on-finished": "2.4.1", 55 | "qs": "6.10.3", 56 | "raw-body": "2.5.1", 57 | "type-is": "~1.6.18", 58 | "unpipe": "1.0.0" 59 | }, 60 | "engines": { 61 | "node": ">= 0.8", 62 | "npm": "1.2.8000 || >= 1.4.16" 63 | } 64 | }, 65 | "node_modules/bytes": { 66 | "version": "3.1.2", 67 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 68 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 69 | "engines": { 70 | "node": ">= 0.8" 71 | } 72 | }, 73 | "node_modules/call-bind": { 74 | "version": "1.0.2", 75 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 76 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 77 | "dependencies": { 78 | "function-bind": "^1.1.1", 79 | "get-intrinsic": "^1.0.2" 80 | }, 81 | "funding": { 82 | "url": "https://github.com/sponsors/ljharb" 83 | } 84 | }, 85 | "node_modules/content-disposition": { 86 | "version": "0.5.4", 87 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 88 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 89 | "dependencies": { 90 | "safe-buffer": "5.2.1" 91 | }, 92 | "engines": { 93 | "node": ">= 0.6" 94 | } 95 | }, 96 | "node_modules/content-type": { 97 | "version": "1.0.4", 98 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 99 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", 100 | "engines": { 101 | "node": ">= 0.6" 102 | } 103 | }, 104 | "node_modules/cookie": { 105 | "version": "0.5.0", 106 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 107 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 108 | "engines": { 109 | "node": ">= 0.6" 110 | } 111 | }, 112 | "node_modules/cookie-signature": { 113 | "version": "1.0.6", 114 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 115 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 116 | }, 117 | "node_modules/debug": { 118 | "version": "2.6.9", 119 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 120 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 121 | "dependencies": { 122 | "ms": "2.0.0" 123 | } 124 | }, 125 | "node_modules/depd": { 126 | "version": "2.0.0", 127 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 128 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 129 | "engines": { 130 | "node": ">= 0.8" 131 | } 132 | }, 133 | "node_modules/destroy": { 134 | "version": "1.2.0", 135 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 136 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 137 | "engines": { 138 | "node": ">= 0.8", 139 | "npm": "1.2.8000 || >= 1.4.16" 140 | } 141 | }, 142 | "node_modules/dotenv": { 143 | "version": "16.0.1", 144 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", 145 | "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", 146 | "engines": { 147 | "node": ">=12" 148 | } 149 | }, 150 | "node_modules/ee-first": { 151 | "version": "1.1.1", 152 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 153 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 154 | }, 155 | "node_modules/encodeurl": { 156 | "version": "1.0.2", 157 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 158 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 159 | "engines": { 160 | "node": ">= 0.8" 161 | } 162 | }, 163 | "node_modules/escape-html": { 164 | "version": "1.0.3", 165 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 166 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 167 | }, 168 | "node_modules/etag": { 169 | "version": "1.8.1", 170 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 171 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 172 | "engines": { 173 | "node": ">= 0.6" 174 | } 175 | }, 176 | "node_modules/express": { 177 | "version": "4.18.1", 178 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", 179 | "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", 180 | "dependencies": { 181 | "accepts": "~1.3.8", 182 | "array-flatten": "1.1.1", 183 | "body-parser": "1.20.0", 184 | "content-disposition": "0.5.4", 185 | "content-type": "~1.0.4", 186 | "cookie": "0.5.0", 187 | "cookie-signature": "1.0.6", 188 | "debug": "2.6.9", 189 | "depd": "2.0.0", 190 | "encodeurl": "~1.0.2", 191 | "escape-html": "~1.0.3", 192 | "etag": "~1.8.1", 193 | "finalhandler": "1.2.0", 194 | "fresh": "0.5.2", 195 | "http-errors": "2.0.0", 196 | "merge-descriptors": "1.0.1", 197 | "methods": "~1.1.2", 198 | "on-finished": "2.4.1", 199 | "parseurl": "~1.3.3", 200 | "path-to-regexp": "0.1.7", 201 | "proxy-addr": "~2.0.7", 202 | "qs": "6.10.3", 203 | "range-parser": "~1.2.1", 204 | "safe-buffer": "5.2.1", 205 | "send": "0.18.0", 206 | "serve-static": "1.15.0", 207 | "setprototypeof": "1.2.0", 208 | "statuses": "2.0.1", 209 | "type-is": "~1.6.18", 210 | "utils-merge": "1.0.1", 211 | "vary": "~1.1.2" 212 | }, 213 | "engines": { 214 | "node": ">= 0.10.0" 215 | } 216 | }, 217 | "node_modules/finalhandler": { 218 | "version": "1.2.0", 219 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 220 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 221 | "dependencies": { 222 | "debug": "2.6.9", 223 | "encodeurl": "~1.0.2", 224 | "escape-html": "~1.0.3", 225 | "on-finished": "2.4.1", 226 | "parseurl": "~1.3.3", 227 | "statuses": "2.0.1", 228 | "unpipe": "~1.0.0" 229 | }, 230 | "engines": { 231 | "node": ">= 0.8" 232 | } 233 | }, 234 | "node_modules/forwarded": { 235 | "version": "0.2.0", 236 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 237 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 238 | "engines": { 239 | "node": ">= 0.6" 240 | } 241 | }, 242 | "node_modules/fresh": { 243 | "version": "0.5.2", 244 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 245 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 246 | "engines": { 247 | "node": ">= 0.6" 248 | } 249 | }, 250 | "node_modules/function-bind": { 251 | "version": "1.1.1", 252 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 253 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 254 | }, 255 | "node_modules/get-intrinsic": { 256 | "version": "1.1.2", 257 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", 258 | "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", 259 | "dependencies": { 260 | "function-bind": "^1.1.1", 261 | "has": "^1.0.3", 262 | "has-symbols": "^1.0.3" 263 | }, 264 | "funding": { 265 | "url": "https://github.com/sponsors/ljharb" 266 | } 267 | }, 268 | "node_modules/has": { 269 | "version": "1.0.3", 270 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 271 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 272 | "dependencies": { 273 | "function-bind": "^1.1.1" 274 | }, 275 | "engines": { 276 | "node": ">= 0.4.0" 277 | } 278 | }, 279 | "node_modules/has-symbols": { 280 | "version": "1.0.3", 281 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 282 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 283 | "engines": { 284 | "node": ">= 0.4" 285 | }, 286 | "funding": { 287 | "url": "https://github.com/sponsors/ljharb" 288 | } 289 | }, 290 | "node_modules/http-errors": { 291 | "version": "2.0.0", 292 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 293 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 294 | "dependencies": { 295 | "depd": "2.0.0", 296 | "inherits": "2.0.4", 297 | "setprototypeof": "1.2.0", 298 | "statuses": "2.0.1", 299 | "toidentifier": "1.0.1" 300 | }, 301 | "engines": { 302 | "node": ">= 0.8" 303 | } 304 | }, 305 | "node_modules/iconv-lite": { 306 | "version": "0.4.24", 307 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 308 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 309 | "dependencies": { 310 | "safer-buffer": ">= 2.1.2 < 3" 311 | }, 312 | "engines": { 313 | "node": ">=0.10.0" 314 | } 315 | }, 316 | "node_modules/inherits": { 317 | "version": "2.0.4", 318 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 319 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 320 | }, 321 | "node_modules/ipaddr.js": { 322 | "version": "1.9.1", 323 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 324 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 325 | "engines": { 326 | "node": ">= 0.10" 327 | } 328 | }, 329 | "node_modules/media-typer": { 330 | "version": "0.3.0", 331 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 332 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 333 | "engines": { 334 | "node": ">= 0.6" 335 | } 336 | }, 337 | "node_modules/merge-descriptors": { 338 | "version": "1.0.1", 339 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 340 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 341 | }, 342 | "node_modules/methods": { 343 | "version": "1.1.2", 344 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 345 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 346 | "engines": { 347 | "node": ">= 0.6" 348 | } 349 | }, 350 | "node_modules/mime": { 351 | "version": "1.6.0", 352 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 353 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 354 | "bin": { 355 | "mime": "cli.js" 356 | }, 357 | "engines": { 358 | "node": ">=4" 359 | } 360 | }, 361 | "node_modules/mime-db": { 362 | "version": "1.52.0", 363 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 364 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 365 | "engines": { 366 | "node": ">= 0.6" 367 | } 368 | }, 369 | "node_modules/mime-types": { 370 | "version": "2.1.35", 371 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 372 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 373 | "dependencies": { 374 | "mime-db": "1.52.0" 375 | }, 376 | "engines": { 377 | "node": ">= 0.6" 378 | } 379 | }, 380 | "node_modules/ms": { 381 | "version": "2.0.0", 382 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 383 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 384 | }, 385 | "node_modules/negotiator": { 386 | "version": "0.6.3", 387 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 388 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 389 | "engines": { 390 | "node": ">= 0.6" 391 | } 392 | }, 393 | "node_modules/object-inspect": { 394 | "version": "1.12.2", 395 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 396 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", 397 | "funding": { 398 | "url": "https://github.com/sponsors/ljharb" 399 | } 400 | }, 401 | "node_modules/on-finished": { 402 | "version": "2.4.1", 403 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 404 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 405 | "dependencies": { 406 | "ee-first": "1.1.1" 407 | }, 408 | "engines": { 409 | "node": ">= 0.8" 410 | } 411 | }, 412 | "node_modules/parseurl": { 413 | "version": "1.3.3", 414 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 415 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 416 | "engines": { 417 | "node": ">= 0.8" 418 | } 419 | }, 420 | "node_modules/path-to-regexp": { 421 | "version": "0.1.7", 422 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 423 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 424 | }, 425 | "node_modules/proxy-addr": { 426 | "version": "2.0.7", 427 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 428 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 429 | "dependencies": { 430 | "forwarded": "0.2.0", 431 | "ipaddr.js": "1.9.1" 432 | }, 433 | "engines": { 434 | "node": ">= 0.10" 435 | } 436 | }, 437 | "node_modules/qs": { 438 | "version": "6.10.3", 439 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", 440 | "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", 441 | "dependencies": { 442 | "side-channel": "^1.0.4" 443 | }, 444 | "engines": { 445 | "node": ">=0.6" 446 | }, 447 | "funding": { 448 | "url": "https://github.com/sponsors/ljharb" 449 | } 450 | }, 451 | "node_modules/range-parser": { 452 | "version": "1.2.1", 453 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 454 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 455 | "engines": { 456 | "node": ">= 0.6" 457 | } 458 | }, 459 | "node_modules/raw-body": { 460 | "version": "2.5.1", 461 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 462 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 463 | "dependencies": { 464 | "bytes": "3.1.2", 465 | "http-errors": "2.0.0", 466 | "iconv-lite": "0.4.24", 467 | "unpipe": "1.0.0" 468 | }, 469 | "engines": { 470 | "node": ">= 0.8" 471 | } 472 | }, 473 | "node_modules/safe-buffer": { 474 | "version": "5.2.1", 475 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 476 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 477 | "funding": [ 478 | { 479 | "type": "github", 480 | "url": "https://github.com/sponsors/feross" 481 | }, 482 | { 483 | "type": "patreon", 484 | "url": "https://www.patreon.com/feross" 485 | }, 486 | { 487 | "type": "consulting", 488 | "url": "https://feross.org/support" 489 | } 490 | ] 491 | }, 492 | "node_modules/safer-buffer": { 493 | "version": "2.1.2", 494 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 495 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 496 | }, 497 | "node_modules/send": { 498 | "version": "0.18.0", 499 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 500 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 501 | "dependencies": { 502 | "debug": "2.6.9", 503 | "depd": "2.0.0", 504 | "destroy": "1.2.0", 505 | "encodeurl": "~1.0.2", 506 | "escape-html": "~1.0.3", 507 | "etag": "~1.8.1", 508 | "fresh": "0.5.2", 509 | "http-errors": "2.0.0", 510 | "mime": "1.6.0", 511 | "ms": "2.1.3", 512 | "on-finished": "2.4.1", 513 | "range-parser": "~1.2.1", 514 | "statuses": "2.0.1" 515 | }, 516 | "engines": { 517 | "node": ">= 0.8.0" 518 | } 519 | }, 520 | "node_modules/send/node_modules/ms": { 521 | "version": "2.1.3", 522 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 523 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 524 | }, 525 | "node_modules/serve-static": { 526 | "version": "1.15.0", 527 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 528 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 529 | "dependencies": { 530 | "encodeurl": "~1.0.2", 531 | "escape-html": "~1.0.3", 532 | "parseurl": "~1.3.3", 533 | "send": "0.18.0" 534 | }, 535 | "engines": { 536 | "node": ">= 0.8.0" 537 | } 538 | }, 539 | "node_modules/setprototypeof": { 540 | "version": "1.2.0", 541 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 542 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 543 | }, 544 | "node_modules/side-channel": { 545 | "version": "1.0.4", 546 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 547 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 548 | "dependencies": { 549 | "call-bind": "^1.0.0", 550 | "get-intrinsic": "^1.0.2", 551 | "object-inspect": "^1.9.0" 552 | }, 553 | "funding": { 554 | "url": "https://github.com/sponsors/ljharb" 555 | } 556 | }, 557 | "node_modules/statuses": { 558 | "version": "2.0.1", 559 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 560 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 561 | "engines": { 562 | "node": ">= 0.8" 563 | } 564 | }, 565 | "node_modules/toidentifier": { 566 | "version": "1.0.1", 567 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 568 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 569 | "engines": { 570 | "node": ">=0.6" 571 | } 572 | }, 573 | "node_modules/type-is": { 574 | "version": "1.6.18", 575 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 576 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 577 | "dependencies": { 578 | "media-typer": "0.3.0", 579 | "mime-types": "~2.1.24" 580 | }, 581 | "engines": { 582 | "node": ">= 0.6" 583 | } 584 | }, 585 | "node_modules/unpipe": { 586 | "version": "1.0.0", 587 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 588 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 589 | "engines": { 590 | "node": ">= 0.8" 591 | } 592 | }, 593 | "node_modules/utils-merge": { 594 | "version": "1.0.1", 595 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 596 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 597 | "engines": { 598 | "node": ">= 0.4.0" 599 | } 600 | }, 601 | "node_modules/vary": { 602 | "version": "1.1.2", 603 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 604 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 605 | "engines": { 606 | "node": ">= 0.8" 607 | } 608 | } 609 | }, 610 | "dependencies": { 611 | "@planetscale/database": { 612 | "version": "0.5.0", 613 | "resolved": "https://registry.npmjs.org/@planetscale/database/-/database-0.5.0.tgz", 614 | "integrity": "sha512-6DexUnNup44ciLNwnJFhM5DH1xTR5ILa8y5DiMOUkUcjZ0bcyraLH4kVuJkJQg2yI9vQXItwVk6Z+TfykCx2Aw==" 615 | }, 616 | "accepts": { 617 | "version": "1.3.8", 618 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 619 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 620 | "requires": { 621 | "mime-types": "~2.1.34", 622 | "negotiator": "0.6.3" 623 | } 624 | }, 625 | "array-flatten": { 626 | "version": "1.1.1", 627 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 628 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 629 | }, 630 | "body-parser": { 631 | "version": "1.20.0", 632 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", 633 | "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", 634 | "requires": { 635 | "bytes": "3.1.2", 636 | "content-type": "~1.0.4", 637 | "debug": "2.6.9", 638 | "depd": "2.0.0", 639 | "destroy": "1.2.0", 640 | "http-errors": "2.0.0", 641 | "iconv-lite": "0.4.24", 642 | "on-finished": "2.4.1", 643 | "qs": "6.10.3", 644 | "raw-body": "2.5.1", 645 | "type-is": "~1.6.18", 646 | "unpipe": "1.0.0" 647 | } 648 | }, 649 | "bytes": { 650 | "version": "3.1.2", 651 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 652 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" 653 | }, 654 | "call-bind": { 655 | "version": "1.0.2", 656 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 657 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 658 | "requires": { 659 | "function-bind": "^1.1.1", 660 | "get-intrinsic": "^1.0.2" 661 | } 662 | }, 663 | "content-disposition": { 664 | "version": "0.5.4", 665 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 666 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 667 | "requires": { 668 | "safe-buffer": "5.2.1" 669 | } 670 | }, 671 | "content-type": { 672 | "version": "1.0.4", 673 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 674 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 675 | }, 676 | "cookie": { 677 | "version": "0.5.0", 678 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 679 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" 680 | }, 681 | "cookie-signature": { 682 | "version": "1.0.6", 683 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 684 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 685 | }, 686 | "debug": { 687 | "version": "2.6.9", 688 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 689 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 690 | "requires": { 691 | "ms": "2.0.0" 692 | } 693 | }, 694 | "depd": { 695 | "version": "2.0.0", 696 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 697 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" 698 | }, 699 | "destroy": { 700 | "version": "1.2.0", 701 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 702 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" 703 | }, 704 | "dotenv": { 705 | "version": "16.0.1", 706 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", 707 | "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" 708 | }, 709 | "ee-first": { 710 | "version": "1.1.1", 711 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 712 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 713 | }, 714 | "encodeurl": { 715 | "version": "1.0.2", 716 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 717 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" 718 | }, 719 | "escape-html": { 720 | "version": "1.0.3", 721 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 722 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 723 | }, 724 | "etag": { 725 | "version": "1.8.1", 726 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 727 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" 728 | }, 729 | "express": { 730 | "version": "4.18.1", 731 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", 732 | "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", 733 | "requires": { 734 | "accepts": "~1.3.8", 735 | "array-flatten": "1.1.1", 736 | "body-parser": "1.20.0", 737 | "content-disposition": "0.5.4", 738 | "content-type": "~1.0.4", 739 | "cookie": "0.5.0", 740 | "cookie-signature": "1.0.6", 741 | "debug": "2.6.9", 742 | "depd": "2.0.0", 743 | "encodeurl": "~1.0.2", 744 | "escape-html": "~1.0.3", 745 | "etag": "~1.8.1", 746 | "finalhandler": "1.2.0", 747 | "fresh": "0.5.2", 748 | "http-errors": "2.0.0", 749 | "merge-descriptors": "1.0.1", 750 | "methods": "~1.1.2", 751 | "on-finished": "2.4.1", 752 | "parseurl": "~1.3.3", 753 | "path-to-regexp": "0.1.7", 754 | "proxy-addr": "~2.0.7", 755 | "qs": "6.10.3", 756 | "range-parser": "~1.2.1", 757 | "safe-buffer": "5.2.1", 758 | "send": "0.18.0", 759 | "serve-static": "1.15.0", 760 | "setprototypeof": "1.2.0", 761 | "statuses": "2.0.1", 762 | "type-is": "~1.6.18", 763 | "utils-merge": "1.0.1", 764 | "vary": "~1.1.2" 765 | } 766 | }, 767 | "finalhandler": { 768 | "version": "1.2.0", 769 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 770 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 771 | "requires": { 772 | "debug": "2.6.9", 773 | "encodeurl": "~1.0.2", 774 | "escape-html": "~1.0.3", 775 | "on-finished": "2.4.1", 776 | "parseurl": "~1.3.3", 777 | "statuses": "2.0.1", 778 | "unpipe": "~1.0.0" 779 | } 780 | }, 781 | "forwarded": { 782 | "version": "0.2.0", 783 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 784 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" 785 | }, 786 | "fresh": { 787 | "version": "0.5.2", 788 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 789 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" 790 | }, 791 | "function-bind": { 792 | "version": "1.1.1", 793 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 794 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 795 | }, 796 | "get-intrinsic": { 797 | "version": "1.1.2", 798 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", 799 | "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", 800 | "requires": { 801 | "function-bind": "^1.1.1", 802 | "has": "^1.0.3", 803 | "has-symbols": "^1.0.3" 804 | } 805 | }, 806 | "has": { 807 | "version": "1.0.3", 808 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 809 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 810 | "requires": { 811 | "function-bind": "^1.1.1" 812 | } 813 | }, 814 | "has-symbols": { 815 | "version": "1.0.3", 816 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 817 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" 818 | }, 819 | "http-errors": { 820 | "version": "2.0.0", 821 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 822 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 823 | "requires": { 824 | "depd": "2.0.0", 825 | "inherits": "2.0.4", 826 | "setprototypeof": "1.2.0", 827 | "statuses": "2.0.1", 828 | "toidentifier": "1.0.1" 829 | } 830 | }, 831 | "iconv-lite": { 832 | "version": "0.4.24", 833 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 834 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 835 | "requires": { 836 | "safer-buffer": ">= 2.1.2 < 3" 837 | } 838 | }, 839 | "inherits": { 840 | "version": "2.0.4", 841 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 842 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 843 | }, 844 | "ipaddr.js": { 845 | "version": "1.9.1", 846 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 847 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 848 | }, 849 | "media-typer": { 850 | "version": "0.3.0", 851 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 852 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" 853 | }, 854 | "merge-descriptors": { 855 | "version": "1.0.1", 856 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 857 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 858 | }, 859 | "methods": { 860 | "version": "1.1.2", 861 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 862 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" 863 | }, 864 | "mime": { 865 | "version": "1.6.0", 866 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 867 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 868 | }, 869 | "mime-db": { 870 | "version": "1.52.0", 871 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 872 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" 873 | }, 874 | "mime-types": { 875 | "version": "2.1.35", 876 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 877 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 878 | "requires": { 879 | "mime-db": "1.52.0" 880 | } 881 | }, 882 | "ms": { 883 | "version": "2.0.0", 884 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 885 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 886 | }, 887 | "negotiator": { 888 | "version": "0.6.3", 889 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 890 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" 891 | }, 892 | "object-inspect": { 893 | "version": "1.12.2", 894 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 895 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" 896 | }, 897 | "on-finished": { 898 | "version": "2.4.1", 899 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 900 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 901 | "requires": { 902 | "ee-first": "1.1.1" 903 | } 904 | }, 905 | "parseurl": { 906 | "version": "1.3.3", 907 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 908 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 909 | }, 910 | "path-to-regexp": { 911 | "version": "0.1.7", 912 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 913 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 914 | }, 915 | "proxy-addr": { 916 | "version": "2.0.7", 917 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 918 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 919 | "requires": { 920 | "forwarded": "0.2.0", 921 | "ipaddr.js": "1.9.1" 922 | } 923 | }, 924 | "qs": { 925 | "version": "6.10.3", 926 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", 927 | "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", 928 | "requires": { 929 | "side-channel": "^1.0.4" 930 | } 931 | }, 932 | "range-parser": { 933 | "version": "1.2.1", 934 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 935 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 936 | }, 937 | "raw-body": { 938 | "version": "2.5.1", 939 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 940 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 941 | "requires": { 942 | "bytes": "3.1.2", 943 | "http-errors": "2.0.0", 944 | "iconv-lite": "0.4.24", 945 | "unpipe": "1.0.0" 946 | } 947 | }, 948 | "safe-buffer": { 949 | "version": "5.2.1", 950 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 951 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 952 | }, 953 | "safer-buffer": { 954 | "version": "2.1.2", 955 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 956 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 957 | }, 958 | "send": { 959 | "version": "0.18.0", 960 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 961 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 962 | "requires": { 963 | "debug": "2.6.9", 964 | "depd": "2.0.0", 965 | "destroy": "1.2.0", 966 | "encodeurl": "~1.0.2", 967 | "escape-html": "~1.0.3", 968 | "etag": "~1.8.1", 969 | "fresh": "0.5.2", 970 | "http-errors": "2.0.0", 971 | "mime": "1.6.0", 972 | "ms": "2.1.3", 973 | "on-finished": "2.4.1", 974 | "range-parser": "~1.2.1", 975 | "statuses": "2.0.1" 976 | }, 977 | "dependencies": { 978 | "ms": { 979 | "version": "2.1.3", 980 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 981 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 982 | } 983 | } 984 | }, 985 | "serve-static": { 986 | "version": "1.15.0", 987 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 988 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 989 | "requires": { 990 | "encodeurl": "~1.0.2", 991 | "escape-html": "~1.0.3", 992 | "parseurl": "~1.3.3", 993 | "send": "0.18.0" 994 | } 995 | }, 996 | "setprototypeof": { 997 | "version": "1.2.0", 998 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 999 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 1000 | }, 1001 | "side-channel": { 1002 | "version": "1.0.4", 1003 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 1004 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 1005 | "requires": { 1006 | "call-bind": "^1.0.0", 1007 | "get-intrinsic": "^1.0.2", 1008 | "object-inspect": "^1.9.0" 1009 | } 1010 | }, 1011 | "statuses": { 1012 | "version": "2.0.1", 1013 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 1014 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" 1015 | }, 1016 | "toidentifier": { 1017 | "version": "1.0.1", 1018 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 1019 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" 1020 | }, 1021 | "type-is": { 1022 | "version": "1.6.18", 1023 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 1024 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 1025 | "requires": { 1026 | "media-typer": "0.3.0", 1027 | "mime-types": "~2.1.24" 1028 | } 1029 | }, 1030 | "unpipe": { 1031 | "version": "1.0.0", 1032 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1033 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" 1034 | }, 1035 | "utils-merge": { 1036 | "version": "1.0.1", 1037 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1038 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" 1039 | }, 1040 | "vary": { 1041 | "version": "1.1.2", 1042 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1043 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" 1044 | } 1045 | } 1046 | } 1047 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "database-js-starter", 3 | "version": "1.0.0", 4 | "description": "A sample Node.js application that uses the database-js package.", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "start": "node index.js", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/planetscale/database-js-starter.git" 14 | }, 15 | "author": "Brian Morrison II", 16 | "license": "CC0-1.0", 17 | "bugs": { 18 | "url": "https://github.com/planetscale/database-js-starter/issues" 19 | }, 20 | "homepage": "https://github.com/planetscale/database-js-starter#readme", 21 | "dependencies": { 22 | "@planetscale/database": "^0.5.0", 23 | "dotenv": "^16.0.1", 24 | "express": "^4.18.1" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample.env: -------------------------------------------------------------------------------- 1 | # Rename this file to '.env' and add your values before starting the app 2 | DATABASE_HOST="" 3 | DATABASE_USERNAME="" 4 | DATABASE_PASSWORD="" -------------------------------------------------------------------------------- /scripts/seed-database.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | pscale shell travel_db main < ./travel_db.sql 4 | -------------------------------------------------------------------------------- /scripts/travel_db.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE hotels( 2 | id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, 3 | name VARCHAR(50) NOT NULL, 4 | address VARCHAR(50) NOT NULL, 5 | stars FLOAT(2) UNSIGNED 6 | ); 7 | 8 | INSERT INTO hotels (id, name, address, stars) VALUES 9 | (1, 'Four Seasons Resort Jackson hole', '7680 Granite Loop Rd, Teton Village, WY 83025', 4.7), 10 | (2, 'The Galt House', '140 N Fourth St, Louisville, KY 40202', 4), 11 | (3, 'The Foundry Hotel Asheville', '51 S Market St, Asheville, NC 28801', 4.7), 12 | (4, 'Hotel del Coronado', '1500 Orange Ave, Coronado, CA 92118', 4.5), 13 | (5, 'Montage Kapalua Bay', '1 Bay Dr, Lahaina, HI 96761', 4.7); 14 | 15 | CREATE TABLE rooms( 16 | id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, 17 | room_type VARCHAR(100) NOT NULL, 18 | price FLOAT(2) UNSIGNED, 19 | hotel_id INT UNSIGNED NOT NULL 20 | ); 21 | 22 | INSERT INTO rooms (id, room_type, price, hotel_id) VALUES 23 | (1, '2 Bedroom Premier Ocean View Residence', 4430, 5), 24 | (2, '3 Bedroom Ocean View Residence', 4850, 5), 25 | (3, '3 Bedroom Partial Ocean Grand Residence', 5400, 5), 26 | (4, 'Foundry King Hearing Acc', 435, 3), 27 | (5, 'Foundry King', 435, 3), 28 | (6, 'Foundry Double Queen', 444, 3), 29 | (7, 'Victorian 1Q', 663, 4), 30 | (8, 'Victorian 1K', 712, 4), 31 | (9, 'Victorian 1K Deluxe', 736, 4), 32 | (10, 'Deluxe Room, West Tower', 156, 2), 33 | (11, 'Deluxe Room, 1 King', 156, 2), 34 | (12, 'Executive 1-Bedroom Suite, East Tower', 218, 2), 35 | (13, 'Valley-Side Accessible Room', 1335, 1), 36 | (14, 'Resort-View One Bedroom Suite', 2535, 1), 37 | (15, 'Specialty Suite', 4210, 1); 38 | 39 | CREATE TABLE guests( 40 | id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, 41 | name VARCHAR(100), 42 | phone_num VARCHAR(20) 43 | ); 44 | 45 | INSERT INTO guests (id, name, phone_num) VALUES 46 | (1, 'Rylie Garcia', '994-994-2129'), 47 | (2, 'Aurora Parson', '719-466-8864'), 48 | (3, 'Marley Cruz', '906-412-2003'), 49 | (4, 'Brinley Webster', '547-866-0595'), 50 | (5, 'Elliana Woods', '694-322-8326'), 51 | (6, 'Carson Green', '542-884-3956'), 52 | (7, 'Kalani Hanson', '260-745-3172'), 53 | (8, 'Harvey Davidson', '201-273-9185'), 54 | (9, 'Austin Barnes', '440-217-2357'), 55 | (10, 'Luke Evans', '251-682-6663'); 56 | 57 | CREATE TABLE bookings( 58 | id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, 59 | check_in DATETIME NOT NULL, 60 | check_out DATETIME NOT NULL, 61 | room_id INT UNSIGNED NOT NULL 62 | ); 63 | 64 | INSERT INTO bookings (id, check_in, check_out, room_id) VALUES 65 | (1, '2022-08-11 15:00:00', '2022-08-12 11:00:00', 2), 66 | (2, '2022-08-19 15:00:00', '2022-08-24 11:00:00', 4), 67 | (3, '2022-09-03 15:00:00', '2022-09-04 11:00:00', 8), 68 | (4, '2022-09-03 13:00:00', '2022-09-09 10:00:00', 9), 69 | (5, '2022-09-12 16:00:00', '2022-10-12 11:00:00', 3), 70 | (6, '2022-09-14 15:00:00', '2022-09-15 11:00:00', 7); 71 | 72 | CREATE TABLE booking_guests( 73 | id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, 74 | booking_id INT UNSIGNED, 75 | guest_id INT UNSIGNED 76 | ); 77 | 78 | INSERT INTO booking_guests (booking_id, guest_id) VALUES 79 | (1, 1), 80 | (1, 2), 81 | (2, 3), 82 | (3, 7), 83 | (3, 8), 84 | (3, 9), 85 | (4, 10), 86 | (5, 4), 87 | (6, 5), 88 | (6, 6); -------------------------------------------------------------------------------- /tests.http: -------------------------------------------------------------------------------- 1 | ### Fetch hotels 2 | get http://localhost:3000 3 | 4 | ### Add hotel 5 | post http://localhost:3000 6 | Content-Type: application/json 7 | 8 | { 9 | "name": "Montage Kapalua Bay 2", 10 | "address": "1 Bay Dr, Lahaina, HI 96761", 11 | "stars": 4 12 | } 13 | 14 | ### Update hotel 15 | put http://localhost:3000/5 16 | Content-Type: application/json 17 | 18 | { 19 | "name": "Montage Kapalua Bay 2 (updated)", 20 | "address": "1 Bay Dr, Lahaina, HI 96762", 21 | "stars": 6 22 | } 23 | 24 | ### Delete hotel 25 | delete http://localhost:3000/5 26 | --------------------------------------------------------------------------------