├── .env.example ├── .github ├── FUNDING.yml └── workflows │ └── codeql.yml ├── .gitignore ├── LICENSE ├── README.md ├── Twitter Clone.postman_collection.json ├── app-middlewares ├── auth.js ├── tweets.js └── user.js ├── crud └── create.js ├── dbConfig.js ├── helpers ├── connection.js ├── md5.js ├── query.js └── values-for-insert.js ├── package-lock.json ├── package.json ├── query-builders ├── feed-query.js └── tweet-query.js ├── server.js └── twitter-clone-postman.png /.env.example: -------------------------------------------------------------------------------- 1 | DB_HOST=localhost 2 | DB_USER= 3 | DB_PASS= 4 | DB_DATABASE=twitter_clone 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: time-to-hack 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '17 23 * * 2' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Use only 'java' to analyze code written in Java, Kotlin or both 38 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 39 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 40 | 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v3 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v2 48 | with: 49 | languages: ${{ matrix.language }} 50 | # If you wish to specify custom queries, you can do so here or in a config file. 51 | # By default, queries listed here will override any specified in a config file. 52 | # Prefix the list here with "+" to use these queries and those in the config file. 53 | 54 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 55 | # queries: security-extended,security-and-quality 56 | 57 | 58 | # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). 59 | # If this step fails, then you should remove it and run the build manually (see below) 60 | - name: Autobuild 61 | uses: github/codeql-action/autobuild@v2 62 | 63 | # ℹ️ Command-line programs to run using the OS shell. 64 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 65 | 66 | # If the Autobuild fails above, remove it and uncomment the following three lines. 67 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 68 | 69 | # - run: | 70 | # echo "Run, Build Application using script" 71 | # ./location_of_script_within_repo/buildscript.sh 72 | 73 | - name: Perform CodeQL Analysis 74 | uses: github/codeql-action/analyze@v2 75 | with: 76 | category: "/language:${{matrix.language}}" 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | *.spf 64 | .env 65 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Time to Hack 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # express-mysql 2 | 3 | 4 | ![](//res.cloudinary.com/time2hack/image/upload/q_auto:good/creating-rest-api-in-node-js-with-express-and-mysql-social-md.jpg) 5 | 6 | Code for understanding for creating REST API in Node.js with Express and MySQL. 7 | 8 | The article/tutorial can be be read here: https://time2hack.com/2019/09/creating-rest-api-in-node-js-with-express-and-mysql/ 9 | 10 | You cna run this collection in Postman with following button: 11 | 12 | [![Run in Postman](https://run.pstmn.io/button.svg)](https://app.getpostman.com/run-collection/addfc209f1ab0fc6c873) 13 | 14 | ---- 15 | 16 | ![](./twitter-clone-postman.png) 17 | 18 | 19 | Or Download and import in Postman from here: Download 20 | 21 | ----- 22 | 23 | ```sql 24 | CREATE DATABASE twitter_clone; 25 | 26 | use twitter_clone; 27 | 28 | CREATE TABLE users( 29 | id int NOT NULL AUTO_INCREMENT, 30 | username varchar(15) NOT NULL, 31 | password varchar(32) NOT NULL, 32 | followers int DEFAULT 0, 33 | following int DEFAULT 0, 34 | tweets int DEFAULT 0, 35 | PRIMARY KEY (id) 36 | ); 37 | 38 | CREATE TABLE following( 39 | id int NOT NULL AUTO_INCREMENT, 40 | user1_id int REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 41 | user2_id int REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 42 | PRIMARY KEY (id) 43 | ); 44 | 45 | CREATE TABLE tweets( 46 | id int NOT NULL AUTO_INCREMENT, 47 | username varchar(15) NOT NULL, 48 | user_id int REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, 49 | tweet varchar(140) NOT NULL, 50 | timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 51 | PRIMARY KEY (id) 52 | ); 53 | 54 | INSERT INTO USERS(username, password) VALUE('pankaj', MD5('pankaj')); 55 | 56 | INSERT INTO USERS(username, password) VALUE('tim', MD5('tim')); 57 | 58 | INSERT INTO USERS(username, password) VALUE('jim', MD5('jim')); 59 | 60 | INSERT INTO TWEETS(username, user_id, tweet) VALUE('pankaj', 1, 'Hello World Again!'); 61 | 62 | INSERT INTO FOLLOWING(user1_id, user2_id) VALUE(1, 2); 63 | INSERT INTO FOLLOWING(user1_id, user2_id) VALUE(1, 3); 64 | INSERT INTO FOLLOWING(user1_id, user2_id) VALUE(3, 1); 65 | 66 | SELECT * FROM tweets; 67 | 68 | # Followers 69 | 70 | SELECT 71 | USER_INFO.*, username as user1_username 72 | FROM (SELECT 73 | user1_id, user2_id, username as user2_username 74 | FROM FOLLOWING LEFT JOIN USERS ON user2_id = users.id 75 | WHERE user1_id = 1) as USER_INFO 76 | LEFT JOIN USERS ON user1_id = users.id ; 77 | 78 | # Following 79 | 80 | SELECT 81 | USER_INFO.*, username as user1_username 82 | FROM (SELECT 83 | user1_id, user2_id, username as user2_username 84 | FROM FOLLOWING LEFT JOIN USERS ON user2_id = users.id 85 | WHERE user2_id = 1) as USER_INFO 86 | LEFT JOIN USERS ON user1_id = users.id ; 87 | ``` 88 | -------------------------------------------------------------------------------- /Twitter Clone.postman_collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": { 3 | "_postman_id": "78149020-40a3-4657-80a9-7683bdae2c78", 4 | "name": "Twitter Clone", 5 | "description": "This collection is created to help understand the Rest API creation on Node.js with Express and MySQL\n\nThe original article can be found here: https://time2hack.com/2019/09/creating-rest-api-in-node-js-with-express-and-mysql/", 6 | "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" 7 | }, 8 | "item": [ 9 | { 10 | "name": "Tweets", 11 | "item": [ 12 | { 13 | "name": "Feed", 14 | "request": { 15 | "method": "GET", 16 | "header": [], 17 | "url": { 18 | "raw": "{{url}}/tweets/feed", 19 | "host": [ 20 | "{{url}}" 21 | ], 22 | "path": [ 23 | "tweets", 24 | "feed" 25 | ] 26 | }, 27 | "description": "User's Feed" 28 | }, 29 | "response": [] 30 | }, 31 | { 32 | "name": "Tweet from Feed", 33 | "request": { 34 | "method": "GET", 35 | "header": [], 36 | "url": { 37 | "raw": "{{url}}/tweets/10", 38 | "host": [ 39 | "{{url}}" 40 | ], 41 | "path": [ 42 | "tweets", 43 | "10" 44 | ] 45 | }, 46 | "description": "Tweet from User's Feed" 47 | }, 48 | "response": [] 49 | } 50 | ], 51 | "protocolProfileBehavior": {} 52 | }, 53 | { 54 | "name": "User", 55 | "item": [ 56 | { 57 | "name": "Logged in User Profile", 58 | "request": { 59 | "method": "GET", 60 | "header": [], 61 | "url": { 62 | "raw": "{{url}}/user", 63 | "host": [ 64 | "{{url}}" 65 | ], 66 | "path": [ 67 | "user" 68 | ] 69 | } 70 | }, 71 | "response": [] 72 | }, 73 | { 74 | "name": "Get User's Followers", 75 | "request": { 76 | "method": "GET", 77 | "header": [], 78 | "url": { 79 | "raw": "{{url}}/user/followers", 80 | "host": [ 81 | "{{url}}" 82 | ], 83 | "path": [ 84 | "user", 85 | "followers" 86 | ] 87 | } 88 | }, 89 | "response": [] 90 | }, 91 | { 92 | "name": "Get Whom User is Following", 93 | "request": { 94 | "method": "GET", 95 | "header": [], 96 | "url": { 97 | "raw": "{{url}}/user/following", 98 | "host": [ 99 | "{{url}}" 100 | ], 101 | "path": [ 102 | "user", 103 | "following" 104 | ] 105 | } 106 | }, 107 | "response": [] 108 | }, 109 | { 110 | "name": "User Follow new Friend", 111 | "request": { 112 | "method": "POST", 113 | "header": [], 114 | "body": { 115 | "mode": "formdata", 116 | "formdata": [ 117 | { 118 | "key": "id", 119 | "value": "5", 120 | "type": "text" 121 | } 122 | ] 123 | }, 124 | "url": { 125 | "raw": "{{url}}/user/following", 126 | "host": [ 127 | "{{url}}" 128 | ], 129 | "path": [ 130 | "user", 131 | "following" 132 | ] 133 | } 134 | }, 135 | "response": [] 136 | }, 137 | { 138 | "name": "Get Settings", 139 | "request": { 140 | "method": "GET", 141 | "header": [], 142 | "url": { 143 | "raw": "{{url}}/user/settings", 144 | "host": [ 145 | "{{url}}" 146 | ], 147 | "path": [ 148 | "user", 149 | "settings" 150 | ] 151 | } 152 | }, 153 | "response": [] 154 | }, 155 | { 156 | "name": "Update Settings", 157 | "request": { 158 | "method": "PUT", 159 | "header": [], 160 | "body": { 161 | "mode": "formdata", 162 | "formdata": [ 163 | { 164 | "key": "email", 165 | "value": "true", 166 | "type": "text" 167 | }, 168 | { 169 | "key": "sms", 170 | "value": "false", 171 | "type": "text" 172 | } 173 | ] 174 | }, 175 | "url": { 176 | "raw": "{{url}}/user/settings", 177 | "host": [ 178 | "{{url}}" 179 | ], 180 | "path": [ 181 | "user", 182 | "settings" 183 | ] 184 | } 185 | }, 186 | "response": [] 187 | } 188 | ], 189 | "protocolProfileBehavior": {} 190 | }, 191 | { 192 | "name": "Register", 193 | "event": [ 194 | { 195 | "listen": "test", 196 | "script": { 197 | "id": "ed766847-6bde-48fa-9675-d2b1631814dc", 198 | "exec": [ 199 | "", 200 | "pm.test(\"Resposne has ID\", function () {", 201 | " var jsonData = pm.response.json();", 202 | " pm.expect(jsonData.id).to.not.eql(null);", 203 | "});", 204 | "pm.environment.set(\"user\", pm.response.json().id);", 205 | "" 206 | ], 207 | "type": "text/javascript" 208 | } 209 | } 210 | ], 211 | "request": { 212 | "method": "POST", 213 | "header": [ 214 | { 215 | "key": "Content-Type", 216 | "name": "Content-Type", 217 | "value": "application/x-www-form-urlencoded", 218 | "type": "text" 219 | } 220 | ], 221 | "body": { 222 | "mode": "urlencoded", 223 | "urlencoded": [ 224 | { 225 | "key": "username", 226 | "value": "r_{{$randomUserName}}", 227 | "type": "text" 228 | }, 229 | { 230 | "key": "password", 231 | "value": "random-password", 232 | "type": "text" 233 | } 234 | ] 235 | }, 236 | "url": { 237 | "raw": "{{url}}/auth/register", 238 | "host": [ 239 | "{{url}}" 240 | ], 241 | "path": [ 242 | "auth", 243 | "register" 244 | ] 245 | }, 246 | "description": "# Register New User\n---\n\n## Params\n\n`username`: `String`\n`password`: `String`\n\nReturns the new User's ID and Set's to Environment" 247 | }, 248 | "response": [] 249 | }, 250 | { 251 | "name": "Login", 252 | "event": [ 253 | { 254 | "listen": "test", 255 | "script": { 256 | "id": "6297fe46-d7b5-49f6-982f-5b0e0f467cc3", 257 | "exec": [ 258 | "", 259 | "pm.test(\"Resposne has ID\", function () {", 260 | " var jsonData = pm.response.json();", 261 | " pm.expect(jsonData.id).to.not.eql(null);", 262 | "});", 263 | "pm.environment.set(\"user\", pm.response.json().id);", 264 | "" 265 | ], 266 | "type": "text/javascript" 267 | } 268 | } 269 | ], 270 | "request": { 271 | "method": "POST", 272 | "header": [ 273 | { 274 | "key": "Content-Type", 275 | "name": "Content-Type", 276 | "value": "application/x-www-form-urlencoded", 277 | "type": "text" 278 | } 279 | ], 280 | "body": { 281 | "mode": "urlencoded", 282 | "urlencoded": [ 283 | { 284 | "key": "username", 285 | "value": "pankaj", 286 | "type": "text" 287 | }, 288 | { 289 | "key": "password", 290 | "value": "pankaj", 291 | "type": "text" 292 | } 293 | ] 294 | }, 295 | "url": { 296 | "raw": "{{url}}/auth/login", 297 | "host": [ 298 | "{{url}}" 299 | ], 300 | "path": [ 301 | "auth", 302 | "login" 303 | ] 304 | }, 305 | "description": "# Login\n---\n\n## Params\n\n`username`: `String`\n`password`: `String`\n\nReturns the User's ID and Set's to Environment" 306 | }, 307 | "response": [] 308 | } 309 | ], 310 | "event": [ 311 | { 312 | "listen": "prerequest", 313 | "script": { 314 | "id": "9f38fe7c-852d-47ea-94c0-a30a02fe80f1", 315 | "type": "text/javascript", 316 | "exec": [ 317 | "" 318 | ] 319 | } 320 | }, 321 | { 322 | "listen": "test", 323 | "script": { 324 | "id": "fbd831b3-89ea-4af7-9e1c-b34bd57dba5e", 325 | "type": "text/javascript", 326 | "exec": [ 327 | "" 328 | ] 329 | } 330 | } 331 | ], 332 | "variable": [ 333 | { 334 | "id": "163f6187-2a19-4028-b6d8-ec8709bc560b", 335 | "key": "url", 336 | "value": "http://localhost:3000", 337 | "type": "string" 338 | }, 339 | { 340 | "id": "974aa83a-3a22-483b-8363-e514a2742d5e", 341 | "key": "user", 342 | "value": "1", 343 | "type": "string" 344 | }, 345 | { 346 | "id": "ddcb6d1f-4270-4364-bdcf-5e75ec9afeb4", 347 | "key": "randomPassword", 348 | "value": "random-password", 349 | "type": "string" 350 | } 351 | ], 352 | "protocolProfileBehavior": {} 353 | } -------------------------------------------------------------------------------- /app-middlewares/auth.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const connection = require('../helpers/connection'); 3 | const query = require('../helpers/query'); 4 | 5 | const router = express.Router(); 6 | const dbConfig = require('../dbConfig'); 7 | 8 | const create = require('../crud/create'); 9 | 10 | router.post('/register', async (req, res) => { 11 | const { username, password } = req.body; 12 | const conn = await connection(dbConfig).catch(e => {}); 13 | const result = await create( 14 | conn, 15 | 'USERS', 16 | ['username', 'password'], 17 | [username, { toString: () => `MD5('${password}')`}] 18 | ); 19 | 20 | const [user = {}] = result; 21 | res.send({ 22 | id: user.id || null, 23 | username: user.username || null, 24 | }); 25 | }); 26 | 27 | router.post('/login', async (req, res) => { 28 | const { username, password } = req.body; 29 | const conn = await connection(dbConfig).catch(e => {}); 30 | const user = await query( 31 | conn, 32 | `SELECT id, username FROM USERS WHERE username=? AND password=MD5(?)`, 33 | [username, password] 34 | ); 35 | res.send(user[0] || { id: null, username: null }); 36 | }); 37 | 38 | module.exports = router; 39 | -------------------------------------------------------------------------------- /app-middlewares/tweets.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const connection = require('../helpers/connection'); 3 | const query = require('../helpers/query'); 4 | const feedQuery = require('../query-builders/feed-query'); 5 | const tweetQuery = require('../query-builders/tweet-query'); 6 | 7 | const router = express.Router(); 8 | const dbConfig = require('../dbConfig'); 9 | 10 | router.get('/feed', async (req, res) => { 11 | const user = 1; 12 | const pivot = null; 13 | const conn = await connection(dbConfig).catch(e => {}); 14 | const feed = await query(conn, feedQuery(user, pivot)) 15 | res.send(feed); 16 | }); 17 | 18 | router.get('/:id', async (req, res) => { 19 | const { id } = req.params; 20 | const conn = await connection(dbConfig).catch(e => {}); 21 | const tweet = await query(conn, tweetQuery(), [id]) 22 | res.send(tweet[0]); 23 | }); 24 | 25 | module.exports = router; 26 | -------------------------------------------------------------------------------- /app-middlewares/user.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const connection = require('../helpers/connection'); 3 | const query = require('../helpers/query'); 4 | 5 | const router = express.Router(); 6 | const dbConfig = require('../dbConfig'); 7 | 8 | // GET 9 | // /user 10 | router.get('/', async (req, res) => { 11 | const user = 1; 12 | const conn = await connection(dbConfig).catch(e => {}); 13 | const currentUser = await query(conn, `SELECT * FROM USERS 14 | WHERE id = ?`, [user]) 15 | res.send(currentUser[0]); 16 | }); 17 | 18 | // GET 19 | // /user/followers 20 | router.get('/followers', async (req, res) => { 21 | const user = 1; 22 | const conn = await connection(dbConfig).catch(e => {}); 23 | const followers = await query(conn, `SELECT 24 | USER_INFO.*, username as user1_username 25 | FROM (SELECT 26 | user1_id, user2_id, username as user2_username 27 | FROM FOLLOWING LEFT JOIN USERS ON user2_id = users.id 28 | WHERE user1_id = ?) as USER_INFO 29 | LEFT JOIN USERS ON user1_id = users.id`, [user]) 30 | res.send(followers); 31 | }); 32 | 33 | // GET 34 | // /user/following 35 | router.get('/following', async (req, res) => { 36 | const user = 1; 37 | const conn = await connection(dbConfig).catch(e => {}); 38 | const followers = await query(conn, `SELECT 39 | USER_INFO.*, username as user1_username 40 | FROM (SELECT 41 | user1_id, user2_id, username as user2_username 42 | FROM FOLLOWING LEFT JOIN USERS ON user2_id = users.id 43 | WHERE user2_id = ?) as USER_INFO 44 | LEFT JOIN USERS ON user1_id = users.id`, [user]) 45 | res.send(followers); 46 | }); 47 | 48 | // POST 49 | // /user/following 50 | router.post('/following', async (req, res) => { 51 | const user = 1; 52 | const { id } = req.params; 53 | const conn = await connection(dbConfig).catch(e => {}); 54 | const follow = await query(conn, `INSERT INTO FOLLOWING 55 | (user1_id, user2_id) 56 | VALUE (?, ?)`, [user, id]) 57 | res.send(follow); 58 | }); 59 | // GET 60 | // /user/settings 61 | router.get('/settings', async (req, res) => { 62 | const user = 1; 63 | const conn = await connection(dbConfig).catch(e => {}); 64 | const settings = await query(conn, `SELECT * FROM SETTINGS WHERE user_id = ?`, [user]) 65 | res.send(settings); 66 | }); 67 | 68 | // PUT 69 | // /user/settings 70 | router.put('/settings', async (req, res) => { 71 | const user = 1; 72 | const vals = req.body; 73 | const values = Object.keys(vals).map(k => `${k}=${vals[k]}`); 74 | const conn = await connection(dbConfig).catch(e => {}); 75 | const status = await query(conn, `UPDATE SETTINGS 76 | SET ? WHERE user_id = ?`, [values, user]) 77 | res.send(status); 78 | }); 79 | 80 | module.exports = router; 81 | -------------------------------------------------------------------------------- /crud/create.js: -------------------------------------------------------------------------------- 1 | const query = require('../helpers/query'); 2 | const valuesForQuery = require('../helpers/values-for-insert'); 3 | 4 | /** 5 | * @param {} conn MySQL Connection reference 6 | * @param {String} table Table to insert the values 7 | * @param {[String]} columns Array of column names 8 | * @param {[String]} values Array of values for those column names, can be multidientional 9 | */ 10 | module.exports = async (conn, table, columns, values) => { 11 | const VALUES = valuesForQuery(values) 12 | try { 13 | const user = await query(conn, `INSERT INTO ${table}(${columns.join(', ')}) VALUES ${VALUES};`); 14 | if (user.insertId) { 15 | console.log(user.insertId); 16 | return await query(conn, `SELECT * FROM ${table} WHERE ID=?`, [user.insertId]); 17 | } 18 | return user; 19 | } catch(e) { console.log(e)} 20 | } 21 | -------------------------------------------------------------------------------- /dbConfig.js: -------------------------------------------------------------------------------- 1 | const dotenv = require("dotenv") 2 | 3 | dotenv.config(); 4 | 5 | // Get the Host from Environment or use default 6 | const host = process.env.DB_HOST; 7 | 8 | // Get the User for DB from Environment or use default 9 | const user = process.env.DB_USER; 10 | 11 | // Get the Password for DB from Environment or use default 12 | const password = process.env.DB_PASS; 13 | 14 | // Get the Database from Environment or use default 15 | const database = process.env.DB_DATABASE; 16 | 17 | if(!host || !user || !password || !database) { 18 | console.error('Needed credentials not found! Please create .env file from .env.example and fill the values'); 19 | process.exit(1); 20 | } 21 | 22 | module.exports = { host, user, password, database }; 23 | -------------------------------------------------------------------------------- /helpers/connection.js: -------------------------------------------------------------------------------- 1 | const mysql = require('mysql'); 2 | 3 | module.exports = async (params) => new Promise( 4 | (resolve, reject) => { 5 | const connection = mysql.createConnection(params); 6 | connection.connect(error => { 7 | if (error) { 8 | reject(error); 9 | return; 10 | } 11 | resolve(connection); 12 | }) 13 | }); 14 | -------------------------------------------------------------------------------- /helpers/md5.js: -------------------------------------------------------------------------------- 1 | const md5 = require("nodejs-md5"); 2 | 3 | module.exports = (str) => new Promise((resolve, reject) => md5.string.quiet(str, (e, md5str) => { 4 | if (e) { 5 | reject(e); 6 | return; 7 | } 8 | resolve(md5str); 9 | })); 10 | -------------------------------------------------------------------------------- /helpers/query.js: -------------------------------------------------------------------------------- 1 | module.exports = async (conn, q, params) => new Promise( 2 | (resolve, reject) => { 3 | const handler = (error, result) => { 4 | if (error) { 5 | reject(error); 6 | return; 7 | } 8 | resolve(result); 9 | } 10 | conn.query(q, params, handler); 11 | }).catch(console.log); 12 | -------------------------------------------------------------------------------- /helpers/values-for-insert.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {[String]} values Array of values for those column names 3 | */ 4 | const valueForQuery = (_values) => { 5 | const values = _values.map(item => { 6 | let val; 7 | switch (typeof item) { 8 | case 'number': 9 | return item; 10 | case 'string': 11 | val = item; 12 | break; 13 | default: 14 | return item.toString(); 15 | } 16 | return `'${val}'`; 17 | }) 18 | return `(${values.join(', ')})`; 19 | }; 20 | 21 | /** 22 | * @param {[String]} values Array of values for those column names, can be multidientional 23 | */ 24 | const valuesForQuery = (values) => { 25 | const value = values[0]; 26 | let VALUES = ''; 27 | if (value instanceof Array) { 28 | VALUES = values.map(valueForQuery).join(', ') 29 | } else { 30 | VALUES = valueForQuery(values); 31 | } 32 | return VALUES; 33 | } 34 | 35 | module.exports = { 36 | valueForQuery, 37 | valuesForQuery, 38 | } 39 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-mysql", 3 | "version": "0.1.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "express-mysql", 9 | "version": "0.1.0", 10 | "dependencies": { 11 | "body-parser": "^1.20.1", 12 | "dotenv": "^8.1.0", 13 | "express": "^4.18.2", 14 | "mysql": "^2.17.1", 15 | "nodejs-md5": "^1.1.0" 16 | } 17 | }, 18 | "node_modules/accepts": { 19 | "version": "1.3.8", 20 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 21 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 22 | "dependencies": { 23 | "mime-types": "~2.1.34", 24 | "negotiator": "0.6.3" 25 | }, 26 | "engines": { 27 | "node": ">= 0.6" 28 | } 29 | }, 30 | "node_modules/array-flatten": { 31 | "version": "1.1.1", 32 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 33 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 34 | }, 35 | "node_modules/bignumber.js": { 36 | "version": "7.2.1", 37 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", 38 | "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==", 39 | "engines": { 40 | "node": "*" 41 | } 42 | }, 43 | "node_modules/body-parser": { 44 | "version": "1.20.1", 45 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", 46 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 47 | "dependencies": { 48 | "bytes": "3.1.2", 49 | "content-type": "~1.0.4", 50 | "debug": "2.6.9", 51 | "depd": "2.0.0", 52 | "destroy": "1.2.0", 53 | "http-errors": "2.0.0", 54 | "iconv-lite": "0.4.24", 55 | "on-finished": "2.4.1", 56 | "qs": "6.11.0", 57 | "raw-body": "2.5.1", 58 | "type-is": "~1.6.18", 59 | "unpipe": "1.0.0" 60 | }, 61 | "engines": { 62 | "node": ">= 0.8", 63 | "npm": "1.2.8000 || >= 1.4.16" 64 | } 65 | }, 66 | "node_modules/bytes": { 67 | "version": "3.1.2", 68 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 69 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", 70 | "engines": { 71 | "node": ">= 0.8" 72 | } 73 | }, 74 | "node_modules/call-bind": { 75 | "version": "1.0.2", 76 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 77 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 78 | "dependencies": { 79 | "function-bind": "^1.1.1", 80 | "get-intrinsic": "^1.0.2" 81 | }, 82 | "funding": { 83 | "url": "https://github.com/sponsors/ljharb" 84 | } 85 | }, 86 | "node_modules/content-disposition": { 87 | "version": "0.5.4", 88 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 89 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 90 | "dependencies": { 91 | "safe-buffer": "5.2.1" 92 | }, 93 | "engines": { 94 | "node": ">= 0.6" 95 | } 96 | }, 97 | "node_modules/content-disposition/node_modules/safe-buffer": { 98 | "version": "5.2.1", 99 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 100 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 101 | "funding": [ 102 | { 103 | "type": "github", 104 | "url": "https://github.com/sponsors/feross" 105 | }, 106 | { 107 | "type": "patreon", 108 | "url": "https://www.patreon.com/feross" 109 | }, 110 | { 111 | "type": "consulting", 112 | "url": "https://feross.org/support" 113 | } 114 | ] 115 | }, 116 | "node_modules/content-type": { 117 | "version": "1.0.4", 118 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 119 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", 120 | "engines": { 121 | "node": ">= 0.6" 122 | } 123 | }, 124 | "node_modules/cookie": { 125 | "version": "0.5.0", 126 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 127 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", 128 | "engines": { 129 | "node": ">= 0.6" 130 | } 131 | }, 132 | "node_modules/cookie-signature": { 133 | "version": "1.0.6", 134 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 135 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 136 | }, 137 | "node_modules/core-util-is": { 138 | "version": "1.0.2", 139 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 140 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 141 | }, 142 | "node_modules/debug": { 143 | "version": "2.6.9", 144 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 145 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 146 | "dependencies": { 147 | "ms": "2.0.0" 148 | } 149 | }, 150 | "node_modules/depd": { 151 | "version": "2.0.0", 152 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 153 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", 154 | "engines": { 155 | "node": ">= 0.8" 156 | } 157 | }, 158 | "node_modules/destroy": { 159 | "version": "1.2.0", 160 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 161 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", 162 | "engines": { 163 | "node": ">= 0.8", 164 | "npm": "1.2.8000 || >= 1.4.16" 165 | } 166 | }, 167 | "node_modules/diff_match_patch": { 168 | "version": "0.1.1", 169 | "resolved": "https://registry.npmjs.org/diff_match_patch/-/diff_match_patch-0.1.1.tgz", 170 | "integrity": "sha1-0/FNW3b7S1qc9EcGJh2ttb2X7bw=", 171 | "engines": { 172 | "node": "*" 173 | } 174 | }, 175 | "node_modules/dotenv": { 176 | "version": "8.1.0", 177 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz", 178 | "integrity": "sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA==", 179 | "engines": { 180 | "node": ">=8" 181 | } 182 | }, 183 | "node_modules/ee-first": { 184 | "version": "1.1.1", 185 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 186 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 187 | }, 188 | "node_modules/encodeurl": { 189 | "version": "1.0.2", 190 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 191 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", 192 | "engines": { 193 | "node": ">= 0.8" 194 | } 195 | }, 196 | "node_modules/escape-html": { 197 | "version": "1.0.3", 198 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 199 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 200 | }, 201 | "node_modules/etag": { 202 | "version": "1.8.1", 203 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 204 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", 205 | "engines": { 206 | "node": ">= 0.6" 207 | } 208 | }, 209 | "node_modules/exceptions": { 210 | "version": "0.1.1", 211 | "resolved": "https://registry.npmjs.org/exceptions/-/exceptions-0.1.1.tgz", 212 | "integrity": "sha1-twOQB5XCjwetadusX2h4b5RWIbI=", 213 | "dependencies": { 214 | "formaterrors": "0.1.1" 215 | }, 216 | "engines": { 217 | "node": "*" 218 | } 219 | }, 220 | "node_modules/express": { 221 | "version": "4.18.2", 222 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", 223 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 224 | "dependencies": { 225 | "accepts": "~1.3.8", 226 | "array-flatten": "1.1.1", 227 | "body-parser": "1.20.1", 228 | "content-disposition": "0.5.4", 229 | "content-type": "~1.0.4", 230 | "cookie": "0.5.0", 231 | "cookie-signature": "1.0.6", 232 | "debug": "2.6.9", 233 | "depd": "2.0.0", 234 | "encodeurl": "~1.0.2", 235 | "escape-html": "~1.0.3", 236 | "etag": "~1.8.1", 237 | "finalhandler": "1.2.0", 238 | "fresh": "0.5.2", 239 | "http-errors": "2.0.0", 240 | "merge-descriptors": "1.0.1", 241 | "methods": "~1.1.2", 242 | "on-finished": "2.4.1", 243 | "parseurl": "~1.3.3", 244 | "path-to-regexp": "0.1.7", 245 | "proxy-addr": "~2.0.7", 246 | "qs": "6.11.0", 247 | "range-parser": "~1.2.1", 248 | "safe-buffer": "5.2.1", 249 | "send": "0.18.0", 250 | "serve-static": "1.15.0", 251 | "setprototypeof": "1.2.0", 252 | "statuses": "2.0.1", 253 | "type-is": "~1.6.18", 254 | "utils-merge": "1.0.1", 255 | "vary": "~1.1.2" 256 | }, 257 | "engines": { 258 | "node": ">= 0.10.0" 259 | } 260 | }, 261 | "node_modules/express/node_modules/safe-buffer": { 262 | "version": "5.2.1", 263 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 264 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 265 | "funding": [ 266 | { 267 | "type": "github", 268 | "url": "https://github.com/sponsors/feross" 269 | }, 270 | { 271 | "type": "patreon", 272 | "url": "https://www.patreon.com/feross" 273 | }, 274 | { 275 | "type": "consulting", 276 | "url": "https://feross.org/support" 277 | } 278 | ] 279 | }, 280 | "node_modules/finalhandler": { 281 | "version": "1.2.0", 282 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 283 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 284 | "dependencies": { 285 | "debug": "2.6.9", 286 | "encodeurl": "~1.0.2", 287 | "escape-html": "~1.0.3", 288 | "on-finished": "2.4.1", 289 | "parseurl": "~1.3.3", 290 | "statuses": "2.0.1", 291 | "unpipe": "~1.0.0" 292 | }, 293 | "engines": { 294 | "node": ">= 0.8" 295 | } 296 | }, 297 | "node_modules/formaterrors": { 298 | "version": "0.1.1", 299 | "resolved": "https://registry.npmjs.org/formaterrors/-/formaterrors-0.1.1.tgz", 300 | "integrity": "sha1-fjZz5HTfeoOXE5KBgpNito/ODes=", 301 | "dependencies": { 302 | "diff_match_patch": "0.1.1", 303 | "stack-trace": "0.0.6" 304 | }, 305 | "engines": { 306 | "node": "*" 307 | } 308 | }, 309 | "node_modules/forwarded": { 310 | "version": "0.2.0", 311 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 312 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", 313 | "engines": { 314 | "node": ">= 0.6" 315 | } 316 | }, 317 | "node_modules/fresh": { 318 | "version": "0.5.2", 319 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 320 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", 321 | "engines": { 322 | "node": ">= 0.6" 323 | } 324 | }, 325 | "node_modules/fs": { 326 | "version": "0.0.1-security", 327 | "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", 328 | "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=" 329 | }, 330 | "node_modules/function-bind": { 331 | "version": "1.1.1", 332 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 333 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 334 | }, 335 | "node_modules/get-intrinsic": { 336 | "version": "1.1.3", 337 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 338 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 339 | "dependencies": { 340 | "function-bind": "^1.1.1", 341 | "has": "^1.0.3", 342 | "has-symbols": "^1.0.3" 343 | }, 344 | "funding": { 345 | "url": "https://github.com/sponsors/ljharb" 346 | } 347 | }, 348 | "node_modules/has": { 349 | "version": "1.0.3", 350 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 351 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 352 | "dependencies": { 353 | "function-bind": "^1.1.1" 354 | }, 355 | "engines": { 356 | "node": ">= 0.4.0" 357 | } 358 | }, 359 | "node_modules/has-symbols": { 360 | "version": "1.0.3", 361 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 362 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 363 | "engines": { 364 | "node": ">= 0.4" 365 | }, 366 | "funding": { 367 | "url": "https://github.com/sponsors/ljharb" 368 | } 369 | }, 370 | "node_modules/http-errors": { 371 | "version": "2.0.0", 372 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 373 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 374 | "dependencies": { 375 | "depd": "2.0.0", 376 | "inherits": "2.0.4", 377 | "setprototypeof": "1.2.0", 378 | "statuses": "2.0.1", 379 | "toidentifier": "1.0.1" 380 | }, 381 | "engines": { 382 | "node": ">= 0.8" 383 | } 384 | }, 385 | "node_modules/http-errors/node_modules/inherits": { 386 | "version": "2.0.4", 387 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 388 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 389 | }, 390 | "node_modules/iconv-lite": { 391 | "version": "0.4.24", 392 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 393 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 394 | "dependencies": { 395 | "safer-buffer": ">= 2.1.2 < 3" 396 | }, 397 | "engines": { 398 | "node": ">=0.10.0" 399 | } 400 | }, 401 | "node_modules/inherits": { 402 | "version": "2.0.3", 403 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 404 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 405 | }, 406 | "node_modules/ipaddr.js": { 407 | "version": "1.9.1", 408 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 409 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", 410 | "engines": { 411 | "node": ">= 0.10" 412 | } 413 | }, 414 | "node_modules/isarray": { 415 | "version": "1.0.0", 416 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 417 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 418 | }, 419 | "node_modules/media-typer": { 420 | "version": "0.3.0", 421 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 422 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", 423 | "engines": { 424 | "node": ">= 0.6" 425 | } 426 | }, 427 | "node_modules/merge-descriptors": { 428 | "version": "1.0.1", 429 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 430 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 431 | }, 432 | "node_modules/methods": { 433 | "version": "1.1.2", 434 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 435 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", 436 | "engines": { 437 | "node": ">= 0.6" 438 | } 439 | }, 440 | "node_modules/mime": { 441 | "version": "1.6.0", 442 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 443 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 444 | "bin": { 445 | "mime": "cli.js" 446 | }, 447 | "engines": { 448 | "node": ">=4" 449 | } 450 | }, 451 | "node_modules/mime-db": { 452 | "version": "1.52.0", 453 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 454 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 455 | "engines": { 456 | "node": ">= 0.6" 457 | } 458 | }, 459 | "node_modules/mime-types": { 460 | "version": "2.1.35", 461 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 462 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 463 | "dependencies": { 464 | "mime-db": "1.52.0" 465 | }, 466 | "engines": { 467 | "node": ">= 0.6" 468 | } 469 | }, 470 | "node_modules/ms": { 471 | "version": "2.0.0", 472 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 473 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 474 | }, 475 | "node_modules/mysql": { 476 | "version": "2.17.1", 477 | "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.17.1.tgz", 478 | "integrity": "sha512-7vMqHQ673SAk5C8fOzTG2LpPcf3bNt0oL3sFpxPEEFp1mdlDcrLK0On7z8ZYKaaHrHwNcQ/MTUz7/oobZ2OyyA==", 479 | "dependencies": { 480 | "bignumber.js": "7.2.1", 481 | "readable-stream": "2.3.6", 482 | "safe-buffer": "5.1.2", 483 | "sqlstring": "2.3.1" 484 | }, 485 | "engines": { 486 | "node": ">= 0.6" 487 | } 488 | }, 489 | "node_modules/negotiator": { 490 | "version": "0.6.3", 491 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 492 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", 493 | "engines": { 494 | "node": ">= 0.6" 495 | } 496 | }, 497 | "node_modules/nodejs-md5": { 498 | "version": "1.1.0", 499 | "resolved": "https://registry.npmjs.org/nodejs-md5/-/nodejs-md5-1.1.0.tgz", 500 | "integrity": "sha512-U4oSRfiATjfqBM37c5MBSo7JyLnHcWsD4xvyMUJw4AdPCOg0aMvB40M8H50yvHLMbPokY7HufPPokEJw+AwlpQ==", 501 | "dependencies": { 502 | "exceptions": "latest", 503 | "fs": "latest" 504 | } 505 | }, 506 | "node_modules/object-inspect": { 507 | "version": "1.12.2", 508 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 509 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", 510 | "funding": { 511 | "url": "https://github.com/sponsors/ljharb" 512 | } 513 | }, 514 | "node_modules/on-finished": { 515 | "version": "2.4.1", 516 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 517 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 518 | "dependencies": { 519 | "ee-first": "1.1.1" 520 | }, 521 | "engines": { 522 | "node": ">= 0.8" 523 | } 524 | }, 525 | "node_modules/parseurl": { 526 | "version": "1.3.3", 527 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 528 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", 529 | "engines": { 530 | "node": ">= 0.8" 531 | } 532 | }, 533 | "node_modules/path-to-regexp": { 534 | "version": "0.1.7", 535 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 536 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 537 | }, 538 | "node_modules/process-nextick-args": { 539 | "version": "2.0.1", 540 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 541 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 542 | }, 543 | "node_modules/proxy-addr": { 544 | "version": "2.0.7", 545 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 546 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 547 | "dependencies": { 548 | "forwarded": "0.2.0", 549 | "ipaddr.js": "1.9.1" 550 | }, 551 | "engines": { 552 | "node": ">= 0.10" 553 | } 554 | }, 555 | "node_modules/qs": { 556 | "version": "6.11.0", 557 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 558 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 559 | "dependencies": { 560 | "side-channel": "^1.0.4" 561 | }, 562 | "engines": { 563 | "node": ">=0.6" 564 | }, 565 | "funding": { 566 | "url": "https://github.com/sponsors/ljharb" 567 | } 568 | }, 569 | "node_modules/range-parser": { 570 | "version": "1.2.1", 571 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 572 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", 573 | "engines": { 574 | "node": ">= 0.6" 575 | } 576 | }, 577 | "node_modules/raw-body": { 578 | "version": "2.5.1", 579 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 580 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 581 | "dependencies": { 582 | "bytes": "3.1.2", 583 | "http-errors": "2.0.0", 584 | "iconv-lite": "0.4.24", 585 | "unpipe": "1.0.0" 586 | }, 587 | "engines": { 588 | "node": ">= 0.8" 589 | } 590 | }, 591 | "node_modules/readable-stream": { 592 | "version": "2.3.6", 593 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 594 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 595 | "dependencies": { 596 | "core-util-is": "~1.0.0", 597 | "inherits": "~2.0.3", 598 | "isarray": "~1.0.0", 599 | "process-nextick-args": "~2.0.0", 600 | "safe-buffer": "~5.1.1", 601 | "string_decoder": "~1.1.1", 602 | "util-deprecate": "~1.0.1" 603 | } 604 | }, 605 | "node_modules/safe-buffer": { 606 | "version": "5.1.2", 607 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 608 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 609 | }, 610 | "node_modules/safer-buffer": { 611 | "version": "2.1.2", 612 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 613 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 614 | }, 615 | "node_modules/send": { 616 | "version": "0.18.0", 617 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 618 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 619 | "dependencies": { 620 | "debug": "2.6.9", 621 | "depd": "2.0.0", 622 | "destroy": "1.2.0", 623 | "encodeurl": "~1.0.2", 624 | "escape-html": "~1.0.3", 625 | "etag": "~1.8.1", 626 | "fresh": "0.5.2", 627 | "http-errors": "2.0.0", 628 | "mime": "1.6.0", 629 | "ms": "2.1.3", 630 | "on-finished": "2.4.1", 631 | "range-parser": "~1.2.1", 632 | "statuses": "2.0.1" 633 | }, 634 | "engines": { 635 | "node": ">= 0.8.0" 636 | } 637 | }, 638 | "node_modules/send/node_modules/ms": { 639 | "version": "2.1.3", 640 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 641 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 642 | }, 643 | "node_modules/serve-static": { 644 | "version": "1.15.0", 645 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 646 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 647 | "dependencies": { 648 | "encodeurl": "~1.0.2", 649 | "escape-html": "~1.0.3", 650 | "parseurl": "~1.3.3", 651 | "send": "0.18.0" 652 | }, 653 | "engines": { 654 | "node": ">= 0.8.0" 655 | } 656 | }, 657 | "node_modules/setprototypeof": { 658 | "version": "1.2.0", 659 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 660 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 661 | }, 662 | "node_modules/side-channel": { 663 | "version": "1.0.4", 664 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 665 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 666 | "dependencies": { 667 | "call-bind": "^1.0.0", 668 | "get-intrinsic": "^1.0.2", 669 | "object-inspect": "^1.9.0" 670 | }, 671 | "funding": { 672 | "url": "https://github.com/sponsors/ljharb" 673 | } 674 | }, 675 | "node_modules/sqlstring": { 676 | "version": "2.3.1", 677 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", 678 | "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=", 679 | "engines": { 680 | "node": ">= 0.6" 681 | } 682 | }, 683 | "node_modules/stack-trace": { 684 | "version": "0.0.6", 685 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.6.tgz", 686 | "integrity": "sha1-HnGb1qJin/CcGJ4Xqe+QKpT8XbA=", 687 | "engines": { 688 | "node": "*" 689 | } 690 | }, 691 | "node_modules/statuses": { 692 | "version": "2.0.1", 693 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 694 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", 695 | "engines": { 696 | "node": ">= 0.8" 697 | } 698 | }, 699 | "node_modules/string_decoder": { 700 | "version": "1.1.1", 701 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 702 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 703 | "dependencies": { 704 | "safe-buffer": "~5.1.0" 705 | } 706 | }, 707 | "node_modules/toidentifier": { 708 | "version": "1.0.1", 709 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 710 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", 711 | "engines": { 712 | "node": ">=0.6" 713 | } 714 | }, 715 | "node_modules/type-is": { 716 | "version": "1.6.18", 717 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 718 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 719 | "dependencies": { 720 | "media-typer": "0.3.0", 721 | "mime-types": "~2.1.24" 722 | }, 723 | "engines": { 724 | "node": ">= 0.6" 725 | } 726 | }, 727 | "node_modules/unpipe": { 728 | "version": "1.0.0", 729 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 730 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", 731 | "engines": { 732 | "node": ">= 0.8" 733 | } 734 | }, 735 | "node_modules/util-deprecate": { 736 | "version": "1.0.2", 737 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 738 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 739 | }, 740 | "node_modules/utils-merge": { 741 | "version": "1.0.1", 742 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 743 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", 744 | "engines": { 745 | "node": ">= 0.4.0" 746 | } 747 | }, 748 | "node_modules/vary": { 749 | "version": "1.1.2", 750 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 751 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", 752 | "engines": { 753 | "node": ">= 0.8" 754 | } 755 | } 756 | }, 757 | "dependencies": { 758 | "accepts": { 759 | "version": "1.3.8", 760 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", 761 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", 762 | "requires": { 763 | "mime-types": "~2.1.34", 764 | "negotiator": "0.6.3" 765 | } 766 | }, 767 | "array-flatten": { 768 | "version": "1.1.1", 769 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 770 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" 771 | }, 772 | "bignumber.js": { 773 | "version": "7.2.1", 774 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", 775 | "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" 776 | }, 777 | "body-parser": { 778 | "version": "1.20.1", 779 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", 780 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", 781 | "requires": { 782 | "bytes": "3.1.2", 783 | "content-type": "~1.0.4", 784 | "debug": "2.6.9", 785 | "depd": "2.0.0", 786 | "destroy": "1.2.0", 787 | "http-errors": "2.0.0", 788 | "iconv-lite": "0.4.24", 789 | "on-finished": "2.4.1", 790 | "qs": "6.11.0", 791 | "raw-body": "2.5.1", 792 | "type-is": "~1.6.18", 793 | "unpipe": "1.0.0" 794 | } 795 | }, 796 | "bytes": { 797 | "version": "3.1.2", 798 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", 799 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" 800 | }, 801 | "call-bind": { 802 | "version": "1.0.2", 803 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", 804 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", 805 | "requires": { 806 | "function-bind": "^1.1.1", 807 | "get-intrinsic": "^1.0.2" 808 | } 809 | }, 810 | "content-disposition": { 811 | "version": "0.5.4", 812 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", 813 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", 814 | "requires": { 815 | "safe-buffer": "5.2.1" 816 | }, 817 | "dependencies": { 818 | "safe-buffer": { 819 | "version": "5.2.1", 820 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 821 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 822 | } 823 | } 824 | }, 825 | "content-type": { 826 | "version": "1.0.4", 827 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 828 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 829 | }, 830 | "cookie": { 831 | "version": "0.5.0", 832 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", 833 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" 834 | }, 835 | "cookie-signature": { 836 | "version": "1.0.6", 837 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 838 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" 839 | }, 840 | "core-util-is": { 841 | "version": "1.0.2", 842 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 843 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 844 | }, 845 | "debug": { 846 | "version": "2.6.9", 847 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 848 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 849 | "requires": { 850 | "ms": "2.0.0" 851 | } 852 | }, 853 | "depd": { 854 | "version": "2.0.0", 855 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 856 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" 857 | }, 858 | "destroy": { 859 | "version": "1.2.0", 860 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", 861 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" 862 | }, 863 | "diff_match_patch": { 864 | "version": "0.1.1", 865 | "resolved": "https://registry.npmjs.org/diff_match_patch/-/diff_match_patch-0.1.1.tgz", 866 | "integrity": "sha1-0/FNW3b7S1qc9EcGJh2ttb2X7bw=" 867 | }, 868 | "dotenv": { 869 | "version": "8.1.0", 870 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz", 871 | "integrity": "sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA==" 872 | }, 873 | "ee-first": { 874 | "version": "1.1.1", 875 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 876 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" 877 | }, 878 | "encodeurl": { 879 | "version": "1.0.2", 880 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 881 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" 882 | }, 883 | "escape-html": { 884 | "version": "1.0.3", 885 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 886 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" 887 | }, 888 | "etag": { 889 | "version": "1.8.1", 890 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 891 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" 892 | }, 893 | "exceptions": { 894 | "version": "0.1.1", 895 | "resolved": "https://registry.npmjs.org/exceptions/-/exceptions-0.1.1.tgz", 896 | "integrity": "sha1-twOQB5XCjwetadusX2h4b5RWIbI=", 897 | "requires": { 898 | "formaterrors": "0.1.1" 899 | } 900 | }, 901 | "express": { 902 | "version": "4.18.2", 903 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", 904 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", 905 | "requires": { 906 | "accepts": "~1.3.8", 907 | "array-flatten": "1.1.1", 908 | "body-parser": "1.20.1", 909 | "content-disposition": "0.5.4", 910 | "content-type": "~1.0.4", 911 | "cookie": "0.5.0", 912 | "cookie-signature": "1.0.6", 913 | "debug": "2.6.9", 914 | "depd": "2.0.0", 915 | "encodeurl": "~1.0.2", 916 | "escape-html": "~1.0.3", 917 | "etag": "~1.8.1", 918 | "finalhandler": "1.2.0", 919 | "fresh": "0.5.2", 920 | "http-errors": "2.0.0", 921 | "merge-descriptors": "1.0.1", 922 | "methods": "~1.1.2", 923 | "on-finished": "2.4.1", 924 | "parseurl": "~1.3.3", 925 | "path-to-regexp": "0.1.7", 926 | "proxy-addr": "~2.0.7", 927 | "qs": "6.11.0", 928 | "range-parser": "~1.2.1", 929 | "safe-buffer": "5.2.1", 930 | "send": "0.18.0", 931 | "serve-static": "1.15.0", 932 | "setprototypeof": "1.2.0", 933 | "statuses": "2.0.1", 934 | "type-is": "~1.6.18", 935 | "utils-merge": "1.0.1", 936 | "vary": "~1.1.2" 937 | }, 938 | "dependencies": { 939 | "safe-buffer": { 940 | "version": "5.2.1", 941 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 942 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 943 | } 944 | } 945 | }, 946 | "finalhandler": { 947 | "version": "1.2.0", 948 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", 949 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", 950 | "requires": { 951 | "debug": "2.6.9", 952 | "encodeurl": "~1.0.2", 953 | "escape-html": "~1.0.3", 954 | "on-finished": "2.4.1", 955 | "parseurl": "~1.3.3", 956 | "statuses": "2.0.1", 957 | "unpipe": "~1.0.0" 958 | } 959 | }, 960 | "formaterrors": { 961 | "version": "0.1.1", 962 | "resolved": "https://registry.npmjs.org/formaterrors/-/formaterrors-0.1.1.tgz", 963 | "integrity": "sha1-fjZz5HTfeoOXE5KBgpNito/ODes=", 964 | "requires": { 965 | "diff_match_patch": "0.1.1", 966 | "stack-trace": "0.0.6" 967 | } 968 | }, 969 | "forwarded": { 970 | "version": "0.2.0", 971 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", 972 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" 973 | }, 974 | "fresh": { 975 | "version": "0.5.2", 976 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 977 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" 978 | }, 979 | "fs": { 980 | "version": "0.0.1-security", 981 | "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", 982 | "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=" 983 | }, 984 | "function-bind": { 985 | "version": "1.1.1", 986 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 987 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 988 | }, 989 | "get-intrinsic": { 990 | "version": "1.1.3", 991 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 992 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 993 | "requires": { 994 | "function-bind": "^1.1.1", 995 | "has": "^1.0.3", 996 | "has-symbols": "^1.0.3" 997 | } 998 | }, 999 | "has": { 1000 | "version": "1.0.3", 1001 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1002 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1003 | "requires": { 1004 | "function-bind": "^1.1.1" 1005 | } 1006 | }, 1007 | "has-symbols": { 1008 | "version": "1.0.3", 1009 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 1010 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" 1011 | }, 1012 | "http-errors": { 1013 | "version": "2.0.0", 1014 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", 1015 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", 1016 | "requires": { 1017 | "depd": "2.0.0", 1018 | "inherits": "2.0.4", 1019 | "setprototypeof": "1.2.0", 1020 | "statuses": "2.0.1", 1021 | "toidentifier": "1.0.1" 1022 | }, 1023 | "dependencies": { 1024 | "inherits": { 1025 | "version": "2.0.4", 1026 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1027 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1028 | } 1029 | } 1030 | }, 1031 | "iconv-lite": { 1032 | "version": "0.4.24", 1033 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 1034 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 1035 | "requires": { 1036 | "safer-buffer": ">= 2.1.2 < 3" 1037 | } 1038 | }, 1039 | "inherits": { 1040 | "version": "2.0.3", 1041 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1042 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 1043 | }, 1044 | "ipaddr.js": { 1045 | "version": "1.9.1", 1046 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", 1047 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" 1048 | }, 1049 | "isarray": { 1050 | "version": "1.0.0", 1051 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1052 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 1053 | }, 1054 | "media-typer": { 1055 | "version": "0.3.0", 1056 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 1057 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" 1058 | }, 1059 | "merge-descriptors": { 1060 | "version": "1.0.1", 1061 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 1062 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" 1063 | }, 1064 | "methods": { 1065 | "version": "1.1.2", 1066 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 1067 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" 1068 | }, 1069 | "mime": { 1070 | "version": "1.6.0", 1071 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 1072 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 1073 | }, 1074 | "mime-db": { 1075 | "version": "1.52.0", 1076 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 1077 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" 1078 | }, 1079 | "mime-types": { 1080 | "version": "2.1.35", 1081 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 1082 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 1083 | "requires": { 1084 | "mime-db": "1.52.0" 1085 | } 1086 | }, 1087 | "ms": { 1088 | "version": "2.0.0", 1089 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1090 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" 1091 | }, 1092 | "mysql": { 1093 | "version": "2.17.1", 1094 | "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.17.1.tgz", 1095 | "integrity": "sha512-7vMqHQ673SAk5C8fOzTG2LpPcf3bNt0oL3sFpxPEEFp1mdlDcrLK0On7z8ZYKaaHrHwNcQ/MTUz7/oobZ2OyyA==", 1096 | "requires": { 1097 | "bignumber.js": "7.2.1", 1098 | "readable-stream": "2.3.6", 1099 | "safe-buffer": "5.1.2", 1100 | "sqlstring": "2.3.1" 1101 | } 1102 | }, 1103 | "negotiator": { 1104 | "version": "0.6.3", 1105 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", 1106 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" 1107 | }, 1108 | "nodejs-md5": { 1109 | "version": "1.1.0", 1110 | "resolved": "https://registry.npmjs.org/nodejs-md5/-/nodejs-md5-1.1.0.tgz", 1111 | "integrity": "sha512-U4oSRfiATjfqBM37c5MBSo7JyLnHcWsD4xvyMUJw4AdPCOg0aMvB40M8H50yvHLMbPokY7HufPPokEJw+AwlpQ==", 1112 | "requires": { 1113 | "exceptions": "latest", 1114 | "fs": "latest" 1115 | } 1116 | }, 1117 | "object-inspect": { 1118 | "version": "1.12.2", 1119 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", 1120 | "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" 1121 | }, 1122 | "on-finished": { 1123 | "version": "2.4.1", 1124 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", 1125 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", 1126 | "requires": { 1127 | "ee-first": "1.1.1" 1128 | } 1129 | }, 1130 | "parseurl": { 1131 | "version": "1.3.3", 1132 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 1133 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 1134 | }, 1135 | "path-to-regexp": { 1136 | "version": "0.1.7", 1137 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 1138 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" 1139 | }, 1140 | "process-nextick-args": { 1141 | "version": "2.0.1", 1142 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 1143 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" 1144 | }, 1145 | "proxy-addr": { 1146 | "version": "2.0.7", 1147 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", 1148 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", 1149 | "requires": { 1150 | "forwarded": "0.2.0", 1151 | "ipaddr.js": "1.9.1" 1152 | } 1153 | }, 1154 | "qs": { 1155 | "version": "6.11.0", 1156 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", 1157 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", 1158 | "requires": { 1159 | "side-channel": "^1.0.4" 1160 | } 1161 | }, 1162 | "range-parser": { 1163 | "version": "1.2.1", 1164 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 1165 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 1166 | }, 1167 | "raw-body": { 1168 | "version": "2.5.1", 1169 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", 1170 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", 1171 | "requires": { 1172 | "bytes": "3.1.2", 1173 | "http-errors": "2.0.0", 1174 | "iconv-lite": "0.4.24", 1175 | "unpipe": "1.0.0" 1176 | } 1177 | }, 1178 | "readable-stream": { 1179 | "version": "2.3.6", 1180 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 1181 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 1182 | "requires": { 1183 | "core-util-is": "~1.0.0", 1184 | "inherits": "~2.0.3", 1185 | "isarray": "~1.0.0", 1186 | "process-nextick-args": "~2.0.0", 1187 | "safe-buffer": "~5.1.1", 1188 | "string_decoder": "~1.1.1", 1189 | "util-deprecate": "~1.0.1" 1190 | } 1191 | }, 1192 | "safe-buffer": { 1193 | "version": "5.1.2", 1194 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1195 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1196 | }, 1197 | "safer-buffer": { 1198 | "version": "2.1.2", 1199 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1200 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1201 | }, 1202 | "send": { 1203 | "version": "0.18.0", 1204 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", 1205 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", 1206 | "requires": { 1207 | "debug": "2.6.9", 1208 | "depd": "2.0.0", 1209 | "destroy": "1.2.0", 1210 | "encodeurl": "~1.0.2", 1211 | "escape-html": "~1.0.3", 1212 | "etag": "~1.8.1", 1213 | "fresh": "0.5.2", 1214 | "http-errors": "2.0.0", 1215 | "mime": "1.6.0", 1216 | "ms": "2.1.3", 1217 | "on-finished": "2.4.1", 1218 | "range-parser": "~1.2.1", 1219 | "statuses": "2.0.1" 1220 | }, 1221 | "dependencies": { 1222 | "ms": { 1223 | "version": "2.1.3", 1224 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1225 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 1226 | } 1227 | } 1228 | }, 1229 | "serve-static": { 1230 | "version": "1.15.0", 1231 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", 1232 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", 1233 | "requires": { 1234 | "encodeurl": "~1.0.2", 1235 | "escape-html": "~1.0.3", 1236 | "parseurl": "~1.3.3", 1237 | "send": "0.18.0" 1238 | } 1239 | }, 1240 | "setprototypeof": { 1241 | "version": "1.2.0", 1242 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", 1243 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" 1244 | }, 1245 | "side-channel": { 1246 | "version": "1.0.4", 1247 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", 1248 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", 1249 | "requires": { 1250 | "call-bind": "^1.0.0", 1251 | "get-intrinsic": "^1.0.2", 1252 | "object-inspect": "^1.9.0" 1253 | } 1254 | }, 1255 | "sqlstring": { 1256 | "version": "2.3.1", 1257 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", 1258 | "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" 1259 | }, 1260 | "stack-trace": { 1261 | "version": "0.0.6", 1262 | "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.6.tgz", 1263 | "integrity": "sha1-HnGb1qJin/CcGJ4Xqe+QKpT8XbA=" 1264 | }, 1265 | "statuses": { 1266 | "version": "2.0.1", 1267 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", 1268 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" 1269 | }, 1270 | "string_decoder": { 1271 | "version": "1.1.1", 1272 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1273 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1274 | "requires": { 1275 | "safe-buffer": "~5.1.0" 1276 | } 1277 | }, 1278 | "toidentifier": { 1279 | "version": "1.0.1", 1280 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", 1281 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" 1282 | }, 1283 | "type-is": { 1284 | "version": "1.6.18", 1285 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 1286 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 1287 | "requires": { 1288 | "media-typer": "0.3.0", 1289 | "mime-types": "~2.1.24" 1290 | } 1291 | }, 1292 | "unpipe": { 1293 | "version": "1.0.0", 1294 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1295 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" 1296 | }, 1297 | "util-deprecate": { 1298 | "version": "1.0.2", 1299 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1300 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1301 | }, 1302 | "utils-merge": { 1303 | "version": "1.0.1", 1304 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1305 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" 1306 | }, 1307 | "vary": { 1308 | "version": "1.1.2", 1309 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1310 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" 1311 | } 1312 | } 1313 | } 1314 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-mysql", 3 | "version": "0.1.0", 4 | "private": true, 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/time2hack/express-mysql.git" 12 | }, 13 | "keywords": [ 14 | "express", 15 | "mysql", 16 | "time2hack" 17 | ], 18 | "author": "", 19 | "bugs": { 20 | "url": "https://github.com/time2hack/express-mysql/issues" 21 | }, 22 | "homepage": "https://github.com/time2hack/express-mysql#readme", 23 | "dependencies": { 24 | "body-parser": "^1.20.1", 25 | "dotenv": "^8.1.0", 26 | "express": "^4.18.2", 27 | "mysql": "^2.17.1", 28 | "nodejs-md5": "^1.1.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /query-builders/feed-query.js: -------------------------------------------------------------------------------- 1 | module.exports = (user, pivot) => ` 2 | SELECT id, username, tweet, timestamp 3 | FROM tweets WHERE ( user_id = ${user} 4 | OR ( user_id IN ( 5 | SELECT user2_id FROM following WHERE user1_id = ${user} 6 | ) ) 7 | ) ${pivot ? `AND id < ${pivot}` : ''} 8 | ORDER BY id DESC 9 | LIMIT 0, 50`; 10 | -------------------------------------------------------------------------------- /query-builders/tweet-query.js: -------------------------------------------------------------------------------- 1 | module.exports = () => `SELECT * FROM TWEETS WHERE id = ?`; 2 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const bodyParser = require('body-parser'); 3 | const dbConfig = require('./dbConfig'); 4 | // ↑ exports = {user, password, host, databse} 5 | const tweetsRouter = require('./app-middlewares/tweets'); 6 | const userRouter = require('./app-middlewares/user'); 7 | const authRouter = require('./app-middlewares/auth'); 8 | 9 | const app = express(); 10 | const port = 3000; 11 | 12 | // parse application/x-www-form-urlencoded 13 | app.use(bodyParser.urlencoded({ extended: false })) 14 | 15 | // parse various different custom JSON types as JSON 16 | app.use(bodyParser.json({ type: 'application/*+json' })); 17 | 18 | app.use((req, res, next) => { 19 | res.header('Access-Control-Allow-Origin', '*'); 20 | res.header( 21 | 'Access-Control-Allow-Headers', 22 | 'Origin, X-Requested-With, Content-Type, Accept', 23 | ); 24 | next(); 25 | }); 26 | 27 | const connection = require('./helpers/connection'); 28 | const query = require('./helpers/query'); 29 | 30 | app.get('/', (req, res) => res.send('Hello World!')); 31 | 32 | app.get('/list', async (req, res) => { 33 | const conn = await connection(dbConfig).catch(e => {}); 34 | const results = await query(conn, 'SELECT * FROM tweets').catch(console.log); 35 | res.json({ results }); 36 | }) 37 | 38 | app.use('/tweets', tweetsRouter); 39 | app.use('/user', userRouter); 40 | app.use('/auth', authRouter); 41 | 42 | app.listen(port, () => console.log(`Example app listening on port ${port}!`)); 43 | -------------------------------------------------------------------------------- /twitter-clone-postman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/time2hack/express-mysql/c958ac92c9f0da5c6b973d637313d4430b2ca45c/twitter-clone-postman.png --------------------------------------------------------------------------------