├── .gitignore ├── LICENSE ├── README2.md ├── ReadMe.md ├── Readme.md ├── _data ├── bootcamps.json ├── courses.json ├── reviews.json └── users.json ├── config ├── config.env.env └── db.js ├── controllers ├── auth.js ├── bootcamps.js ├── courses.js ├── reviews.js └── users.js ├── middleware ├── advancedResults.js ├── async.js ├── auth.js ├── error.js └── logger.js ├── models ├── Bootcamp.js ├── Course.js ├── Review.js └── User.js ├── package-lock.json ├── package.json ├── public ├── fonts │ ├── glyphicons-halflings-regular.eot │ ├── glyphicons-halflings-regular.woff │ └── glyphicons-halflings-regular.woff2 └── index.html ├── routes ├── auth.js ├── bootcamps.js ├── courses.js ├── reviews.js └── users.js ├── seeder.js ├── server.js └── utils ├── errorResponse.js ├── geocoder.js └── sendEmail.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store 3 | config/config.env -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Packt 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 | -------------------------------------------------------------------------------- /README2.md: -------------------------------------------------------------------------------- 1 | # DevCamper API 2 | 3 | > Backend API for DevCamper application, which is a bootcamp directory website 4 | 5 | ## Usage 6 | 7 | Rename "config/config.env.env" to "config/config.env" and update the values/settings to your own 8 | 9 | ## Install Dependencies 10 | 11 | ``` 12 | npm install 13 | ``` 14 | 15 | ## Run App 16 | 17 | ``` 18 | # Run in dev mode 19 | npm run dev 20 | 21 | # Run in prod mode 22 | npm start 23 | ``` 24 | 25 | ## Database Seeder 26 | 27 | To seed the database with users, bootcamps, courses and reviews with data from the "\_data" folder, run 28 | 29 | ``` 30 | # Destroy all data 31 | node seeder -d 32 | 33 | # Import all data 34 | node seeder -i 35 | ``` 36 | 37 | ## Demo 38 | 39 | The API is live at [devcamper.io](https://devcamper.io) 40 | 41 | Extensive documentation with examples [here](https://documenter.getpostman.com/view/8923145/SVtVVTzd?version=latest) 42 | 43 | - Version: 1.0.0 44 | - License: MIT 45 | - Author: Brad Traversy 46 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | This is the code repository for [ Node.js API Masterclass with Express and MongoDB [Video]](https://www.packtpub.com/web-development/node-js-api-masterclass-with-express-and-mongodb-video), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the video course from start to finish. 2 | ## About the Video Course 3 | This course will help you to create an extensive, in-depth backend API for DevCamper, a Bootcamp directory app. You’ll learn how to deploy a professional API with documentation from the ground up. 4 | 5 | The course starts with an overview of the project and an introduction to the HTTP essentials and Postman client. You’ll study HTTP status codes and how to send data to the server. The next section of the course will take you through the DevCamper project and show you how to create routes and responses in Express along with creating controller methods. As you make progress, you’ll learn how to create, fetch, and update and delete Bootcamps. You’ll also get to grips with the concepts of authentication, users, and permissions. 6 | 7 | By the end of the course, you’ll be able to build a real-world backend RESTful API for a Bootcamp directory app and have learned about advanced Mongoose queries. 8 | 9 |

What You Will Learn

10 |
11 |
18 | 19 | ### Course Requirements 20 | For successful completion of this course, students will need knowledge of the following:
21 | • Javascript fundamentals
22 | • Basic programming principles and control structures
23 | • Modern Javascript (ES6) - Arrows, promises, destructuring and more
24 |
25 | 26 | 27 | ### Recommended Hardware Requirements:
28 | For an optimal experience with hands-on labs and other practical activities, we recommend the following configuration: 29 |
30 | • Windows 10
31 | • OS: Microsoft Windows 10/8 (incl.64-bit)
32 | • Processor: Dual core processor
33 | • Memory: 4 GB RAM minimum, 8 GB RAM recommended
34 | • Storage: 1.5 GB hard disk space + at least 1 GB for caches
35 | • Optional: GPU: NVIDIA® GPU card with CUDA® Compute Capability 3.5 or higher.
36 | 37 | 38 | 39 | ## Related Products 40 | * [RESTful API Design with Node, Express, and MongoDB [Video]](https://www.packtpub.com/application-development/restful-api-design-node-express-and-mongodb-video) 41 | 42 | * [The Complete Node.js Developer Course (3rd Edition) [Video]](https://www.packtpub.com/application-development/complete-nodejs-developer-course-3rd-edition-video) 43 | 44 | * [Node.js, Express and MongoDB Dev to Deployment [Video]](https://www.packtpub.com/application-development/nodejs-express-and-mongodb-dev-deployment-video) 45 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /_data/bootcamps.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "_id": "5d713995b721c3bb38c1f5d0", 4 | "user": "5d7a514b5d2c12c7449be045", 5 | "name": "Devworks Bootcamp", 6 | "description": "Devworks is a full stack JavaScript Bootcamp located in the heart of Boston that focuses on the technologies you need to get a high paying job as a web developer", 7 | "website": "https://devworks.com", 8 | "phone": "(111) 111-1111", 9 | "email": "enroll@devworks.com", 10 | "address": "233 Bay State Rd Boston MA 02215", 11 | "careers": ["Web Development", "UI/UX", "Business"], 12 | "housing": true, 13 | "jobAssistance": true, 14 | "jobGuarantee": false, 15 | "acceptGi": true 16 | }, 17 | { 18 | "_id": "5d713a66ec8f2b88b8f830b8", 19 | "user": "5d7a514b5d2c12c7449be046", 20 | "name": "ModernTech Bootcamp", 21 | "description": "ModernTech has one goal, and that is to make you a rockstar developer and/or designer with a six figure salary. We teach both development and UI/UX", 22 | "website": "https://moderntech.com", 23 | "phone": "(222) 222-2222", 24 | "email": "enroll@moderntech.com", 25 | "address": "220 Pawtucket St, Lowell, MA 01854", 26 | "careers": ["Web Development", "UI/UX", "Mobile Development"], 27 | "housing": false, 28 | "jobAssistance": true, 29 | "jobGuarantee": false, 30 | "acceptGi": true 31 | }, 32 | { 33 | "_id": "5d725a037b292f5f8ceff787", 34 | "user": "5c8a1d5b0190b214360dc031", 35 | "name": "Codemasters", 36 | "description": "Is coding your passion? Codemasters will give you the skills and the tools to become the best developer possible. We specialize in full stack web development and data science", 37 | "website": "https://codemasters.com", 38 | "phone": "(333) 333-3333", 39 | "email": "enroll@codemasters.com", 40 | "address": "85 South Prospect Street Burlington VT 05405", 41 | "careers": ["Web Development", "Data Science", "Business"], 42 | "housing": false, 43 | "jobAssistance": false, 44 | "jobGuarantee": false, 45 | "acceptGi": false 46 | }, 47 | { 48 | "_id": "5d725a1b7b292f5f8ceff788", 49 | "user": "5c8a1d5b0190b214360dc032", 50 | "name": "Devcentral Bootcamp", 51 | "description": "Is coding your passion? Codemasters will give you the skills and the tools to become the best developer possible. We specialize in front end and full stack web development", 52 | "website": "https://devcentral.com", 53 | "phone": "(444) 444-4444", 54 | "email": "enroll@devcentral.com", 55 | "address": "45 Upper College Rd Kingston RI 02881", 56 | "careers": [ 57 | "Mobile Development", 58 | "Web Development", 59 | "Data Science", 60 | "Business" 61 | ], 62 | "housing": false, 63 | "jobAssistance": true, 64 | "jobGuarantee": true, 65 | "acceptGi": true 66 | } 67 | ] 68 | -------------------------------------------------------------------------------- /_data/courses.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "_id": "5d725a4a7b292f5f8ceff789", 4 | "title": "Front End Web Development", 5 | "description": "This course will provide you with all of the essentials to become a successful frontend web developer. You will learn to master HTML, CSS and front end JavaScript, along with tools like Git, VSCode and front end frameworks like Vue", 6 | "weeks": 8, 7 | "tuition": 8000, 8 | "minimumSkill": "beginner", 9 | "scholarshipsAvailable": true, 10 | "bootcamp": "5d713995b721c3bb38c1f5d0", 11 | "user": "5d7a514b5d2c12c7449be045" 12 | }, 13 | { 14 | "_id": "5d725c84c4ded7bcb480eaa0", 15 | "title": "Full Stack Web Development", 16 | "description": "In this course you will learn full stack web development, first learning all about the frontend with HTML/CSS/JS/Vue and then the backend with Node.js/Express/MongoDB", 17 | "weeks": 12, 18 | "tuition": 10000, 19 | "minimumSkill": "intermediate", 20 | "scholarshipsAvailable": true, 21 | "bootcamp": "5d713995b721c3bb38c1f5d0", 22 | "user": "5d7a514b5d2c12c7449be045" 23 | }, 24 | { 25 | "_id": "5d725cb9c4ded7bcb480eaa1", 26 | "title": "Full Stack Web Dev", 27 | "description": "In this course you will learn all about the front end with HTML, CSS and JavaScript. You will master tools like Git and Webpack and also learn C# and ASP.NET with Postgres", 28 | "weeks": 10, 29 | "tuition": 12000, 30 | "minimumSkill": "intermediate", 31 | "scholarshipsAvailable": true, 32 | "bootcamp": "5d713a66ec8f2b88b8f830b8", 33 | "user": "5d7a514b5d2c12c7449be046" 34 | }, 35 | { 36 | "_id": "5d725cd2c4ded7bcb480eaa2", 37 | "title": "UI/UX", 38 | "description": "In this course you will learn to create beautiful interfaces. It is a mix of design and development to create modern user experiences on both web and mobile", 39 | "weeks": 12, 40 | "tuition": 10000, 41 | "minimumSkill": "intermediate", 42 | "scholarshipsAvailable": true, 43 | "bootcamp": "5d713a66ec8f2b88b8f830b8", 44 | "user": "5d7a514b5d2c12c7449be046" 45 | }, 46 | { 47 | "_id": "5d725ce8c4ded7bcb480eaa3", 48 | "title": "Web Design & Development", 49 | "description": "Get started building websites and web apps with HTML/CSS/JavaScript/PHP. We teach you", 50 | "weeks": 10, 51 | "tuition": 12000, 52 | "minimumSkill": "beginner", 53 | "scholarshipsAvailable": true, 54 | "bootcamp": "5d725a037b292f5f8ceff787", 55 | "user": "5c8a1d5b0190b214360dc031" 56 | }, 57 | { 58 | "_id": "5d725cfec4ded7bcb480eaa4", 59 | "title": "Data Science Program", 60 | "description": "In this course you will learn Python for data science, machine learning and big data tools", 61 | "weeks": 10, 62 | "tuition": 9000, 63 | "minimumSkill": "intermediate", 64 | "scholarshipsAvailable": false, 65 | "bootcamp": "5d725a037b292f5f8ceff787", 66 | "user": "5c8a1d5b0190b214360dc031" 67 | }, 68 | { 69 | "_id": "5d725cfec4ded7bcb480eaa5", 70 | "title": "Web Development", 71 | "description": "This course will teach you how to build high quality web applications with technologies like React, Node.js, PHP & Laravel", 72 | "weeks": 8, 73 | "tuition": 8000, 74 | "minimumSkill": "beginner", 75 | "scholarshipsAvailable": false, 76 | "bootcamp": "5d725a1b7b292f5f8ceff788", 77 | "user": "5c8a1d5b0190b214360dc032" 78 | }, 79 | { 80 | "_id": "5d725cfec4ded7bcb480eaa6", 81 | "title": "Software QA", 82 | "description": "This course will teach you everything you need to know about quality assurance", 83 | "weeks": 6, 84 | "tuition": 5000, 85 | "minimumSkill": "intermediate", 86 | "scholarshipsAvailable": false, 87 | "bootcamp": "5d725a1b7b292f5f8ceff788", 88 | "user": "5c8a1d5b0190b214360dc032" 89 | }, 90 | { 91 | "_id": "5d725cfec4ded7bcb480eaa7", 92 | "title": "IOS Development", 93 | "description": "Get started building mobile applications for IOS using Swift and other tools", 94 | "weeks": 8, 95 | "tuition": 6000, 96 | "minimumSkill": "intermediate", 97 | "scholarshipsAvailable": false, 98 | "bootcamp": "5d725a1b7b292f5f8ceff788", 99 | "user": "5c8a1d5b0190b214360dc032" 100 | } 101 | ] 102 | -------------------------------------------------------------------------------- /_data/reviews.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "_id": "5d7a514b5d2c12c7449be020", 4 | "title": "Learned a ton!", 5 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque", 6 | "rating": "8", 7 | "bootcamp": "5d713995b721c3bb38c1f5d0", 8 | "user": "5c8a1d5b0190b214360dc033" 9 | }, 10 | { 11 | "_id": "5d7a514b5d2c12c7449be021", 12 | "title": "Great bootcamp", 13 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque", 14 | "rating": "10", 15 | "bootcamp": "5d713995b721c3bb38c1f5d0", 16 | "user": "5c8a1d5b0190b214360dc034" 17 | }, 18 | { 19 | "_id": "5d7a514b5d2c12c7449be022", 20 | "title": "Got me a developer job", 21 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque", 22 | "rating": "7", 23 | "bootcamp": "5d713a66ec8f2b88b8f830b8", 24 | "user": "5c8a1d5b0190b214360dc035" 25 | }, 26 | { 27 | "_id": "5d7a514b5d2c12c7449be023", 28 | "title": "Not that great", 29 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque", 30 | "rating": "4", 31 | "bootcamp": "5d713a66ec8f2b88b8f830b8", 32 | "user": "5c8a1d5b0190b214360dc036" 33 | }, 34 | { 35 | "_id": "5d7a514b5d2c12c7449be024", 36 | "title": "Great overall experience", 37 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque", 38 | "rating": "7", 39 | "bootcamp": "5d725a037b292f5f8ceff787", 40 | "user": "5c8a1d5b0190b214360dc037" 41 | }, 42 | { 43 | "_id": "5d7a514b5d2c12c7449be025", 44 | "title": "Not worth the money", 45 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque", 46 | "rating": "5", 47 | "bootcamp": "5d725a037b292f5f8ceff787", 48 | "user": "5c8a1d5b0190b214360dc038" 49 | }, 50 | { 51 | "_id": "5d7a514b5d2c12c7449be026", 52 | "title": "Best instructors", 53 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque", 54 | "rating": "10", 55 | "bootcamp": "5d725a1b7b292f5f8ceff788", 56 | "user": "5c8a1d5b0190b214360dc039" 57 | }, 58 | { 59 | "_id": "5d7a514b5d2c12c7449be027", 60 | "title": "Was worth the investment", 61 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque", 62 | "rating": "7", 63 | "bootcamp": "5d725a1b7b292f5f8ceff788", 64 | "user": "5c8a1d5b0190b214360dc040" 65 | } 66 | ] 67 | -------------------------------------------------------------------------------- /_data/users.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "_id": "5d7a514b5d2c12c7449be042", 4 | "name": "Admin Account", 5 | "email": "admin@gmail.com", 6 | "role": "user", 7 | "password": "123456" 8 | }, 9 | { 10 | "_id": "5d7a514b5d2c12c7449be043", 11 | "name": "Publisher Account", 12 | "email": "publisher@gmail.com", 13 | "role": "publisher", 14 | "password": "123456" 15 | }, 16 | { 17 | "_id": "5d7a514b5d2c12c7449be044", 18 | "name": "User Account", 19 | "email": "user@gmail.com", 20 | "role": "user", 21 | "password": "123456" 22 | }, 23 | { 24 | "_id": "5d7a514b5d2c12c7449be045", 25 | "name": "John Doe", 26 | "email": "john@gmail.com", 27 | "role": "publisher", 28 | "password": "123456" 29 | }, 30 | { 31 | "_id": "5d7a514b5d2c12c7449be046", 32 | "name": "Kevin Smith", 33 | "email": "kevin@gmail.com", 34 | "role": "publisher", 35 | "password": "123456" 36 | }, 37 | { 38 | "_id": "5c8a1d5b0190b214360dc031", 39 | "name": "Mary Williams", 40 | "email": "mary@gmail.com", 41 | "role": "publisher", 42 | "password": "123456" 43 | }, 44 | { 45 | "_id": "5c8a1d5b0190b214360dc032", 46 | "name": "Sasha Ryan", 47 | "email": "sasha@gmail.com", 48 | "role": "publisher", 49 | "password": "123456" 50 | }, 51 | { 52 | "_id": "5c8a1d5b0190b214360dc033", 53 | "name": "Greg Harris", 54 | "email": "greg@gmail.com", 55 | "role": "user", 56 | "password": "123456" 57 | }, 58 | { 59 | "_id": "5c8a1d5b0190b214360dc034", 60 | "name": "Derek Glover", 61 | "email": "derek@gmail.com", 62 | "role": "user", 63 | "password": "123456" 64 | }, 65 | { 66 | "_id": "5c8a1d5b0190b214360dc035", 67 | "name": "Stephanie Hanson", 68 | "email": "steph@gmail.com", 69 | "role": "user", 70 | "password": "123456" 71 | }, 72 | { 73 | "_id": "5c8a1d5b0190b214360dc036", 74 | "name": "Jerry Wiliams", 75 | "email": "jerry@gmail.com", 76 | "role": "user", 77 | "password": "123456" 78 | }, 79 | { 80 | "_id": "5c8a1d5b0190b214360dc037", 81 | "name": "Maggie Johnson", 82 | "email": "maggie@gmail.com", 83 | "role": "user", 84 | "password": "123456" 85 | }, 86 | { 87 | "_id": "5c8a1d5b0190b214360dc038", 88 | "name": "Barry Dickens", 89 | "email": "barry@gmail.com", 90 | "role": "user", 91 | "password": "123456" 92 | }, 93 | { 94 | "_id": "5c8a1d5b0190b214360dc039", 95 | "name": "Ryan Bolin", 96 | "email": "ryan@gmail.com", 97 | "role": "user", 98 | "password": "123456" 99 | }, 100 | { 101 | "_id": "5c8a1d5b0190b214360dc040", 102 | "name": "Sara Kensing", 103 | "email": "sara@gmail.com", 104 | "role": "user", 105 | "password": "123456" 106 | } 107 | ] 108 | -------------------------------------------------------------------------------- /config/config.env.env: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | PORT=5000 3 | 4 | MONGO_URI= 5 | 6 | GEOCODER_PROVIDER=mapquest 7 | GEOCODER_API_KEY= 8 | 9 | FILE_UPLOAD_PATH= ./public/uploads 10 | MAX_FILE_UPLOAD=1000000 11 | 12 | JWT_SECRET= 13 | JWT_EXPIRE=30d 14 | JWT_COOKIE_EXPIRE=30 15 | 16 | SMTP_HOST=smtp.mailtrap.io 17 | SMTP_PORT=2525 18 | SMTP_EMAIL= 19 | SMTP_PASSWORD= 20 | FROM_EMAIL= 21 | FROM_NAME= -------------------------------------------------------------------------------- /config/db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const connectDB = async () => { 4 | const conn = await mongoose.connect(process.env.MONGO_URI, { 5 | useNewUrlParser: true, 6 | useCreateIndex: true, 7 | useFindAndModify: false, 8 | useUnifiedTopology: true 9 | }); 10 | 11 | console.log(`MongoDB Connected: ${conn.connection.host}`.cyan.underline.bold); 12 | }; 13 | 14 | module.exports = connectDB; 15 | -------------------------------------------------------------------------------- /controllers/auth.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | const ErrorResponse = require('../utils/errorResponse'); 3 | const asyncHandler = require('../middleware/async'); 4 | const sendEmail = require('../utils/sendEmail'); 5 | const User = require('../models/User'); 6 | 7 | // @desc Register user 8 | // @route POST /api/v1/auth/register 9 | // @access Public 10 | exports.register = asyncHandler(async (req, res, next) => { 11 | const { name, email, password, role } = req.body; 12 | 13 | // Create user 14 | const user = await User.create({ 15 | name, 16 | email, 17 | password, 18 | role 19 | }); 20 | 21 | sendTokenResponse(user, 200, res); 22 | }); 23 | 24 | // @desc Login user 25 | // @route POST /api/v1/auth/login 26 | // @access Public 27 | exports.login = asyncHandler(async (req, res, next) => { 28 | const { email, password } = req.body; 29 | 30 | // Validate emil & password 31 | if (!email || !password) { 32 | return next(new ErrorResponse('Please provide an email and password', 400)); 33 | } 34 | 35 | // Check for user 36 | const user = await User.findOne({ email }).select('+password'); 37 | 38 | if (!user) { 39 | return next(new ErrorResponse('Invalid credentials', 401)); 40 | } 41 | 42 | // Check if password matches 43 | const isMatch = await user.matchPassword(password); 44 | 45 | if (!isMatch) { 46 | return next(new ErrorResponse('Invalid credentials', 401)); 47 | } 48 | 49 | sendTokenResponse(user, 200, res); 50 | }); 51 | 52 | // @desc Log user out / clear cookie 53 | // @route GET /api/v1/auth/logout 54 | // @access Public 55 | exports.logout = asyncHandler(async (req, res, next) => { 56 | res.cookie('token', 'none', { 57 | expires: new Date(Date.now() + 10 * 1000), 58 | httpOnly: true 59 | }); 60 | 61 | res.status(200).json({ 62 | success: true, 63 | data: {} 64 | }); 65 | }); 66 | 67 | // @desc Get current logged in user 68 | // @route GET /api/v1/auth/me 69 | // @access Private 70 | exports.getMe = asyncHandler(async (req, res, next) => { 71 | // user is already available in req due to the protect middleware 72 | const user = req.user; 73 | 74 | res.status(200).json({ 75 | success: true, 76 | data: user 77 | }); 78 | }); 79 | 80 | // @desc Update user details 81 | // @route PUT /api/v1/auth/updatedetails 82 | // @access Private 83 | exports.updateDetails = asyncHandler(async (req, res, next) => { 84 | const fieldsToUpdate = { 85 | name: req.body.name, 86 | email: req.body.email 87 | }; 88 | 89 | const user = await User.findByIdAndUpdate(req.user.id, fieldsToUpdate, { 90 | new: true, 91 | runValidators: true 92 | }); 93 | 94 | res.status(200).json({ 95 | success: true, 96 | data: user 97 | }); 98 | }); 99 | 100 | // @desc Update password 101 | // @route PUT /api/v1/auth/updatepassword 102 | // @access Private 103 | exports.updatePassword = asyncHandler(async (req, res, next) => { 104 | const user = await User.findById(req.user.id).select('+password'); 105 | 106 | // Check current password 107 | if (!(await user.matchPassword(req.body.currentPassword))) { 108 | return next(new ErrorResponse('Password is incorrect', 401)); 109 | } 110 | 111 | user.password = req.body.newPassword; 112 | await user.save(); 113 | 114 | sendTokenResponse(user, 200, res); 115 | }); 116 | 117 | // @desc Forgot password 118 | // @route POST /api/v1/auth/forgotpassword 119 | // @access Public 120 | exports.forgotPassword = asyncHandler(async (req, res, next) => { 121 | const user = await User.findOne({ email: req.body.email }); 122 | 123 | if (!user) { 124 | return next(new ErrorResponse('There is no user with that email', 404)); 125 | } 126 | 127 | // Get reset token 128 | const resetToken = user.getResetPasswordToken(); 129 | 130 | await user.save({ validateBeforeSave: false }); 131 | 132 | // Create reset url 133 | const resetUrl = `${req.protocol}://${req.get( 134 | 'host' 135 | )}/api/v1/auth/resetpassword/${resetToken}`; 136 | 137 | const message = `You are receiving this email because you (or someone else) has requested the reset of a password. Please make a PUT request to: \n\n ${resetUrl}`; 138 | 139 | try { 140 | await sendEmail({ 141 | email: user.email, 142 | subject: 'Password reset token', 143 | message 144 | }); 145 | 146 | res.status(200).json({ success: true, data: 'Email sent' }); 147 | } catch (err) { 148 | console.log(err); 149 | user.resetPasswordToken = undefined; 150 | user.resetPasswordExpire = undefined; 151 | 152 | await user.save({ validateBeforeSave: false }); 153 | 154 | return next(new ErrorResponse('Email could not be sent', 500)); 155 | } 156 | }); 157 | 158 | // @desc Reset password 159 | // @route PUT /api/v1/auth/resetpassword/:resettoken 160 | // @access Public 161 | exports.resetPassword = asyncHandler(async (req, res, next) => { 162 | // Get hashed token 163 | const resetPasswordToken = crypto 164 | .createHash('sha256') 165 | .update(req.params.resettoken) 166 | .digest('hex'); 167 | 168 | const user = await User.findOne({ 169 | resetPasswordToken, 170 | resetPasswordExpire: { $gt: Date.now() } 171 | }); 172 | 173 | if (!user) { 174 | return next(new ErrorResponse('Invalid token', 400)); 175 | } 176 | 177 | // Set new password 178 | user.password = req.body.password; 179 | user.resetPasswordToken = undefined; 180 | user.resetPasswordExpire = undefined; 181 | await user.save(); 182 | 183 | sendTokenResponse(user, 200, res); 184 | }); 185 | 186 | // Get token from model, create cookie and send response 187 | const sendTokenResponse = (user, statusCode, res) => { 188 | // Create token 189 | const token = user.getSignedJwtToken(); 190 | 191 | const options = { 192 | expires: new Date( 193 | Date.now() + process.env.JWT_COOKIE_EXPIRE * 24 * 60 * 60 * 1000 194 | ), 195 | httpOnly: true 196 | }; 197 | 198 | if (process.env.NODE_ENV === 'production') { 199 | options.secure = true; 200 | } 201 | 202 | res 203 | .status(statusCode) 204 | .cookie('token', token, options) 205 | .json({ 206 | success: true, 207 | token 208 | }); 209 | }; 210 | -------------------------------------------------------------------------------- /controllers/bootcamps.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const ErrorResponse = require('../utils/errorResponse'); 3 | const asyncHandler = require('../middleware/async'); 4 | const geocoder = require('../utils/geocoder'); 5 | const Bootcamp = require('../models/Bootcamp'); 6 | 7 | // @desc Get all bootcamps 8 | // @route GET /api/v1/bootcamps 9 | // @access Public 10 | exports.getBootcamps = asyncHandler(async (req, res, next) => { 11 | res.status(200).json(res.advancedResults); 12 | }); 13 | 14 | // @desc Get single bootcamp 15 | // @route GET /api/v1/bootcamps/:id 16 | // @access Public 17 | exports.getBootcamp = asyncHandler(async (req, res, next) => { 18 | const bootcamp = await Bootcamp.findById(req.params.id); 19 | 20 | if (!bootcamp) { 21 | return next( 22 | new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404) 23 | ); 24 | } 25 | 26 | res.status(200).json({ success: true, data: bootcamp }); 27 | }); 28 | 29 | // @desc Create new bootcamp 30 | // @route POST /api/v1/bootcamps 31 | // @access Private 32 | exports.createBootcamp = asyncHandler(async (req, res, next) => { 33 | // Add user to req,body 34 | req.body.user = req.user.id; 35 | 36 | // Check for published bootcamp 37 | const publishedBootcamp = await Bootcamp.findOne({ user: req.user.id }); 38 | 39 | // If the user is not an admin, they can only add one bootcamp 40 | if (publishedBootcamp && req.user.role !== 'admin') { 41 | return next( 42 | new ErrorResponse( 43 | `The user with ID ${req.user.id} has already published a bootcamp`, 44 | 400 45 | ) 46 | ); 47 | } 48 | 49 | const bootcamp = await Bootcamp.create(req.body); 50 | 51 | res.status(201).json({ 52 | success: true, 53 | data: bootcamp 54 | }); 55 | }); 56 | 57 | // @desc Update bootcamp 58 | // @route PUT /api/v1/bootcamps/:id 59 | // @access Private 60 | exports.updateBootcamp = asyncHandler(async (req, res, next) => { 61 | let bootcamp = await Bootcamp.findById(req.params.id); 62 | 63 | if (!bootcamp) { 64 | return next( 65 | new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404) 66 | ); 67 | } 68 | 69 | // Make sure user is bootcamp owner 70 | if (bootcamp.user.toString() !== req.user.id && req.user.role !== 'admin') { 71 | return next( 72 | new ErrorResponse( 73 | `User ${req.user.id} is not authorized to update this bootcamp`, 74 | 401 75 | ) 76 | ); 77 | } 78 | 79 | bootcamp = await Bootcamp.findByIdAndUpdate(req.params.id, req.body, { 80 | new: true, 81 | runValidators: true 82 | }); 83 | 84 | res.status(200).json({ success: true, data: bootcamp }); 85 | }); 86 | 87 | // @desc Delete bootcamp 88 | // @route DELETE /api/v1/bootcamps/:id 89 | // @access Private 90 | exports.deleteBootcamp = asyncHandler(async (req, res, next) => { 91 | const bootcamp = await Bootcamp.findById(req.params.id); 92 | 93 | if (!bootcamp) { 94 | return next( 95 | new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404) 96 | ); 97 | } 98 | 99 | // Make sure user is bootcamp owner 100 | if (bootcamp.user.toString() !== req.user.id && req.user.role !== 'admin') { 101 | return next( 102 | new ErrorResponse( 103 | `User ${req.user.id} is not authorized to delete this bootcamp`, 104 | 401 105 | ) 106 | ); 107 | } 108 | 109 | await bootcamp.remove(); 110 | 111 | res.status(200).json({ success: true, data: {} }); 112 | }); 113 | 114 | // @desc Get bootcamps within a radius 115 | // @route GET /api/v1/bootcamps/radius/:zipcode/:distance 116 | // @access Private 117 | exports.getBootcampsInRadius = asyncHandler(async (req, res, next) => { 118 | const { zipcode, distance } = req.params; 119 | 120 | // Get lat/lng from geocoder 121 | const loc = await geocoder.geocode(zipcode); 122 | const lat = loc[0].latitude; 123 | const lng = loc[0].longitude; 124 | 125 | // Calc radius using radians 126 | // Divide dist by radius of Earth 127 | // Earth Radius = 3,963 mi / 6,378 km 128 | const radius = distance / 3963; 129 | 130 | const bootcamps = await Bootcamp.find({ 131 | location: { $geoWithin: { $centerSphere: [[lng, lat], radius] } } 132 | }); 133 | 134 | res.status(200).json({ 135 | success: true, 136 | count: bootcamps.length, 137 | data: bootcamps 138 | }); 139 | }); 140 | 141 | // @desc Upload photo for bootcamp 142 | // @route PUT /api/v1/bootcamps/:id/photo 143 | // @access Private 144 | exports.bootcampPhotoUpload = asyncHandler(async (req, res, next) => { 145 | const bootcamp = await Bootcamp.findById(req.params.id); 146 | 147 | if (!bootcamp) { 148 | return next( 149 | new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404) 150 | ); 151 | } 152 | 153 | // Make sure user is bootcamp owner 154 | if (bootcamp.user.toString() !== req.user.id && req.user.role !== 'admin') { 155 | return next( 156 | new ErrorResponse( 157 | `User ${req.user.id} is not authorized to update this bootcamp`, 158 | 401 159 | ) 160 | ); 161 | } 162 | 163 | if (!req.files) { 164 | return next(new ErrorResponse(`Please upload a file`, 400)); 165 | } 166 | 167 | const file = req.files.file; 168 | 169 | // Make sure the image is a photo 170 | if (!file.mimetype.startsWith('image')) { 171 | return next(new ErrorResponse(`Please upload an image file`, 400)); 172 | } 173 | 174 | // Check filesize 175 | if (file.size > process.env.MAX_FILE_UPLOAD) { 176 | return next( 177 | new ErrorResponse( 178 | `Please upload an image less than ${process.env.MAX_FILE_UPLOAD}`, 179 | 400 180 | ) 181 | ); 182 | } 183 | 184 | // Create custom filename 185 | file.name = `photo_${bootcamp._id}${path.parse(file.name).ext}`; 186 | 187 | file.mv(`${process.env.FILE_UPLOAD_PATH}/${file.name}`, async err => { 188 | if (err) { 189 | console.error(err); 190 | return next(new ErrorResponse(`Problem with file upload`, 500)); 191 | } 192 | 193 | await Bootcamp.findByIdAndUpdate(req.params.id, { photo: file.name }); 194 | 195 | res.status(200).json({ 196 | success: true, 197 | data: file.name 198 | }); 199 | }); 200 | }); 201 | -------------------------------------------------------------------------------- /controllers/courses.js: -------------------------------------------------------------------------------- 1 | const ErrorResponse = require('../utils/errorResponse'); 2 | const asyncHandler = require('../middleware/async'); 3 | const Course = require('../models/Course'); 4 | const Bootcamp = require('../models/Bootcamp'); 5 | 6 | // @desc Get courses 7 | // @route GET /api/v1/courses 8 | // @route GET /api/v1/bootcamps/:bootcampId/courses 9 | // @access Public 10 | exports.getCourses = asyncHandler(async (req, res, next) => { 11 | if (req.params.bootcampId) { 12 | const courses = await Course.find({ bootcamp: req.params.bootcampId }); 13 | 14 | return res.status(200).json({ 15 | success: true, 16 | count: courses.length, 17 | data: courses 18 | }); 19 | } else { 20 | res.status(200).json(res.advancedResults); 21 | } 22 | }); 23 | 24 | // @desc Get single course 25 | // @route GET /api/v1/courses/:id 26 | // @access Public 27 | exports.getCourse = asyncHandler(async (req, res, next) => { 28 | const course = await Course.findById(req.params.id).populate({ 29 | path: 'bootcamp', 30 | select: 'name description' 31 | }); 32 | 33 | if (!course) { 34 | return next( 35 | new ErrorResponse(`No course with the id of ${req.params.id}`, 404) 36 | ); 37 | } 38 | 39 | res.status(200).json({ 40 | success: true, 41 | data: course 42 | }); 43 | }); 44 | 45 | // @desc Add course 46 | // @route POST /api/v1/bootcamps/:bootcampId/courses 47 | // @access Private 48 | exports.addCourse = asyncHandler(async (req, res, next) => { 49 | req.body.bootcamp = req.params.bootcampId; 50 | req.body.user = req.user.id; 51 | 52 | const bootcamp = await Bootcamp.findById(req.params.bootcampId); 53 | 54 | if (!bootcamp) { 55 | return next( 56 | new ErrorResponse( 57 | `No bootcamp with the id of ${req.params.bootcampId}`, 58 | 404 59 | ) 60 | ); 61 | } 62 | 63 | // Make sure user is bootcamp owner 64 | if (bootcamp.user.toString() !== req.user.id && req.user.role !== 'admin') { 65 | return next( 66 | new ErrorResponse( 67 | `User ${req.user.id} is not authorized to add a course to bootcamp ${bootcamp._id}`, 68 | 401 69 | ) 70 | ); 71 | } 72 | 73 | const course = await Course.create(req.body); 74 | 75 | res.status(200).json({ 76 | success: true, 77 | data: course 78 | }); 79 | }); 80 | 81 | // @desc Update course 82 | // @route PUT /api/v1/courses/:id 83 | // @access Private 84 | exports.updateCourse = asyncHandler(async (req, res, next) => { 85 | let course = await Course.findById(req.params.id); 86 | 87 | if (!course) { 88 | return next( 89 | new ErrorResponse(`No course with the id of ${req.params.id}`, 404) 90 | ); 91 | } 92 | 93 | // Make sure user is course owner 94 | if (course.user.toString() !== req.user.id && req.user.role !== 'admin') { 95 | return next( 96 | new ErrorResponse( 97 | `User ${req.user.id} is not authorized to update course ${course._id}`, 98 | 401 99 | ) 100 | ); 101 | } 102 | 103 | course = await Course.findByIdAndUpdate(req.params.id, req.body, { 104 | new: true, 105 | runValidators: true 106 | }); 107 | 108 | course.save(); 109 | 110 | res.status(200).json({ 111 | success: true, 112 | data: course 113 | }); 114 | }); 115 | 116 | // @desc Delete course 117 | // @route DELETE /api/v1/courses/:id 118 | // @access Private 119 | exports.deleteCourse = asyncHandler(async (req, res, next) => { 120 | const course = await Course.findById(req.params.id); 121 | 122 | if (!course) { 123 | return next( 124 | new ErrorResponse(`No course with the id of ${req.params.id}`, 404) 125 | ); 126 | } 127 | 128 | // Make sure user is course owner 129 | if (course.user.toString() !== req.user.id && req.user.role !== 'admin') { 130 | return next( 131 | new ErrorResponse( 132 | `User ${req.user.id} is not authorized to delete course ${course._id}`, 133 | 401 134 | ) 135 | ); 136 | } 137 | 138 | await course.remove(); 139 | 140 | res.status(200).json({ 141 | success: true, 142 | data: {} 143 | }); 144 | }); 145 | -------------------------------------------------------------------------------- /controllers/reviews.js: -------------------------------------------------------------------------------- 1 | const ErrorResponse = require('../utils/errorResponse'); 2 | const asyncHandler = require('../middleware/async'); 3 | const Review = require('../models/Review'); 4 | const Bootcamp = require('../models/Bootcamp'); 5 | 6 | // @desc Get reviews 7 | // @route GET /api/v1/reviews 8 | // @route GET /api/v1/bootcamps/:bootcampId/reviews 9 | // @access Public 10 | exports.getReviews = asyncHandler(async (req, res, next) => { 11 | if (req.params.bootcampId) { 12 | const reviews = await Review.find({ bootcamp: req.params.bootcampId }); 13 | 14 | return res.status(200).json({ 15 | success: true, 16 | count: reviews.length, 17 | data: reviews 18 | }); 19 | } else { 20 | res.status(200).json(res.advancedResults); 21 | } 22 | }); 23 | 24 | // @desc Get single review 25 | // @route GET /api/v1/reviews/:id 26 | // @access Public 27 | exports.getReview = asyncHandler(async (req, res, next) => { 28 | const review = await Review.findById(req.params.id).populate({ 29 | path: 'bootcamp', 30 | select: 'name description' 31 | }); 32 | 33 | if (!review) { 34 | return next( 35 | new ErrorResponse(`No review found with the id of ${req.params.id}`, 404) 36 | ); 37 | } 38 | 39 | res.status(200).json({ 40 | success: true, 41 | data: review 42 | }); 43 | }); 44 | 45 | // @desc Add review 46 | // @route POST /api/v1/bootcamps/:bootcampId/reviews 47 | // @access Private 48 | exports.addReview = asyncHandler(async (req, res, next) => { 49 | req.body.bootcamp = req.params.bootcampId; 50 | req.body.user = req.user.id; 51 | 52 | const bootcamp = await Bootcamp.findById(req.params.bootcampId); 53 | 54 | if (!bootcamp) { 55 | return next( 56 | new ErrorResponse( 57 | `No bootcamp with the id of ${req.params.bootcampId}`, 58 | 404 59 | ) 60 | ); 61 | } 62 | 63 | const review = await Review.create(req.body); 64 | 65 | res.status(201).json({ 66 | success: true, 67 | data: review 68 | }); 69 | }); 70 | 71 | // @desc Update review 72 | // @route PUT /api/v1/reviews/:id 73 | // @access Private 74 | exports.updateReview = asyncHandler(async (req, res, next) => { 75 | let review = await Review.findById(req.params.id); 76 | 77 | if (!review) { 78 | return next( 79 | new ErrorResponse(`No review with the id of ${req.params.id}`, 404) 80 | ); 81 | } 82 | 83 | // Make sure review belongs to user or user is admin 84 | if (review.user.toString() !== req.user.id && req.user.role !== 'admin') { 85 | return next(new ErrorResponse(`Not authorized to update review`, 401)); 86 | } 87 | 88 | review = await Review.findByIdAndUpdate(req.params.id, req.body, { 89 | new: true, 90 | runValidators: true 91 | }); 92 | 93 | review.save(); 94 | 95 | res.status(200).json({ 96 | success: true, 97 | data: review 98 | }); 99 | }); 100 | 101 | // @desc Delete review 102 | // @route DELETE /api/v1/reviews/:id 103 | // @access Private 104 | exports.deleteReview = asyncHandler(async (req, res, next) => { 105 | const review = await Review.findById(req.params.id); 106 | 107 | if (!review) { 108 | return next( 109 | new ErrorResponse(`No review with the id of ${req.params.id}`, 404) 110 | ); 111 | } 112 | 113 | // Make sure review belongs to user or user is admin 114 | if (review.user.toString() !== req.user.id && req.user.role !== 'admin') { 115 | return next(new ErrorResponse(`Not authorized to update review`, 401)); 116 | } 117 | 118 | await review.remove(); 119 | 120 | res.status(200).json({ 121 | success: true, 122 | data: {} 123 | }); 124 | }); 125 | -------------------------------------------------------------------------------- /controllers/users.js: -------------------------------------------------------------------------------- 1 | const ErrorResponse = require('../utils/errorResponse'); 2 | const asyncHandler = require('../middleware/async'); 3 | const User = require('../models/User'); 4 | 5 | // @desc Get all users 6 | // @route GET /api/v1/users 7 | // @access Private/Admin 8 | exports.getUsers = asyncHandler(async (req, res, next) => { 9 | res.status(200).json(res.advancedResults); 10 | }); 11 | 12 | // @desc Get single user 13 | // @route GET /api/v1/users/:id 14 | // @access Private/Admin 15 | exports.getUser = asyncHandler(async (req, res, next) => { 16 | const user = await User.findById(req.params.id); 17 | 18 | res.status(200).json({ 19 | success: true, 20 | data: user 21 | }); 22 | }); 23 | 24 | // @desc Create user 25 | // @route POST /api/v1/users 26 | // @access Private/Admin 27 | exports.createUser = asyncHandler(async (req, res, next) => { 28 | const user = await User.create(req.body); 29 | 30 | res.status(201).json({ 31 | success: true, 32 | data: user 33 | }); 34 | }); 35 | 36 | // @desc Update user 37 | // @route PUT /api/v1/users/:id 38 | // @access Private/Admin 39 | exports.updateUser = asyncHandler(async (req, res, next) => { 40 | const user = await User.findByIdAndUpdate(req.params.id, req.body, { 41 | new: true, 42 | runValidators: true 43 | }); 44 | 45 | res.status(200).json({ 46 | success: true, 47 | data: user 48 | }); 49 | }); 50 | 51 | // @desc Delete user 52 | // @route DELETE /api/v1/users/:id 53 | // @access Private/Admin 54 | exports.deleteUser = asyncHandler(async (req, res, next) => { 55 | await User.findByIdAndDelete(req.params.id); 56 | 57 | res.status(200).json({ 58 | success: true, 59 | data: {} 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /middleware/advancedResults.js: -------------------------------------------------------------------------------- 1 | const advancedResults = (model, populate) => async (req, res, next) => { 2 | let query; 3 | 4 | // Copy req.query 5 | const reqQuery = { ...req.query }; 6 | 7 | // Fields to exclude 8 | const removeFields = ['select', 'sort', 'page', 'limit']; 9 | 10 | // Loop over removeFields and delete them from reqQuery 11 | removeFields.forEach(param => delete reqQuery[param]); 12 | 13 | // Create query string 14 | let queryStr = JSON.stringify(reqQuery); 15 | 16 | // Create operators ($gt, $gte, etc) 17 | queryStr = queryStr.replace(/\b(gt|gte|lt|lte|in)\b/g, match => `$${match}`); 18 | 19 | // Finding resource 20 | query = model.find(JSON.parse(queryStr)); 21 | 22 | // Select Fields 23 | if (req.query.select) { 24 | const fields = req.query.select.split(',').join(' '); 25 | query = query.select(fields); 26 | } 27 | 28 | // Sort 29 | if (req.query.sort) { 30 | const sortBy = req.query.sort.split(',').join(' '); 31 | query = query.sort(sortBy); 32 | } else { 33 | query = query.sort('-createdAt'); 34 | } 35 | 36 | // Pagination 37 | const page = parseInt(req.query.page, 10) || 1; 38 | const limit = parseInt(req.query.limit, 10) || 25; 39 | const startIndex = (page - 1) * limit; 40 | const endIndex = page * limit; 41 | const total = await model.countDocuments(JSON.parse(queryStr)); 42 | 43 | query = query.skip(startIndex).limit(limit); 44 | 45 | if (populate) { 46 | query = query.populate(populate); 47 | } 48 | 49 | // Executing query 50 | const results = await query; 51 | 52 | // Pagination result 53 | const pagination = {}; 54 | 55 | if (endIndex < total) { 56 | pagination.next = { 57 | page: page + 1, 58 | limit 59 | }; 60 | } 61 | 62 | if (startIndex > 0) { 63 | pagination.prev = { 64 | page: page - 1, 65 | limit 66 | }; 67 | } 68 | 69 | res.advancedResults = { 70 | success: true, 71 | count: results.length, 72 | pagination, 73 | data: results 74 | }; 75 | 76 | next(); 77 | }; 78 | 79 | module.exports = advancedResults; 80 | -------------------------------------------------------------------------------- /middleware/async.js: -------------------------------------------------------------------------------- 1 | const asyncHandler = fn => (req, res, next) => 2 | Promise.resolve(fn(req, res, next)).catch(next); 3 | 4 | module.exports = asyncHandler; 5 | -------------------------------------------------------------------------------- /middleware/auth.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken'); 2 | const asyncHandler = require('./async'); 3 | const ErrorResponse = require('../utils/errorResponse'); 4 | const User = require('../models/User'); 5 | 6 | // Protect routes 7 | exports.protect = asyncHandler(async (req, res, next) => { 8 | let token; 9 | 10 | if ( 11 | req.headers.authorization && 12 | req.headers.authorization.startsWith('Bearer') 13 | ) { 14 | // Set token from Bearer token in header 15 | token = req.headers.authorization.split(' ')[1]; 16 | // Set token from cookie 17 | } 18 | // else if (req.cookies.token) { 19 | // token = req.cookies.token; 20 | // } 21 | 22 | // Make sure token exists 23 | if (!token) { 24 | return next(new ErrorResponse('Not authorized to access this route', 401)); 25 | } 26 | 27 | try { 28 | // Verify token 29 | const decoded = jwt.verify(token, process.env.JWT_SECRET); 30 | 31 | req.user = await User.findById(decoded.id); 32 | 33 | next(); 34 | } catch (err) { 35 | return next(new ErrorResponse('Not authorized to access this route', 401)); 36 | } 37 | }); 38 | 39 | // Grant access to specific roles 40 | exports.authorize = (...roles) => { 41 | return (req, res, next) => { 42 | if (!roles.includes(req.user.role)) { 43 | return next( 44 | new ErrorResponse( 45 | `User role ${req.user.role} is not authorized to access this route`, 46 | 403 47 | ) 48 | ); 49 | } 50 | next(); 51 | }; 52 | }; 53 | -------------------------------------------------------------------------------- /middleware/error.js: -------------------------------------------------------------------------------- 1 | const ErrorResponse = require('../utils/errorResponse'); 2 | 3 | const errorHandler = (err, req, res, next) => { 4 | let error = { ...err }; 5 | 6 | error.message = err.message; 7 | 8 | // Log to console for dev 9 | console.log(err); 10 | 11 | // Mongoose bad ObjectId 12 | if (err.name === 'CastError') { 13 | const message = `Resource not found`; 14 | error = new ErrorResponse(message, 404); 15 | } 16 | 17 | // Mongoose duplicate key 18 | if (err.code === 11000) { 19 | const message = 'Duplicate field value entered'; 20 | error = new ErrorResponse(message, 400); 21 | } 22 | 23 | // Mongoose validation error 24 | if (err.name === 'ValidationError') { 25 | const message = Object.values(err.errors).map(val => val.message); 26 | error = new ErrorResponse(message, 400); 27 | } 28 | 29 | res.status(error.statusCode || 500).json({ 30 | success: false, 31 | error: error.message || 'Server Error' 32 | }); 33 | }; 34 | 35 | module.exports = errorHandler; 36 | -------------------------------------------------------------------------------- /middleware/logger.js: -------------------------------------------------------------------------------- 1 | // @desc Logs request to console 2 | const logger = (req, res, next) => { 3 | console.log( 4 | `${req.method} ${req.protocol}://${req.get('host')}${req.originalUrl}` 5 | ); 6 | next(); 7 | }; 8 | 9 | module.exports = logger; 10 | -------------------------------------------------------------------------------- /models/Bootcamp.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const slugify = require('slugify'); 3 | const geocoder = require('../utils/geocoder'); 4 | 5 | const BootcampSchema = new mongoose.Schema( 6 | { 7 | name: { 8 | type: String, 9 | required: [true, 'Please add a name'], 10 | unique: true, 11 | trim: true, 12 | maxlength: [50, 'Name can not be more than 50 characters'] 13 | }, 14 | slug: String, 15 | description: { 16 | type: String, 17 | required: [true, 'Please add a description'], 18 | maxlength: [500, 'Description can not be more than 500 characters'] 19 | }, 20 | website: { 21 | type: String, 22 | match: [ 23 | /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/, 24 | 'Please use a valid URL with HTTP or HTTPS' 25 | ] 26 | }, 27 | phone: { 28 | type: String, 29 | maxlength: [20, 'Phone number can not be longer than 20 characters'] 30 | }, 31 | email: { 32 | type: String, 33 | match: [ 34 | /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/, 35 | 'Please add a valid email' 36 | ] 37 | }, 38 | address: { 39 | type: String, 40 | required: [true, 'Please add an address'] 41 | }, 42 | location: { 43 | // GeoJSON Point 44 | type: { 45 | type: String, 46 | enum: ['Point'] 47 | }, 48 | coordinates: { 49 | type: [Number], 50 | index: '2dsphere' 51 | }, 52 | formattedAddress: String, 53 | street: String, 54 | city: String, 55 | state: String, 56 | zipcode: String, 57 | country: String 58 | }, 59 | careers: { 60 | // Array of strings 61 | type: [String], 62 | required: true, 63 | enum: [ 64 | 'Web Development', 65 | 'Mobile Development', 66 | 'UI/UX', 67 | 'Data Science', 68 | 'Business', 69 | 'Other' 70 | ] 71 | }, 72 | averageRating: { 73 | type: Number, 74 | min: [1, 'Rating must be at least 1'], 75 | max: [10, 'Rating must can not be more than 10'] 76 | }, 77 | averageCost: Number, 78 | photo: { 79 | type: String, 80 | default: 'no-photo.jpg' 81 | }, 82 | housing: { 83 | type: Boolean, 84 | default: false 85 | }, 86 | jobAssistance: { 87 | type: Boolean, 88 | default: false 89 | }, 90 | jobGuarantee: { 91 | type: Boolean, 92 | default: false 93 | }, 94 | acceptGi: { 95 | type: Boolean, 96 | default: false 97 | }, 98 | createdAt: { 99 | type: Date, 100 | default: Date.now 101 | }, 102 | user: { 103 | type: mongoose.Schema.ObjectId, 104 | ref: 'User', 105 | required: true 106 | } 107 | }, 108 | { 109 | toJSON: { virtuals: true }, 110 | toObject: { virtuals: true } 111 | } 112 | ); 113 | 114 | // Create bootcamp slug from the name 115 | BootcampSchema.pre('save', function(next) { 116 | this.slug = slugify(this.name, { lower: true }); 117 | next(); 118 | }); 119 | 120 | // Geocode & create location field 121 | BootcampSchema.pre('save', async function(next) { 122 | const loc = await geocoder.geocode(this.address); 123 | this.location = { 124 | type: 'Point', 125 | coordinates: [loc[0].longitude, loc[0].latitude], 126 | formattedAddress: loc[0].formattedAddress, 127 | street: loc[0].streetName, 128 | city: loc[0].city, 129 | state: loc[0].stateCode, 130 | zipcode: loc[0].zipcode, 131 | country: loc[0].countryCode 132 | }; 133 | 134 | // Do not save address in DB 135 | this.address = undefined; 136 | next(); 137 | }); 138 | 139 | // Cascade delete courses when a bootcamp is deleted 140 | BootcampSchema.pre('remove', async function(next) { 141 | console.log(`Courses being removed from bootcamp ${this._id}`); 142 | await this.model('Course').deleteMany({ bootcamp: this._id }); 143 | next(); 144 | }); 145 | 146 | // Reverse populate with virtuals 147 | BootcampSchema.virtual('courses', { 148 | ref: 'Course', 149 | localField: '_id', 150 | foreignField: 'bootcamp', 151 | justOne: false 152 | }); 153 | 154 | module.exports = mongoose.model('Bootcamp', BootcampSchema); 155 | -------------------------------------------------------------------------------- /models/Course.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const CourseSchema = new mongoose.Schema({ 4 | title: { 5 | type: String, 6 | trim: true, 7 | required: [true, 'Please add a course title'] 8 | }, 9 | description: { 10 | type: String, 11 | required: [true, 'Please add a description'] 12 | }, 13 | weeks: { 14 | type: String, 15 | required: [true, 'Please add number of weeks'] 16 | }, 17 | tuition: { 18 | type: Number, 19 | required: [true, 'Please add a tuition cost'] 20 | }, 21 | minimumSkill: { 22 | type: String, 23 | required: [true, 'Please add a minimum skill'], 24 | enum: ['beginner', 'intermediate', 'advanced'] 25 | }, 26 | scholarshipAvailable: { 27 | type: Boolean, 28 | default: false 29 | }, 30 | createdAt: { 31 | type: Date, 32 | default: Date.now 33 | }, 34 | bootcamp: { 35 | type: mongoose.Schema.ObjectId, 36 | ref: 'Bootcamp', 37 | required: true 38 | }, 39 | user: { 40 | type: mongoose.Schema.ObjectId, 41 | ref: 'User', 42 | required: true 43 | } 44 | }); 45 | 46 | // Static method to get avg of course tuitions 47 | CourseSchema.statics.getAverageCost = async function(bootcampId) { 48 | const obj = await this.aggregate([ 49 | { 50 | $match: { bootcamp: bootcampId } 51 | }, 52 | { 53 | $group: { 54 | _id: '$bootcamp', 55 | averageCost: { $avg: '$tuition' } 56 | } 57 | } 58 | ]); 59 | 60 | try { 61 | await this.model('Bootcamp').findByIdAndUpdate(bootcampId, { 62 | averageCost: Math.ceil(obj[0].averageCost / 10) * 10 63 | }); 64 | } catch (err) { 65 | console.error(err); 66 | } 67 | }; 68 | 69 | // Call getAverageCost after save 70 | CourseSchema.post('save', async function() { 71 | await this.constructor.getAverageCost(this.bootcamp); 72 | }); 73 | 74 | // Call getAverageCost after remove 75 | CourseSchema.post('remove', async function () { 76 | await this.constructor.getAverageCost(this.bootcamp); 77 | }); 78 | 79 | 80 | module.exports = mongoose.model('Course', CourseSchema); 81 | -------------------------------------------------------------------------------- /models/Review.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const ReviewSchema = new mongoose.Schema({ 4 | title: { 5 | type: String, 6 | trim: true, 7 | required: [true, 'Please add a title for the review'], 8 | maxlength: 100 9 | }, 10 | text: { 11 | type: String, 12 | required: [true, 'Please add some text'] 13 | }, 14 | rating: { 15 | type: Number, 16 | min: 1, 17 | max: 10, 18 | required: [true, 'Please add a rating between 1 and 10'] 19 | }, 20 | createdAt: { 21 | type: Date, 22 | default: Date.now 23 | }, 24 | bootcamp: { 25 | type: mongoose.Schema.ObjectId, 26 | ref: 'Bootcamp', 27 | required: true 28 | }, 29 | user: { 30 | type: mongoose.Schema.ObjectId, 31 | ref: 'User', 32 | required: true 33 | } 34 | }); 35 | 36 | // Prevent user from submitting more than one review per bootcamp 37 | ReviewSchema.index({ bootcamp: 1, user: 1 }, { unique: true }); 38 | 39 | // Static method to get avg rating and save 40 | ReviewSchema.statics.getAverageRating = async function(bootcampId) { 41 | const obj = await this.aggregate([ 42 | { 43 | $match: { bootcamp: bootcampId } 44 | }, 45 | { 46 | $group: { 47 | _id: '$bootcamp', 48 | averageRating: { $avg: '$rating' } 49 | } 50 | } 51 | ]); 52 | 53 | try { 54 | await this.model('Bootcamp').findByIdAndUpdate(bootcampId, { 55 | averageRating: obj[0].averageRating 56 | }); 57 | } catch (err) { 58 | console.error(err); 59 | } 60 | }; 61 | 62 | // Call getAverageCost after save 63 | ReviewSchema.post('save', async function() { 64 | await this.constructor.getAverageRating(this.bootcamp); 65 | }); 66 | 67 | // Call getAverageCost before remove 68 | ReviewSchema.pre('remove', async function() { 69 | await this.constructor.getAverageRating(this.bootcamp); 70 | }); 71 | 72 | module.exports = mongoose.model('Review', ReviewSchema); 73 | -------------------------------------------------------------------------------- /models/User.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | const mongoose = require('mongoose'); 3 | const bcrypt = require('bcryptjs'); 4 | const jwt = require('jsonwebtoken'); 5 | 6 | const UserSchema = new mongoose.Schema({ 7 | name: { 8 | type: String, 9 | required: [true, 'Please add a name'] 10 | }, 11 | email: { 12 | type: String, 13 | required: [true, 'Please add an email'], 14 | unique: true, 15 | match: [ 16 | /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/, 17 | 'Please add a valid email' 18 | ] 19 | }, 20 | role: { 21 | type: String, 22 | enum: ['user', 'publisher'], 23 | default: 'user' 24 | }, 25 | password: { 26 | type: String, 27 | required: [true, 'Please add a password'], 28 | minlength: 6, 29 | select: false 30 | }, 31 | resetPasswordToken: String, 32 | resetPasswordExpire: Date, 33 | createdAt: { 34 | type: Date, 35 | default: Date.now 36 | } 37 | }); 38 | 39 | // Encrypt password using bcrypt 40 | UserSchema.pre('save', async function(next) { 41 | if (!this.isModified('password')) { 42 | next(); 43 | } 44 | 45 | const salt = await bcrypt.genSalt(10); 46 | this.password = await bcrypt.hash(this.password, salt); 47 | }); 48 | 49 | // Sign JWT and return 50 | UserSchema.methods.getSignedJwtToken = function() { 51 | return jwt.sign({ id: this._id }, process.env.JWT_SECRET, { 52 | expiresIn: process.env.JWT_EXPIRE 53 | }); 54 | }; 55 | 56 | // Match user entered password to hashed password in database 57 | UserSchema.methods.matchPassword = async function(enteredPassword) { 58 | return await bcrypt.compare(enteredPassword, this.password); 59 | }; 60 | 61 | // Generate and hash password token 62 | UserSchema.methods.getResetPasswordToken = function() { 63 | // Generate token 64 | const resetToken = crypto.randomBytes(20).toString('hex'); 65 | 66 | // Hash token and set to resetPasswordToken field 67 | this.resetPasswordToken = crypto 68 | .createHash('sha256') 69 | .update(resetToken) 70 | .digest('hex'); 71 | 72 | // Set expire 73 | this.resetPasswordExpire = Date.now() + 10 * 60 * 1000; 74 | 75 | return resetToken; 76 | }; 77 | 78 | module.exports = mongoose.model('User', UserSchema); 79 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devcamper_api", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "abbrev": { 8 | "version": "1.1.1", 9 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 10 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", 11 | "dev": true 12 | }, 13 | "accepts": { 14 | "version": "1.3.7", 15 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 16 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 17 | "requires": { 18 | "mime-types": "~2.1.24", 19 | "negotiator": "0.6.2" 20 | } 21 | }, 22 | "ajv": { 23 | "version": "6.10.2", 24 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", 25 | "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", 26 | "requires": { 27 | "fast-deep-equal": "^2.0.1", 28 | "fast-json-stable-stringify": "^2.0.0", 29 | "json-schema-traverse": "^0.4.1", 30 | "uri-js": "^4.2.2" 31 | } 32 | }, 33 | "ansi-align": { 34 | "version": "2.0.0", 35 | "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", 36 | "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", 37 | "dev": true, 38 | "requires": { 39 | "string-width": "^2.0.0" 40 | } 41 | }, 42 | "ansi-regex": { 43 | "version": "3.0.0", 44 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 45 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", 46 | "dev": true 47 | }, 48 | "ansi-styles": { 49 | "version": "3.2.1", 50 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 51 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 52 | "dev": true, 53 | "requires": { 54 | "color-convert": "^1.9.0" 55 | } 56 | }, 57 | "anymatch": { 58 | "version": "2.0.0", 59 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", 60 | "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", 61 | "dev": true, 62 | "requires": { 63 | "micromatch": "^3.1.4", 64 | "normalize-path": "^2.1.1" 65 | }, 66 | "dependencies": { 67 | "normalize-path": { 68 | "version": "2.1.1", 69 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", 70 | "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", 71 | "dev": true, 72 | "requires": { 73 | "remove-trailing-separator": "^1.0.1" 74 | } 75 | } 76 | } 77 | }, 78 | "arr-diff": { 79 | "version": "4.0.0", 80 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", 81 | "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", 82 | "dev": true 83 | }, 84 | "arr-flatten": { 85 | "version": "1.1.0", 86 | "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", 87 | "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", 88 | "dev": true 89 | }, 90 | "arr-union": { 91 | "version": "3.1.0", 92 | "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", 93 | "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", 94 | "dev": true 95 | }, 96 | "array-flatten": { 97 | "version": "1.1.1", 98 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 99 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 100 | }, 101 | "array-unique": { 102 | "version": "0.3.2", 103 | "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", 104 | "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", 105 | "dev": true 106 | }, 107 | "asn1": { 108 | "version": "0.2.4", 109 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 110 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 111 | "requires": { 112 | "safer-buffer": "~2.1.0" 113 | } 114 | }, 115 | "assert-plus": { 116 | "version": "1.0.0", 117 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 118 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 119 | }, 120 | "assign-symbols": { 121 | "version": "1.0.0", 122 | "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", 123 | "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", 124 | "dev": true 125 | }, 126 | "async-each": { 127 | "version": "1.0.3", 128 | "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", 129 | "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", 130 | "dev": true 131 | }, 132 | "asynckit": { 133 | "version": "0.4.0", 134 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 135 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 136 | }, 137 | "atob": { 138 | "version": "2.1.2", 139 | "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", 140 | "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", 141 | "dev": true 142 | }, 143 | "aws-sign2": { 144 | "version": "0.7.0", 145 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 146 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 147 | }, 148 | "aws4": { 149 | "version": "1.8.0", 150 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 151 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" 152 | }, 153 | "balanced-match": { 154 | "version": "1.0.0", 155 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 156 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 157 | "dev": true 158 | }, 159 | "base": { 160 | "version": "0.11.2", 161 | "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", 162 | "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", 163 | "dev": true, 164 | "requires": { 165 | "cache-base": "^1.0.1", 166 | "class-utils": "^0.3.5", 167 | "component-emitter": "^1.2.1", 168 | "define-property": "^1.0.0", 169 | "isobject": "^3.0.1", 170 | "mixin-deep": "^1.2.0", 171 | "pascalcase": "^0.1.1" 172 | }, 173 | "dependencies": { 174 | "define-property": { 175 | "version": "1.0.0", 176 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 177 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 178 | "dev": true, 179 | "requires": { 180 | "is-descriptor": "^1.0.0" 181 | } 182 | }, 183 | "is-accessor-descriptor": { 184 | "version": "1.0.0", 185 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 186 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 187 | "dev": true, 188 | "requires": { 189 | "kind-of": "^6.0.0" 190 | } 191 | }, 192 | "is-data-descriptor": { 193 | "version": "1.0.0", 194 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 195 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 196 | "dev": true, 197 | "requires": { 198 | "kind-of": "^6.0.0" 199 | } 200 | }, 201 | "is-descriptor": { 202 | "version": "1.0.2", 203 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 204 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 205 | "dev": true, 206 | "requires": { 207 | "is-accessor-descriptor": "^1.0.0", 208 | "is-data-descriptor": "^1.0.0", 209 | "kind-of": "^6.0.2" 210 | } 211 | } 212 | } 213 | }, 214 | "basic-auth": { 215 | "version": "2.0.1", 216 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", 217 | "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", 218 | "requires": { 219 | "safe-buffer": "5.1.2" 220 | } 221 | }, 222 | "bcrypt-pbkdf": { 223 | "version": "1.0.2", 224 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 225 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 226 | "requires": { 227 | "tweetnacl": "^0.14.3" 228 | } 229 | }, 230 | "bcryptjs": { 231 | "version": "2.4.3", 232 | "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", 233 | "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" 234 | }, 235 | "binary-extensions": { 236 | "version": "1.13.1", 237 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", 238 | "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", 239 | "dev": true 240 | }, 241 | "bluebird": { 242 | "version": "3.5.1", 243 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", 244 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" 245 | }, 246 | "body-parser": { 247 | "version": "1.19.0", 248 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", 249 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 250 | "requires": { 251 | "bytes": "3.1.0", 252 | "content-type": "~1.0.4", 253 | "debug": "2.6.9", 254 | "depd": "~1.1.2", 255 | "http-errors": "1.7.2", 256 | "iconv-lite": "0.4.24", 257 | "on-finished": "~2.3.0", 258 | "qs": "6.7.0", 259 | "raw-body": "2.4.0", 260 | "type-is": "~1.6.17" 261 | } 262 | }, 263 | "bowser": { 264 | "version": "2.7.0", 265 | "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.7.0.tgz", 266 | "integrity": "sha512-aIlMvstvu8x+34KEiOHD3AsBgdrzg6sxALYiukOWhFvGMbQI6TRP/iY0LMhUrHs56aD6P1G0Z7h45PUJaa5m9w==" 267 | }, 268 | "boxen": { 269 | "version": "1.3.0", 270 | "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", 271 | "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", 272 | "dev": true, 273 | "requires": { 274 | "ansi-align": "^2.0.0", 275 | "camelcase": "^4.0.0", 276 | "chalk": "^2.0.1", 277 | "cli-boxes": "^1.0.0", 278 | "string-width": "^2.0.0", 279 | "term-size": "^1.2.0", 280 | "widest-line": "^2.0.0" 281 | } 282 | }, 283 | "brace-expansion": { 284 | "version": "1.1.11", 285 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 286 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 287 | "dev": true, 288 | "requires": { 289 | "balanced-match": "^1.0.0", 290 | "concat-map": "0.0.1" 291 | } 292 | }, 293 | "braces": { 294 | "version": "2.3.2", 295 | "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", 296 | "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", 297 | "dev": true, 298 | "requires": { 299 | "arr-flatten": "^1.1.0", 300 | "array-unique": "^0.3.2", 301 | "extend-shallow": "^2.0.1", 302 | "fill-range": "^4.0.0", 303 | "isobject": "^3.0.1", 304 | "repeat-element": "^1.1.2", 305 | "snapdragon": "^0.8.1", 306 | "snapdragon-node": "^2.0.1", 307 | "split-string": "^3.0.2", 308 | "to-regex": "^3.0.1" 309 | }, 310 | "dependencies": { 311 | "extend-shallow": { 312 | "version": "2.0.1", 313 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 314 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 315 | "dev": true, 316 | "requires": { 317 | "is-extendable": "^0.1.0" 318 | } 319 | } 320 | } 321 | }, 322 | "bson": { 323 | "version": "1.1.1", 324 | "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.1.tgz", 325 | "integrity": "sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg==" 326 | }, 327 | "buffer-equal-constant-time": { 328 | "version": "1.0.1", 329 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 330 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" 331 | }, 332 | "busboy": { 333 | "version": "0.2.14", 334 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", 335 | "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", 336 | "requires": { 337 | "dicer": "0.2.5", 338 | "readable-stream": "1.1.x" 339 | }, 340 | "dependencies": { 341 | "isarray": { 342 | "version": "0.0.1", 343 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 344 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 345 | }, 346 | "readable-stream": { 347 | "version": "1.1.14", 348 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 349 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 350 | "requires": { 351 | "core-util-is": "~1.0.0", 352 | "inherits": "~2.0.1", 353 | "isarray": "0.0.1", 354 | "string_decoder": "~0.10.x" 355 | } 356 | }, 357 | "string_decoder": { 358 | "version": "0.10.31", 359 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 360 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 361 | } 362 | } 363 | }, 364 | "bytes": { 365 | "version": "3.1.0", 366 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 367 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 368 | }, 369 | "cache-base": { 370 | "version": "1.0.1", 371 | "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", 372 | "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", 373 | "dev": true, 374 | "requires": { 375 | "collection-visit": "^1.0.0", 376 | "component-emitter": "^1.2.1", 377 | "get-value": "^2.0.6", 378 | "has-value": "^1.0.0", 379 | "isobject": "^3.0.1", 380 | "set-value": "^2.0.0", 381 | "to-object-path": "^0.3.0", 382 | "union-value": "^1.0.0", 383 | "unset-value": "^1.0.0" 384 | } 385 | }, 386 | "camelcase": { 387 | "version": "4.1.0", 388 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", 389 | "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", 390 | "dev": true 391 | }, 392 | "camelize": { 393 | "version": "1.0.0", 394 | "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", 395 | "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" 396 | }, 397 | "capture-stack-trace": { 398 | "version": "1.0.1", 399 | "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", 400 | "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", 401 | "dev": true 402 | }, 403 | "caseless": { 404 | "version": "0.12.0", 405 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 406 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 407 | }, 408 | "chalk": { 409 | "version": "2.4.2", 410 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 411 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 412 | "dev": true, 413 | "requires": { 414 | "ansi-styles": "^3.2.1", 415 | "escape-string-regexp": "^1.0.5", 416 | "supports-color": "^5.3.0" 417 | } 418 | }, 419 | "chokidar": { 420 | "version": "2.1.8", 421 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", 422 | "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", 423 | "dev": true, 424 | "requires": { 425 | "anymatch": "^2.0.0", 426 | "async-each": "^1.0.1", 427 | "braces": "^2.3.2", 428 | "fsevents": "^1.2.7", 429 | "glob-parent": "^3.1.0", 430 | "inherits": "^2.0.3", 431 | "is-binary-path": "^1.0.0", 432 | "is-glob": "^4.0.0", 433 | "normalize-path": "^3.0.0", 434 | "path-is-absolute": "^1.0.0", 435 | "readdirp": "^2.2.1", 436 | "upath": "^1.1.1" 437 | } 438 | }, 439 | "ci-info": { 440 | "version": "1.6.0", 441 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", 442 | "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", 443 | "dev": true 444 | }, 445 | "class-utils": { 446 | "version": "0.3.6", 447 | "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", 448 | "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", 449 | "dev": true, 450 | "requires": { 451 | "arr-union": "^3.1.0", 452 | "define-property": "^0.2.5", 453 | "isobject": "^3.0.0", 454 | "static-extend": "^0.1.1" 455 | }, 456 | "dependencies": { 457 | "define-property": { 458 | "version": "0.2.5", 459 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 460 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 461 | "dev": true, 462 | "requires": { 463 | "is-descriptor": "^0.1.0" 464 | } 465 | } 466 | } 467 | }, 468 | "cli-boxes": { 469 | "version": "1.0.0", 470 | "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", 471 | "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", 472 | "dev": true 473 | }, 474 | "collection-visit": { 475 | "version": "1.0.0", 476 | "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", 477 | "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", 478 | "dev": true, 479 | "requires": { 480 | "map-visit": "^1.0.0", 481 | "object-visit": "^1.0.0" 482 | } 483 | }, 484 | "color-convert": { 485 | "version": "1.9.3", 486 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 487 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 488 | "dev": true, 489 | "requires": { 490 | "color-name": "1.1.3" 491 | } 492 | }, 493 | "color-name": { 494 | "version": "1.1.3", 495 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 496 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 497 | "dev": true 498 | }, 499 | "colors": { 500 | "version": "1.4.0", 501 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", 502 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==" 503 | }, 504 | "combined-stream": { 505 | "version": "1.0.8", 506 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 507 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 508 | "requires": { 509 | "delayed-stream": "~1.0.0" 510 | } 511 | }, 512 | "component-emitter": { 513 | "version": "1.3.0", 514 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", 515 | "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", 516 | "dev": true 517 | }, 518 | "concat-map": { 519 | "version": "0.0.1", 520 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 521 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 522 | "dev": true 523 | }, 524 | "configstore": { 525 | "version": "3.1.2", 526 | "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", 527 | "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", 528 | "dev": true, 529 | "requires": { 530 | "dot-prop": "^4.1.0", 531 | "graceful-fs": "^4.1.2", 532 | "make-dir": "^1.0.0", 533 | "unique-string": "^1.0.0", 534 | "write-file-atomic": "^2.0.0", 535 | "xdg-basedir": "^3.0.0" 536 | } 537 | }, 538 | "content-disposition": { 539 | "version": "0.5.3", 540 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 541 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 542 | "requires": { 543 | "safe-buffer": "5.1.2" 544 | } 545 | }, 546 | "content-security-policy-builder": { 547 | "version": "2.1.0", 548 | "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz", 549 | "integrity": "sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ==" 550 | }, 551 | "content-type": { 552 | "version": "1.0.4", 553 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 554 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 555 | }, 556 | "cookie": { 557 | "version": "0.4.0", 558 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", 559 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 560 | }, 561 | "cookie-parser": { 562 | "version": "1.4.4", 563 | "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz", 564 | "integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==", 565 | "requires": { 566 | "cookie": "0.3.1", 567 | "cookie-signature": "1.0.6" 568 | }, 569 | "dependencies": { 570 | "cookie": { 571 | "version": "0.3.1", 572 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 573 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 574 | } 575 | } 576 | }, 577 | "cookie-signature": { 578 | "version": "1.0.6", 579 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 580 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 581 | }, 582 | "copy-descriptor": { 583 | "version": "0.1.1", 584 | "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", 585 | "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", 586 | "dev": true 587 | }, 588 | "core-util-is": { 589 | "version": "1.0.2", 590 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 591 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 592 | }, 593 | "cors": { 594 | "version": "2.8.5", 595 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", 596 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", 597 | "requires": { 598 | "object-assign": "^4", 599 | "vary": "^1" 600 | } 601 | }, 602 | "create-error-class": { 603 | "version": "3.0.2", 604 | "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", 605 | "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", 606 | "dev": true, 607 | "requires": { 608 | "capture-stack-trace": "^1.0.0" 609 | } 610 | }, 611 | "cross-spawn": { 612 | "version": "5.1.0", 613 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", 614 | "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", 615 | "dev": true, 616 | "requires": { 617 | "lru-cache": "^4.0.1", 618 | "shebang-command": "^1.2.0", 619 | "which": "^1.2.9" 620 | } 621 | }, 622 | "crypto-random-string": { 623 | "version": "1.0.0", 624 | "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", 625 | "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", 626 | "dev": true 627 | }, 628 | "dashdash": { 629 | "version": "1.14.1", 630 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 631 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 632 | "requires": { 633 | "assert-plus": "^1.0.0" 634 | } 635 | }, 636 | "dasherize": { 637 | "version": "2.0.0", 638 | "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz", 639 | "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg=" 640 | }, 641 | "debug": { 642 | "version": "2.6.9", 643 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 644 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 645 | "requires": { 646 | "ms": "2.0.0" 647 | } 648 | }, 649 | "decode-uri-component": { 650 | "version": "0.2.0", 651 | "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", 652 | "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", 653 | "dev": true 654 | }, 655 | "deep-extend": { 656 | "version": "0.6.0", 657 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 658 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 659 | "dev": true 660 | }, 661 | "define-property": { 662 | "version": "2.0.2", 663 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", 664 | "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", 665 | "dev": true, 666 | "requires": { 667 | "is-descriptor": "^1.0.2", 668 | "isobject": "^3.0.1" 669 | }, 670 | "dependencies": { 671 | "is-accessor-descriptor": { 672 | "version": "1.0.0", 673 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 674 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 675 | "dev": true, 676 | "requires": { 677 | "kind-of": "^6.0.0" 678 | } 679 | }, 680 | "is-data-descriptor": { 681 | "version": "1.0.0", 682 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 683 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 684 | "dev": true, 685 | "requires": { 686 | "kind-of": "^6.0.0" 687 | } 688 | }, 689 | "is-descriptor": { 690 | "version": "1.0.2", 691 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 692 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 693 | "dev": true, 694 | "requires": { 695 | "is-accessor-descriptor": "^1.0.0", 696 | "is-data-descriptor": "^1.0.0", 697 | "kind-of": "^6.0.2" 698 | } 699 | } 700 | } 701 | }, 702 | "delayed-stream": { 703 | "version": "1.0.0", 704 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 705 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 706 | }, 707 | "depd": { 708 | "version": "1.1.2", 709 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 710 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 711 | }, 712 | "destroy": { 713 | "version": "1.0.4", 714 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 715 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 716 | }, 717 | "dicer": { 718 | "version": "0.2.5", 719 | "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", 720 | "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", 721 | "requires": { 722 | "readable-stream": "1.1.x", 723 | "streamsearch": "0.1.2" 724 | }, 725 | "dependencies": { 726 | "isarray": { 727 | "version": "0.0.1", 728 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 729 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 730 | }, 731 | "readable-stream": { 732 | "version": "1.1.14", 733 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 734 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 735 | "requires": { 736 | "core-util-is": "~1.0.0", 737 | "inherits": "~2.0.1", 738 | "isarray": "0.0.1", 739 | "string_decoder": "~0.10.x" 740 | } 741 | }, 742 | "string_decoder": { 743 | "version": "0.10.31", 744 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 745 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 746 | } 747 | } 748 | }, 749 | "dns-prefetch-control": { 750 | "version": "0.2.0", 751 | "resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz", 752 | "integrity": "sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q==" 753 | }, 754 | "dont-sniff-mimetype": { 755 | "version": "1.1.0", 756 | "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz", 757 | "integrity": "sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug==" 758 | }, 759 | "dot-prop": { 760 | "version": "4.2.0", 761 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", 762 | "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", 763 | "dev": true, 764 | "requires": { 765 | "is-obj": "^1.0.0" 766 | } 767 | }, 768 | "dotenv": { 769 | "version": "8.1.0", 770 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz", 771 | "integrity": "sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA==" 772 | }, 773 | "duplexer3": { 774 | "version": "0.1.4", 775 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", 776 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", 777 | "dev": true 778 | }, 779 | "ecc-jsbn": { 780 | "version": "0.1.2", 781 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 782 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 783 | "requires": { 784 | "jsbn": "~0.1.0", 785 | "safer-buffer": "^2.1.0" 786 | } 787 | }, 788 | "ecdsa-sig-formatter": { 789 | "version": "1.0.11", 790 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", 791 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", 792 | "requires": { 793 | "safe-buffer": "^5.0.1" 794 | } 795 | }, 796 | "ee-first": { 797 | "version": "1.1.1", 798 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 799 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 800 | }, 801 | "encodeurl": { 802 | "version": "1.0.2", 803 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 804 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 805 | }, 806 | "escape-html": { 807 | "version": "1.0.3", 808 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 809 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 810 | }, 811 | "escape-string-regexp": { 812 | "version": "1.0.5", 813 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 814 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 815 | "dev": true 816 | }, 817 | "etag": { 818 | "version": "1.8.1", 819 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 820 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 821 | }, 822 | "execa": { 823 | "version": "0.7.0", 824 | "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", 825 | "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", 826 | "dev": true, 827 | "requires": { 828 | "cross-spawn": "^5.0.1", 829 | "get-stream": "^3.0.0", 830 | "is-stream": "^1.1.0", 831 | "npm-run-path": "^2.0.0", 832 | "p-finally": "^1.0.0", 833 | "signal-exit": "^3.0.0", 834 | "strip-eof": "^1.0.0" 835 | } 836 | }, 837 | "expand-brackets": { 838 | "version": "2.1.4", 839 | "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", 840 | "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", 841 | "dev": true, 842 | "requires": { 843 | "debug": "^2.3.3", 844 | "define-property": "^0.2.5", 845 | "extend-shallow": "^2.0.1", 846 | "posix-character-classes": "^0.1.0", 847 | "regex-not": "^1.0.0", 848 | "snapdragon": "^0.8.1", 849 | "to-regex": "^3.0.1" 850 | }, 851 | "dependencies": { 852 | "define-property": { 853 | "version": "0.2.5", 854 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 855 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 856 | "dev": true, 857 | "requires": { 858 | "is-descriptor": "^0.1.0" 859 | } 860 | }, 861 | "extend-shallow": { 862 | "version": "2.0.1", 863 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 864 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 865 | "dev": true, 866 | "requires": { 867 | "is-extendable": "^0.1.0" 868 | } 869 | } 870 | } 871 | }, 872 | "expect-ct": { 873 | "version": "0.2.0", 874 | "resolved": "https://registry.npmjs.org/expect-ct/-/expect-ct-0.2.0.tgz", 875 | "integrity": "sha512-6SK3MG/Bbhm8MsgyJAylg+ucIOU71/FzyFalcfu5nY19dH8y/z0tBJU0wrNBXD4B27EoQtqPF/9wqH0iYAd04g==" 876 | }, 877 | "express": { 878 | "version": "4.17.1", 879 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", 880 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", 881 | "requires": { 882 | "accepts": "~1.3.7", 883 | "array-flatten": "1.1.1", 884 | "body-parser": "1.19.0", 885 | "content-disposition": "0.5.3", 886 | "content-type": "~1.0.4", 887 | "cookie": "0.4.0", 888 | "cookie-signature": "1.0.6", 889 | "debug": "2.6.9", 890 | "depd": "~1.1.2", 891 | "encodeurl": "~1.0.2", 892 | "escape-html": "~1.0.3", 893 | "etag": "~1.8.1", 894 | "finalhandler": "~1.1.2", 895 | "fresh": "0.5.2", 896 | "merge-descriptors": "1.0.1", 897 | "methods": "~1.1.2", 898 | "on-finished": "~2.3.0", 899 | "parseurl": "~1.3.3", 900 | "path-to-regexp": "0.1.7", 901 | "proxy-addr": "~2.0.5", 902 | "qs": "6.7.0", 903 | "range-parser": "~1.2.1", 904 | "safe-buffer": "5.1.2", 905 | "send": "0.17.1", 906 | "serve-static": "1.14.1", 907 | "setprototypeof": "1.1.1", 908 | "statuses": "~1.5.0", 909 | "type-is": "~1.6.18", 910 | "utils-merge": "1.0.1", 911 | "vary": "~1.1.2" 912 | } 913 | }, 914 | "express-fileupload": { 915 | "version": "1.1.6-alpha.5", 916 | "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.1.6-alpha.5.tgz", 917 | "integrity": "sha512-M/PLB3moD1stnfYUHGtAVqfdjOz0VSY00NWnA9CpSEyPxhs/lEeperWOffaBzom+DO8Sq1z1okJOy2N4MDRYtA==", 918 | "requires": { 919 | "busboy": "^0.2.14" 920 | } 921 | }, 922 | "express-mongo-sanitize": { 923 | "version": "1.3.2", 924 | "resolved": "https://registry.npmjs.org/express-mongo-sanitize/-/express-mongo-sanitize-1.3.2.tgz", 925 | "integrity": "sha1-+6QE9sBBV3y+7sTdkFfO+7Q53lo=" 926 | }, 927 | "express-rate-limit": { 928 | "version": "5.0.0", 929 | "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.0.0.tgz", 930 | "integrity": "sha512-dhT57wqxfqmkOi4HM7NuT4Gd7gbUgSK2ocG27Y6lwm8lbOAw9XQfeANawGq8wLDtlGPO1ZgDj0HmKsykTxfFAg==" 931 | }, 932 | "extend": { 933 | "version": "3.0.2", 934 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 935 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 936 | }, 937 | "extend-shallow": { 938 | "version": "3.0.2", 939 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", 940 | "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", 941 | "dev": true, 942 | "requires": { 943 | "assign-symbols": "^1.0.0", 944 | "is-extendable": "^1.0.1" 945 | }, 946 | "dependencies": { 947 | "is-extendable": { 948 | "version": "1.0.1", 949 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 950 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 951 | "dev": true, 952 | "requires": { 953 | "is-plain-object": "^2.0.4" 954 | } 955 | } 956 | } 957 | }, 958 | "extglob": { 959 | "version": "2.0.4", 960 | "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", 961 | "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", 962 | "dev": true, 963 | "requires": { 964 | "array-unique": "^0.3.2", 965 | "define-property": "^1.0.0", 966 | "expand-brackets": "^2.1.4", 967 | "extend-shallow": "^2.0.1", 968 | "fragment-cache": "^0.2.1", 969 | "regex-not": "^1.0.0", 970 | "snapdragon": "^0.8.1", 971 | "to-regex": "^3.0.1" 972 | }, 973 | "dependencies": { 974 | "define-property": { 975 | "version": "1.0.0", 976 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 977 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 978 | "dev": true, 979 | "requires": { 980 | "is-descriptor": "^1.0.0" 981 | } 982 | }, 983 | "extend-shallow": { 984 | "version": "2.0.1", 985 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 986 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 987 | "dev": true, 988 | "requires": { 989 | "is-extendable": "^0.1.0" 990 | } 991 | }, 992 | "is-accessor-descriptor": { 993 | "version": "1.0.0", 994 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 995 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 996 | "dev": true, 997 | "requires": { 998 | "kind-of": "^6.0.0" 999 | } 1000 | }, 1001 | "is-data-descriptor": { 1002 | "version": "1.0.0", 1003 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 1004 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 1005 | "dev": true, 1006 | "requires": { 1007 | "kind-of": "^6.0.0" 1008 | } 1009 | }, 1010 | "is-descriptor": { 1011 | "version": "1.0.2", 1012 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 1013 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 1014 | "dev": true, 1015 | "requires": { 1016 | "is-accessor-descriptor": "^1.0.0", 1017 | "is-data-descriptor": "^1.0.0", 1018 | "kind-of": "^6.0.2" 1019 | } 1020 | } 1021 | } 1022 | }, 1023 | "extsprintf": { 1024 | "version": "1.3.0", 1025 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 1026 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 1027 | }, 1028 | "fast-deep-equal": { 1029 | "version": "2.0.1", 1030 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 1031 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" 1032 | }, 1033 | "fast-json-stable-stringify": { 1034 | "version": "2.0.0", 1035 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 1036 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 1037 | }, 1038 | "feature-policy": { 1039 | "version": "0.3.0", 1040 | "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz", 1041 | "integrity": "sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==" 1042 | }, 1043 | "fill-range": { 1044 | "version": "4.0.0", 1045 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", 1046 | "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", 1047 | "dev": true, 1048 | "requires": { 1049 | "extend-shallow": "^2.0.1", 1050 | "is-number": "^3.0.0", 1051 | "repeat-string": "^1.6.1", 1052 | "to-regex-range": "^2.1.0" 1053 | }, 1054 | "dependencies": { 1055 | "extend-shallow": { 1056 | "version": "2.0.1", 1057 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 1058 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 1059 | "dev": true, 1060 | "requires": { 1061 | "is-extendable": "^0.1.0" 1062 | } 1063 | } 1064 | } 1065 | }, 1066 | "finalhandler": { 1067 | "version": "1.1.2", 1068 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 1069 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 1070 | "requires": { 1071 | "debug": "2.6.9", 1072 | "encodeurl": "~1.0.2", 1073 | "escape-html": "~1.0.3", 1074 | "on-finished": "~2.3.0", 1075 | "parseurl": "~1.3.3", 1076 | "statuses": "~1.5.0", 1077 | "unpipe": "~1.0.0" 1078 | } 1079 | }, 1080 | "for-in": { 1081 | "version": "1.0.2", 1082 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", 1083 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", 1084 | "dev": true 1085 | }, 1086 | "forever-agent": { 1087 | "version": "0.6.1", 1088 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 1089 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 1090 | }, 1091 | "form-data": { 1092 | "version": "2.3.3", 1093 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 1094 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 1095 | "requires": { 1096 | "asynckit": "^0.4.0", 1097 | "combined-stream": "^1.0.6", 1098 | "mime-types": "^2.1.12" 1099 | } 1100 | }, 1101 | "forwarded": { 1102 | "version": "0.1.2", 1103 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 1104 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 1105 | }, 1106 | "fragment-cache": { 1107 | "version": "0.2.1", 1108 | "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", 1109 | "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", 1110 | "dev": true, 1111 | "requires": { 1112 | "map-cache": "^0.2.2" 1113 | } 1114 | }, 1115 | "frameguard": { 1116 | "version": "3.1.0", 1117 | "resolved": "https://registry.npmjs.org/frameguard/-/frameguard-3.1.0.tgz", 1118 | "integrity": "sha512-TxgSKM+7LTA6sidjOiSZK9wxY0ffMPY3Wta//MqwmX0nZuEHc8QrkV8Fh3ZhMJeiH+Uyh/tcaarImRy8u77O7g==" 1119 | }, 1120 | "fresh": { 1121 | "version": "0.5.2", 1122 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 1123 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 1124 | }, 1125 | "fsevents": { 1126 | "version": "1.2.9", 1127 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", 1128 | "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", 1129 | "dev": true, 1130 | "optional": true, 1131 | "requires": { 1132 | "nan": "^2.12.1", 1133 | "node-pre-gyp": "^0.12.0" 1134 | }, 1135 | "dependencies": { 1136 | "abbrev": { 1137 | "version": "1.1.1", 1138 | "bundled": true, 1139 | "dev": true, 1140 | "optional": true 1141 | }, 1142 | "ansi-regex": { 1143 | "version": "2.1.1", 1144 | "bundled": true, 1145 | "dev": true, 1146 | "optional": true 1147 | }, 1148 | "aproba": { 1149 | "version": "1.2.0", 1150 | "bundled": true, 1151 | "dev": true, 1152 | "optional": true 1153 | }, 1154 | "are-we-there-yet": { 1155 | "version": "1.1.5", 1156 | "bundled": true, 1157 | "dev": true, 1158 | "optional": true, 1159 | "requires": { 1160 | "delegates": "^1.0.0", 1161 | "readable-stream": "^2.0.6" 1162 | } 1163 | }, 1164 | "balanced-match": { 1165 | "version": "1.0.0", 1166 | "bundled": true, 1167 | "dev": true, 1168 | "optional": true 1169 | }, 1170 | "brace-expansion": { 1171 | "version": "1.1.11", 1172 | "bundled": true, 1173 | "dev": true, 1174 | "optional": true, 1175 | "requires": { 1176 | "balanced-match": "^1.0.0", 1177 | "concat-map": "0.0.1" 1178 | } 1179 | }, 1180 | "chownr": { 1181 | "version": "1.1.1", 1182 | "bundled": true, 1183 | "dev": true, 1184 | "optional": true 1185 | }, 1186 | "code-point-at": { 1187 | "version": "1.1.0", 1188 | "bundled": true, 1189 | "dev": true, 1190 | "optional": true 1191 | }, 1192 | "concat-map": { 1193 | "version": "0.0.1", 1194 | "bundled": true, 1195 | "dev": true, 1196 | "optional": true 1197 | }, 1198 | "console-control-strings": { 1199 | "version": "1.1.0", 1200 | "bundled": true, 1201 | "dev": true, 1202 | "optional": true 1203 | }, 1204 | "core-util-is": { 1205 | "version": "1.0.2", 1206 | "bundled": true, 1207 | "dev": true, 1208 | "optional": true 1209 | }, 1210 | "debug": { 1211 | "version": "4.1.1", 1212 | "bundled": true, 1213 | "dev": true, 1214 | "optional": true, 1215 | "requires": { 1216 | "ms": "^2.1.1" 1217 | } 1218 | }, 1219 | "deep-extend": { 1220 | "version": "0.6.0", 1221 | "bundled": true, 1222 | "dev": true, 1223 | "optional": true 1224 | }, 1225 | "delegates": { 1226 | "version": "1.0.0", 1227 | "bundled": true, 1228 | "dev": true, 1229 | "optional": true 1230 | }, 1231 | "detect-libc": { 1232 | "version": "1.0.3", 1233 | "bundled": true, 1234 | "dev": true, 1235 | "optional": true 1236 | }, 1237 | "fs-minipass": { 1238 | "version": "1.2.5", 1239 | "bundled": true, 1240 | "dev": true, 1241 | "optional": true, 1242 | "requires": { 1243 | "minipass": "^2.2.1" 1244 | } 1245 | }, 1246 | "fs.realpath": { 1247 | "version": "1.0.0", 1248 | "bundled": true, 1249 | "dev": true, 1250 | "optional": true 1251 | }, 1252 | "gauge": { 1253 | "version": "2.7.4", 1254 | "bundled": true, 1255 | "dev": true, 1256 | "optional": true, 1257 | "requires": { 1258 | "aproba": "^1.0.3", 1259 | "console-control-strings": "^1.0.0", 1260 | "has-unicode": "^2.0.0", 1261 | "object-assign": "^4.1.0", 1262 | "signal-exit": "^3.0.0", 1263 | "string-width": "^1.0.1", 1264 | "strip-ansi": "^3.0.1", 1265 | "wide-align": "^1.1.0" 1266 | } 1267 | }, 1268 | "glob": { 1269 | "version": "7.1.3", 1270 | "bundled": true, 1271 | "dev": true, 1272 | "optional": true, 1273 | "requires": { 1274 | "fs.realpath": "^1.0.0", 1275 | "inflight": "^1.0.4", 1276 | "inherits": "2", 1277 | "minimatch": "^3.0.4", 1278 | "once": "^1.3.0", 1279 | "path-is-absolute": "^1.0.0" 1280 | } 1281 | }, 1282 | "has-unicode": { 1283 | "version": "2.0.1", 1284 | "bundled": true, 1285 | "dev": true, 1286 | "optional": true 1287 | }, 1288 | "iconv-lite": { 1289 | "version": "0.4.24", 1290 | "bundled": true, 1291 | "dev": true, 1292 | "optional": true, 1293 | "requires": { 1294 | "safer-buffer": ">= 2.1.2 < 3" 1295 | } 1296 | }, 1297 | "ignore-walk": { 1298 | "version": "3.0.1", 1299 | "bundled": true, 1300 | "dev": true, 1301 | "optional": true, 1302 | "requires": { 1303 | "minimatch": "^3.0.4" 1304 | } 1305 | }, 1306 | "inflight": { 1307 | "version": "1.0.6", 1308 | "bundled": true, 1309 | "dev": true, 1310 | "optional": true, 1311 | "requires": { 1312 | "once": "^1.3.0", 1313 | "wrappy": "1" 1314 | } 1315 | }, 1316 | "inherits": { 1317 | "version": "2.0.3", 1318 | "bundled": true, 1319 | "dev": true, 1320 | "optional": true 1321 | }, 1322 | "ini": { 1323 | "version": "1.3.5", 1324 | "bundled": true, 1325 | "dev": true, 1326 | "optional": true 1327 | }, 1328 | "is-fullwidth-code-point": { 1329 | "version": "1.0.0", 1330 | "bundled": true, 1331 | "dev": true, 1332 | "optional": true, 1333 | "requires": { 1334 | "number-is-nan": "^1.0.0" 1335 | } 1336 | }, 1337 | "isarray": { 1338 | "version": "1.0.0", 1339 | "bundled": true, 1340 | "dev": true, 1341 | "optional": true 1342 | }, 1343 | "minimatch": { 1344 | "version": "3.0.4", 1345 | "bundled": true, 1346 | "dev": true, 1347 | "optional": true, 1348 | "requires": { 1349 | "brace-expansion": "^1.1.7" 1350 | } 1351 | }, 1352 | "minimist": { 1353 | "version": "0.0.8", 1354 | "bundled": true, 1355 | "dev": true, 1356 | "optional": true 1357 | }, 1358 | "minipass": { 1359 | "version": "2.3.5", 1360 | "bundled": true, 1361 | "dev": true, 1362 | "optional": true, 1363 | "requires": { 1364 | "safe-buffer": "^5.1.2", 1365 | "yallist": "^3.0.0" 1366 | } 1367 | }, 1368 | "minizlib": { 1369 | "version": "1.2.1", 1370 | "bundled": true, 1371 | "dev": true, 1372 | "optional": true, 1373 | "requires": { 1374 | "minipass": "^2.2.1" 1375 | } 1376 | }, 1377 | "mkdirp": { 1378 | "version": "0.5.1", 1379 | "bundled": true, 1380 | "dev": true, 1381 | "optional": true, 1382 | "requires": { 1383 | "minimist": "0.0.8" 1384 | } 1385 | }, 1386 | "ms": { 1387 | "version": "2.1.1", 1388 | "bundled": true, 1389 | "dev": true, 1390 | "optional": true 1391 | }, 1392 | "needle": { 1393 | "version": "2.3.0", 1394 | "bundled": true, 1395 | "dev": true, 1396 | "optional": true, 1397 | "requires": { 1398 | "debug": "^4.1.0", 1399 | "iconv-lite": "^0.4.4", 1400 | "sax": "^1.2.4" 1401 | } 1402 | }, 1403 | "node-pre-gyp": { 1404 | "version": "0.12.0", 1405 | "bundled": true, 1406 | "dev": true, 1407 | "optional": true, 1408 | "requires": { 1409 | "detect-libc": "^1.0.2", 1410 | "mkdirp": "^0.5.1", 1411 | "needle": "^2.2.1", 1412 | "nopt": "^4.0.1", 1413 | "npm-packlist": "^1.1.6", 1414 | "npmlog": "^4.0.2", 1415 | "rc": "^1.2.7", 1416 | "rimraf": "^2.6.1", 1417 | "semver": "^5.3.0", 1418 | "tar": "^4" 1419 | } 1420 | }, 1421 | "nopt": { 1422 | "version": "4.0.1", 1423 | "bundled": true, 1424 | "dev": true, 1425 | "optional": true, 1426 | "requires": { 1427 | "abbrev": "1", 1428 | "osenv": "^0.1.4" 1429 | } 1430 | }, 1431 | "npm-bundled": { 1432 | "version": "1.0.6", 1433 | "bundled": true, 1434 | "dev": true, 1435 | "optional": true 1436 | }, 1437 | "npm-packlist": { 1438 | "version": "1.4.1", 1439 | "bundled": true, 1440 | "dev": true, 1441 | "optional": true, 1442 | "requires": { 1443 | "ignore-walk": "^3.0.1", 1444 | "npm-bundled": "^1.0.1" 1445 | } 1446 | }, 1447 | "npmlog": { 1448 | "version": "4.1.2", 1449 | "bundled": true, 1450 | "dev": true, 1451 | "optional": true, 1452 | "requires": { 1453 | "are-we-there-yet": "~1.1.2", 1454 | "console-control-strings": "~1.1.0", 1455 | "gauge": "~2.7.3", 1456 | "set-blocking": "~2.0.0" 1457 | } 1458 | }, 1459 | "number-is-nan": { 1460 | "version": "1.0.1", 1461 | "bundled": true, 1462 | "dev": true, 1463 | "optional": true 1464 | }, 1465 | "object-assign": { 1466 | "version": "4.1.1", 1467 | "bundled": true, 1468 | "dev": true, 1469 | "optional": true 1470 | }, 1471 | "once": { 1472 | "version": "1.4.0", 1473 | "bundled": true, 1474 | "dev": true, 1475 | "optional": true, 1476 | "requires": { 1477 | "wrappy": "1" 1478 | } 1479 | }, 1480 | "os-homedir": { 1481 | "version": "1.0.2", 1482 | "bundled": true, 1483 | "dev": true, 1484 | "optional": true 1485 | }, 1486 | "os-tmpdir": { 1487 | "version": "1.0.2", 1488 | "bundled": true, 1489 | "dev": true, 1490 | "optional": true 1491 | }, 1492 | "osenv": { 1493 | "version": "0.1.5", 1494 | "bundled": true, 1495 | "dev": true, 1496 | "optional": true, 1497 | "requires": { 1498 | "os-homedir": "^1.0.0", 1499 | "os-tmpdir": "^1.0.0" 1500 | } 1501 | }, 1502 | "path-is-absolute": { 1503 | "version": "1.0.1", 1504 | "bundled": true, 1505 | "dev": true, 1506 | "optional": true 1507 | }, 1508 | "process-nextick-args": { 1509 | "version": "2.0.0", 1510 | "bundled": true, 1511 | "dev": true, 1512 | "optional": true 1513 | }, 1514 | "rc": { 1515 | "version": "1.2.8", 1516 | "bundled": true, 1517 | "dev": true, 1518 | "optional": true, 1519 | "requires": { 1520 | "deep-extend": "^0.6.0", 1521 | "ini": "~1.3.0", 1522 | "minimist": "^1.2.0", 1523 | "strip-json-comments": "~2.0.1" 1524 | }, 1525 | "dependencies": { 1526 | "minimist": { 1527 | "version": "1.2.0", 1528 | "bundled": true, 1529 | "dev": true, 1530 | "optional": true 1531 | } 1532 | } 1533 | }, 1534 | "readable-stream": { 1535 | "version": "2.3.6", 1536 | "bundled": true, 1537 | "dev": true, 1538 | "optional": true, 1539 | "requires": { 1540 | "core-util-is": "~1.0.0", 1541 | "inherits": "~2.0.3", 1542 | "isarray": "~1.0.0", 1543 | "process-nextick-args": "~2.0.0", 1544 | "safe-buffer": "~5.1.1", 1545 | "string_decoder": "~1.1.1", 1546 | "util-deprecate": "~1.0.1" 1547 | } 1548 | }, 1549 | "rimraf": { 1550 | "version": "2.6.3", 1551 | "bundled": true, 1552 | "dev": true, 1553 | "optional": true, 1554 | "requires": { 1555 | "glob": "^7.1.3" 1556 | } 1557 | }, 1558 | "safe-buffer": { 1559 | "version": "5.1.2", 1560 | "bundled": true, 1561 | "dev": true, 1562 | "optional": true 1563 | }, 1564 | "safer-buffer": { 1565 | "version": "2.1.2", 1566 | "bundled": true, 1567 | "dev": true, 1568 | "optional": true 1569 | }, 1570 | "sax": { 1571 | "version": "1.2.4", 1572 | "bundled": true, 1573 | "dev": true, 1574 | "optional": true 1575 | }, 1576 | "semver": { 1577 | "version": "5.7.0", 1578 | "bundled": true, 1579 | "dev": true, 1580 | "optional": true 1581 | }, 1582 | "set-blocking": { 1583 | "version": "2.0.0", 1584 | "bundled": true, 1585 | "dev": true, 1586 | "optional": true 1587 | }, 1588 | "signal-exit": { 1589 | "version": "3.0.2", 1590 | "bundled": true, 1591 | "dev": true, 1592 | "optional": true 1593 | }, 1594 | "string-width": { 1595 | "version": "1.0.2", 1596 | "bundled": true, 1597 | "dev": true, 1598 | "optional": true, 1599 | "requires": { 1600 | "code-point-at": "^1.0.0", 1601 | "is-fullwidth-code-point": "^1.0.0", 1602 | "strip-ansi": "^3.0.0" 1603 | } 1604 | }, 1605 | "string_decoder": { 1606 | "version": "1.1.1", 1607 | "bundled": true, 1608 | "dev": true, 1609 | "optional": true, 1610 | "requires": { 1611 | "safe-buffer": "~5.1.0" 1612 | } 1613 | }, 1614 | "strip-ansi": { 1615 | "version": "3.0.1", 1616 | "bundled": true, 1617 | "dev": true, 1618 | "optional": true, 1619 | "requires": { 1620 | "ansi-regex": "^2.0.0" 1621 | } 1622 | }, 1623 | "strip-json-comments": { 1624 | "version": "2.0.1", 1625 | "bundled": true, 1626 | "dev": true, 1627 | "optional": true 1628 | }, 1629 | "tar": { 1630 | "version": "4.4.8", 1631 | "bundled": true, 1632 | "dev": true, 1633 | "optional": true, 1634 | "requires": { 1635 | "chownr": "^1.1.1", 1636 | "fs-minipass": "^1.2.5", 1637 | "minipass": "^2.3.4", 1638 | "minizlib": "^1.1.1", 1639 | "mkdirp": "^0.5.0", 1640 | "safe-buffer": "^5.1.2", 1641 | "yallist": "^3.0.2" 1642 | } 1643 | }, 1644 | "util-deprecate": { 1645 | "version": "1.0.2", 1646 | "bundled": true, 1647 | "dev": true, 1648 | "optional": true 1649 | }, 1650 | "wide-align": { 1651 | "version": "1.1.3", 1652 | "bundled": true, 1653 | "dev": true, 1654 | "optional": true, 1655 | "requires": { 1656 | "string-width": "^1.0.2 || 2" 1657 | } 1658 | }, 1659 | "wrappy": { 1660 | "version": "1.0.2", 1661 | "bundled": true, 1662 | "dev": true, 1663 | "optional": true 1664 | }, 1665 | "yallist": { 1666 | "version": "3.0.3", 1667 | "bundled": true, 1668 | "dev": true, 1669 | "optional": true 1670 | } 1671 | } 1672 | }, 1673 | "get-stream": { 1674 | "version": "3.0.0", 1675 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", 1676 | "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", 1677 | "dev": true 1678 | }, 1679 | "get-value": { 1680 | "version": "2.0.6", 1681 | "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", 1682 | "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", 1683 | "dev": true 1684 | }, 1685 | "getpass": { 1686 | "version": "0.1.7", 1687 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 1688 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 1689 | "requires": { 1690 | "assert-plus": "^1.0.0" 1691 | } 1692 | }, 1693 | "glob-parent": { 1694 | "version": "3.1.0", 1695 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", 1696 | "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", 1697 | "dev": true, 1698 | "requires": { 1699 | "is-glob": "^3.1.0", 1700 | "path-dirname": "^1.0.0" 1701 | }, 1702 | "dependencies": { 1703 | "is-glob": { 1704 | "version": "3.1.0", 1705 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", 1706 | "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", 1707 | "dev": true, 1708 | "requires": { 1709 | "is-extglob": "^2.1.0" 1710 | } 1711 | } 1712 | } 1713 | }, 1714 | "global-dirs": { 1715 | "version": "0.1.1", 1716 | "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", 1717 | "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", 1718 | "dev": true, 1719 | "requires": { 1720 | "ini": "^1.3.4" 1721 | } 1722 | }, 1723 | "got": { 1724 | "version": "6.7.1", 1725 | "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", 1726 | "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", 1727 | "dev": true, 1728 | "requires": { 1729 | "create-error-class": "^3.0.0", 1730 | "duplexer3": "^0.1.4", 1731 | "get-stream": "^3.0.0", 1732 | "is-redirect": "^1.0.0", 1733 | "is-retry-allowed": "^1.0.0", 1734 | "is-stream": "^1.0.0", 1735 | "lowercase-keys": "^1.0.0", 1736 | "safe-buffer": "^5.0.1", 1737 | "timed-out": "^4.0.0", 1738 | "unzip-response": "^2.0.1", 1739 | "url-parse-lax": "^1.0.0" 1740 | } 1741 | }, 1742 | "graceful-fs": { 1743 | "version": "4.2.2", 1744 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", 1745 | "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", 1746 | "dev": true 1747 | }, 1748 | "har-schema": { 1749 | "version": "2.0.0", 1750 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 1751 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 1752 | }, 1753 | "har-validator": { 1754 | "version": "5.1.3", 1755 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", 1756 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", 1757 | "requires": { 1758 | "ajv": "^6.5.5", 1759 | "har-schema": "^2.0.0" 1760 | } 1761 | }, 1762 | "has-flag": { 1763 | "version": "3.0.0", 1764 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1765 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 1766 | "dev": true 1767 | }, 1768 | "has-value": { 1769 | "version": "1.0.0", 1770 | "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", 1771 | "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", 1772 | "dev": true, 1773 | "requires": { 1774 | "get-value": "^2.0.6", 1775 | "has-values": "^1.0.0", 1776 | "isobject": "^3.0.0" 1777 | } 1778 | }, 1779 | "has-values": { 1780 | "version": "1.0.0", 1781 | "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", 1782 | "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", 1783 | "dev": true, 1784 | "requires": { 1785 | "is-number": "^3.0.0", 1786 | "kind-of": "^4.0.0" 1787 | }, 1788 | "dependencies": { 1789 | "kind-of": { 1790 | "version": "4.0.0", 1791 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", 1792 | "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", 1793 | "dev": true, 1794 | "requires": { 1795 | "is-buffer": "^1.1.5" 1796 | } 1797 | } 1798 | } 1799 | }, 1800 | "helmet": { 1801 | "version": "3.21.1", 1802 | "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.21.1.tgz", 1803 | "integrity": "sha512-IC/54Lxvvad2YiUdgLmPlNFKLhNuG++waTF5KPYq/Feo3NNhqMFbcLAlbVkai+9q0+4uxjxGPJ9bNykG+3zZNg==", 1804 | "requires": { 1805 | "depd": "2.0.0", 1806 | "dns-prefetch-control": "0.2.0", 1807 | "dont-sniff-mimetype": "1.1.0", 1808 | "expect-ct": "0.2.0", 1809 | "feature-policy": "0.3.0", 1810 | "frameguard": "3.1.0", 1811 | "helmet-crossdomain": "0.4.0", 1812 | "helmet-csp": "2.9.2", 1813 | "hide-powered-by": "1.1.0", 1814 | "hpkp": "2.0.0", 1815 | "hsts": "2.2.0", 1816 | "ienoopen": "1.1.0", 1817 | "nocache": "2.1.0", 1818 | "referrer-policy": "1.2.0", 1819 | "x-xss-protection": "1.3.0" 1820 | }, 1821 | "dependencies": { 1822 | "depd": { 1823 | "version": "2.0.0", 1824 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 1825 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" 1826 | } 1827 | } 1828 | }, 1829 | "helmet-crossdomain": { 1830 | "version": "0.4.0", 1831 | "resolved": "https://registry.npmjs.org/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz", 1832 | "integrity": "sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA==" 1833 | }, 1834 | "helmet-csp": { 1835 | "version": "2.9.2", 1836 | "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.9.2.tgz", 1837 | "integrity": "sha512-Lt5WqNfbNjEJ6ysD4UNpVktSyjEKfU9LVJ1LaFmPfYseg/xPealPfgHhtqdAdjPDopp5zbg/VWCyp4cluMIckw==", 1838 | "requires": { 1839 | "bowser": "^2.6.1", 1840 | "camelize": "1.0.0", 1841 | "content-security-policy-builder": "2.1.0", 1842 | "dasherize": "2.0.0" 1843 | } 1844 | }, 1845 | "hide-powered-by": { 1846 | "version": "1.1.0", 1847 | "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.1.0.tgz", 1848 | "integrity": "sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg==" 1849 | }, 1850 | "hpkp": { 1851 | "version": "2.0.0", 1852 | "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz", 1853 | "integrity": "sha1-EOFCJk52IVpdMMROxD3mTe5tFnI=" 1854 | }, 1855 | "hpp": { 1856 | "version": "0.2.2", 1857 | "resolved": "https://registry.npmjs.org/hpp/-/hpp-0.2.2.tgz", 1858 | "integrity": "sha1-DsX3dHIEmnQ2HYW6K4jiRwpDVvg=", 1859 | "requires": { 1860 | "lodash": "^4.7.0", 1861 | "type-is": "^1.6.12" 1862 | } 1863 | }, 1864 | "hsts": { 1865 | "version": "2.2.0", 1866 | "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.2.0.tgz", 1867 | "integrity": "sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ==", 1868 | "requires": { 1869 | "depd": "2.0.0" 1870 | }, 1871 | "dependencies": { 1872 | "depd": { 1873 | "version": "2.0.0", 1874 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", 1875 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" 1876 | } 1877 | } 1878 | }, 1879 | "http-errors": { 1880 | "version": "1.7.2", 1881 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 1882 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 1883 | "requires": { 1884 | "depd": "~1.1.2", 1885 | "inherits": "2.0.3", 1886 | "setprototypeof": "1.1.1", 1887 | "statuses": ">= 1.5.0 < 2", 1888 | "toidentifier": "1.0.0" 1889 | } 1890 | }, 1891 | "http-signature": { 1892 | "version": "1.2.0", 1893 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 1894 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 1895 | "requires": { 1896 | "assert-plus": "^1.0.0", 1897 | "jsprim": "^1.2.2", 1898 | "sshpk": "^1.7.0" 1899 | } 1900 | }, 1901 | "iconv-lite": { 1902 | "version": "0.4.24", 1903 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 1904 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 1905 | "requires": { 1906 | "safer-buffer": ">= 2.1.2 < 3" 1907 | } 1908 | }, 1909 | "ienoopen": { 1910 | "version": "1.1.0", 1911 | "resolved": "https://registry.npmjs.org/ienoopen/-/ienoopen-1.1.0.tgz", 1912 | "integrity": "sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ==" 1913 | }, 1914 | "ignore-by-default": { 1915 | "version": "1.0.1", 1916 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", 1917 | "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", 1918 | "dev": true 1919 | }, 1920 | "import-lazy": { 1921 | "version": "2.1.0", 1922 | "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", 1923 | "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", 1924 | "dev": true 1925 | }, 1926 | "imurmurhash": { 1927 | "version": "0.1.4", 1928 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 1929 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 1930 | "dev": true 1931 | }, 1932 | "inherits": { 1933 | "version": "2.0.3", 1934 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1935 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 1936 | }, 1937 | "ini": { 1938 | "version": "1.3.5", 1939 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", 1940 | "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", 1941 | "dev": true 1942 | }, 1943 | "ipaddr.js": { 1944 | "version": "1.9.0", 1945 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", 1946 | "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" 1947 | }, 1948 | "is-accessor-descriptor": { 1949 | "version": "0.1.6", 1950 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", 1951 | "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", 1952 | "dev": true, 1953 | "requires": { 1954 | "kind-of": "^3.0.2" 1955 | }, 1956 | "dependencies": { 1957 | "kind-of": { 1958 | "version": "3.2.2", 1959 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1960 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1961 | "dev": true, 1962 | "requires": { 1963 | "is-buffer": "^1.1.5" 1964 | } 1965 | } 1966 | } 1967 | }, 1968 | "is-binary-path": { 1969 | "version": "1.0.1", 1970 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", 1971 | "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", 1972 | "dev": true, 1973 | "requires": { 1974 | "binary-extensions": "^1.0.0" 1975 | } 1976 | }, 1977 | "is-buffer": { 1978 | "version": "1.1.6", 1979 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 1980 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", 1981 | "dev": true 1982 | }, 1983 | "is-ci": { 1984 | "version": "1.2.1", 1985 | "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", 1986 | "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", 1987 | "dev": true, 1988 | "requires": { 1989 | "ci-info": "^1.5.0" 1990 | } 1991 | }, 1992 | "is-data-descriptor": { 1993 | "version": "0.1.4", 1994 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", 1995 | "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", 1996 | "dev": true, 1997 | "requires": { 1998 | "kind-of": "^3.0.2" 1999 | }, 2000 | "dependencies": { 2001 | "kind-of": { 2002 | "version": "3.2.2", 2003 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 2004 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 2005 | "dev": true, 2006 | "requires": { 2007 | "is-buffer": "^1.1.5" 2008 | } 2009 | } 2010 | } 2011 | }, 2012 | "is-descriptor": { 2013 | "version": "0.1.6", 2014 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", 2015 | "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", 2016 | "dev": true, 2017 | "requires": { 2018 | "is-accessor-descriptor": "^0.1.6", 2019 | "is-data-descriptor": "^0.1.4", 2020 | "kind-of": "^5.0.0" 2021 | }, 2022 | "dependencies": { 2023 | "kind-of": { 2024 | "version": "5.1.0", 2025 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", 2026 | "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", 2027 | "dev": true 2028 | } 2029 | } 2030 | }, 2031 | "is-extendable": { 2032 | "version": "0.1.1", 2033 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", 2034 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", 2035 | "dev": true 2036 | }, 2037 | "is-extglob": { 2038 | "version": "2.1.1", 2039 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 2040 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 2041 | "dev": true 2042 | }, 2043 | "is-fullwidth-code-point": { 2044 | "version": "2.0.0", 2045 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 2046 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", 2047 | "dev": true 2048 | }, 2049 | "is-glob": { 2050 | "version": "4.0.1", 2051 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", 2052 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", 2053 | "dev": true, 2054 | "requires": { 2055 | "is-extglob": "^2.1.1" 2056 | } 2057 | }, 2058 | "is-installed-globally": { 2059 | "version": "0.1.0", 2060 | "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", 2061 | "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", 2062 | "dev": true, 2063 | "requires": { 2064 | "global-dirs": "^0.1.0", 2065 | "is-path-inside": "^1.0.0" 2066 | } 2067 | }, 2068 | "is-npm": { 2069 | "version": "1.0.0", 2070 | "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", 2071 | "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", 2072 | "dev": true 2073 | }, 2074 | "is-number": { 2075 | "version": "3.0.0", 2076 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", 2077 | "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", 2078 | "dev": true, 2079 | "requires": { 2080 | "kind-of": "^3.0.2" 2081 | }, 2082 | "dependencies": { 2083 | "kind-of": { 2084 | "version": "3.2.2", 2085 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 2086 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 2087 | "dev": true, 2088 | "requires": { 2089 | "is-buffer": "^1.1.5" 2090 | } 2091 | } 2092 | } 2093 | }, 2094 | "is-obj": { 2095 | "version": "1.0.1", 2096 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", 2097 | "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", 2098 | "dev": true 2099 | }, 2100 | "is-path-inside": { 2101 | "version": "1.0.1", 2102 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", 2103 | "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", 2104 | "dev": true, 2105 | "requires": { 2106 | "path-is-inside": "^1.0.1" 2107 | } 2108 | }, 2109 | "is-plain-object": { 2110 | "version": "2.0.4", 2111 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", 2112 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", 2113 | "dev": true, 2114 | "requires": { 2115 | "isobject": "^3.0.1" 2116 | } 2117 | }, 2118 | "is-redirect": { 2119 | "version": "1.0.0", 2120 | "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", 2121 | "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", 2122 | "dev": true 2123 | }, 2124 | "is-retry-allowed": { 2125 | "version": "1.2.0", 2126 | "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", 2127 | "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", 2128 | "dev": true 2129 | }, 2130 | "is-stream": { 2131 | "version": "1.1.0", 2132 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 2133 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", 2134 | "dev": true 2135 | }, 2136 | "is-typedarray": { 2137 | "version": "1.0.0", 2138 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 2139 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 2140 | }, 2141 | "is-windows": { 2142 | "version": "1.0.2", 2143 | "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", 2144 | "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", 2145 | "dev": true 2146 | }, 2147 | "isarray": { 2148 | "version": "1.0.0", 2149 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 2150 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 2151 | "dev": true 2152 | }, 2153 | "isexe": { 2154 | "version": "2.0.0", 2155 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 2156 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 2157 | "dev": true 2158 | }, 2159 | "isobject": { 2160 | "version": "3.0.1", 2161 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", 2162 | "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", 2163 | "dev": true 2164 | }, 2165 | "isstream": { 2166 | "version": "0.1.2", 2167 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 2168 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 2169 | }, 2170 | "jsbn": { 2171 | "version": "0.1.1", 2172 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 2173 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 2174 | }, 2175 | "json-schema": { 2176 | "version": "0.2.3", 2177 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 2178 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 2179 | }, 2180 | "json-schema-traverse": { 2181 | "version": "0.4.1", 2182 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 2183 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 2184 | }, 2185 | "json-stringify-safe": { 2186 | "version": "5.0.1", 2187 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 2188 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 2189 | }, 2190 | "jsonwebtoken": { 2191 | "version": "8.5.1", 2192 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", 2193 | "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", 2194 | "requires": { 2195 | "jws": "^3.2.2", 2196 | "lodash.includes": "^4.3.0", 2197 | "lodash.isboolean": "^3.0.3", 2198 | "lodash.isinteger": "^4.0.4", 2199 | "lodash.isnumber": "^3.0.3", 2200 | "lodash.isplainobject": "^4.0.6", 2201 | "lodash.isstring": "^4.0.1", 2202 | "lodash.once": "^4.0.0", 2203 | "ms": "^2.1.1", 2204 | "semver": "^5.6.0" 2205 | }, 2206 | "dependencies": { 2207 | "ms": { 2208 | "version": "2.1.2", 2209 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 2210 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 2211 | } 2212 | } 2213 | }, 2214 | "jsprim": { 2215 | "version": "1.4.1", 2216 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 2217 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 2218 | "requires": { 2219 | "assert-plus": "1.0.0", 2220 | "extsprintf": "1.3.0", 2221 | "json-schema": "0.2.3", 2222 | "verror": "1.10.0" 2223 | } 2224 | }, 2225 | "jwa": { 2226 | "version": "1.4.1", 2227 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", 2228 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", 2229 | "requires": { 2230 | "buffer-equal-constant-time": "1.0.1", 2231 | "ecdsa-sig-formatter": "1.0.11", 2232 | "safe-buffer": "^5.0.1" 2233 | } 2234 | }, 2235 | "jws": { 2236 | "version": "3.2.2", 2237 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", 2238 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", 2239 | "requires": { 2240 | "jwa": "^1.4.1", 2241 | "safe-buffer": "^5.0.1" 2242 | } 2243 | }, 2244 | "kareem": { 2245 | "version": "2.3.1", 2246 | "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz", 2247 | "integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw==" 2248 | }, 2249 | "kind-of": { 2250 | "version": "6.0.2", 2251 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", 2252 | "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", 2253 | "dev": true 2254 | }, 2255 | "latest-version": { 2256 | "version": "3.1.0", 2257 | "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", 2258 | "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", 2259 | "dev": true, 2260 | "requires": { 2261 | "package-json": "^4.0.0" 2262 | } 2263 | }, 2264 | "lodash": { 2265 | "version": "4.17.15", 2266 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", 2267 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" 2268 | }, 2269 | "lodash.includes": { 2270 | "version": "4.3.0", 2271 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", 2272 | "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" 2273 | }, 2274 | "lodash.isboolean": { 2275 | "version": "3.0.3", 2276 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", 2277 | "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" 2278 | }, 2279 | "lodash.isinteger": { 2280 | "version": "4.0.4", 2281 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", 2282 | "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" 2283 | }, 2284 | "lodash.isnumber": { 2285 | "version": "3.0.3", 2286 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", 2287 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" 2288 | }, 2289 | "lodash.isplainobject": { 2290 | "version": "4.0.6", 2291 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 2292 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" 2293 | }, 2294 | "lodash.isstring": { 2295 | "version": "4.0.1", 2296 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", 2297 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" 2298 | }, 2299 | "lodash.once": { 2300 | "version": "4.1.1", 2301 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", 2302 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" 2303 | }, 2304 | "lowercase-keys": { 2305 | "version": "1.0.1", 2306 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", 2307 | "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", 2308 | "dev": true 2309 | }, 2310 | "lru-cache": { 2311 | "version": "4.1.5", 2312 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", 2313 | "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", 2314 | "dev": true, 2315 | "requires": { 2316 | "pseudomap": "^1.0.2", 2317 | "yallist": "^2.1.2" 2318 | } 2319 | }, 2320 | "make-dir": { 2321 | "version": "1.3.0", 2322 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", 2323 | "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", 2324 | "dev": true, 2325 | "requires": { 2326 | "pify": "^3.0.0" 2327 | } 2328 | }, 2329 | "map-cache": { 2330 | "version": "0.2.2", 2331 | "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", 2332 | "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", 2333 | "dev": true 2334 | }, 2335 | "map-visit": { 2336 | "version": "1.0.0", 2337 | "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", 2338 | "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", 2339 | "dev": true, 2340 | "requires": { 2341 | "object-visit": "^1.0.0" 2342 | } 2343 | }, 2344 | "media-typer": { 2345 | "version": "0.3.0", 2346 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 2347 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 2348 | }, 2349 | "merge-descriptors": { 2350 | "version": "1.0.1", 2351 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 2352 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 2353 | }, 2354 | "methods": { 2355 | "version": "1.1.2", 2356 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 2357 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 2358 | }, 2359 | "micromatch": { 2360 | "version": "3.1.10", 2361 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", 2362 | "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", 2363 | "dev": true, 2364 | "requires": { 2365 | "arr-diff": "^4.0.0", 2366 | "array-unique": "^0.3.2", 2367 | "braces": "^2.3.1", 2368 | "define-property": "^2.0.2", 2369 | "extend-shallow": "^3.0.2", 2370 | "extglob": "^2.0.4", 2371 | "fragment-cache": "^0.2.1", 2372 | "kind-of": "^6.0.2", 2373 | "nanomatch": "^1.2.9", 2374 | "object.pick": "^1.3.0", 2375 | "regex-not": "^1.0.0", 2376 | "snapdragon": "^0.8.1", 2377 | "to-regex": "^3.0.2" 2378 | } 2379 | }, 2380 | "mime": { 2381 | "version": "1.6.0", 2382 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 2383 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 2384 | }, 2385 | "mime-db": { 2386 | "version": "1.40.0", 2387 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", 2388 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" 2389 | }, 2390 | "mime-types": { 2391 | "version": "2.1.24", 2392 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", 2393 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", 2394 | "requires": { 2395 | "mime-db": "1.40.0" 2396 | } 2397 | }, 2398 | "minimatch": { 2399 | "version": "3.0.4", 2400 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 2401 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 2402 | "dev": true, 2403 | "requires": { 2404 | "brace-expansion": "^1.1.7" 2405 | } 2406 | }, 2407 | "minimist": { 2408 | "version": "1.2.0", 2409 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 2410 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 2411 | "dev": true 2412 | }, 2413 | "mixin-deep": { 2414 | "version": "1.3.2", 2415 | "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", 2416 | "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", 2417 | "dev": true, 2418 | "requires": { 2419 | "for-in": "^1.0.2", 2420 | "is-extendable": "^1.0.1" 2421 | }, 2422 | "dependencies": { 2423 | "is-extendable": { 2424 | "version": "1.0.1", 2425 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 2426 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 2427 | "dev": true, 2428 | "requires": { 2429 | "is-plain-object": "^2.0.4" 2430 | } 2431 | } 2432 | } 2433 | }, 2434 | "mongodb": { 2435 | "version": "3.3.2", 2436 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.3.2.tgz", 2437 | "integrity": "sha512-fqJt3iywelk4yKu/lfwQg163Bjpo5zDKhXiohycvon4iQHbrfflSAz9AIlRE6496Pm/dQKQK5bMigdVo2s6gBg==", 2438 | "requires": { 2439 | "bson": "^1.1.1", 2440 | "require_optional": "^1.0.1", 2441 | "safe-buffer": "^5.1.2" 2442 | } 2443 | }, 2444 | "mongoose": { 2445 | "version": "5.7.5", 2446 | "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.7.5.tgz", 2447 | "integrity": "sha512-BZ4FxtnbTurc/wcm/hLltLdI4IDxo4nsE0D9q58YymTdZwreNzwO62CcjVtaHhmr8HmJtOInp2W/T12FZaMf8g==", 2448 | "requires": { 2449 | "bson": "~1.1.1", 2450 | "kareem": "2.3.1", 2451 | "mongodb": "3.3.2", 2452 | "mongoose-legacy-pluralize": "1.0.2", 2453 | "mpath": "0.6.0", 2454 | "mquery": "3.2.2", 2455 | "ms": "2.1.2", 2456 | "regexp-clone": "1.0.0", 2457 | "safe-buffer": "5.1.2", 2458 | "sift": "7.0.1", 2459 | "sliced": "1.0.1" 2460 | }, 2461 | "dependencies": { 2462 | "ms": { 2463 | "version": "2.1.2", 2464 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 2465 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 2466 | } 2467 | } 2468 | }, 2469 | "mongoose-legacy-pluralize": { 2470 | "version": "1.0.2", 2471 | "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", 2472 | "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" 2473 | }, 2474 | "morgan": { 2475 | "version": "1.9.1", 2476 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", 2477 | "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", 2478 | "requires": { 2479 | "basic-auth": "~2.0.0", 2480 | "debug": "2.6.9", 2481 | "depd": "~1.1.2", 2482 | "on-finished": "~2.3.0", 2483 | "on-headers": "~1.0.1" 2484 | } 2485 | }, 2486 | "mpath": { 2487 | "version": "0.6.0", 2488 | "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.6.0.tgz", 2489 | "integrity": "sha512-i75qh79MJ5Xo/sbhxrDrPSEG0H/mr1kcZXJ8dH6URU5jD/knFxCVqVC/gVSW7GIXL/9hHWlT9haLbCXWOll3qw==" 2490 | }, 2491 | "mquery": { 2492 | "version": "3.2.2", 2493 | "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.2.tgz", 2494 | "integrity": "sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q==", 2495 | "requires": { 2496 | "bluebird": "3.5.1", 2497 | "debug": "3.1.0", 2498 | "regexp-clone": "^1.0.0", 2499 | "safe-buffer": "5.1.2", 2500 | "sliced": "1.0.1" 2501 | }, 2502 | "dependencies": { 2503 | "debug": { 2504 | "version": "3.1.0", 2505 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 2506 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 2507 | "requires": { 2508 | "ms": "2.0.0" 2509 | } 2510 | } 2511 | } 2512 | }, 2513 | "ms": { 2514 | "version": "2.0.0", 2515 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 2516 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 2517 | }, 2518 | "nan": { 2519 | "version": "2.14.0", 2520 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", 2521 | "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", 2522 | "dev": true, 2523 | "optional": true 2524 | }, 2525 | "nanomatch": { 2526 | "version": "1.2.13", 2527 | "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", 2528 | "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", 2529 | "dev": true, 2530 | "requires": { 2531 | "arr-diff": "^4.0.0", 2532 | "array-unique": "^0.3.2", 2533 | "define-property": "^2.0.2", 2534 | "extend-shallow": "^3.0.2", 2535 | "fragment-cache": "^0.2.1", 2536 | "is-windows": "^1.0.2", 2537 | "kind-of": "^6.0.2", 2538 | "object.pick": "^1.3.0", 2539 | "regex-not": "^1.0.0", 2540 | "snapdragon": "^0.8.1", 2541 | "to-regex": "^3.0.1" 2542 | } 2543 | }, 2544 | "negotiator": { 2545 | "version": "0.6.2", 2546 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 2547 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 2548 | }, 2549 | "nocache": { 2550 | "version": "2.1.0", 2551 | "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz", 2552 | "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==" 2553 | }, 2554 | "node-geocoder": { 2555 | "version": "3.24.0", 2556 | "resolved": "https://registry.npmjs.org/node-geocoder/-/node-geocoder-3.24.0.tgz", 2557 | "integrity": "sha512-2k+NfKCcF+HhElT2TtfTGwCsBaxTWy3dYhLDFB4dpPIa20kMPGZQkJR6Qrow4zTKP5DQMIY4UwRsDWo4mkAumQ==", 2558 | "requires": { 2559 | "bluebird": "^3.5.2", 2560 | "request": "^2.88.0", 2561 | "request-promise": "^4.2.2" 2562 | }, 2563 | "dependencies": { 2564 | "bluebird": { 2565 | "version": "3.5.5", 2566 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", 2567 | "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" 2568 | } 2569 | } 2570 | }, 2571 | "nodemailer": { 2572 | "version": "6.3.0", 2573 | "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.3.0.tgz", 2574 | "integrity": "sha512-TEHBNBPHv7Ie/0o3HXnb7xrPSSQmH1dXwQKRaMKDBGt/ZN54lvDVujP6hKkO/vjkIYL9rK8kHSG11+G42Nhxuw==" 2575 | }, 2576 | "nodemon": { 2577 | "version": "1.19.2", 2578 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.2.tgz", 2579 | "integrity": "sha512-hRLYaw5Ihyw9zK7NF+9EUzVyS6Cvgc14yh8CAYr38tPxJa6UrOxwAQ351GwrgoanHCF0FalQFn6w5eoX/LGdJw==", 2580 | "dev": true, 2581 | "requires": { 2582 | "chokidar": "^2.1.5", 2583 | "debug": "^3.1.0", 2584 | "ignore-by-default": "^1.0.1", 2585 | "minimatch": "^3.0.4", 2586 | "pstree.remy": "^1.1.6", 2587 | "semver": "^5.5.0", 2588 | "supports-color": "^5.2.0", 2589 | "touch": "^3.1.0", 2590 | "undefsafe": "^2.0.2", 2591 | "update-notifier": "^2.5.0" 2592 | }, 2593 | "dependencies": { 2594 | "debug": { 2595 | "version": "3.2.6", 2596 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 2597 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 2598 | "dev": true, 2599 | "requires": { 2600 | "ms": "^2.1.1" 2601 | } 2602 | }, 2603 | "ms": { 2604 | "version": "2.1.2", 2605 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 2606 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 2607 | "dev": true 2608 | } 2609 | } 2610 | }, 2611 | "nopt": { 2612 | "version": "1.0.10", 2613 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", 2614 | "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", 2615 | "dev": true, 2616 | "requires": { 2617 | "abbrev": "1" 2618 | } 2619 | }, 2620 | "normalize-path": { 2621 | "version": "3.0.0", 2622 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 2623 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 2624 | "dev": true 2625 | }, 2626 | "npm-run-path": { 2627 | "version": "2.0.2", 2628 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", 2629 | "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", 2630 | "dev": true, 2631 | "requires": { 2632 | "path-key": "^2.0.0" 2633 | } 2634 | }, 2635 | "oauth-sign": { 2636 | "version": "0.9.0", 2637 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 2638 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 2639 | }, 2640 | "object-assign": { 2641 | "version": "4.1.1", 2642 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 2643 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 2644 | }, 2645 | "object-copy": { 2646 | "version": "0.1.0", 2647 | "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", 2648 | "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", 2649 | "dev": true, 2650 | "requires": { 2651 | "copy-descriptor": "^0.1.0", 2652 | "define-property": "^0.2.5", 2653 | "kind-of": "^3.0.3" 2654 | }, 2655 | "dependencies": { 2656 | "define-property": { 2657 | "version": "0.2.5", 2658 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 2659 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 2660 | "dev": true, 2661 | "requires": { 2662 | "is-descriptor": "^0.1.0" 2663 | } 2664 | }, 2665 | "kind-of": { 2666 | "version": "3.2.2", 2667 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 2668 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 2669 | "dev": true, 2670 | "requires": { 2671 | "is-buffer": "^1.1.5" 2672 | } 2673 | } 2674 | } 2675 | }, 2676 | "object-visit": { 2677 | "version": "1.0.1", 2678 | "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", 2679 | "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", 2680 | "dev": true, 2681 | "requires": { 2682 | "isobject": "^3.0.0" 2683 | } 2684 | }, 2685 | "object.pick": { 2686 | "version": "1.3.0", 2687 | "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", 2688 | "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", 2689 | "dev": true, 2690 | "requires": { 2691 | "isobject": "^3.0.1" 2692 | } 2693 | }, 2694 | "on-finished": { 2695 | "version": "2.3.0", 2696 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 2697 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 2698 | "requires": { 2699 | "ee-first": "1.1.1" 2700 | } 2701 | }, 2702 | "on-headers": { 2703 | "version": "1.0.2", 2704 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", 2705 | "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" 2706 | }, 2707 | "p-finally": { 2708 | "version": "1.0.0", 2709 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", 2710 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", 2711 | "dev": true 2712 | }, 2713 | "package-json": { 2714 | "version": "4.0.1", 2715 | "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", 2716 | "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", 2717 | "dev": true, 2718 | "requires": { 2719 | "got": "^6.7.1", 2720 | "registry-auth-token": "^3.0.1", 2721 | "registry-url": "^3.0.3", 2722 | "semver": "^5.1.0" 2723 | } 2724 | }, 2725 | "parseurl": { 2726 | "version": "1.3.3", 2727 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 2728 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 2729 | }, 2730 | "pascalcase": { 2731 | "version": "0.1.1", 2732 | "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", 2733 | "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", 2734 | "dev": true 2735 | }, 2736 | "path-dirname": { 2737 | "version": "1.0.2", 2738 | "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", 2739 | "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", 2740 | "dev": true 2741 | }, 2742 | "path-is-absolute": { 2743 | "version": "1.0.1", 2744 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 2745 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 2746 | "dev": true 2747 | }, 2748 | "path-is-inside": { 2749 | "version": "1.0.2", 2750 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", 2751 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", 2752 | "dev": true 2753 | }, 2754 | "path-key": { 2755 | "version": "2.0.1", 2756 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 2757 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", 2758 | "dev": true 2759 | }, 2760 | "path-to-regexp": { 2761 | "version": "0.1.7", 2762 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 2763 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 2764 | }, 2765 | "performance-now": { 2766 | "version": "2.1.0", 2767 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 2768 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 2769 | }, 2770 | "pify": { 2771 | "version": "3.0.0", 2772 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", 2773 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", 2774 | "dev": true 2775 | }, 2776 | "posix-character-classes": { 2777 | "version": "0.1.1", 2778 | "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", 2779 | "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", 2780 | "dev": true 2781 | }, 2782 | "prepend-http": { 2783 | "version": "1.0.4", 2784 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", 2785 | "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", 2786 | "dev": true 2787 | }, 2788 | "process-nextick-args": { 2789 | "version": "2.0.1", 2790 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", 2791 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", 2792 | "dev": true 2793 | }, 2794 | "proxy-addr": { 2795 | "version": "2.0.5", 2796 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", 2797 | "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", 2798 | "requires": { 2799 | "forwarded": "~0.1.2", 2800 | "ipaddr.js": "1.9.0" 2801 | } 2802 | }, 2803 | "pseudomap": { 2804 | "version": "1.0.2", 2805 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 2806 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", 2807 | "dev": true 2808 | }, 2809 | "psl": { 2810 | "version": "1.4.0", 2811 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", 2812 | "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==" 2813 | }, 2814 | "pstree.remy": { 2815 | "version": "1.1.7", 2816 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", 2817 | "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", 2818 | "dev": true 2819 | }, 2820 | "punycode": { 2821 | "version": "2.1.1", 2822 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 2823 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 2824 | }, 2825 | "qs": { 2826 | "version": "6.7.0", 2827 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", 2828 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" 2829 | }, 2830 | "range-parser": { 2831 | "version": "1.2.1", 2832 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 2833 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 2834 | }, 2835 | "raw-body": { 2836 | "version": "2.4.0", 2837 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", 2838 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 2839 | "requires": { 2840 | "bytes": "3.1.0", 2841 | "http-errors": "1.7.2", 2842 | "iconv-lite": "0.4.24", 2843 | "unpipe": "1.0.0" 2844 | } 2845 | }, 2846 | "rc": { 2847 | "version": "1.2.8", 2848 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 2849 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 2850 | "dev": true, 2851 | "requires": { 2852 | "deep-extend": "^0.6.0", 2853 | "ini": "~1.3.0", 2854 | "minimist": "^1.2.0", 2855 | "strip-json-comments": "~2.0.1" 2856 | } 2857 | }, 2858 | "readable-stream": { 2859 | "version": "2.3.6", 2860 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 2861 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 2862 | "dev": true, 2863 | "requires": { 2864 | "core-util-is": "~1.0.0", 2865 | "inherits": "~2.0.3", 2866 | "isarray": "~1.0.0", 2867 | "process-nextick-args": "~2.0.0", 2868 | "safe-buffer": "~5.1.1", 2869 | "string_decoder": "~1.1.1", 2870 | "util-deprecate": "~1.0.1" 2871 | } 2872 | }, 2873 | "readdirp": { 2874 | "version": "2.2.1", 2875 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", 2876 | "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", 2877 | "dev": true, 2878 | "requires": { 2879 | "graceful-fs": "^4.1.11", 2880 | "micromatch": "^3.1.10", 2881 | "readable-stream": "^2.0.2" 2882 | } 2883 | }, 2884 | "referrer-policy": { 2885 | "version": "1.2.0", 2886 | "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz", 2887 | "integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==" 2888 | }, 2889 | "regex-not": { 2890 | "version": "1.0.2", 2891 | "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", 2892 | "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", 2893 | "dev": true, 2894 | "requires": { 2895 | "extend-shallow": "^3.0.2", 2896 | "safe-regex": "^1.1.0" 2897 | } 2898 | }, 2899 | "regexp-clone": { 2900 | "version": "1.0.0", 2901 | "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", 2902 | "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==" 2903 | }, 2904 | "registry-auth-token": { 2905 | "version": "3.4.0", 2906 | "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", 2907 | "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", 2908 | "dev": true, 2909 | "requires": { 2910 | "rc": "^1.1.6", 2911 | "safe-buffer": "^5.0.1" 2912 | } 2913 | }, 2914 | "registry-url": { 2915 | "version": "3.1.0", 2916 | "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", 2917 | "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", 2918 | "dev": true, 2919 | "requires": { 2920 | "rc": "^1.0.1" 2921 | } 2922 | }, 2923 | "remove-trailing-separator": { 2924 | "version": "1.1.0", 2925 | "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", 2926 | "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", 2927 | "dev": true 2928 | }, 2929 | "repeat-element": { 2930 | "version": "1.1.3", 2931 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", 2932 | "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", 2933 | "dev": true 2934 | }, 2935 | "repeat-string": { 2936 | "version": "1.6.1", 2937 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 2938 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", 2939 | "dev": true 2940 | }, 2941 | "request": { 2942 | "version": "2.88.0", 2943 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 2944 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 2945 | "requires": { 2946 | "aws-sign2": "~0.7.0", 2947 | "aws4": "^1.8.0", 2948 | "caseless": "~0.12.0", 2949 | "combined-stream": "~1.0.6", 2950 | "extend": "~3.0.2", 2951 | "forever-agent": "~0.6.1", 2952 | "form-data": "~2.3.2", 2953 | "har-validator": "~5.1.0", 2954 | "http-signature": "~1.2.0", 2955 | "is-typedarray": "~1.0.0", 2956 | "isstream": "~0.1.2", 2957 | "json-stringify-safe": "~5.0.1", 2958 | "mime-types": "~2.1.19", 2959 | "oauth-sign": "~0.9.0", 2960 | "performance-now": "^2.1.0", 2961 | "qs": "~6.5.2", 2962 | "safe-buffer": "^5.1.2", 2963 | "tough-cookie": "~2.4.3", 2964 | "tunnel-agent": "^0.6.0", 2965 | "uuid": "^3.3.2" 2966 | }, 2967 | "dependencies": { 2968 | "qs": { 2969 | "version": "6.5.2", 2970 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 2971 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 2972 | } 2973 | } 2974 | }, 2975 | "request-promise": { 2976 | "version": "4.2.4", 2977 | "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.4.tgz", 2978 | "integrity": "sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg==", 2979 | "requires": { 2980 | "bluebird": "^3.5.0", 2981 | "request-promise-core": "1.1.2", 2982 | "stealthy-require": "^1.1.1", 2983 | "tough-cookie": "^2.3.3" 2984 | } 2985 | }, 2986 | "request-promise-core": { 2987 | "version": "1.1.2", 2988 | "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", 2989 | "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", 2990 | "requires": { 2991 | "lodash": "^4.17.11" 2992 | } 2993 | }, 2994 | "require_optional": { 2995 | "version": "1.0.1", 2996 | "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", 2997 | "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", 2998 | "requires": { 2999 | "resolve-from": "^2.0.0", 3000 | "semver": "^5.1.0" 3001 | } 3002 | }, 3003 | "resolve-from": { 3004 | "version": "2.0.0", 3005 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", 3006 | "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" 3007 | }, 3008 | "resolve-url": { 3009 | "version": "0.2.1", 3010 | "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", 3011 | "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", 3012 | "dev": true 3013 | }, 3014 | "ret": { 3015 | "version": "0.1.15", 3016 | "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", 3017 | "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", 3018 | "dev": true 3019 | }, 3020 | "safe-buffer": { 3021 | "version": "5.1.2", 3022 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 3023 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 3024 | }, 3025 | "safe-regex": { 3026 | "version": "1.1.0", 3027 | "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", 3028 | "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", 3029 | "dev": true, 3030 | "requires": { 3031 | "ret": "~0.1.10" 3032 | } 3033 | }, 3034 | "safer-buffer": { 3035 | "version": "2.1.2", 3036 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 3037 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 3038 | }, 3039 | "semver": { 3040 | "version": "5.7.1", 3041 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", 3042 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" 3043 | }, 3044 | "semver-diff": { 3045 | "version": "2.1.0", 3046 | "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", 3047 | "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", 3048 | "dev": true, 3049 | "requires": { 3050 | "semver": "^5.0.3" 3051 | } 3052 | }, 3053 | "send": { 3054 | "version": "0.17.1", 3055 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", 3056 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", 3057 | "requires": { 3058 | "debug": "2.6.9", 3059 | "depd": "~1.1.2", 3060 | "destroy": "~1.0.4", 3061 | "encodeurl": "~1.0.2", 3062 | "escape-html": "~1.0.3", 3063 | "etag": "~1.8.1", 3064 | "fresh": "0.5.2", 3065 | "http-errors": "~1.7.2", 3066 | "mime": "1.6.0", 3067 | "ms": "2.1.1", 3068 | "on-finished": "~2.3.0", 3069 | "range-parser": "~1.2.1", 3070 | "statuses": "~1.5.0" 3071 | }, 3072 | "dependencies": { 3073 | "ms": { 3074 | "version": "2.1.1", 3075 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 3076 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 3077 | } 3078 | } 3079 | }, 3080 | "serve-static": { 3081 | "version": "1.14.1", 3082 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", 3083 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", 3084 | "requires": { 3085 | "encodeurl": "~1.0.2", 3086 | "escape-html": "~1.0.3", 3087 | "parseurl": "~1.3.3", 3088 | "send": "0.17.1" 3089 | } 3090 | }, 3091 | "set-value": { 3092 | "version": "2.0.1", 3093 | "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", 3094 | "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", 3095 | "dev": true, 3096 | "requires": { 3097 | "extend-shallow": "^2.0.1", 3098 | "is-extendable": "^0.1.1", 3099 | "is-plain-object": "^2.0.3", 3100 | "split-string": "^3.0.1" 3101 | }, 3102 | "dependencies": { 3103 | "extend-shallow": { 3104 | "version": "2.0.1", 3105 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 3106 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 3107 | "dev": true, 3108 | "requires": { 3109 | "is-extendable": "^0.1.0" 3110 | } 3111 | } 3112 | } 3113 | }, 3114 | "setprototypeof": { 3115 | "version": "1.1.1", 3116 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 3117 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 3118 | }, 3119 | "shebang-command": { 3120 | "version": "1.2.0", 3121 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 3122 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 3123 | "dev": true, 3124 | "requires": { 3125 | "shebang-regex": "^1.0.0" 3126 | } 3127 | }, 3128 | "shebang-regex": { 3129 | "version": "1.0.0", 3130 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 3131 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", 3132 | "dev": true 3133 | }, 3134 | "sift": { 3135 | "version": "7.0.1", 3136 | "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz", 3137 | "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g==" 3138 | }, 3139 | "signal-exit": { 3140 | "version": "3.0.2", 3141 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 3142 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 3143 | "dev": true 3144 | }, 3145 | "sliced": { 3146 | "version": "1.0.1", 3147 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", 3148 | "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" 3149 | }, 3150 | "slugify": { 3151 | "version": "1.3.5", 3152 | "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.5.tgz", 3153 | "integrity": "sha512-5VCnH7aS13b0UqWOs7Ef3E5rkhFe8Od+cp7wybFv5mv/sYSRkucZlJX0bamAJky7b2TTtGvrJBWVdpdEicsSrA==" 3154 | }, 3155 | "snapdragon": { 3156 | "version": "0.8.2", 3157 | "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", 3158 | "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", 3159 | "dev": true, 3160 | "requires": { 3161 | "base": "^0.11.1", 3162 | "debug": "^2.2.0", 3163 | "define-property": "^0.2.5", 3164 | "extend-shallow": "^2.0.1", 3165 | "map-cache": "^0.2.2", 3166 | "source-map": "^0.5.6", 3167 | "source-map-resolve": "^0.5.0", 3168 | "use": "^3.1.0" 3169 | }, 3170 | "dependencies": { 3171 | "define-property": { 3172 | "version": "0.2.5", 3173 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 3174 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 3175 | "dev": true, 3176 | "requires": { 3177 | "is-descriptor": "^0.1.0" 3178 | } 3179 | }, 3180 | "extend-shallow": { 3181 | "version": "2.0.1", 3182 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 3183 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 3184 | "dev": true, 3185 | "requires": { 3186 | "is-extendable": "^0.1.0" 3187 | } 3188 | } 3189 | } 3190 | }, 3191 | "snapdragon-node": { 3192 | "version": "2.1.1", 3193 | "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", 3194 | "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", 3195 | "dev": true, 3196 | "requires": { 3197 | "define-property": "^1.0.0", 3198 | "isobject": "^3.0.0", 3199 | "snapdragon-util": "^3.0.1" 3200 | }, 3201 | "dependencies": { 3202 | "define-property": { 3203 | "version": "1.0.0", 3204 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", 3205 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", 3206 | "dev": true, 3207 | "requires": { 3208 | "is-descriptor": "^1.0.0" 3209 | } 3210 | }, 3211 | "is-accessor-descriptor": { 3212 | "version": "1.0.0", 3213 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", 3214 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", 3215 | "dev": true, 3216 | "requires": { 3217 | "kind-of": "^6.0.0" 3218 | } 3219 | }, 3220 | "is-data-descriptor": { 3221 | "version": "1.0.0", 3222 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", 3223 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", 3224 | "dev": true, 3225 | "requires": { 3226 | "kind-of": "^6.0.0" 3227 | } 3228 | }, 3229 | "is-descriptor": { 3230 | "version": "1.0.2", 3231 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", 3232 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", 3233 | "dev": true, 3234 | "requires": { 3235 | "is-accessor-descriptor": "^1.0.0", 3236 | "is-data-descriptor": "^1.0.0", 3237 | "kind-of": "^6.0.2" 3238 | } 3239 | } 3240 | } 3241 | }, 3242 | "snapdragon-util": { 3243 | "version": "3.0.1", 3244 | "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", 3245 | "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", 3246 | "dev": true, 3247 | "requires": { 3248 | "kind-of": "^3.2.0" 3249 | }, 3250 | "dependencies": { 3251 | "kind-of": { 3252 | "version": "3.2.2", 3253 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 3254 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 3255 | "dev": true, 3256 | "requires": { 3257 | "is-buffer": "^1.1.5" 3258 | } 3259 | } 3260 | } 3261 | }, 3262 | "source-map": { 3263 | "version": "0.5.7", 3264 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 3265 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 3266 | "dev": true 3267 | }, 3268 | "source-map-resolve": { 3269 | "version": "0.5.2", 3270 | "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", 3271 | "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", 3272 | "dev": true, 3273 | "requires": { 3274 | "atob": "^2.1.1", 3275 | "decode-uri-component": "^0.2.0", 3276 | "resolve-url": "^0.2.1", 3277 | "source-map-url": "^0.4.0", 3278 | "urix": "^0.1.0" 3279 | } 3280 | }, 3281 | "source-map-url": { 3282 | "version": "0.4.0", 3283 | "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", 3284 | "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", 3285 | "dev": true 3286 | }, 3287 | "split-string": { 3288 | "version": "3.1.0", 3289 | "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", 3290 | "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", 3291 | "dev": true, 3292 | "requires": { 3293 | "extend-shallow": "^3.0.0" 3294 | } 3295 | }, 3296 | "sshpk": { 3297 | "version": "1.16.1", 3298 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 3299 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 3300 | "requires": { 3301 | "asn1": "~0.2.3", 3302 | "assert-plus": "^1.0.0", 3303 | "bcrypt-pbkdf": "^1.0.0", 3304 | "dashdash": "^1.12.0", 3305 | "ecc-jsbn": "~0.1.1", 3306 | "getpass": "^0.1.1", 3307 | "jsbn": "~0.1.0", 3308 | "safer-buffer": "^2.0.2", 3309 | "tweetnacl": "~0.14.0" 3310 | } 3311 | }, 3312 | "static-extend": { 3313 | "version": "0.1.2", 3314 | "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", 3315 | "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", 3316 | "dev": true, 3317 | "requires": { 3318 | "define-property": "^0.2.5", 3319 | "object-copy": "^0.1.0" 3320 | }, 3321 | "dependencies": { 3322 | "define-property": { 3323 | "version": "0.2.5", 3324 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", 3325 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", 3326 | "dev": true, 3327 | "requires": { 3328 | "is-descriptor": "^0.1.0" 3329 | } 3330 | } 3331 | } 3332 | }, 3333 | "statuses": { 3334 | "version": "1.5.0", 3335 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 3336 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 3337 | }, 3338 | "stealthy-require": { 3339 | "version": "1.1.1", 3340 | "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", 3341 | "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" 3342 | }, 3343 | "streamsearch": { 3344 | "version": "0.1.2", 3345 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", 3346 | "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" 3347 | }, 3348 | "string-width": { 3349 | "version": "2.1.1", 3350 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 3351 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 3352 | "dev": true, 3353 | "requires": { 3354 | "is-fullwidth-code-point": "^2.0.0", 3355 | "strip-ansi": "^4.0.0" 3356 | } 3357 | }, 3358 | "string_decoder": { 3359 | "version": "1.1.1", 3360 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 3361 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 3362 | "dev": true, 3363 | "requires": { 3364 | "safe-buffer": "~5.1.0" 3365 | } 3366 | }, 3367 | "strip-ansi": { 3368 | "version": "4.0.0", 3369 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 3370 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 3371 | "dev": true, 3372 | "requires": { 3373 | "ansi-regex": "^3.0.0" 3374 | } 3375 | }, 3376 | "strip-eof": { 3377 | "version": "1.0.0", 3378 | "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", 3379 | "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", 3380 | "dev": true 3381 | }, 3382 | "strip-json-comments": { 3383 | "version": "2.0.1", 3384 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 3385 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", 3386 | "dev": true 3387 | }, 3388 | "supports-color": { 3389 | "version": "5.5.0", 3390 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 3391 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 3392 | "dev": true, 3393 | "requires": { 3394 | "has-flag": "^3.0.0" 3395 | } 3396 | }, 3397 | "term-size": { 3398 | "version": "1.2.0", 3399 | "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", 3400 | "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", 3401 | "dev": true, 3402 | "requires": { 3403 | "execa": "^0.7.0" 3404 | } 3405 | }, 3406 | "timed-out": { 3407 | "version": "4.0.1", 3408 | "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", 3409 | "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", 3410 | "dev": true 3411 | }, 3412 | "to-object-path": { 3413 | "version": "0.3.0", 3414 | "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", 3415 | "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", 3416 | "dev": true, 3417 | "requires": { 3418 | "kind-of": "^3.0.2" 3419 | }, 3420 | "dependencies": { 3421 | "kind-of": { 3422 | "version": "3.2.2", 3423 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 3424 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 3425 | "dev": true, 3426 | "requires": { 3427 | "is-buffer": "^1.1.5" 3428 | } 3429 | } 3430 | } 3431 | }, 3432 | "to-regex": { 3433 | "version": "3.0.2", 3434 | "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", 3435 | "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", 3436 | "dev": true, 3437 | "requires": { 3438 | "define-property": "^2.0.2", 3439 | "extend-shallow": "^3.0.2", 3440 | "regex-not": "^1.0.2", 3441 | "safe-regex": "^1.1.0" 3442 | } 3443 | }, 3444 | "to-regex-range": { 3445 | "version": "2.1.1", 3446 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", 3447 | "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", 3448 | "dev": true, 3449 | "requires": { 3450 | "is-number": "^3.0.0", 3451 | "repeat-string": "^1.6.1" 3452 | } 3453 | }, 3454 | "toidentifier": { 3455 | "version": "1.0.0", 3456 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 3457 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 3458 | }, 3459 | "touch": { 3460 | "version": "3.1.0", 3461 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", 3462 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", 3463 | "dev": true, 3464 | "requires": { 3465 | "nopt": "~1.0.10" 3466 | } 3467 | }, 3468 | "tough-cookie": { 3469 | "version": "2.4.3", 3470 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 3471 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 3472 | "requires": { 3473 | "psl": "^1.1.24", 3474 | "punycode": "^1.4.1" 3475 | }, 3476 | "dependencies": { 3477 | "punycode": { 3478 | "version": "1.4.1", 3479 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 3480 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 3481 | } 3482 | } 3483 | }, 3484 | "tunnel-agent": { 3485 | "version": "0.6.0", 3486 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 3487 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 3488 | "requires": { 3489 | "safe-buffer": "^5.0.1" 3490 | } 3491 | }, 3492 | "tweetnacl": { 3493 | "version": "0.14.5", 3494 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 3495 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 3496 | }, 3497 | "type-is": { 3498 | "version": "1.6.18", 3499 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 3500 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 3501 | "requires": { 3502 | "media-typer": "0.3.0", 3503 | "mime-types": "~2.1.24" 3504 | } 3505 | }, 3506 | "undefsafe": { 3507 | "version": "2.0.2", 3508 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", 3509 | "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", 3510 | "dev": true, 3511 | "requires": { 3512 | "debug": "^2.2.0" 3513 | } 3514 | }, 3515 | "union-value": { 3516 | "version": "1.0.1", 3517 | "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", 3518 | "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", 3519 | "dev": true, 3520 | "requires": { 3521 | "arr-union": "^3.1.0", 3522 | "get-value": "^2.0.6", 3523 | "is-extendable": "^0.1.1", 3524 | "set-value": "^2.0.1" 3525 | } 3526 | }, 3527 | "unique-string": { 3528 | "version": "1.0.0", 3529 | "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", 3530 | "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", 3531 | "dev": true, 3532 | "requires": { 3533 | "crypto-random-string": "^1.0.0" 3534 | } 3535 | }, 3536 | "unpipe": { 3537 | "version": "1.0.0", 3538 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 3539 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 3540 | }, 3541 | "unset-value": { 3542 | "version": "1.0.0", 3543 | "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", 3544 | "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", 3545 | "dev": true, 3546 | "requires": { 3547 | "has-value": "^0.3.1", 3548 | "isobject": "^3.0.0" 3549 | }, 3550 | "dependencies": { 3551 | "has-value": { 3552 | "version": "0.3.1", 3553 | "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", 3554 | "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", 3555 | "dev": true, 3556 | "requires": { 3557 | "get-value": "^2.0.3", 3558 | "has-values": "^0.1.4", 3559 | "isobject": "^2.0.0" 3560 | }, 3561 | "dependencies": { 3562 | "isobject": { 3563 | "version": "2.1.0", 3564 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", 3565 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", 3566 | "dev": true, 3567 | "requires": { 3568 | "isarray": "1.0.0" 3569 | } 3570 | } 3571 | } 3572 | }, 3573 | "has-values": { 3574 | "version": "0.1.4", 3575 | "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", 3576 | "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", 3577 | "dev": true 3578 | } 3579 | } 3580 | }, 3581 | "unzip-response": { 3582 | "version": "2.0.1", 3583 | "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", 3584 | "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", 3585 | "dev": true 3586 | }, 3587 | "upath": { 3588 | "version": "1.2.0", 3589 | "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", 3590 | "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", 3591 | "dev": true 3592 | }, 3593 | "update-notifier": { 3594 | "version": "2.5.0", 3595 | "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", 3596 | "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", 3597 | "dev": true, 3598 | "requires": { 3599 | "boxen": "^1.2.1", 3600 | "chalk": "^2.0.1", 3601 | "configstore": "^3.0.0", 3602 | "import-lazy": "^2.1.0", 3603 | "is-ci": "^1.0.10", 3604 | "is-installed-globally": "^0.1.0", 3605 | "is-npm": "^1.0.0", 3606 | "latest-version": "^3.0.0", 3607 | "semver-diff": "^2.0.0", 3608 | "xdg-basedir": "^3.0.0" 3609 | } 3610 | }, 3611 | "uri-js": { 3612 | "version": "4.2.2", 3613 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 3614 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 3615 | "requires": { 3616 | "punycode": "^2.1.0" 3617 | } 3618 | }, 3619 | "urix": { 3620 | "version": "0.1.0", 3621 | "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", 3622 | "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", 3623 | "dev": true 3624 | }, 3625 | "url-parse-lax": { 3626 | "version": "1.0.0", 3627 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", 3628 | "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", 3629 | "dev": true, 3630 | "requires": { 3631 | "prepend-http": "^1.0.1" 3632 | } 3633 | }, 3634 | "use": { 3635 | "version": "3.1.1", 3636 | "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", 3637 | "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", 3638 | "dev": true 3639 | }, 3640 | "util-deprecate": { 3641 | "version": "1.0.2", 3642 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 3643 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 3644 | "dev": true 3645 | }, 3646 | "utils-merge": { 3647 | "version": "1.0.1", 3648 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 3649 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 3650 | }, 3651 | "uuid": { 3652 | "version": "3.3.3", 3653 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", 3654 | "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" 3655 | }, 3656 | "vary": { 3657 | "version": "1.1.2", 3658 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 3659 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 3660 | }, 3661 | "verror": { 3662 | "version": "1.10.0", 3663 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 3664 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 3665 | "requires": { 3666 | "assert-plus": "^1.0.0", 3667 | "core-util-is": "1.0.2", 3668 | "extsprintf": "^1.2.0" 3669 | } 3670 | }, 3671 | "which": { 3672 | "version": "1.3.1", 3673 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 3674 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 3675 | "dev": true, 3676 | "requires": { 3677 | "isexe": "^2.0.0" 3678 | } 3679 | }, 3680 | "widest-line": { 3681 | "version": "2.0.1", 3682 | "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", 3683 | "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", 3684 | "dev": true, 3685 | "requires": { 3686 | "string-width": "^2.1.1" 3687 | } 3688 | }, 3689 | "write-file-atomic": { 3690 | "version": "2.4.3", 3691 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", 3692 | "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", 3693 | "dev": true, 3694 | "requires": { 3695 | "graceful-fs": "^4.1.11", 3696 | "imurmurhash": "^0.1.4", 3697 | "signal-exit": "^3.0.2" 3698 | } 3699 | }, 3700 | "x-xss-protection": { 3701 | "version": "1.3.0", 3702 | "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz", 3703 | "integrity": "sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg==" 3704 | }, 3705 | "xdg-basedir": { 3706 | "version": "3.0.0", 3707 | "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", 3708 | "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", 3709 | "dev": true 3710 | }, 3711 | "xss-clean": { 3712 | "version": "0.1.1", 3713 | "resolved": "https://registry.npmjs.org/xss-clean/-/xss-clean-0.1.1.tgz", 3714 | "integrity": "sha1-07poTYXM1SBUlj0BrWqzbWYtsaU=", 3715 | "requires": { 3716 | "xss-filters": "1.2.6" 3717 | } 3718 | }, 3719 | "xss-filters": { 3720 | "version": "1.2.6", 3721 | "resolved": "https://registry.npmjs.org/xss-filters/-/xss-filters-1.2.6.tgz", 3722 | "integrity": "sha1-aLOQicsd/4udvIiUhIObL1B/XFU=" 3723 | }, 3724 | "yallist": { 3725 | "version": "2.1.2", 3726 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 3727 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", 3728 | "dev": true 3729 | } 3730 | } 3731 | } 3732 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devcamper_api", 3 | "version": "1.0.0", 4 | "description": "Devcamper backend API", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "NODE_ENV=production node server", 8 | "dev": "nodemon server" 9 | }, 10 | "author": "Brad Traversy", 11 | "license": "MIT", 12 | "dependencies": { 13 | "bcryptjs": "^2.4.3", 14 | "colors": "^1.4.0", 15 | "cookie-parser": "^1.4.4", 16 | "cors": "^2.8.5", 17 | "dotenv": "^8.1.0", 18 | "express": "^4.17.1", 19 | "express-fileupload": "^1.1.6-alpha.5", 20 | "express-mongo-sanitize": "^1.3.2", 21 | "express-rate-limit": "^5.0.0", 22 | "helmet": "^3.21.1", 23 | "hpp": "^0.2.2", 24 | "jsonwebtoken": "^8.5.1", 25 | "mongoose": "^5.7.5", 26 | "morgan": "^1.9.1", 27 | "node-geocoder": "^3.24.0", 28 | "nodemailer": "^6.3.0", 29 | "slugify": "^1.3.5", 30 | "xss-clean": "^0.1.1" 31 | }, 32 | "devDependencies": { 33 | "nodemon": "^1.19.2" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Node.js-API-Masterclass-with-Express-and-MongoDB/c2b83902107508247c145202033f23e0280d8f48/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Node.js-API-Masterclass-with-Express-and-MongoDB/c2b83902107508247c145202033f23e0280d8f48/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Node.js-API-Masterclass-with-Express-and-MongoDB/c2b83902107508247c145202033f23e0280d8f48/public/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /routes/auth.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const { 3 | register, 4 | login, 5 | logout, 6 | getMe, 7 | forgotPassword, 8 | resetPassword, 9 | updateDetails, 10 | updatePassword 11 | } = require('../controllers/auth'); 12 | 13 | const router = express.Router(); 14 | 15 | const { protect } = require('../middleware/auth'); 16 | 17 | router.post('/register', register); 18 | router.post('/login', login); 19 | router.get('/logout', logout); 20 | router.get('/me', protect, getMe); 21 | router.put('/updatedetails', protect, updateDetails); 22 | router.put('/updatepassword', protect, updatePassword); 23 | router.post('/forgotpassword', forgotPassword); 24 | router.put('/resetpassword/:resettoken', resetPassword); 25 | 26 | module.exports = router; 27 | -------------------------------------------------------------------------------- /routes/bootcamps.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const { 3 | getBootcamps, 4 | getBootcamp, 5 | createBootcamp, 6 | updateBootcamp, 7 | deleteBootcamp, 8 | getBootcampsInRadius, 9 | bootcampPhotoUpload 10 | } = require('../controllers/bootcamps'); 11 | 12 | const Bootcamp = require('../models/Bootcamp'); 13 | 14 | // Include other resource routers 15 | const courseRouter = require('./courses'); 16 | const reviewRouter = require('./reviews'); 17 | 18 | const router = express.Router(); 19 | 20 | const advancedResults = require('../middleware/advancedResults'); 21 | const { protect, authorize } = require('../middleware/auth'); 22 | 23 | // Re-route into other resource routers 24 | router.use('/:bootcampId/courses', courseRouter); 25 | router.use('/:bootcampId/reviews', reviewRouter); 26 | 27 | router.route('/radius/:zipcode/:distance').get(getBootcampsInRadius); 28 | 29 | router 30 | .route('/:id/photo') 31 | .put(protect, authorize('publisher', 'admin'), bootcampPhotoUpload); 32 | 33 | router 34 | .route('/') 35 | .get(advancedResults(Bootcamp, 'courses'), getBootcamps) 36 | .post(protect, authorize('publisher', 'admin'), createBootcamp); 37 | 38 | router 39 | .route('/:id') 40 | .get(getBootcamp) 41 | .put(protect, authorize('publisher', 'admin'), updateBootcamp) 42 | .delete(protect, authorize('publisher', 'admin'), deleteBootcamp); 43 | 44 | module.exports = router; 45 | -------------------------------------------------------------------------------- /routes/courses.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const { 3 | getCourses, 4 | getCourse, 5 | addCourse, 6 | updateCourse, 7 | deleteCourse 8 | } = require('../controllers/courses'); 9 | 10 | const Course = require('../models/Course'); 11 | 12 | const router = express.Router({ mergeParams: true }); 13 | 14 | const advancedResults = require('../middleware/advancedResults'); 15 | const { protect, authorize } = require('../middleware/auth'); 16 | 17 | router 18 | .route('/') 19 | .get( 20 | advancedResults(Course, { 21 | path: 'bootcamp', 22 | select: 'name description' 23 | }), 24 | getCourses 25 | ) 26 | .post(protect, authorize('publisher', 'admin'), addCourse); 27 | 28 | router 29 | .route('/:id') 30 | .get(getCourse) 31 | .put(protect, authorize('publisher', 'admin'), updateCourse) 32 | .delete(protect, authorize('publisher', 'admin'), deleteCourse); 33 | 34 | module.exports = router; 35 | -------------------------------------------------------------------------------- /routes/reviews.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const { 3 | getReviews, 4 | getReview, 5 | addReview, 6 | updateReview, 7 | deleteReview 8 | } = require('../controllers/reviews'); 9 | 10 | const Review = require('../models/Review'); 11 | 12 | const router = express.Router({ mergeParams: true }); 13 | 14 | const advancedResults = require('../middleware/advancedResults'); 15 | const { protect, authorize } = require('../middleware/auth'); 16 | 17 | router 18 | .route('/') 19 | .get( 20 | advancedResults(Review, { 21 | path: 'bootcamp', 22 | select: 'name description' 23 | }), 24 | getReviews 25 | ) 26 | .post(protect, authorize('user', 'admin'), addReview); 27 | 28 | router 29 | .route('/:id') 30 | .get(getReview) 31 | .put(protect, authorize('user', 'admin'), updateReview) 32 | .delete(protect, authorize('user', 'admin'), deleteReview); 33 | 34 | module.exports = router; 35 | -------------------------------------------------------------------------------- /routes/users.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const { 3 | getUsers, 4 | getUser, 5 | createUser, 6 | updateUser, 7 | deleteUser 8 | } = require('../controllers/users'); 9 | 10 | const User = require('../models/User'); 11 | 12 | const router = express.Router({ mergeParams: true }); 13 | 14 | const advancedResults = require('../middleware/advancedResults'); 15 | const { protect, authorize } = require('../middleware/auth'); 16 | 17 | router.use(protect); 18 | router.use(authorize('admin')); 19 | 20 | router 21 | .route('/') 22 | .get(advancedResults(User), getUsers) 23 | .post(createUser); 24 | 25 | router 26 | .route('/:id') 27 | .get(getUser) 28 | .put(updateUser) 29 | .delete(deleteUser); 30 | 31 | module.exports = router; 32 | -------------------------------------------------------------------------------- /seeder.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const mongoose = require('mongoose'); 3 | const colors = require('colors'); 4 | const dotenv = require('dotenv'); 5 | 6 | // Load env vars 7 | dotenv.config({ path: './config/config.env' }); 8 | 9 | // Load models 10 | const Bootcamp = require('./models/Bootcamp'); 11 | const Course = require('./models/Course'); 12 | const User = require('./models/User'); 13 | const Review = require('./models/Review'); 14 | 15 | // Connect to DB 16 | mongoose.connect(process.env.MONGO_URI, { 17 | useNewUrlParser: true, 18 | useCreateIndex: true, 19 | useFindAndModify: false, 20 | useUnifiedTopology: true 21 | }); 22 | 23 | // Read JSON files 24 | const bootcamps = JSON.parse( 25 | fs.readFileSync(`${__dirname}/_data/bootcamps.json`, 'utf-8') 26 | ); 27 | 28 | const courses = JSON.parse( 29 | fs.readFileSync(`${__dirname}/_data/courses.json`, 'utf-8') 30 | ); 31 | 32 | const users = JSON.parse( 33 | fs.readFileSync(`${__dirname}/_data/users.json`, 'utf-8') 34 | ); 35 | 36 | const reviews = JSON.parse( 37 | fs.readFileSync(`${__dirname}/_data/reviews.json`, 'utf-8') 38 | ); 39 | 40 | // Import into DB 41 | const importData = async () => { 42 | try { 43 | await Bootcamp.create(bootcamps); 44 | await Course.create(courses); 45 | await User.create(users); 46 | await Review.create(reviews); 47 | console.log('Data Imported...'.green.inverse); 48 | process.exit(); 49 | } catch (err) { 50 | console.error(err); 51 | } 52 | }; 53 | 54 | // Delete data 55 | const deleteData = async () => { 56 | try { 57 | await Bootcamp.deleteMany(); 58 | await Course.deleteMany(); 59 | await User.deleteMany(); 60 | await Review.deleteMany(); 61 | console.log('Data Destroyed...'.red.inverse); 62 | process.exit(); 63 | } catch (err) { 64 | console.error(err); 65 | } 66 | }; 67 | 68 | if (process.argv[2] === '-i') { 69 | importData(); 70 | } else if (process.argv[2] === '-d') { 71 | deleteData(); 72 | } 73 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const express = require('express'); 3 | const dotenv = require('dotenv'); 4 | const morgan = require('morgan'); 5 | const colors = require('colors'); 6 | const fileupload = require('express-fileupload'); 7 | const cookieParser = require('cookie-parser'); 8 | const mongoSanitize = require('express-mongo-sanitize'); 9 | const helmet = require('helmet'); 10 | const xss = require('xss-clean'); 11 | const rateLimit = require('express-rate-limit'); 12 | const hpp = require('hpp'); 13 | const cors = require('cors'); 14 | const errorHandler = require('./middleware/error'); 15 | const connectDB = require('./config/db'); 16 | 17 | // Load env vars 18 | dotenv.config({ path: './config/config.env' }); 19 | 20 | // Connect to database 21 | connectDB(); 22 | 23 | // Route files 24 | const bootcamps = require('./routes/bootcamps'); 25 | const courses = require('./routes/courses'); 26 | const auth = require('./routes/auth'); 27 | const users = require('./routes/users'); 28 | const reviews = require('./routes/reviews'); 29 | 30 | const app = express(); 31 | 32 | // Body parser 33 | app.use(express.json()); 34 | 35 | // Cookie parser 36 | app.use(cookieParser()); 37 | 38 | // Dev logging middleware 39 | if (process.env.NODE_ENV === 'development') { 40 | app.use(morgan('dev')); 41 | } 42 | 43 | // File uploading 44 | app.use(fileupload()); 45 | 46 | // Sanitize data 47 | app.use(mongoSanitize()); 48 | 49 | // Set security headers 50 | app.use(helmet()); 51 | 52 | // Prevent XSS attacks 53 | app.use(xss()); 54 | 55 | // Rate limiting 56 | const limiter = rateLimit({ 57 | windowMs: 10 * 60 * 1000, // 10 mins 58 | max: 100 59 | }); 60 | app.use(limiter); 61 | 62 | // Prevent http param pollution 63 | app.use(hpp()); 64 | 65 | // Enable CORS 66 | app.use(cors()); 67 | 68 | // Set static folder 69 | app.use(express.static(path.join(__dirname, 'public'))); 70 | 71 | // Mount routers 72 | app.use('/api/v1/bootcamps', bootcamps); 73 | app.use('/api/v1/courses', courses); 74 | app.use('/api/v1/auth', auth); 75 | app.use('/api/v1/users', users); 76 | app.use('/api/v1/reviews', reviews); 77 | 78 | app.use(errorHandler); 79 | 80 | const PORT = process.env.PORT || 5000; 81 | 82 | const server = app.listen( 83 | PORT, 84 | console.log( 85 | `Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold 86 | ) 87 | ); 88 | 89 | // Handle unhandled promise rejections 90 | process.on('unhandledRejection', (err, promise) => { 91 | console.log(`Error: ${err.message}`.red); 92 | // Close server & exit process 93 | // server.close(() => process.exit(1)); 94 | }); 95 | -------------------------------------------------------------------------------- /utils/errorResponse.js: -------------------------------------------------------------------------------- 1 | class ErrorResponse extends Error { 2 | constructor(message, statusCode) { 3 | super(message); 4 | this.statusCode = statusCode; 5 | 6 | Error.captureStackTrace(this, this.constructor); 7 | } 8 | } 9 | 10 | module.exports = ErrorResponse; 11 | -------------------------------------------------------------------------------- /utils/geocoder.js: -------------------------------------------------------------------------------- 1 | const NodeGeocoder = require('node-geocoder'); 2 | 3 | const options = { 4 | provider: process.env.GEOCODER_PROVIDER, 5 | httpAdapter: 'https', 6 | apiKey: process.env.GEOCODER_API_KEY, 7 | formatter: null 8 | }; 9 | 10 | const geocoder = NodeGeocoder(options); 11 | 12 | module.exports = geocoder; 13 | -------------------------------------------------------------------------------- /utils/sendEmail.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require('nodemailer'); 2 | 3 | const sendEmail = async options => { 4 | const transporter = nodemailer.createTransport({ 5 | host: process.env.SMTP_HOST, 6 | port: process.env.SMTP_PORT, 7 | auth: { 8 | user: process.env.SMTP_EMAIL, 9 | pass: process.env.SMTP_PASSWORD 10 | } 11 | }); 12 | 13 | const message = { 14 | from: `${process.env.FROM_NAME} <${process.env.FROM_EMAIL}>`, 15 | to: options.email, 16 | subject: options.subject, 17 | text: options.message 18 | }; 19 | 20 | const info = await transporter.sendMail(message); 21 | 22 | console.log('Message sent: %s', info.messageId); 23 | }; 24 | 25 | module.exports = sendEmail; 26 | --------------------------------------------------------------------------------