├── .gitignore ├── advanced ├── backend-with-auth │ ├── .env │ ├── app.js │ ├── load-dummy-data.js │ ├── models │ │ ├── car.js │ │ ├── database.js │ │ ├── index.js │ │ └── user.js │ ├── package-lock.json │ ├── package.json │ ├── resolvers │ │ ├── car.js │ │ ├── index.js │ │ └── user.js │ └── typeDefs │ │ ├── car.js │ │ ├── default.js │ │ ├── index.js │ │ └── user.js └── frontend-with-auth │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── photos │ ├── man.jpg │ └── woman.jpg │ ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json │ └── src │ ├── ActiveSession.js │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── Error.js │ ├── Hidden.js │ ├── Login.js │ ├── Logout.js │ ├── Navigation.js │ ├── Profile.js │ ├── Register.js │ ├── components │ ├── container.js │ └── index.js │ ├── index.js │ ├── logo.svg │ ├── pages │ └── main-page.js │ └── serviceWorker.js ├── basic ├── api │ ├── cars.js │ ├── index.js │ ├── package-lock.json │ └── package.json ├── backend │ ├── api │ │ ├── cars.js │ │ └── index.js │ ├── car-rest-consumer.js │ ├── index.js │ ├── package-lock.json │ ├── package.json │ ├── resolvers.js │ ├── schema.js │ └── utils.js ├── frontend │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ └── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── components │ │ ├── container.js │ │ └── index.js │ │ ├── index.js │ │ ├── logo.svg │ │ ├── pages │ │ ├── car.js │ │ ├── cars.js │ │ └── index.js │ │ └── serviceWorker.js └── hooks-frontend │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json │ └── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── components │ ├── container.js │ └── index.js │ ├── index.js │ ├── logo.svg │ ├── pages │ ├── car.js │ ├── cars.js │ └── index.js │ └── serviceWorker.js └── links.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | uploads/ -------------------------------------------------------------------------------- /advanced/backend-with-auth/.env: -------------------------------------------------------------------------------- 1 | JWT_SECRET=s3cr3t 2 | CLOUD_NAME=tamas-demo 3 | API_KEY=212496679715456 4 | API_SECRET=oc5JV8poIagylelheRiVjA0KTzc -------------------------------------------------------------------------------- /advanced/backend-with-auth/app.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const express = require('express'); 3 | const app = express(); 4 | const { ApolloServer } = require('apollo-server-express'); 5 | const cors = require('cors'); 6 | const fileUpload = require('express-fileupload'); 7 | 8 | const models = require('./models'); 9 | const typeDefs = require('./typeDefs'); 10 | const resolvers = require('./resolvers'); 11 | 12 | const jwt = require('jsonwebtoken'); 13 | app.use(cors()); 14 | app.use(fileUpload()); 15 | 16 | const getLoggedInUser = req => { 17 | const token = req.headers['x-auth-token']; 18 | if (token) { 19 | try { 20 | return jwt.verify(token, process.env.JWT_SECRET); 21 | } catch(error) { 22 | throw new Error('Session expired'); 23 | } 24 | } 25 | }; 26 | 27 | const server = new ApolloServer({ 28 | typeDefs, 29 | resolvers, 30 | context: ({ req }) => ({ 31 | models, 32 | secret: process.env.JWT_SECRET, 33 | me: getLoggedInUser(req) 34 | }), 35 | playground: true 36 | }); 37 | server.applyMiddleware({ app }); 38 | 39 | app.post('/upload', (req, res) => { 40 | let uploadedFile = req.files.file; 41 | const filename = req.files.file.name; 42 | uploadedFile.mv(`${__dirname}/uploads/${filename}`, error => { 43 | if (error) { 44 | return res.status(500).send(error); 45 | } 46 | return res.json(filename); 47 | }); 48 | }); 49 | 50 | app.listen(3000, () => console.info('Apollo GraphQL server is running on port 3000')); -------------------------------------------------------------------------------- /advanced/backend-with-auth/load-dummy-data.js: -------------------------------------------------------------------------------- 1 | const { sequelize } = require('./models/database'); 2 | const models = require('./models'); 3 | 4 | const createData = async() => { 5 | await models.User.create({ 6 | name: 'Tamas', 7 | username: 'tamas', 8 | password: 'test1', 9 | cars: [{ 10 | make: 'Mercedes', 11 | model: 'A250', 12 | colour: 'black' 13 | }] 14 | }, { 15 | include: [models.Car] 16 | }); 17 | 18 | await models.User.create({ 19 | name: 'Susan', 20 | username: 'susan', 21 | password: 'test2', 22 | cars: [{ 23 | make: 'Toyota', 24 | model: 'Yaris', 25 | colour: 'Red' 26 | }] 27 | }, { 28 | include: [models.Car] 29 | }); 30 | 31 | await models.User.create({ 32 | name: 'Steven', 33 | username: 'steven', 34 | password: 'test3', 35 | cars: [{ 36 | make: 'Fiat', 37 | model: '500', 38 | colour: 'Yellow' 39 | }, { 40 | make: 'Ford', 41 | model: 'Focus', 42 | colour: 'Green' 43 | }] 44 | }, { 45 | include: [models.Car] 46 | }); 47 | } 48 | 49 | sequelize.sync({ force: true }).then(async() => { 50 | try { 51 | await createData(); 52 | process.exit(); 53 | } catch(error) { 54 | console.error(error); 55 | } 56 | }); -------------------------------------------------------------------------------- /advanced/backend-with-auth/models/car.js: -------------------------------------------------------------------------------- 1 | const car = (sequelize, DataTypes) => { 2 | const Car = sequelize.define('car', { 3 | make: { 4 | type: DataTypes.STRING 5 | }, 6 | model: { 7 | type: DataTypes.STRING 8 | }, 9 | colour: { 10 | type: DataTypes.STRING 11 | } 12 | }); 13 | 14 | Car.associate = models => { 15 | Car.belongsTo(models.User); 16 | }; 17 | 18 | return Car; 19 | } 20 | 21 | module.exports = car; -------------------------------------------------------------------------------- /advanced/backend-with-auth/models/database.js: -------------------------------------------------------------------------------- 1 | const Sequelize = require('sequelize'); 2 | const sequelize = new Sequelize('graphql', 'root', 'marina', { 3 | dialect: 'mysql', 4 | define: { 5 | timestamps: false 6 | }, 7 | logging: false 8 | }); 9 | 10 | module.exports = { 11 | sequelize 12 | }; -------------------------------------------------------------------------------- /advanced/backend-with-auth/models/index.js: -------------------------------------------------------------------------------- 1 | const { sequelize } = require('./database'); 2 | 3 | const UserModel = sequelize.import('./user'); 4 | const CarModel = sequelize.import('./car'); 5 | 6 | const models = { 7 | User: UserModel, 8 | Car: CarModel 9 | }; 10 | 11 | Object.keys(models).forEach(key => { 12 | if ('associate' in models[key]) { 13 | models[key].associate(models); 14 | } 15 | }); 16 | 17 | module.exports = models; -------------------------------------------------------------------------------- /advanced/backend-with-auth/models/user.js: -------------------------------------------------------------------------------- 1 | const bcrypt = require('bcrypt'); 2 | 3 | const user = (sequelize, DataTypes) => { 4 | const User = sequelize.define('user', { 5 | name: { 6 | type: DataTypes.STRING 7 | }, 8 | username: { 9 | type: DataTypes.STRING, 10 | unique: true, 11 | validate: { 12 | notEmpty: true 13 | } 14 | }, 15 | password: { 16 | type: DataTypes.STRING, 17 | validate: { 18 | notEmpty: true 19 | } 20 | }, 21 | photo: { 22 | type: DataTypes.STRING 23 | } 24 | }); 25 | 26 | User.prototype.hashPassword = async function() { 27 | return await bcrypt.hash(this.password, 10); 28 | }; 29 | 30 | User.prototype.validatePassword = async function(password) { 31 | return await bcrypt.compare(password, this.password); 32 | } 33 | 34 | User.associate = models => { 35 | User.hasMany(models.Car, { onDelete: 'CASCADE' }) 36 | }; 37 | 38 | User.beforeCreate(async user => { 39 | user.password = await user.hashPassword(user.password); 40 | }); 41 | 42 | return User; 43 | } 44 | 45 | module.exports = user; -------------------------------------------------------------------------------- /advanced/backend-with-auth/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphql-database-final", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@apollographql/apollo-tools": { 8 | "version": "0.2.9", 9 | "resolved": "https://registry.npmjs.org/@apollographql/apollo-tools/-/apollo-tools-0.2.9.tgz", 10 | "integrity": "sha512-AEIQwPkS0QLbkpb6WyRhV4aOMxuErasp47ABv5niDKOasQH8mrD8JSGKJAHuQxVe4kB8DE9sLRoc5qeQ0KFCHA==", 11 | "requires": { 12 | "apollo-env": "0.2.5" 13 | } 14 | }, 15 | "@apollographql/graphql-playground-html": { 16 | "version": "1.6.6", 17 | "resolved": "https://registry.npmjs.org/@apollographql/graphql-playground-html/-/graphql-playground-html-1.6.6.tgz", 18 | "integrity": "sha512-lqK94b+caNtmKFs5oUVXlSpN3sm5IXZ+KfhMxOtr0LR2SqErzkoJilitjDvJ1WbjHlxLI7WtCjRmOLdOGJqtMQ==" 19 | }, 20 | "@protobufjs/aspromise": { 21 | "version": "1.1.2", 22 | "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", 23 | "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" 24 | }, 25 | "@protobufjs/base64": { 26 | "version": "1.1.2", 27 | "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", 28 | "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" 29 | }, 30 | "@protobufjs/codegen": { 31 | "version": "2.0.4", 32 | "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", 33 | "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" 34 | }, 35 | "@protobufjs/eventemitter": { 36 | "version": "1.1.0", 37 | "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", 38 | "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" 39 | }, 40 | "@protobufjs/fetch": { 41 | "version": "1.1.0", 42 | "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", 43 | "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", 44 | "requires": { 45 | "@protobufjs/aspromise": "^1.1.1", 46 | "@protobufjs/inquire": "^1.1.0" 47 | } 48 | }, 49 | "@protobufjs/float": { 50 | "version": "1.0.2", 51 | "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", 52 | "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" 53 | }, 54 | "@protobufjs/inquire": { 55 | "version": "1.1.0", 56 | "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", 57 | "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" 58 | }, 59 | "@protobufjs/path": { 60 | "version": "1.1.2", 61 | "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", 62 | "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" 63 | }, 64 | "@protobufjs/pool": { 65 | "version": "1.1.0", 66 | "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", 67 | "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" 68 | }, 69 | "@protobufjs/utf8": { 70 | "version": "1.1.0", 71 | "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", 72 | "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" 73 | }, 74 | "@types/accepts": { 75 | "version": "1.3.5", 76 | "resolved": "http://registry.npmjs.org/@types/accepts/-/accepts-1.3.5.tgz", 77 | "integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==", 78 | "requires": { 79 | "@types/node": "*" 80 | } 81 | }, 82 | "@types/body-parser": { 83 | "version": "1.17.0", 84 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.0.tgz", 85 | "integrity": "sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==", 86 | "requires": { 87 | "@types/connect": "*", 88 | "@types/node": "*" 89 | } 90 | }, 91 | "@types/connect": { 92 | "version": "3.4.32", 93 | "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", 94 | "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", 95 | "requires": { 96 | "@types/node": "*" 97 | } 98 | }, 99 | "@types/cors": { 100 | "version": "2.8.4", 101 | "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.4.tgz", 102 | "integrity": "sha512-ipZjBVsm2tF/n8qFGOuGBkUij9X9ZswVi9G3bx/6dz7POpVa6gVHcj1wsX/LVEn9MMF41fxK/PnZPPoTD1UFPw==", 103 | "requires": { 104 | "@types/express": "*" 105 | } 106 | }, 107 | "@types/events": { 108 | "version": "1.2.0", 109 | "resolved": "http://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", 110 | "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==" 111 | }, 112 | "@types/express": { 113 | "version": "4.16.0", 114 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.16.0.tgz", 115 | "integrity": "sha512-TtPEYumsmSTtTetAPXlJVf3kEqb6wZK0bZojpJQrnD/djV4q1oB6QQ8aKvKqwNPACoe02GNiy5zDzcYivR5Z2w==", 116 | "requires": { 117 | "@types/body-parser": "*", 118 | "@types/express-serve-static-core": "*", 119 | "@types/serve-static": "*" 120 | } 121 | }, 122 | "@types/express-serve-static-core": { 123 | "version": "4.16.0", 124 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.0.tgz", 125 | "integrity": "sha512-lTeoCu5NxJU4OD9moCgm0ESZzweAx0YqsAcab6OB0EB3+As1OaHtKnaGJvcngQxYsi9UNv0abn4/DRavrRxt4w==", 126 | "requires": { 127 | "@types/events": "*", 128 | "@types/node": "*", 129 | "@types/range-parser": "*" 130 | } 131 | }, 132 | "@types/long": { 133 | "version": "4.0.0", 134 | "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz", 135 | "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==" 136 | }, 137 | "@types/mime": { 138 | "version": "2.0.0", 139 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz", 140 | "integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==" 141 | }, 142 | "@types/node": { 143 | "version": "10.12.15", 144 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.15.tgz", 145 | "integrity": "sha512-9kROxduaN98QghwwHmxXO2Xz3MaWf+I1sLVAA6KJDF5xix+IyXVhds0MAfdNwtcpSrzhaTsNB0/jnL86fgUhqA==" 146 | }, 147 | "@types/range-parser": { 148 | "version": "1.2.3", 149 | "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", 150 | "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" 151 | }, 152 | "@types/serve-static": { 153 | "version": "1.13.2", 154 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz", 155 | "integrity": "sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==", 156 | "requires": { 157 | "@types/express-serve-static-core": "*", 158 | "@types/mime": "*" 159 | } 160 | }, 161 | "@types/ws": { 162 | "version": "6.0.1", 163 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.1.tgz", 164 | "integrity": "sha512-EzH8k1gyZ4xih/MaZTXwT2xOkPiIMSrhQ9b8wrlX88L0T02eYsddatQlwVFlEPyEqV0ChpdpNnE51QPH6NVT4Q==", 165 | "requires": { 166 | "@types/events": "*", 167 | "@types/node": "*" 168 | } 169 | }, 170 | "abbrev": { 171 | "version": "1.1.1", 172 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 173 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" 174 | }, 175 | "accepts": { 176 | "version": "1.3.5", 177 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 178 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 179 | "requires": { 180 | "mime-types": "~2.1.18", 181 | "negotiator": "0.6.1" 182 | } 183 | }, 184 | "ansi-regex": { 185 | "version": "2.1.1", 186 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 187 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" 188 | }, 189 | "any-promise": { 190 | "version": "1.3.0", 191 | "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", 192 | "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" 193 | }, 194 | "apollo-cache-control": { 195 | "version": "0.4.0", 196 | "resolved": "https://registry.npmjs.org/apollo-cache-control/-/apollo-cache-control-0.4.0.tgz", 197 | "integrity": "sha512-WuriaNQIugTE8gYwfBWWCbbQTSKul/cV4JMi5UgqNIUvjHvnKZQLKbt5uYWow6QQNMkLT9hey8QPYkWpogkeSA==", 198 | "requires": { 199 | "apollo-server-env": "2.2.0", 200 | "graphql-extensions": "0.4.0" 201 | }, 202 | "dependencies": { 203 | "graphql-extensions": { 204 | "version": "0.4.0", 205 | "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.4.0.tgz", 206 | "integrity": "sha512-8TUgIIUVpXWOcqq9RdmTSHUrhc3a/s+saKv9cCl8TYWHK9vyJIdea7ZaSKHGDthZNcsN+C3LulZYRL3Ah8ukoA==", 207 | "requires": { 208 | "@apollographql/apollo-tools": "^0.2.6" 209 | } 210 | } 211 | } 212 | }, 213 | "apollo-datasource": { 214 | "version": "0.2.1", 215 | "resolved": "https://registry.npmjs.org/apollo-datasource/-/apollo-datasource-0.2.1.tgz", 216 | "integrity": "sha512-r185+JTa5KuF1INeTAk7AEP76zwMN6c8Ph1lmpzJMNwBUEzTGnLClrccCskCBx4SxfnkdKbuQdwn9JwCJUWrdg==", 217 | "requires": { 218 | "apollo-server-caching": "0.2.1", 219 | "apollo-server-env": "2.2.0" 220 | } 221 | }, 222 | "apollo-engine-reporting": { 223 | "version": "0.2.0", 224 | "resolved": "https://registry.npmjs.org/apollo-engine-reporting/-/apollo-engine-reporting-0.2.0.tgz", 225 | "integrity": "sha512-Q6FfVb10v/nrv8FaFsPjIYlWh62jaYav3LuMgM9PsHWGK/zRQFXOEwLxcY2UCvG7O1moxF3XGmfBhMgo54py+Q==", 226 | "requires": { 227 | "apollo-engine-reporting-protobuf": "0.2.0", 228 | "apollo-server-env": "2.2.0", 229 | "async-retry": "^1.2.1", 230 | "graphql-extensions": "0.4.0", 231 | "lodash": "^4.17.10" 232 | }, 233 | "dependencies": { 234 | "graphql-extensions": { 235 | "version": "0.4.0", 236 | "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.4.0.tgz", 237 | "integrity": "sha512-8TUgIIUVpXWOcqq9RdmTSHUrhc3a/s+saKv9cCl8TYWHK9vyJIdea7ZaSKHGDthZNcsN+C3LulZYRL3Ah8ukoA==", 238 | "requires": { 239 | "@apollographql/apollo-tools": "^0.2.6" 240 | } 241 | } 242 | } 243 | }, 244 | "apollo-engine-reporting-protobuf": { 245 | "version": "0.2.0", 246 | "resolved": "https://registry.npmjs.org/apollo-engine-reporting-protobuf/-/apollo-engine-reporting-protobuf-0.2.0.tgz", 247 | "integrity": "sha512-qI+GJKN78UMJ9Aq/ORdiM2qymZ5yswem+/VDdVFocq+/e1QqxjnpKjQWISkswci5+WtpJl9SpHBNxG98uHDKkA==", 248 | "requires": { 249 | "protobufjs": "^6.8.6" 250 | } 251 | }, 252 | "apollo-env": { 253 | "version": "0.2.5", 254 | "resolved": "https://registry.npmjs.org/apollo-env/-/apollo-env-0.2.5.tgz", 255 | "integrity": "sha512-Gc7TEbwCl7jJVutnn8TWfzNSkrrqyoo0DP92BQJFU9pZbJhpidoXf2Sw1YwOJl82rRKH3ujM3C8vdZLOgpFcFA==", 256 | "requires": { 257 | "core-js": "^3.0.0-beta.3", 258 | "node-fetch": "^2.2.0" 259 | } 260 | }, 261 | "apollo-link": { 262 | "version": "1.2.5", 263 | "resolved": "https://registry.npmjs.org/apollo-link/-/apollo-link-1.2.5.tgz", 264 | "integrity": "sha512-GJHEE4B06oEB58mpRRwW6ISyvgX2aCqCLjpcE3M/6/4e+ZVeX7fRGpMJJDq2zZ8n7qWdrEuY315JfxzpsJmUhA==", 265 | "requires": { 266 | "apollo-utilities": "^1.0.0", 267 | "zen-observable-ts": "^0.8.12" 268 | } 269 | }, 270 | "apollo-server": { 271 | "version": "2.3.1", 272 | "resolved": "https://registry.npmjs.org/apollo-server/-/apollo-server-2.3.1.tgz", 273 | "integrity": "sha512-+S+/BhLJF9Ms99OK9HpC4P6rcVWTobWWKeLSVdgxqG487i/kwMrCAw/ICrDVJGeOGJRi6PndVu9XdHWHuX1lvQ==", 274 | "requires": { 275 | "apollo-server-core": "2.3.1", 276 | "apollo-server-express": "2.3.1", 277 | "express": "^4.0.0", 278 | "graphql-subscriptions": "^1.0.0", 279 | "graphql-tools": "^4.0.0" 280 | } 281 | }, 282 | "apollo-server-caching": { 283 | "version": "0.2.1", 284 | "resolved": "https://registry.npmjs.org/apollo-server-caching/-/apollo-server-caching-0.2.1.tgz", 285 | "integrity": "sha512-+U9F3X297LL8Gqy6ypfDNEv/DfV/tDht9Dr2z3AMaEkNW1bwO6rmdDL01zYxDuVDVq6Z3qSiNCSO2pXE2F0zmA==", 286 | "requires": { 287 | "lru-cache": "^5.0.0" 288 | } 289 | }, 290 | "apollo-server-core": { 291 | "version": "2.3.1", 292 | "resolved": "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-2.3.1.tgz", 293 | "integrity": "sha512-8jMWYOQIZi9mDJlHe2rXg8Cp4xKYogeRu23jkcNy+k5UjZL+eO+kHXbNFiTaP4HLYYEpe2XE3asxp6q5YUEQeQ==", 294 | "requires": { 295 | "@apollographql/apollo-tools": "^0.2.6", 296 | "@apollographql/graphql-playground-html": "^1.6.6", 297 | "@types/ws": "^6.0.0", 298 | "apollo-cache-control": "0.4.0", 299 | "apollo-datasource": "0.2.1", 300 | "apollo-engine-reporting": "0.2.0", 301 | "apollo-server-caching": "0.2.1", 302 | "apollo-server-env": "2.2.0", 303 | "apollo-server-errors": "2.2.0", 304 | "apollo-server-plugin-base": "0.2.1", 305 | "apollo-tracing": "0.4.0", 306 | "graphql-extensions": "0.4.1", 307 | "graphql-subscriptions": "^1.0.0", 308 | "graphql-tag": "^2.9.2", 309 | "graphql-tools": "^4.0.0", 310 | "graphql-upload": "^8.0.2", 311 | "json-stable-stringify": "^1.0.1", 312 | "lodash": "^4.17.10", 313 | "subscriptions-transport-ws": "^0.9.11", 314 | "ws": "^6.0.0" 315 | } 316 | }, 317 | "apollo-server-env": { 318 | "version": "2.2.0", 319 | "resolved": "https://registry.npmjs.org/apollo-server-env/-/apollo-server-env-2.2.0.tgz", 320 | "integrity": "sha512-wjJiI5nQWPBpNmpiLP389Ezpstp71szS6DHAeTgYLb/ulCw3CTuuA+0/E1bsThVWiQaDeHZE0sE3yI8q2zrYiA==", 321 | "requires": { 322 | "node-fetch": "^2.1.2", 323 | "util.promisify": "^1.0.0" 324 | } 325 | }, 326 | "apollo-server-errors": { 327 | "version": "2.2.0", 328 | "resolved": "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-2.2.0.tgz", 329 | "integrity": "sha512-gV9EZG2tovFtT1cLuCTavnJu2DaKxnXPRNGSTo+SDI6IAk6cdzyW0Gje5N2+3LybI0Wq5KAbW6VLei31S4MWmg==" 330 | }, 331 | "apollo-server-express": { 332 | "version": "2.3.1", 333 | "resolved": "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-2.3.1.tgz", 334 | "integrity": "sha512-J+rObr4GdT/5j6qTByUJoSvZSjTAX/7VqIkr2t+GxwcVUFGet2MdOHuV6rtWKc8CRgvVKfKN6iBrb2EOFcp2LQ==", 335 | "requires": { 336 | "@apollographql/graphql-playground-html": "^1.6.6", 337 | "@types/accepts": "^1.3.5", 338 | "@types/body-parser": "1.17.0", 339 | "@types/cors": "^2.8.4", 340 | "@types/express": "4.16.0", 341 | "accepts": "^1.3.5", 342 | "apollo-server-core": "2.3.1", 343 | "body-parser": "^1.18.3", 344 | "cors": "^2.8.4", 345 | "graphql-subscriptions": "^1.0.0", 346 | "graphql-tools": "^4.0.0", 347 | "type-is": "^1.6.16" 348 | } 349 | }, 350 | "apollo-server-plugin-base": { 351 | "version": "0.2.1", 352 | "resolved": "https://registry.npmjs.org/apollo-server-plugin-base/-/apollo-server-plugin-base-0.2.1.tgz", 353 | "integrity": "sha512-497NIY9VWRYCrMSkgR11IrIUO4Fsy6aGgnpOJoTdLQAnkDD9SJDSRzwKj4gypUoTT2unfKDng4eMxXVZlHvjOw==" 354 | }, 355 | "apollo-tracing": { 356 | "version": "0.4.0", 357 | "resolved": "https://registry.npmjs.org/apollo-tracing/-/apollo-tracing-0.4.0.tgz", 358 | "integrity": "sha512-BlM8iQUQva4fm0xD/pLwkcz0degfB9a/aAn4k4cK36eLVD8XUkl7ptEB0c+cwcj7tOYpV1r5QX1XwdayBzlHSg==", 359 | "requires": { 360 | "apollo-server-env": "2.2.0", 361 | "graphql-extensions": "0.4.0" 362 | }, 363 | "dependencies": { 364 | "graphql-extensions": { 365 | "version": "0.4.0", 366 | "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.4.0.tgz", 367 | "integrity": "sha512-8TUgIIUVpXWOcqq9RdmTSHUrhc3a/s+saKv9cCl8TYWHK9vyJIdea7ZaSKHGDthZNcsN+C3LulZYRL3Ah8ukoA==", 368 | "requires": { 369 | "@apollographql/apollo-tools": "^0.2.6" 370 | } 371 | } 372 | } 373 | }, 374 | "apollo-utilities": { 375 | "version": "1.0.26", 376 | "resolved": "https://registry.npmjs.org/apollo-utilities/-/apollo-utilities-1.0.26.tgz", 377 | "integrity": "sha512-URw7o3phymliqYCYatcird2YRPUU2eWCNvip64U9gQrX56mEfK4m99yBIDCMTpmcvOFsKLii1sIEZsHIs/bvnw==", 378 | "requires": { 379 | "fast-json-stable-stringify": "^2.0.0" 380 | } 381 | }, 382 | "aproba": { 383 | "version": "1.2.0", 384 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", 385 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" 386 | }, 387 | "are-we-there-yet": { 388 | "version": "1.1.5", 389 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", 390 | "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", 391 | "requires": { 392 | "delegates": "^1.0.0", 393 | "readable-stream": "^2.0.6" 394 | }, 395 | "dependencies": { 396 | "isarray": { 397 | "version": "1.0.0", 398 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 399 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 400 | }, 401 | "readable-stream": { 402 | "version": "2.3.6", 403 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 404 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 405 | "requires": { 406 | "core-util-is": "~1.0.0", 407 | "inherits": "~2.0.3", 408 | "isarray": "~1.0.0", 409 | "process-nextick-args": "~2.0.0", 410 | "safe-buffer": "~5.1.1", 411 | "string_decoder": "~1.1.1", 412 | "util-deprecate": "~1.0.1" 413 | } 414 | }, 415 | "string_decoder": { 416 | "version": "1.1.1", 417 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 418 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 419 | "requires": { 420 | "safe-buffer": "~5.1.0" 421 | } 422 | } 423 | } 424 | }, 425 | "array-flatten": { 426 | "version": "1.1.1", 427 | "resolved": "http://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 428 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 429 | }, 430 | "async-limiter": { 431 | "version": "1.0.0", 432 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", 433 | "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" 434 | }, 435 | "async-retry": { 436 | "version": "1.2.3", 437 | "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.2.3.tgz", 438 | "integrity": "sha512-tfDb02Th6CE6pJUF2gjW5ZVjsgwlucVXOEQMvEX9JgSJMs9gAX+Nz3xRuJBKuUYjTSYORqvDBORdAQ3LU59g7Q==", 439 | "requires": { 440 | "retry": "0.12.0" 441 | } 442 | }, 443 | "backo2": { 444 | "version": "1.0.2", 445 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", 446 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" 447 | }, 448 | "balanced-match": { 449 | "version": "1.0.0", 450 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 451 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 452 | }, 453 | "bcrypt": { 454 | "version": "3.0.6", 455 | "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-3.0.6.tgz", 456 | "integrity": "sha512-taA5bCTfXe7FUjKroKky9EXpdhkVvhE5owfxfLYodbrAR1Ul3juLmIQmIQBK4L9a5BuUcE6cqmwT+Da20lF9tg==", 457 | "requires": { 458 | "nan": "2.13.2", 459 | "node-pre-gyp": "0.12.0" 460 | } 461 | }, 462 | "bluebird": { 463 | "version": "3.5.4", 464 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz", 465 | "integrity": "sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw==" 466 | }, 467 | "body-parser": { 468 | "version": "1.18.3", 469 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", 470 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", 471 | "requires": { 472 | "bytes": "3.0.0", 473 | "content-type": "~1.0.4", 474 | "debug": "2.6.9", 475 | "depd": "~1.1.2", 476 | "http-errors": "~1.6.3", 477 | "iconv-lite": "0.4.23", 478 | "on-finished": "~2.3.0", 479 | "qs": "6.5.2", 480 | "raw-body": "2.3.3", 481 | "type-is": "~1.6.16" 482 | }, 483 | "dependencies": { 484 | "http-errors": { 485 | "version": "1.6.3", 486 | "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 487 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 488 | "requires": { 489 | "depd": "~1.1.2", 490 | "inherits": "2.0.3", 491 | "setprototypeof": "1.1.0", 492 | "statuses": ">= 1.4.0 < 2" 493 | } 494 | } 495 | } 496 | }, 497 | "brace-expansion": { 498 | "version": "1.1.11", 499 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 500 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 501 | "requires": { 502 | "balanced-match": "^1.0.0", 503 | "concat-map": "0.0.1" 504 | } 505 | }, 506 | "buffer-equal-constant-time": { 507 | "version": "1.0.1", 508 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 509 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" 510 | }, 511 | "busboy": { 512 | "version": "0.2.14", 513 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", 514 | "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", 515 | "requires": { 516 | "dicer": "0.2.5", 517 | "readable-stream": "1.1.x" 518 | } 519 | }, 520 | "bytes": { 521 | "version": "3.0.0", 522 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 523 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 524 | }, 525 | "charenc": { 526 | "version": "0.0.2", 527 | "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", 528 | "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" 529 | }, 530 | "chownr": { 531 | "version": "1.1.1", 532 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", 533 | "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==" 534 | }, 535 | "cloudinary": { 536 | "version": "1.13.2", 537 | "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-1.13.2.tgz", 538 | "integrity": "sha512-mZWxWxgln6Bkk5QA72BGb1mwRBFs+r94ZzdN37gROPL7FSOslhvFfEvF/Rz/ruPqR7mblMdzVz3wuLQi1oCalw==", 539 | "requires": { 540 | "lodash": "^4.17.11", 541 | "q": "^1.5.1" 542 | } 543 | }, 544 | "cls-bluebird": { 545 | "version": "2.1.0", 546 | "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", 547 | "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", 548 | "requires": { 549 | "is-bluebird": "^1.0.2", 550 | "shimmer": "^1.1.0" 551 | } 552 | }, 553 | "code-point-at": { 554 | "version": "1.1.0", 555 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 556 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" 557 | }, 558 | "concat-map": { 559 | "version": "0.0.1", 560 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 561 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 562 | }, 563 | "console-control-strings": { 564 | "version": "1.1.0", 565 | "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", 566 | "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" 567 | }, 568 | "content-disposition": { 569 | "version": "0.5.2", 570 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 571 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 572 | }, 573 | "content-type": { 574 | "version": "1.0.4", 575 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 576 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 577 | }, 578 | "cookie": { 579 | "version": "0.3.1", 580 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 581 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 582 | }, 583 | "cookie-signature": { 584 | "version": "1.0.6", 585 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 586 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 587 | }, 588 | "core-js": { 589 | "version": "3.0.0-beta.5", 590 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.0.0-beta.5.tgz", 591 | "integrity": "sha512-lv/UPXe8QIvAX4XEgz3u9gpSbYr0Et6gaVhwMEH6SN9Uk+aIhk9IMwQUa35pymUiA4t2THPOaqysDJtX4jcm3w==" 592 | }, 593 | "core-util-is": { 594 | "version": "1.0.2", 595 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 596 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 597 | }, 598 | "cors": { 599 | "version": "2.8.5", 600 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", 601 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", 602 | "requires": { 603 | "object-assign": "^4", 604 | "vary": "^1" 605 | } 606 | }, 607 | "crypt": { 608 | "version": "0.0.2", 609 | "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", 610 | "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" 611 | }, 612 | "debug": { 613 | "version": "2.6.9", 614 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 615 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 616 | "requires": { 617 | "ms": "2.0.0" 618 | } 619 | }, 620 | "deep-extend": { 621 | "version": "0.6.0", 622 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 623 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" 624 | }, 625 | "define-properties": { 626 | "version": "1.1.3", 627 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 628 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 629 | "requires": { 630 | "object-keys": "^1.0.12" 631 | } 632 | }, 633 | "delegates": { 634 | "version": "1.0.0", 635 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", 636 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" 637 | }, 638 | "denque": { 639 | "version": "1.3.0", 640 | "resolved": "https://registry.npmjs.org/denque/-/denque-1.3.0.tgz", 641 | "integrity": "sha512-4SRaSj+PqmrS1soW5/Avd7eJIM2JJIqLLmwhRqIGleZM/8KwZq80njbSS2Iqas+6oARkSkLDHEk4mm78q3JlIg==" 642 | }, 643 | "depd": { 644 | "version": "1.1.2", 645 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 646 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 647 | }, 648 | "deprecated-decorator": { 649 | "version": "0.1.6", 650 | "resolved": "https://registry.npmjs.org/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz", 651 | "integrity": "sha1-AJZjF7ehL+kvPMgx91g68ym4bDc=" 652 | }, 653 | "destroy": { 654 | "version": "1.0.4", 655 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 656 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 657 | }, 658 | "detect-libc": { 659 | "version": "1.0.3", 660 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", 661 | "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" 662 | }, 663 | "dicer": { 664 | "version": "0.2.5", 665 | "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", 666 | "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", 667 | "requires": { 668 | "readable-stream": "1.1.x", 669 | "streamsearch": "0.1.2" 670 | } 671 | }, 672 | "dotenv": { 673 | "version": "6.2.0", 674 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz", 675 | "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w==" 676 | }, 677 | "dottie": { 678 | "version": "2.0.1", 679 | "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.1.tgz", 680 | "integrity": "sha512-ch5OQgvGDK2u8pSZeSYAQaV/lczImd7pMJ7BcEPXmnFVjy4yJIzP6CsODJUTH8mg1tyH1Z2abOiuJO3DjZ/GBw==" 681 | }, 682 | "ecdsa-sig-formatter": { 683 | "version": "1.0.10", 684 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", 685 | "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", 686 | "requires": { 687 | "safe-buffer": "^5.0.1" 688 | } 689 | }, 690 | "ee-first": { 691 | "version": "1.1.1", 692 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 693 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 694 | }, 695 | "encodeurl": { 696 | "version": "1.0.2", 697 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 698 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 699 | }, 700 | "es-abstract": { 701 | "version": "1.12.0", 702 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", 703 | "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", 704 | "requires": { 705 | "es-to-primitive": "^1.1.1", 706 | "function-bind": "^1.1.1", 707 | "has": "^1.0.1", 708 | "is-callable": "^1.1.3", 709 | "is-regex": "^1.0.4" 710 | } 711 | }, 712 | "es-to-primitive": { 713 | "version": "1.2.0", 714 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", 715 | "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", 716 | "requires": { 717 | "is-callable": "^1.1.4", 718 | "is-date-object": "^1.0.1", 719 | "is-symbol": "^1.0.2" 720 | } 721 | }, 722 | "escape-html": { 723 | "version": "1.0.3", 724 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 725 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 726 | }, 727 | "etag": { 728 | "version": "1.8.1", 729 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 730 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 731 | }, 732 | "eventemitter3": { 733 | "version": "3.1.0", 734 | "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", 735 | "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" 736 | }, 737 | "express": { 738 | "version": "4.16.4", 739 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", 740 | "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", 741 | "requires": { 742 | "accepts": "~1.3.5", 743 | "array-flatten": "1.1.1", 744 | "body-parser": "1.18.3", 745 | "content-disposition": "0.5.2", 746 | "content-type": "~1.0.4", 747 | "cookie": "0.3.1", 748 | "cookie-signature": "1.0.6", 749 | "debug": "2.6.9", 750 | "depd": "~1.1.2", 751 | "encodeurl": "~1.0.2", 752 | "escape-html": "~1.0.3", 753 | "etag": "~1.8.1", 754 | "finalhandler": "1.1.1", 755 | "fresh": "0.5.2", 756 | "merge-descriptors": "1.0.1", 757 | "methods": "~1.1.2", 758 | "on-finished": "~2.3.0", 759 | "parseurl": "~1.3.2", 760 | "path-to-regexp": "0.1.7", 761 | "proxy-addr": "~2.0.4", 762 | "qs": "6.5.2", 763 | "range-parser": "~1.2.0", 764 | "safe-buffer": "5.1.2", 765 | "send": "0.16.2", 766 | "serve-static": "1.13.2", 767 | "setprototypeof": "1.1.0", 768 | "statuses": "~1.4.0", 769 | "type-is": "~1.6.16", 770 | "utils-merge": "1.0.1", 771 | "vary": "~1.1.2" 772 | }, 773 | "dependencies": { 774 | "statuses": { 775 | "version": "1.4.0", 776 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 777 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 778 | } 779 | } 780 | }, 781 | "express-fileupload": { 782 | "version": "1.0.0", 783 | "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.0.0.tgz", 784 | "integrity": "sha512-6VS9MiPIXXFFKv5+cRS5+iMh3Zw6KadiSEM+SPRMSC3AEoV3ZOfRUk3ogjDtKVr4o9n3EoHTMyyqbuzBj8gMLw==", 785 | "requires": { 786 | "busboy": "^0.2.14", 787 | "md5": "^2.2.1", 788 | "streamifier": "^0.1.1" 789 | } 790 | }, 791 | "fast-json-stable-stringify": { 792 | "version": "2.0.0", 793 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 794 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 795 | }, 796 | "finalhandler": { 797 | "version": "1.1.1", 798 | "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 799 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 800 | "requires": { 801 | "debug": "2.6.9", 802 | "encodeurl": "~1.0.2", 803 | "escape-html": "~1.0.3", 804 | "on-finished": "~2.3.0", 805 | "parseurl": "~1.3.2", 806 | "statuses": "~1.4.0", 807 | "unpipe": "~1.0.0" 808 | }, 809 | "dependencies": { 810 | "statuses": { 811 | "version": "1.4.0", 812 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 813 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 814 | } 815 | } 816 | }, 817 | "forwarded": { 818 | "version": "0.1.2", 819 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 820 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 821 | }, 822 | "fresh": { 823 | "version": "0.5.2", 824 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 825 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 826 | }, 827 | "fs-capacitor": { 828 | "version": "1.0.1", 829 | "resolved": "https://registry.npmjs.org/fs-capacitor/-/fs-capacitor-1.0.1.tgz", 830 | "integrity": "sha512-XdZK0Q78WP29Vm3FGgJRhRhrBm51PagovzWtW2kJ3Q6cYJbGtZqWSGTSPwvtEkyjIirFd7b8Yes/dpOYjt4RRQ==" 831 | }, 832 | "fs-minipass": { 833 | "version": "1.2.6", 834 | "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz", 835 | "integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==", 836 | "requires": { 837 | "minipass": "^2.2.1" 838 | } 839 | }, 840 | "fs.realpath": { 841 | "version": "1.0.0", 842 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 843 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 844 | }, 845 | "function-bind": { 846 | "version": "1.1.1", 847 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 848 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 849 | }, 850 | "gauge": { 851 | "version": "2.7.4", 852 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", 853 | "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", 854 | "requires": { 855 | "aproba": "^1.0.3", 856 | "console-control-strings": "^1.0.0", 857 | "has-unicode": "^2.0.0", 858 | "object-assign": "^4.1.0", 859 | "signal-exit": "^3.0.0", 860 | "string-width": "^1.0.1", 861 | "strip-ansi": "^3.0.1", 862 | "wide-align": "^1.1.0" 863 | } 864 | }, 865 | "generate-function": { 866 | "version": "2.3.1", 867 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", 868 | "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", 869 | "requires": { 870 | "is-property": "^1.0.2" 871 | } 872 | }, 873 | "glob": { 874 | "version": "7.1.4", 875 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", 876 | "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", 877 | "requires": { 878 | "fs.realpath": "^1.0.0", 879 | "inflight": "^1.0.4", 880 | "inherits": "2", 881 | "minimatch": "^3.0.4", 882 | "once": "^1.3.0", 883 | "path-is-absolute": "^1.0.0" 884 | } 885 | }, 886 | "graphql": { 887 | "version": "14.0.2", 888 | "resolved": "https://registry.npmjs.org/graphql/-/graphql-14.0.2.tgz", 889 | "integrity": "sha512-gUC4YYsaiSJT1h40krG3J+USGlwhzNTXSb4IOZljn9ag5Tj+RkoXrWp+Kh7WyE3t1NCfab5kzCuxBIvOMERMXw==", 890 | "requires": { 891 | "iterall": "^1.2.2" 892 | } 893 | }, 894 | "graphql-extensions": { 895 | "version": "0.4.1", 896 | "resolved": "https://registry.npmjs.org/graphql-extensions/-/graphql-extensions-0.4.1.tgz", 897 | "integrity": "sha512-Xei4rBxbsTHU6dYiq9y1xxbpRMU3+Os7yD3vXV5W4HbTaxRMizDmu6LAvV4oBEi0ttwICHARQjYTjDTDhHnxrQ==", 898 | "requires": { 899 | "@apollographql/apollo-tools": "^0.2.6" 900 | } 901 | }, 902 | "graphql-subscriptions": { 903 | "version": "1.0.0", 904 | "resolved": "https://registry.npmjs.org/graphql-subscriptions/-/graphql-subscriptions-1.0.0.tgz", 905 | "integrity": "sha512-+ytmryoHF1LVf58NKEaNPRUzYyXplm120ntxfPcgOBC7TnK7Tv/4VRHeh4FAR9iL+O1bqhZs4nkibxQ+OA5cDQ==", 906 | "requires": { 907 | "iterall": "^1.2.1" 908 | } 909 | }, 910 | "graphql-tag": { 911 | "version": "2.10.0", 912 | "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.10.0.tgz", 913 | "integrity": "sha512-9FD6cw976TLLf9WYIUPCaaTpniawIjHWZSwIRZSjrfufJamcXbVVYfN2TWvJYbw0Xf2JjYbl1/f2+wDnBVw3/w==" 914 | }, 915 | "graphql-tools": { 916 | "version": "4.0.3", 917 | "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-4.0.3.tgz", 918 | "integrity": "sha512-NNZM0WSnVLX1zIMUxu7SjzLZ4prCp15N5L2T2ro02OVyydZ0fuCnZYRnx/yK9xjGWbZA0Q58yEO//Bv/psJWrg==", 919 | "requires": { 920 | "apollo-link": "^1.2.3", 921 | "apollo-utilities": "^1.0.1", 922 | "deprecated-decorator": "^0.1.6", 923 | "iterall": "^1.1.3", 924 | "uuid": "^3.1.0" 925 | } 926 | }, 927 | "graphql-upload": { 928 | "version": "8.0.2", 929 | "resolved": "https://registry.npmjs.org/graphql-upload/-/graphql-upload-8.0.2.tgz", 930 | "integrity": "sha512-u8a5tKPfJ0rU4MY+B3skabL8pEjMkm3tUzq25KBx6nT0yEWmqUO7Z5tdwvwYLFpkLwew94Gue0ARbZtar3gLTw==", 931 | "requires": { 932 | "busboy": "^0.2.14", 933 | "fs-capacitor": "^1.0.0", 934 | "http-errors": "^1.7.1", 935 | "object-path": "^0.11.4" 936 | } 937 | }, 938 | "has": { 939 | "version": "1.0.3", 940 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 941 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 942 | "requires": { 943 | "function-bind": "^1.1.1" 944 | } 945 | }, 946 | "has-symbols": { 947 | "version": "1.0.0", 948 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", 949 | "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" 950 | }, 951 | "has-unicode": { 952 | "version": "2.0.1", 953 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", 954 | "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" 955 | }, 956 | "http-errors": { 957 | "version": "1.7.1", 958 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.1.tgz", 959 | "integrity": "sha512-jWEUgtZWGSMba9I1N3gc1HmvpBUaNC9vDdA46yScAdp+C5rdEuKWUBLWTQpW9FwSWSbYYs++b6SDCxf9UEJzfw==", 960 | "requires": { 961 | "depd": "~1.1.2", 962 | "inherits": "2.0.3", 963 | "setprototypeof": "1.1.0", 964 | "statuses": ">= 1.5.0 < 2", 965 | "toidentifier": "1.0.0" 966 | } 967 | }, 968 | "iconv-lite": { 969 | "version": "0.4.23", 970 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 971 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 972 | "requires": { 973 | "safer-buffer": ">= 2.1.2 < 3" 974 | } 975 | }, 976 | "ignore-walk": { 977 | "version": "3.0.1", 978 | "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", 979 | "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", 980 | "requires": { 981 | "minimatch": "^3.0.4" 982 | } 983 | }, 984 | "inflection": { 985 | "version": "1.12.0", 986 | "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", 987 | "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" 988 | }, 989 | "inflight": { 990 | "version": "1.0.6", 991 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 992 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 993 | "requires": { 994 | "once": "^1.3.0", 995 | "wrappy": "1" 996 | } 997 | }, 998 | "inherits": { 999 | "version": "2.0.3", 1000 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1001 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 1002 | }, 1003 | "ini": { 1004 | "version": "1.3.5", 1005 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", 1006 | "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" 1007 | }, 1008 | "ipaddr.js": { 1009 | "version": "1.8.0", 1010 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", 1011 | "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" 1012 | }, 1013 | "is-bluebird": { 1014 | "version": "1.0.2", 1015 | "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", 1016 | "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" 1017 | }, 1018 | "is-buffer": { 1019 | "version": "1.1.6", 1020 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 1021 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 1022 | }, 1023 | "is-callable": { 1024 | "version": "1.1.4", 1025 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", 1026 | "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" 1027 | }, 1028 | "is-date-object": { 1029 | "version": "1.0.1", 1030 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", 1031 | "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" 1032 | }, 1033 | "is-fullwidth-code-point": { 1034 | "version": "1.0.0", 1035 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 1036 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 1037 | "requires": { 1038 | "number-is-nan": "^1.0.0" 1039 | } 1040 | }, 1041 | "is-property": { 1042 | "version": "1.0.2", 1043 | "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", 1044 | "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" 1045 | }, 1046 | "is-regex": { 1047 | "version": "1.0.4", 1048 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", 1049 | "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", 1050 | "requires": { 1051 | "has": "^1.0.1" 1052 | } 1053 | }, 1054 | "is-symbol": { 1055 | "version": "1.0.2", 1056 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", 1057 | "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", 1058 | "requires": { 1059 | "has-symbols": "^1.0.0" 1060 | } 1061 | }, 1062 | "isarray": { 1063 | "version": "0.0.1", 1064 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 1065 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 1066 | }, 1067 | "iterall": { 1068 | "version": "1.2.2", 1069 | "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.2.2.tgz", 1070 | "integrity": "sha512-yynBb1g+RFUPY64fTrFv7nsjRrENBQJaX2UL+2Szc9REFrSNm1rpSXHGzhmAy7a9uv3vlvgBlXnf9RqmPH1/DA==" 1071 | }, 1072 | "json-stable-stringify": { 1073 | "version": "1.0.1", 1074 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", 1075 | "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", 1076 | "requires": { 1077 | "jsonify": "~0.0.0" 1078 | } 1079 | }, 1080 | "jsonify": { 1081 | "version": "0.0.0", 1082 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", 1083 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" 1084 | }, 1085 | "jsonwebtoken": { 1086 | "version": "8.4.0", 1087 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.4.0.tgz", 1088 | "integrity": "sha512-coyXjRTCy0pw5WYBpMvWOMN+Kjaik2MwTUIq9cna/W7NpO9E+iYbumZONAz3hcr+tXFJECoQVrtmIoC3Oz0gvg==", 1089 | "requires": { 1090 | "jws": "^3.1.5", 1091 | "lodash.includes": "^4.3.0", 1092 | "lodash.isboolean": "^3.0.3", 1093 | "lodash.isinteger": "^4.0.4", 1094 | "lodash.isnumber": "^3.0.3", 1095 | "lodash.isplainobject": "^4.0.6", 1096 | "lodash.isstring": "^4.0.1", 1097 | "lodash.once": "^4.0.0", 1098 | "ms": "^2.1.1" 1099 | }, 1100 | "dependencies": { 1101 | "ms": { 1102 | "version": "2.1.1", 1103 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 1104 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 1105 | } 1106 | } 1107 | }, 1108 | "jwa": { 1109 | "version": "1.1.6", 1110 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz", 1111 | "integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==", 1112 | "requires": { 1113 | "buffer-equal-constant-time": "1.0.1", 1114 | "ecdsa-sig-formatter": "1.0.10", 1115 | "safe-buffer": "^5.0.1" 1116 | } 1117 | }, 1118 | "jws": { 1119 | "version": "3.1.5", 1120 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz", 1121 | "integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==", 1122 | "requires": { 1123 | "jwa": "^1.1.5", 1124 | "safe-buffer": "^5.0.1" 1125 | } 1126 | }, 1127 | "lodash": { 1128 | "version": "4.17.11", 1129 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 1130 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==" 1131 | }, 1132 | "lodash.includes": { 1133 | "version": "4.3.0", 1134 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", 1135 | "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" 1136 | }, 1137 | "lodash.isboolean": { 1138 | "version": "3.0.3", 1139 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", 1140 | "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" 1141 | }, 1142 | "lodash.isinteger": { 1143 | "version": "4.0.4", 1144 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", 1145 | "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" 1146 | }, 1147 | "lodash.isnumber": { 1148 | "version": "3.0.3", 1149 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", 1150 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" 1151 | }, 1152 | "lodash.isplainobject": { 1153 | "version": "4.0.6", 1154 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 1155 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" 1156 | }, 1157 | "lodash.isstring": { 1158 | "version": "4.0.1", 1159 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", 1160 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" 1161 | }, 1162 | "lodash.once": { 1163 | "version": "4.1.1", 1164 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", 1165 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" 1166 | }, 1167 | "long": { 1168 | "version": "4.0.0", 1169 | "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", 1170 | "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" 1171 | }, 1172 | "lru-cache": { 1173 | "version": "5.1.1", 1174 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 1175 | "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 1176 | "requires": { 1177 | "yallist": "^3.0.2" 1178 | } 1179 | }, 1180 | "md5": { 1181 | "version": "2.2.1", 1182 | "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", 1183 | "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", 1184 | "requires": { 1185 | "charenc": "~0.0.1", 1186 | "crypt": "~0.0.1", 1187 | "is-buffer": "~1.1.1" 1188 | } 1189 | }, 1190 | "media-typer": { 1191 | "version": "0.3.0", 1192 | "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 1193 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 1194 | }, 1195 | "merge-descriptors": { 1196 | "version": "1.0.1", 1197 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 1198 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 1199 | }, 1200 | "methods": { 1201 | "version": "1.1.2", 1202 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 1203 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 1204 | }, 1205 | "mime": { 1206 | "version": "1.4.1", 1207 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 1208 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 1209 | }, 1210 | "mime-db": { 1211 | "version": "1.37.0", 1212 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", 1213 | "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" 1214 | }, 1215 | "mime-types": { 1216 | "version": "2.1.21", 1217 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", 1218 | "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", 1219 | "requires": { 1220 | "mime-db": "~1.37.0" 1221 | } 1222 | }, 1223 | "minimatch": { 1224 | "version": "3.0.4", 1225 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1226 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1227 | "requires": { 1228 | "brace-expansion": "^1.1.7" 1229 | } 1230 | }, 1231 | "minimist": { 1232 | "version": "0.0.8", 1233 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 1234 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" 1235 | }, 1236 | "minipass": { 1237 | "version": "2.3.5", 1238 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", 1239 | "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", 1240 | "requires": { 1241 | "safe-buffer": "^5.1.2", 1242 | "yallist": "^3.0.0" 1243 | } 1244 | }, 1245 | "minizlib": { 1246 | "version": "1.2.1", 1247 | "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", 1248 | "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", 1249 | "requires": { 1250 | "minipass": "^2.2.1" 1251 | } 1252 | }, 1253 | "mkdirp": { 1254 | "version": "0.5.1", 1255 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 1256 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 1257 | "requires": { 1258 | "minimist": "0.0.8" 1259 | } 1260 | }, 1261 | "moment": { 1262 | "version": "2.24.0", 1263 | "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", 1264 | "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" 1265 | }, 1266 | "moment-timezone": { 1267 | "version": "0.5.25", 1268 | "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.25.tgz", 1269 | "integrity": "sha512-DgEaTyN/z0HFaVcVbSyVCUU6HeFdnNC3vE4c9cgu2dgMTvjBUBdBzWfasTBmAW45u5OIMeCJtU8yNjM22DHucw==", 1270 | "requires": { 1271 | "moment": ">= 2.9.0" 1272 | } 1273 | }, 1274 | "ms": { 1275 | "version": "2.0.0", 1276 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1277 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 1278 | }, 1279 | "mysql2": { 1280 | "version": "1.6.4", 1281 | "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-1.6.4.tgz", 1282 | "integrity": "sha512-ZYbYgK06HKfxU45tYYLfwW5gKt8BslfE7FGyULNrf2K2fh+DuEX+e0QKsd2ObpZkMILefaVn8hsakVsTFqravQ==", 1283 | "requires": { 1284 | "denque": "1.3.0", 1285 | "generate-function": "^2.3.1", 1286 | "iconv-lite": "^0.4.24", 1287 | "long": "^4.0.0", 1288 | "lru-cache": "4.1.3", 1289 | "named-placeholders": "1.1.1", 1290 | "seq-queue": "0.0.5", 1291 | "sqlstring": "2.3.1" 1292 | }, 1293 | "dependencies": { 1294 | "iconv-lite": { 1295 | "version": "0.4.24", 1296 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 1297 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 1298 | "requires": { 1299 | "safer-buffer": ">= 2.1.2 < 3" 1300 | } 1301 | }, 1302 | "lru-cache": { 1303 | "version": "4.1.3", 1304 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", 1305 | "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", 1306 | "requires": { 1307 | "pseudomap": "^1.0.2", 1308 | "yallist": "^2.1.2" 1309 | } 1310 | }, 1311 | "yallist": { 1312 | "version": "2.1.2", 1313 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 1314 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" 1315 | } 1316 | } 1317 | }, 1318 | "named-placeholders": { 1319 | "version": "1.1.1", 1320 | "resolved": "http://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.1.tgz", 1321 | "integrity": "sha1-O3oNJiA910s6nfTJz7gnsvuQfmQ=", 1322 | "requires": { 1323 | "lru-cache": "2.5.0" 1324 | }, 1325 | "dependencies": { 1326 | "lru-cache": { 1327 | "version": "2.5.0", 1328 | "resolved": "http://registry.npmjs.org/lru-cache/-/lru-cache-2.5.0.tgz", 1329 | "integrity": "sha1-2COIrpyWC+y+oMc7uet5tsbOmus=" 1330 | } 1331 | } 1332 | }, 1333 | "nan": { 1334 | "version": "2.13.2", 1335 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", 1336 | "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==" 1337 | }, 1338 | "needle": { 1339 | "version": "2.4.0", 1340 | "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", 1341 | "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", 1342 | "requires": { 1343 | "debug": "^3.2.6", 1344 | "iconv-lite": "^0.4.4", 1345 | "sax": "^1.2.4" 1346 | }, 1347 | "dependencies": { 1348 | "debug": { 1349 | "version": "3.2.6", 1350 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", 1351 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", 1352 | "requires": { 1353 | "ms": "^2.1.1" 1354 | } 1355 | }, 1356 | "ms": { 1357 | "version": "2.1.1", 1358 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 1359 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 1360 | } 1361 | } 1362 | }, 1363 | "negotiator": { 1364 | "version": "0.6.1", 1365 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 1366 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 1367 | }, 1368 | "node-fetch": { 1369 | "version": "2.3.0", 1370 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.3.0.tgz", 1371 | "integrity": "sha512-MOd8pV3fxENbryESLgVIeaGKrdl+uaYhCSSVkjeOb/31/njTpcis5aWfdqgNlHIrKOLRbMnfPINPOML2CIFeXA==" 1372 | }, 1373 | "node-pre-gyp": { 1374 | "version": "0.12.0", 1375 | "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz", 1376 | "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", 1377 | "requires": { 1378 | "detect-libc": "^1.0.2", 1379 | "mkdirp": "^0.5.1", 1380 | "needle": "^2.2.1", 1381 | "nopt": "^4.0.1", 1382 | "npm-packlist": "^1.1.6", 1383 | "npmlog": "^4.0.2", 1384 | "rc": "^1.2.7", 1385 | "rimraf": "^2.6.1", 1386 | "semver": "^5.3.0", 1387 | "tar": "^4" 1388 | } 1389 | }, 1390 | "nopt": { 1391 | "version": "4.0.1", 1392 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", 1393 | "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", 1394 | "requires": { 1395 | "abbrev": "1", 1396 | "osenv": "^0.1.4" 1397 | } 1398 | }, 1399 | "npm-bundled": { 1400 | "version": "1.0.6", 1401 | "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz", 1402 | "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==" 1403 | }, 1404 | "npm-packlist": { 1405 | "version": "1.4.1", 1406 | "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz", 1407 | "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", 1408 | "requires": { 1409 | "ignore-walk": "^3.0.1", 1410 | "npm-bundled": "^1.0.1" 1411 | } 1412 | }, 1413 | "npmlog": { 1414 | "version": "4.1.2", 1415 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", 1416 | "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", 1417 | "requires": { 1418 | "are-we-there-yet": "~1.1.2", 1419 | "console-control-strings": "~1.1.0", 1420 | "gauge": "~2.7.3", 1421 | "set-blocking": "~2.0.0" 1422 | } 1423 | }, 1424 | "number-is-nan": { 1425 | "version": "1.0.1", 1426 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 1427 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" 1428 | }, 1429 | "object-assign": { 1430 | "version": "4.1.1", 1431 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1432 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 1433 | }, 1434 | "object-keys": { 1435 | "version": "1.0.12", 1436 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", 1437 | "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" 1438 | }, 1439 | "object-path": { 1440 | "version": "0.11.4", 1441 | "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.4.tgz", 1442 | "integrity": "sha1-NwrnUvvzfePqcKhhwju6iRVpGUk=" 1443 | }, 1444 | "object.getownpropertydescriptors": { 1445 | "version": "2.0.3", 1446 | "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", 1447 | "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", 1448 | "requires": { 1449 | "define-properties": "^1.1.2", 1450 | "es-abstract": "^1.5.1" 1451 | } 1452 | }, 1453 | "on-finished": { 1454 | "version": "2.3.0", 1455 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 1456 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 1457 | "requires": { 1458 | "ee-first": "1.1.1" 1459 | } 1460 | }, 1461 | "once": { 1462 | "version": "1.4.0", 1463 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1464 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1465 | "requires": { 1466 | "wrappy": "1" 1467 | } 1468 | }, 1469 | "os-homedir": { 1470 | "version": "1.0.2", 1471 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 1472 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" 1473 | }, 1474 | "os-tmpdir": { 1475 | "version": "1.0.2", 1476 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 1477 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" 1478 | }, 1479 | "osenv": { 1480 | "version": "0.1.5", 1481 | "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", 1482 | "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", 1483 | "requires": { 1484 | "os-homedir": "^1.0.0", 1485 | "os-tmpdir": "^1.0.0" 1486 | } 1487 | }, 1488 | "parseurl": { 1489 | "version": "1.3.2", 1490 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 1491 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 1492 | }, 1493 | "path-is-absolute": { 1494 | "version": "1.0.1", 1495 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1496 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 1497 | }, 1498 | "path-to-regexp": { 1499 | "version": "0.1.7", 1500 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 1501 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 1502 | }, 1503 | "process-nextick-args": { 1504 | "version": "2.0.0", 1505 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 1506 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" 1507 | }, 1508 | "protobufjs": { 1509 | "version": "6.8.8", 1510 | "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", 1511 | "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", 1512 | "requires": { 1513 | "@protobufjs/aspromise": "^1.1.2", 1514 | "@protobufjs/base64": "^1.1.2", 1515 | "@protobufjs/codegen": "^2.0.4", 1516 | "@protobufjs/eventemitter": "^1.1.0", 1517 | "@protobufjs/fetch": "^1.1.0", 1518 | "@protobufjs/float": "^1.0.2", 1519 | "@protobufjs/inquire": "^1.1.0", 1520 | "@protobufjs/path": "^1.1.2", 1521 | "@protobufjs/pool": "^1.1.0", 1522 | "@protobufjs/utf8": "^1.1.0", 1523 | "@types/long": "^4.0.0", 1524 | "@types/node": "^10.1.0", 1525 | "long": "^4.0.0" 1526 | } 1527 | }, 1528 | "proxy-addr": { 1529 | "version": "2.0.4", 1530 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", 1531 | "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", 1532 | "requires": { 1533 | "forwarded": "~0.1.2", 1534 | "ipaddr.js": "1.8.0" 1535 | } 1536 | }, 1537 | "pseudomap": { 1538 | "version": "1.0.2", 1539 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 1540 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" 1541 | }, 1542 | "q": { 1543 | "version": "1.5.1", 1544 | "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", 1545 | "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" 1546 | }, 1547 | "qs": { 1548 | "version": "6.5.2", 1549 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 1550 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 1551 | }, 1552 | "range-parser": { 1553 | "version": "1.2.0", 1554 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 1555 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 1556 | }, 1557 | "raw-body": { 1558 | "version": "2.3.3", 1559 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", 1560 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", 1561 | "requires": { 1562 | "bytes": "3.0.0", 1563 | "http-errors": "1.6.3", 1564 | "iconv-lite": "0.4.23", 1565 | "unpipe": "1.0.0" 1566 | }, 1567 | "dependencies": { 1568 | "http-errors": { 1569 | "version": "1.6.3", 1570 | "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 1571 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 1572 | "requires": { 1573 | "depd": "~1.1.2", 1574 | "inherits": "2.0.3", 1575 | "setprototypeof": "1.1.0", 1576 | "statuses": ">= 1.4.0 < 2" 1577 | } 1578 | } 1579 | } 1580 | }, 1581 | "rc": { 1582 | "version": "1.2.8", 1583 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 1584 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 1585 | "requires": { 1586 | "deep-extend": "^0.6.0", 1587 | "ini": "~1.3.0", 1588 | "minimist": "^1.2.0", 1589 | "strip-json-comments": "~2.0.1" 1590 | }, 1591 | "dependencies": { 1592 | "minimist": { 1593 | "version": "1.2.0", 1594 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 1595 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 1596 | } 1597 | } 1598 | }, 1599 | "readable-stream": { 1600 | "version": "1.1.14", 1601 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 1602 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 1603 | "requires": { 1604 | "core-util-is": "~1.0.0", 1605 | "inherits": "~2.0.1", 1606 | "isarray": "0.0.1", 1607 | "string_decoder": "~0.10.x" 1608 | } 1609 | }, 1610 | "retry": { 1611 | "version": "0.12.0", 1612 | "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", 1613 | "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" 1614 | }, 1615 | "retry-as-promised": { 1616 | "version": "3.2.0", 1617 | "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", 1618 | "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", 1619 | "requires": { 1620 | "any-promise": "^1.3.0" 1621 | } 1622 | }, 1623 | "rimraf": { 1624 | "version": "2.6.3", 1625 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", 1626 | "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", 1627 | "requires": { 1628 | "glob": "^7.1.3" 1629 | } 1630 | }, 1631 | "safe-buffer": { 1632 | "version": "5.1.2", 1633 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1634 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1635 | }, 1636 | "safer-buffer": { 1637 | "version": "2.1.2", 1638 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 1639 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 1640 | }, 1641 | "sax": { 1642 | "version": "1.2.4", 1643 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", 1644 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" 1645 | }, 1646 | "semver": { 1647 | "version": "5.7.0", 1648 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", 1649 | "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" 1650 | }, 1651 | "send": { 1652 | "version": "0.16.2", 1653 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 1654 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 1655 | "requires": { 1656 | "debug": "2.6.9", 1657 | "depd": "~1.1.2", 1658 | "destroy": "~1.0.4", 1659 | "encodeurl": "~1.0.2", 1660 | "escape-html": "~1.0.3", 1661 | "etag": "~1.8.1", 1662 | "fresh": "0.5.2", 1663 | "http-errors": "~1.6.2", 1664 | "mime": "1.4.1", 1665 | "ms": "2.0.0", 1666 | "on-finished": "~2.3.0", 1667 | "range-parser": "~1.2.0", 1668 | "statuses": "~1.4.0" 1669 | }, 1670 | "dependencies": { 1671 | "http-errors": { 1672 | "version": "1.6.3", 1673 | "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 1674 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 1675 | "requires": { 1676 | "depd": "~1.1.2", 1677 | "inherits": "2.0.3", 1678 | "setprototypeof": "1.1.0", 1679 | "statuses": ">= 1.4.0 < 2" 1680 | } 1681 | }, 1682 | "statuses": { 1683 | "version": "1.4.0", 1684 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 1685 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 1686 | } 1687 | } 1688 | }, 1689 | "seq-queue": { 1690 | "version": "0.0.5", 1691 | "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", 1692 | "integrity": "sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4=" 1693 | }, 1694 | "sequelize": { 1695 | "version": "5.6.1", 1696 | "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.6.1.tgz", 1697 | "integrity": "sha512-QsXUDar6ow0HrF9BtnHRaNumu6qRYb97dfwvez/Z5guH3i6w6k8+bp6gP3VCiDC+2qX+jQIyrYohKg9evy8GFg==", 1698 | "requires": { 1699 | "bluebird": "^3.5.0", 1700 | "cls-bluebird": "^2.1.0", 1701 | "debug": "^4.1.1", 1702 | "dottie": "^2.0.0", 1703 | "inflection": "1.12.0", 1704 | "lodash": "^4.17.11", 1705 | "moment": "^2.24.0", 1706 | "moment-timezone": "^0.5.21", 1707 | "retry-as-promised": "^3.1.0", 1708 | "semver": "^5.6.0", 1709 | "sequelize-pool": "^1.0.2", 1710 | "toposort-class": "^1.0.1", 1711 | "uuid": "^3.2.1", 1712 | "validator": "^10.11.0", 1713 | "wkx": "^0.4.6" 1714 | }, 1715 | "dependencies": { 1716 | "debug": { 1717 | "version": "4.1.1", 1718 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 1719 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 1720 | "requires": { 1721 | "ms": "^2.1.1" 1722 | } 1723 | }, 1724 | "ms": { 1725 | "version": "2.1.1", 1726 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 1727 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 1728 | } 1729 | } 1730 | }, 1731 | "sequelize-pool": { 1732 | "version": "1.0.2", 1733 | "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-1.0.2.tgz", 1734 | "integrity": "sha512-VMKl/gCCdIvB1gFZ7p+oqLFEyZEz3oMMYjkKvfEC7GoO9bBcxmfOOU9RdkoltfXGgBZFigSChihRly2gKtsh2w==", 1735 | "requires": { 1736 | "bluebird": "^3.5.3" 1737 | } 1738 | }, 1739 | "serve-static": { 1740 | "version": "1.13.2", 1741 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 1742 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 1743 | "requires": { 1744 | "encodeurl": "~1.0.2", 1745 | "escape-html": "~1.0.3", 1746 | "parseurl": "~1.3.2", 1747 | "send": "0.16.2" 1748 | } 1749 | }, 1750 | "set-blocking": { 1751 | "version": "2.0.0", 1752 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 1753 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" 1754 | }, 1755 | "setprototypeof": { 1756 | "version": "1.1.0", 1757 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 1758 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 1759 | }, 1760 | "shimmer": { 1761 | "version": "1.2.1", 1762 | "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", 1763 | "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" 1764 | }, 1765 | "signal-exit": { 1766 | "version": "3.0.2", 1767 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1768 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" 1769 | }, 1770 | "sqlstring": { 1771 | "version": "2.3.1", 1772 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", 1773 | "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" 1774 | }, 1775 | "statuses": { 1776 | "version": "1.5.0", 1777 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 1778 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 1779 | }, 1780 | "streamifier": { 1781 | "version": "0.1.1", 1782 | "resolved": "https://registry.npmjs.org/streamifier/-/streamifier-0.1.1.tgz", 1783 | "integrity": "sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8=" 1784 | }, 1785 | "streamsearch": { 1786 | "version": "0.1.2", 1787 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", 1788 | "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" 1789 | }, 1790 | "string-width": { 1791 | "version": "1.0.2", 1792 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 1793 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 1794 | "requires": { 1795 | "code-point-at": "^1.0.0", 1796 | "is-fullwidth-code-point": "^1.0.0", 1797 | "strip-ansi": "^3.0.0" 1798 | } 1799 | }, 1800 | "string_decoder": { 1801 | "version": "0.10.31", 1802 | "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 1803 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 1804 | }, 1805 | "strip-ansi": { 1806 | "version": "3.0.1", 1807 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 1808 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 1809 | "requires": { 1810 | "ansi-regex": "^2.0.0" 1811 | } 1812 | }, 1813 | "strip-json-comments": { 1814 | "version": "2.0.1", 1815 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1816 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" 1817 | }, 1818 | "subscriptions-transport-ws": { 1819 | "version": "0.9.15", 1820 | "resolved": "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.15.tgz", 1821 | "integrity": "sha512-f9eBfWdHsePQV67QIX+VRhf++dn1adyC/PZHP6XI5AfKnZ4n0FW+v5omxwdHVpd4xq2ZijaHEcmlQrhBY79ZWQ==", 1822 | "requires": { 1823 | "backo2": "^1.0.2", 1824 | "eventemitter3": "^3.1.0", 1825 | "iterall": "^1.2.1", 1826 | "symbol-observable": "^1.0.4", 1827 | "ws": "^5.2.0" 1828 | }, 1829 | "dependencies": { 1830 | "ws": { 1831 | "version": "5.2.2", 1832 | "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", 1833 | "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", 1834 | "requires": { 1835 | "async-limiter": "~1.0.0" 1836 | } 1837 | } 1838 | } 1839 | }, 1840 | "symbol-observable": { 1841 | "version": "1.2.0", 1842 | "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", 1843 | "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" 1844 | }, 1845 | "tar": { 1846 | "version": "4.4.8", 1847 | "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", 1848 | "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", 1849 | "requires": { 1850 | "chownr": "^1.1.1", 1851 | "fs-minipass": "^1.2.5", 1852 | "minipass": "^2.3.4", 1853 | "minizlib": "^1.1.1", 1854 | "mkdirp": "^0.5.0", 1855 | "safe-buffer": "^5.1.2", 1856 | "yallist": "^3.0.2" 1857 | } 1858 | }, 1859 | "toidentifier": { 1860 | "version": "1.0.0", 1861 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 1862 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 1863 | }, 1864 | "toposort-class": { 1865 | "version": "1.0.1", 1866 | "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", 1867 | "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" 1868 | }, 1869 | "type-is": { 1870 | "version": "1.6.16", 1871 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", 1872 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", 1873 | "requires": { 1874 | "media-typer": "0.3.0", 1875 | "mime-types": "~2.1.18" 1876 | } 1877 | }, 1878 | "unpipe": { 1879 | "version": "1.0.0", 1880 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1881 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 1882 | }, 1883 | "util-deprecate": { 1884 | "version": "1.0.2", 1885 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1886 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 1887 | }, 1888 | "util.promisify": { 1889 | "version": "1.0.0", 1890 | "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", 1891 | "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", 1892 | "requires": { 1893 | "define-properties": "^1.1.2", 1894 | "object.getownpropertydescriptors": "^2.0.3" 1895 | } 1896 | }, 1897 | "utils-merge": { 1898 | "version": "1.0.1", 1899 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1900 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 1901 | }, 1902 | "uuid": { 1903 | "version": "3.3.2", 1904 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 1905 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 1906 | }, 1907 | "validator": { 1908 | "version": "10.11.0", 1909 | "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", 1910 | "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" 1911 | }, 1912 | "vary": { 1913 | "version": "1.1.2", 1914 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1915 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 1916 | }, 1917 | "wide-align": { 1918 | "version": "1.1.3", 1919 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", 1920 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", 1921 | "requires": { 1922 | "string-width": "^1.0.2 || 2" 1923 | } 1924 | }, 1925 | "wkx": { 1926 | "version": "0.4.6", 1927 | "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.6.tgz", 1928 | "integrity": "sha512-LHxXlzRCYQXA9ZHgs8r7Gafh0gVOE8o3QmudM1PIkOdkXXjW7Thcl+gb2P2dRuKgW8cqkitCRZkkjtmWzpHi7A==", 1929 | "requires": { 1930 | "@types/node": "*" 1931 | } 1932 | }, 1933 | "wrappy": { 1934 | "version": "1.0.2", 1935 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1936 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1937 | }, 1938 | "ws": { 1939 | "version": "6.1.2", 1940 | "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.2.tgz", 1941 | "integrity": "sha512-rfUqzvz0WxmSXtJpPMX2EeASXabOrSMk1ruMOV3JBTBjo4ac2lDjGGsbQSyxj8Odhw5fBib8ZKEjDNvgouNKYw==", 1942 | "requires": { 1943 | "async-limiter": "~1.0.0" 1944 | } 1945 | }, 1946 | "yallist": { 1947 | "version": "3.0.3", 1948 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", 1949 | "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" 1950 | }, 1951 | "zen-observable": { 1952 | "version": "0.8.11", 1953 | "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.11.tgz", 1954 | "integrity": "sha512-N3xXQVr4L61rZvGMpWe8XoCGX8vhU35dPyQ4fm5CY/KDlG0F75un14hjbckPXTDuKUY6V0dqR2giT6xN8Y4GEQ==" 1955 | }, 1956 | "zen-observable-ts": { 1957 | "version": "0.8.12", 1958 | "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-0.8.12.tgz", 1959 | "integrity": "sha512-wwqbD6K6CqDd1T67UFg4hgDqnu2YAnFJDCPYmwN/N6Yfa+2QgoSp+nJomh+FWUdOc1A+553/ElvfoW8Vc/vsLg==", 1960 | "requires": { 1961 | "zen-observable": "^0.8.0" 1962 | } 1963 | } 1964 | } 1965 | } 1966 | -------------------------------------------------------------------------------- /advanced/backend-with-auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphql-database-final", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "dependencies": { 7 | "apollo-server": "^2.3.1", 8 | "apollo-server-express": "^2.3.1", 9 | "bcrypt": "^3.0.6", 10 | "cloudinary": "^1.13.2", 11 | "cors": "^2.8.5", 12 | "dotenv": "^6.2.0", 13 | "express": "^4.16.4", 14 | "express-fileupload": "^1.0.0", 15 | "graphql": "^14.0.2", 16 | "jsonwebtoken": "^8.4.0", 17 | "mysql2": "^1.6.4", 18 | "sequelize": "^5.3.0" 19 | }, 20 | "devDependencies": {}, 21 | "scripts": { 22 | "start": "nodemon app.js" 23 | }, 24 | "keywords": [], 25 | "author": "", 26 | "license": "ISC" 27 | } 28 | -------------------------------------------------------------------------------- /advanced/backend-with-auth/resolvers/car.js: -------------------------------------------------------------------------------- 1 | const resolvers = { 2 | Query: { 3 | cars: (parent, args, { models }) => { 4 | // SELECT * FROM cars; 5 | return models.Car.findAll(); 6 | }, 7 | car: (parent, { id }, { models }) => { 8 | // SELECT * FROM cars WHERE id = `id`; 9 | return models.Car.findByPk(id); 10 | } 11 | }, 12 | Mutation: { 13 | createCar: (parent, { make, model, colour }, { models, me }) => { 14 | if (!me) { 15 | throw new Error('Not authenticated'); 16 | } 17 | 18 | const car = { 19 | make, 20 | model, 21 | colour, 22 | userId: me.id 23 | }; 24 | 25 | return models.Car.create(car); 26 | }, 27 | removeCar: (parent, { id }, { models }) => { 28 | return models.Car.destory({ 29 | where: { 30 | id 31 | } 32 | }); 33 | } 34 | }, 35 | Car: { 36 | owner: (parent, args, { models }) => { 37 | console.log(parent); 38 | // SELECT * FROM users WHERE id = `parent.userId`; 39 | return models.User.findByPk(parent.userId); 40 | } 41 | } 42 | }; 43 | 44 | module.exports = resolvers; -------------------------------------------------------------------------------- /advanced/backend-with-auth/resolvers/index.js: -------------------------------------------------------------------------------- 1 | const userResolvers = require('./user'); 2 | const carResolvers = require('./car'); 3 | 4 | module.exports = [userResolvers, carResolvers]; -------------------------------------------------------------------------------- /advanced/backend-with-auth/resolvers/user.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken'); 2 | const cloudinary = require('cloudinary'); 3 | const { GraphQLScalarType } = require('graphql'); 4 | 5 | cloudinary.config({ 6 | cloud_name: process.env.CLOUD_NAME, 7 | api_key: process.env.API_KEY, 8 | api_secret: process.env.API_SECRET 9 | }); 10 | 11 | const createToken = (user, secret, expiresIn) => { 12 | const { id, name, username, photo } = user; 13 | return jwt.sign({ id, name, username, photo }, secret, { expiresIn }); 14 | } 15 | 16 | const resolvers = { 17 | Query: { 18 | users: (parent, args, { models }) => { 19 | return models.User.findAll(); 20 | }, 21 | user: (parent, { id }, { models }) => { 22 | return models.User.findByPk(id); 23 | }, 24 | me: (parent, args, { me }) => me 25 | }, 26 | Mutation: { 27 | removeUser: (parent, { id }, { models }) => { 28 | return models.User.destroy({ 29 | where: { 30 | id 31 | } 32 | }); 33 | }, 34 | register: async (parent, { name, username, password }, { models }) => { 35 | const user = { 36 | name, 37 | username, 38 | password 39 | }; 40 | // INSERT INTO User VALUES (`name`, `username`, `password`) 41 | const registeredUser = await models.User.create(user); 42 | try { 43 | if (typeof registeredUser.id === 'number') { 44 | return true; 45 | } else { 46 | return false; 47 | } 48 | } catch(error) { 49 | throw new Error(error); 50 | } 51 | }, 52 | login: async (parent, { username, password }, { models, secret }) => { 53 | const user = await models.User.findOne({ where: { username }}); 54 | if (!user) { 55 | throw new Error('User not found'); 56 | } 57 | const validPassword = await user.validatePassword(password); 58 | 59 | if (!validPassword) { 60 | throw new Error('Password is incorrect'); 61 | } 62 | 63 | return { 64 | token: createToken(user, secret, '10m') 65 | }; 66 | }, 67 | uploadImage: async (parent, { filename }, { models, me }) => { 68 | if (!me) { 69 | throw new Error('Not authenticated!'); 70 | } 71 | const path = require('path'); 72 | const mainDir = path.dirname(require.main.filename); 73 | filename = `${mainDir}/uploads/${filename}`; 74 | try { 75 | const photo = await cloudinary.v2.uploader.upload(filename); 76 | await models.User.update({ 77 | photo: `${photo.public_id}.${photo.format}` 78 | }, { 79 | where: { username: me.username } 80 | }); 81 | return `${photo.public_id}.${photo.format}`; 82 | } catch(error) { 83 | throw new Error(error); 84 | } 85 | } 86 | }, 87 | User: { 88 | car: (parent, args, { models }) => { 89 | return models.Car.findAll({ 90 | where: { 91 | userId: parent.id 92 | } 93 | }) 94 | }, 95 | photo: (parent, { options }) => { 96 | let url = cloudinary.url(parent.photo); 97 | if (options) { 98 | const [ width, height, face, radius ] = options; 99 | const cloudinaryOptions = { 100 | ...(face && { crop: 'thumb', gravity: 'face' }), 101 | ...(radius && { radius:`${radius}` }), 102 | fetch_format: 'auto', 103 | quality: 'auto', 104 | width, 105 | height, 106 | secure: true 107 | }; 108 | url = cloudinary.url(parent.photo, cloudinaryOptions); 109 | return url; 110 | } 111 | return url; 112 | } 113 | }, 114 | CloudinaryOptions: new GraphQLScalarType({ 115 | name: 'CloudinaryOptions', 116 | parseValue(value) { 117 | return value; 118 | }, 119 | serialize(value) { 120 | return value; 121 | }, 122 | parseLiteral(ast) { 123 | return ast.value.split(','); 124 | } 125 | }) 126 | }; 127 | 128 | module.exports = resolvers; 129 | -------------------------------------------------------------------------------- /advanced/backend-with-auth/typeDefs/car.js: -------------------------------------------------------------------------------- 1 | const { gql } = require('apollo-server-express'); 2 | module.exports = gql` 3 | extend type Query { 4 | cars: [Car] 5 | car(id: Int!): Car 6 | } 7 | 8 | extend type Mutation { 9 | createCar(make: String!, model: String!, colour: String!): Car! 10 | removeCar(id: Int!): Boolean 11 | } 12 | 13 | type Car { 14 | id: ID! 15 | make: String! 16 | model: String! 17 | colour: String! 18 | owner: User! 19 | } 20 | `; -------------------------------------------------------------------------------- /advanced/backend-with-auth/typeDefs/default.js: -------------------------------------------------------------------------------- 1 | const { gql } = require('apollo-server-express'); 2 | module.exports = gql` 3 | type Query { 4 | _: Boolean 5 | } 6 | 7 | type Mutation { 8 | _: Boolean 9 | } 10 | `; -------------------------------------------------------------------------------- /advanced/backend-with-auth/typeDefs/index.js: -------------------------------------------------------------------------------- 1 | const userSchema = require('./user'); 2 | const carSchema = require('./car'); 3 | 4 | const defaultSchema = require('./default'); 5 | 6 | module.exports = [defaultSchema, userSchema, carSchema]; -------------------------------------------------------------------------------- /advanced/backend-with-auth/typeDefs/user.js: -------------------------------------------------------------------------------- 1 | const { gql } = require('apollo-server-express'); 2 | module.exports = gql` 3 | extend type Query { 4 | users: [User] 5 | user(id: Int!): User 6 | me: User 7 | } 8 | 9 | extend type Mutation { 10 | makeUser(name: String!): User! 11 | removeUser(id: Int!): Boolean 12 | register(name: String!, username: String!, password: String!): Boolean! 13 | login(username: String!, password: String!): Token! 14 | uploadImage(filename: String!): String! 15 | } 16 | 17 | type User { 18 | id: ID! 19 | name: String! 20 | username: String! 21 | photo(options: CloudinaryOptions): String 22 | car: [Car] 23 | } 24 | 25 | type Token { 26 | token: String! 27 | } 28 | 29 | scalar CloudinaryOptions 30 | `; -------------------------------------------------------------------------------- /advanced/frontend-with-auth/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /advanced/frontend-with-auth/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "recording", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@emotion/styled": "^10.0.11", 7 | "apollo-boost": "^0.1.28", 8 | "apollo-cache-inmemory": "^1.5.1", 9 | "apollo-client": "^2.5.1", 10 | "apollo-link": "^1.2.11", 11 | "apollo-link-error": "^1.1.10", 12 | "apollo-link-http": "^1.5.14", 13 | "bcrypt": "^3.0.6", 14 | "graphql": "^14.3.0", 15 | "react": "^16.8.6", 16 | "react-apollo": "^2.5.5", 17 | "react-dom": "^16.8.6", 18 | "react-router-dom": "^4.3.1", 19 | "react-scripts": "2.1.2" 20 | }, 21 | "scripts": { 22 | "start": "react-scripts start", 23 | "build": "react-scripts build", 24 | "test": "react-scripts test", 25 | "eject": "react-scripts eject" 26 | }, 27 | "eslintConfig": { 28 | "extends": "react-app" 29 | }, 30 | "browserslist": [ 31 | ">0.2%", 32 | "not dead", 33 | "not ie <= 11", 34 | "not op_mini all" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /advanced/frontend-with-auth/photos/man.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fullstacktraining/oreilly-react-graphql/9748e24f9b9261812d4035de32ab9fd39264460c/advanced/frontend-with-auth/photos/man.jpg -------------------------------------------------------------------------------- /advanced/frontend-with-auth/photos/woman.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fullstacktraining/oreilly-react-graphql/9748e24f9b9261812d4035de32ab9fd39264460c/advanced/frontend-with-auth/photos/woman.jpg -------------------------------------------------------------------------------- /advanced/frontend-with-auth/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fullstacktraining/oreilly-react-graphql/9748e24f9b9261812d4035de32ab9fd39264460c/advanced/frontend-with-auth/public/favicon.ico -------------------------------------------------------------------------------- /advanced/frontend-with-auth/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 15 | 16 | 25 | React App 26 | 27 | 28 | 29 |
30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /advanced/frontend-with-auth/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/ActiveSession.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Query } from 'react-apollo'; 3 | import gql from 'graphql-tag'; 4 | 5 | const query = gql` 6 | { 7 | me { 8 | id 9 | name 10 | username 11 | photo(options:"350,350,face,50") 12 | car { 13 | id 14 | make 15 | model 16 | } 17 | } 18 | } 19 | `; 20 | 21 | const activeSession = Component => props => ( 22 | 23 | {({ data, refetch }) => ( 24 | 25 | )} 26 | 27 | ); 28 | 29 | export default activeSession; -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | min-height: 100vh; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: calc(10px + 2vmin); 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { BrowserRouter as Router, Route, Redirect } from 'react-router-dom'; 3 | import './App.css'; 4 | import Navigation from './Navigation'; 5 | import LoginPage from './Login'; 6 | import RegisterPage from './Register'; 7 | import ProfilePage from './Profile'; 8 | import activeSession from './ActiveSession'; 9 | import LogoutPage from './Logout'; 10 | import HiddenPage from './Hidden'; 11 | import MainPage from './pages/main-page'; 12 | 13 | class App extends Component { 14 | render() { 15 | return ( 16 | 17 | 18 | 19 |
20 | 21 | this.props.session && this.props.session.me ? : } /> 22 | 23 | this.props.session && this.props.session.me === null ? : } /> 24 | this.props.session && this.props.session.me === null ? : } /> 25 | this.props.session && this.props.session.me === null ? : } /> 26 |
27 |
28 | ); 29 | } 30 | } 31 | 32 | export default activeSession(App); 33 | // export default App; 34 | -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/Error.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | class Error extends Component { 4 | render() { 5 | return ( 6 |
7 |

Error occured: { this.props.message }

8 |
9 | ); 10 | } 11 | } 12 | 13 | export default Error; -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/Hidden.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import activeSession from './ActiveSession'; 3 | 4 | 5 | const HiddenPage = ({ session }) => ( 6 |
7 | { session && session.me && } 8 |
9 | ); 10 | 11 | class Hidden extends Component { 12 | render() { 13 | return ( 14 |
15 |

Hidden page :)

16 |
17 | ); 18 | } 19 | } 20 | 21 | export default activeSession(HiddenPage); -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/Login.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Mutation } from 'react-apollo'; 3 | import gql from 'graphql-tag'; 4 | import { withRouter } from 'react-router-dom'; 5 | 6 | const LOGIN_USER = gql` 7 | mutation login($username: String!, $password: String!) { 8 | login(username: $username, password: $password) { 9 | token 10 | } 11 | } 12 | `; 13 | 14 | const LoginPage = ({ history, refetch }) => ( 15 |
16 |

Login

17 | 18 |
19 | ) 20 | 21 | class LoginForm extends Component { 22 | state = { 23 | username: '', 24 | password: '' 25 | }; 26 | 27 | usernameChanged = ({ target: { value }}) => { 28 | this.setState({ username: value }); 29 | } 30 | passwordChanged = ({ target: { value }}) => { 31 | this.setState({ password: value }); 32 | } 33 | 34 | submitForm = (event, login) => { 35 | event.preventDefault(); 36 | login({ 37 | variables: { 38 | username: this.state.username, 39 | password: this.state.password 40 | } 41 | }).then(async ({ data }) => { 42 | localStorage.setItem('token', data.login.token); 43 | await this.props.refetch(); 44 | this.props.history.push('/profile'); 45 | }).catch(error => console.error(error)); 46 | }; 47 | 48 | render() { 49 | const validForm = 50 | this.state.username !== '' && 51 | this.state.password !== ''; 52 | return ( 53 | 54 | {( login, { loading, error }) => ( 55 |
this.submitForm(evt, login)}> 56 | 65 | 74 |
75 | 76 |
77 |
78 | )} 79 |
80 | ) 81 | } 82 | } 83 | export default withRouter(LoginPage); -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/Logout.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { ApolloConsumer } from 'react-apollo'; 3 | import { withRouter } from 'react-router-dom'; 4 | 5 | const LogoutPage = ({ history }) => ( 6 |
7 | 8 |
9 | ); 10 | 11 | class LogoutButton extends Component { 12 | logout = async (client) => { 13 | localStorage.removeItem('token'); 14 | await client.resetStore(); 15 | this.props.history.push('/login'); 16 | } 17 | 18 | render() { 19 | return ( 20 | 21 | {client => ( 22 | 23 | )} 24 | 25 | ); 26 | } 27 | } 28 | 29 | export default withRouter(LogoutPage); 30 | export { LogoutButton }; -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/Navigation.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | import { LogoutButton } from './Logout'; 4 | 5 | const NavigationNoAuth = () => ( 6 | 10 | ); 11 | 12 | const NavigationWithAuth = () => ( 13 | 18 | ); 19 | 20 | const Navigation = ({ session }) => ( 21 |
22 | { session && session.me ? : } 23 |
24 | ); 25 | 26 | export default Navigation; -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/Profile.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import activeSession from './ActiveSession'; 3 | import gql from 'graphql-tag'; 4 | import { client } from './index'; 5 | import { Query } from 'react-apollo'; 6 | 7 | const UPLOAD_FILE = gql` 8 | mutation($filename: String!) { 9 | uploadImage(filename: $filename) 10 | } 11 | `; 12 | 13 | const ProfilePage = ({ session }) => ( 14 |
15 | { session && session.me && } 16 |
17 | ); 18 | 19 | class Profile extends Component { 20 | state = { 21 | selectedFile: null, 22 | photoUrl: this.props.session.me.photo ? this.props.session.me.photo : null, 23 | temporaryProfileHolder: null 24 | }; 25 | 26 | USER_QUERY = gql`{ 27 | user(id: ${this.props.session.me.id}) { 28 | photo(options:"350,350,face,50") 29 | } 30 | }` 31 | 32 | handleSelectedFile = event => { 33 | this.setState({ 34 | selectedFile: event.target.files[0], 35 | temporaryProfileHolder: null 36 | }); 37 | } 38 | 39 | handleUpload = () => { 40 | const data = new FormData(); 41 | data.append('file', this.state.selectedFile, this.state.selectedFile.name); 42 | 43 | fetch('http://localhost:3000/upload', { 44 | method: 'POST', 45 | mode: 'cors', 46 | body: data 47 | }) 48 | .then(response => response.json()) 49 | .then(async filename => { 50 | await client.mutate({ 51 | variables: { filename }, 52 | mutation: UPLOAD_FILE 53 | }); 54 | const { data } = await client.query({ 55 | query: this.query, 56 | fetchPolicy: 'no-cache' 57 | }); 58 | this.setState({ 59 | temporaryProfileHolder: data.user.photo 60 | }); 61 | }) 62 | .catch(error => console.error(error)); 63 | } 64 | 65 | render() { 66 | return ( 67 |
68 |

Hello again, {this.props.session.me.name}!

69 | 70 | {({ loading, error, data }) => { 71 | if (loading) return

Loading profile photo ...

72 | if (error) return

Error ...

73 | if (data.user.photo) { 74 | return 75 | } else if (this.state.temporaryProfileHolder) { 76 | return 77 | } else { 78 | return 79 | } 80 | }} 81 |
82 |

Upload a profile photo:

83 | 84 |

List of cars:

85 | 89 |
90 | ); 91 | } 92 | } 93 | 94 | export default activeSession(ProfilePage); -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/Register.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Mutation } from 'react-apollo'; 3 | import gql from 'graphql-tag'; 4 | 5 | const REGISTER_USER = gql` 6 | mutation register($name: String!, $username: String!, $password: String!) { 7 | register(name: $name, username: $username, password: $password) 8 | } 9 | `; 10 | 11 | const RegisterPage = () => ( 12 |
13 |

Register

14 | 15 |
16 | ); 17 | 18 | class RegisterForm extends Component { 19 | state = { 20 | name: '', 21 | username: '', 22 | password: '', 23 | success: false 24 | }; 25 | 26 | nameChanged = ({ target: { value }}) => { 27 | this.setState({ name: value }); 28 | } 29 | usernameChanged = ({ target: { value }}) => { 30 | this.setState({ username: value }); 31 | } 32 | passwordChanged = ({ target: { value }}) => { 33 | this.setState({ password: value }); 34 | } 35 | resetFields = () => { 36 | this.setState({ name: '' }); 37 | this.setState({ username: '' }); 38 | this.setState({ password: '' }); 39 | this.setState({ success: false }); 40 | } 41 | 42 | render() { 43 | const validForm = 44 | this.state.name !== '' && 45 | this.state.username !== '' && 46 | this.state.password !== ''; 47 | 48 | return ( 49 | 50 | {( register, { loading, error }) => ( 51 |
{ 53 | evt.preventDefault(); 54 | register({ 55 | variables: { 56 | name: this.state.name, 57 | username: this.state.username, 58 | password: this.state.password 59 | } 60 | }).then(({ data }) => { 61 | this.setState({ 62 | success: data.register 63 | }); 64 | }).catch(error => console.error(error)); 65 | this.resetFields(); 66 | }} 67 | > 68 | 76 | 84 | 92 |
93 | 94 |
95 | { loading &&

Adding user...

} 96 | { error &&

Error, did not register user.

} 97 | { this.state.success &&

Registration successful.

} 98 |
99 | )} 100 |
101 | ); 102 | } 103 | } 104 | 105 | export default RegisterPage; -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/components/container.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import styled from '@emotion/styled' 3 | 4 | export default function PageContainer(props) { 5 | return ( 6 | 7 | {props.children} 8 | 9 | ); 10 | }; 11 | 12 | const Container = styled('div')({ 13 | display: 'flex', 14 | flexDirection: 'column', 15 | flexGrow: 1, 16 | width: '100%', 17 | maxWidth: 600, 18 | margin: '0 auto', 19 | padding: 30, 20 | paddingBottom: 50, 21 | }); -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as PageContainer } from './container'; -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | import Error from './Error'; 5 | import * as serviceWorker from './serviceWorker'; 6 | import ApolloClient from 'apollo-boost'; 7 | import { ApolloProvider, Query } from 'react-apollo'; 8 | import { InMemoryCache } from 'apollo-cache-inmemory' 9 | import gql from 'graphql-tag'; 10 | 11 | const cache = new InMemoryCache(); 12 | export const client = new ApolloClient({ 13 | uri: 'http://localhost:3000/graphql', 14 | onError: (({ operation, graphQLErrors, networkError }) => { 15 | console.log('Errors ===> ', graphQLErrors); 16 | console.log('Network error', networkError); 17 | const { cache } = operation.getContext(); 18 | if (graphQLErrors) { 19 | graphQLErrors.map(({ message, locations, path }) => { 20 | cache.writeData({ 21 | data: { 22 | error: message, 23 | }, 24 | }); 25 | console.log('error message', message); 26 | if (message === 'Unauthorized' || message === 'Context creation failed: Session expired') { 27 | localStorage.removeItem('token'); 28 | } 29 | return message; 30 | }); 31 | } 32 | }), 33 | cache, 34 | request: async operation => { 35 | const token = await localStorage.getItem('token'); 36 | if (token) { 37 | operation.setContext({ 38 | headers: { 39 | 'x-auth-token': token 40 | } 41 | }); 42 | } else { 43 | operation.setContext(); 44 | } 45 | } 46 | }); 47 | 48 | cache.writeData({ 49 | data: { 50 | error: '' 51 | } 52 | }); 53 | 54 | const ERROR_QUERY = gql` 55 | query error { 56 | error @client 57 | } 58 | `; 59 | 60 | ReactDOM.render( 61 | 62 | 63 | {({ data }) => { 64 | // console.log(data); 65 | return (data && data.error) ? 66 | 67 | 68 | 69 | : 70 | ; 71 | }} 72 | 73 | 74 | , document.getElementById('root')); 75 | 76 | // If you want your app to work offline and load faster, you can change 77 | // unregister() to register() below. Note this comes with some pitfalls. 78 | // Learn more about service workers: http://bit.ly/CRA-PWA 79 | serviceWorker.unregister(); 80 | -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/pages/main-page.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | export default function MainPage() { 3 | return ( 4 |

Welcome to this app! :)

5 | ) 6 | }; -------------------------------------------------------------------------------- /advanced/frontend-with-auth/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read http://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit http://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /basic/api/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const bodyParser = require('body-parser'); 4 | const cors = require('cors'); 5 | const cars = require('./cars'); 6 | const REST_PORT = 3000; 7 | 8 | app.use(bodyParser.json()); 9 | app.use(cors()); 10 | 11 | app.get('/api/cars', async (_, res) => { 12 | res.status(200).json(cars); 13 | }); 14 | app.get('/api/cars/:id', async (req, res) => { 15 | const id = +req.params.id; 16 | const car = cars.filter(car => car.id === id); 17 | return res.status(200).json(car); 18 | }); 19 | 20 | app.listen(REST_PORT, () => console.info(`Server is listening on ${REST_PORT} 🎉`)); 21 | -------------------------------------------------------------------------------- /basic/api/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.7", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 10 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 11 | "requires": { 12 | "mime-types": "~2.1.24", 13 | "negotiator": "0.6.2" 14 | } 15 | }, 16 | "array-flatten": { 17 | "version": "1.1.1", 18 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 19 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 20 | }, 21 | "body-parser": { 22 | "version": "1.19.0", 23 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", 24 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", 25 | "requires": { 26 | "bytes": "3.1.0", 27 | "content-type": "~1.0.4", 28 | "debug": "2.6.9", 29 | "depd": "~1.1.2", 30 | "http-errors": "1.7.2", 31 | "iconv-lite": "0.4.24", 32 | "on-finished": "~2.3.0", 33 | "qs": "6.7.0", 34 | "raw-body": "2.4.0", 35 | "type-is": "~1.6.17" 36 | } 37 | }, 38 | "bytes": { 39 | "version": "3.1.0", 40 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", 41 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" 42 | }, 43 | "content-disposition": { 44 | "version": "0.5.3", 45 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", 46 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", 47 | "requires": { 48 | "safe-buffer": "5.1.2" 49 | } 50 | }, 51 | "content-type": { 52 | "version": "1.0.4", 53 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 54 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 55 | }, 56 | "cookie": { 57 | "version": "0.4.0", 58 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", 59 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 60 | }, 61 | "cookie-signature": { 62 | "version": "1.0.6", 63 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 64 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 65 | }, 66 | "cors": { 67 | "version": "2.8.5", 68 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", 69 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", 70 | "requires": { 71 | "object-assign": "^4", 72 | "vary": "^1" 73 | } 74 | }, 75 | "debug": { 76 | "version": "2.6.9", 77 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 78 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 79 | "requires": { 80 | "ms": "2.0.0" 81 | } 82 | }, 83 | "depd": { 84 | "version": "1.1.2", 85 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 86 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 87 | }, 88 | "destroy": { 89 | "version": "1.0.4", 90 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 91 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 92 | }, 93 | "ee-first": { 94 | "version": "1.1.1", 95 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 96 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 97 | }, 98 | "encodeurl": { 99 | "version": "1.0.2", 100 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 101 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 102 | }, 103 | "escape-html": { 104 | "version": "1.0.3", 105 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 106 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 107 | }, 108 | "etag": { 109 | "version": "1.8.1", 110 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 111 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 112 | }, 113 | "express": { 114 | "version": "4.17.1", 115 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", 116 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", 117 | "requires": { 118 | "accepts": "~1.3.7", 119 | "array-flatten": "1.1.1", 120 | "body-parser": "1.19.0", 121 | "content-disposition": "0.5.3", 122 | "content-type": "~1.0.4", 123 | "cookie": "0.4.0", 124 | "cookie-signature": "1.0.6", 125 | "debug": "2.6.9", 126 | "depd": "~1.1.2", 127 | "encodeurl": "~1.0.2", 128 | "escape-html": "~1.0.3", 129 | "etag": "~1.8.1", 130 | "finalhandler": "~1.1.2", 131 | "fresh": "0.5.2", 132 | "merge-descriptors": "1.0.1", 133 | "methods": "~1.1.2", 134 | "on-finished": "~2.3.0", 135 | "parseurl": "~1.3.3", 136 | "path-to-regexp": "0.1.7", 137 | "proxy-addr": "~2.0.5", 138 | "qs": "6.7.0", 139 | "range-parser": "~1.2.1", 140 | "safe-buffer": "5.1.2", 141 | "send": "0.17.1", 142 | "serve-static": "1.14.1", 143 | "setprototypeof": "1.1.1", 144 | "statuses": "~1.5.0", 145 | "type-is": "~1.6.18", 146 | "utils-merge": "1.0.1", 147 | "vary": "~1.1.2" 148 | } 149 | }, 150 | "finalhandler": { 151 | "version": "1.1.2", 152 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", 153 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", 154 | "requires": { 155 | "debug": "2.6.9", 156 | "encodeurl": "~1.0.2", 157 | "escape-html": "~1.0.3", 158 | "on-finished": "~2.3.0", 159 | "parseurl": "~1.3.3", 160 | "statuses": "~1.5.0", 161 | "unpipe": "~1.0.0" 162 | } 163 | }, 164 | "forwarded": { 165 | "version": "0.1.2", 166 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 167 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 168 | }, 169 | "fresh": { 170 | "version": "0.5.2", 171 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 172 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 173 | }, 174 | "http-errors": { 175 | "version": "1.7.2", 176 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", 177 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", 178 | "requires": { 179 | "depd": "~1.1.2", 180 | "inherits": "2.0.3", 181 | "setprototypeof": "1.1.1", 182 | "statuses": ">= 1.5.0 < 2", 183 | "toidentifier": "1.0.0" 184 | } 185 | }, 186 | "iconv-lite": { 187 | "version": "0.4.24", 188 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 189 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 190 | "requires": { 191 | "safer-buffer": ">= 2.1.2 < 3" 192 | } 193 | }, 194 | "inherits": { 195 | "version": "2.0.3", 196 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 197 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 198 | }, 199 | "ipaddr.js": { 200 | "version": "1.9.0", 201 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", 202 | "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" 203 | }, 204 | "media-typer": { 205 | "version": "0.3.0", 206 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 207 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 208 | }, 209 | "merge-descriptors": { 210 | "version": "1.0.1", 211 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 212 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 213 | }, 214 | "methods": { 215 | "version": "1.1.2", 216 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 217 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 218 | }, 219 | "mime": { 220 | "version": "1.6.0", 221 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 222 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" 223 | }, 224 | "mime-db": { 225 | "version": "1.40.0", 226 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", 227 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" 228 | }, 229 | "mime-types": { 230 | "version": "2.1.24", 231 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", 232 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", 233 | "requires": { 234 | "mime-db": "1.40.0" 235 | } 236 | }, 237 | "ms": { 238 | "version": "2.0.0", 239 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 240 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 241 | }, 242 | "negotiator": { 243 | "version": "0.6.2", 244 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 245 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 246 | }, 247 | "object-assign": { 248 | "version": "4.1.1", 249 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 250 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" 251 | }, 252 | "on-finished": { 253 | "version": "2.3.0", 254 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 255 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 256 | "requires": { 257 | "ee-first": "1.1.1" 258 | } 259 | }, 260 | "parseurl": { 261 | "version": "1.3.3", 262 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 263 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 264 | }, 265 | "path-to-regexp": { 266 | "version": "0.1.7", 267 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 268 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 269 | }, 270 | "proxy-addr": { 271 | "version": "2.0.5", 272 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", 273 | "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", 274 | "requires": { 275 | "forwarded": "~0.1.2", 276 | "ipaddr.js": "1.9.0" 277 | } 278 | }, 279 | "qs": { 280 | "version": "6.7.0", 281 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", 282 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" 283 | }, 284 | "range-parser": { 285 | "version": "1.2.1", 286 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 287 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 288 | }, 289 | "raw-body": { 290 | "version": "2.4.0", 291 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", 292 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", 293 | "requires": { 294 | "bytes": "3.1.0", 295 | "http-errors": "1.7.2", 296 | "iconv-lite": "0.4.24", 297 | "unpipe": "1.0.0" 298 | } 299 | }, 300 | "safe-buffer": { 301 | "version": "5.1.2", 302 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 303 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 304 | }, 305 | "safer-buffer": { 306 | "version": "2.1.2", 307 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 308 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 309 | }, 310 | "send": { 311 | "version": "0.17.1", 312 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", 313 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", 314 | "requires": { 315 | "debug": "2.6.9", 316 | "depd": "~1.1.2", 317 | "destroy": "~1.0.4", 318 | "encodeurl": "~1.0.2", 319 | "escape-html": "~1.0.3", 320 | "etag": "~1.8.1", 321 | "fresh": "0.5.2", 322 | "http-errors": "~1.7.2", 323 | "mime": "1.6.0", 324 | "ms": "2.1.1", 325 | "on-finished": "~2.3.0", 326 | "range-parser": "~1.2.1", 327 | "statuses": "~1.5.0" 328 | }, 329 | "dependencies": { 330 | "ms": { 331 | "version": "2.1.1", 332 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 333 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 334 | } 335 | } 336 | }, 337 | "serve-static": { 338 | "version": "1.14.1", 339 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", 340 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", 341 | "requires": { 342 | "encodeurl": "~1.0.2", 343 | "escape-html": "~1.0.3", 344 | "parseurl": "~1.3.3", 345 | "send": "0.17.1" 346 | } 347 | }, 348 | "setprototypeof": { 349 | "version": "1.1.1", 350 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", 351 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" 352 | }, 353 | "statuses": { 354 | "version": "1.5.0", 355 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 356 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 357 | }, 358 | "toidentifier": { 359 | "version": "1.0.0", 360 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", 361 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" 362 | }, 363 | "type-is": { 364 | "version": "1.6.18", 365 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 366 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 367 | "requires": { 368 | "media-typer": "0.3.0", 369 | "mime-types": "~2.1.24" 370 | } 371 | }, 372 | "unpipe": { 373 | "version": "1.0.0", 374 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 375 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 376 | }, 377 | "utils-merge": { 378 | "version": "1.0.1", 379 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 380 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 381 | }, 382 | "vary": { 383 | "version": "1.1.2", 384 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 385 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 386 | } 387 | } 388 | } 389 | -------------------------------------------------------------------------------- /basic/api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "body-parser": "^1.19.0", 14 | "cors": "^2.8.5", 15 | "express": "^4.17.1" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /basic/backend/api/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | const bodyParser = require('body-parser'); 4 | const cors = require('cors'); 5 | const cars = require('./cars'); 6 | const REST_PORT = 3000; 7 | 8 | app.use(bodyParser.json()); 9 | app.use(cors()); 10 | 11 | app.get('/api/cars', async (_, res) => { 12 | res.status(200).json(cars); 13 | }); 14 | app.get('/api/cars/:id', async (req, res) => { 15 | const id = +req.params.id; 16 | const car = cars.filter(car => car.id === id); 17 | return res.status(200).json(car); 18 | }); 19 | 20 | app.listen(REST_PORT, () => console.info(`Server is listening on ${REST_PORT} 🎉`)); -------------------------------------------------------------------------------- /basic/backend/car-rest-consumer.js: -------------------------------------------------------------------------------- 1 | const { RESTDataSource } = require('apollo-datasource-rest'); 2 | 3 | class CarAPI extends RESTDataSource { 4 | constructor() { 5 | super(); 6 | this.baseURL = 'http://localhost:3000/api'; 7 | // this.baseURL = 'https://api-gzwsfutmow.now.sh/api'; 8 | } 9 | 10 | async getCars() { 11 | // HTTP GET http://localhost:3000/api/cars 12 | const response = await this.get('cars'); 13 | return Array.isArray(response) ? response.map(car => this.carReducer(car)) : []; 14 | } 15 | 16 | async getCar({ id }) { 17 | const response = await this.get(`cars/${id}`); 18 | return this.carReducer(response[0]); 19 | } 20 | 21 | carReducer(car) { 22 | return { 23 | id: car.id || 0, 24 | cursor: `${car.id}`, 25 | make: car.make, 26 | model: car.model, 27 | year: car.year || 0, 28 | colour: car.colour, 29 | speed: car.max_speed || 0 30 | } 31 | } 32 | } 33 | 34 | module.exports = CarAPI; -------------------------------------------------------------------------------- /basic/backend/index.js: -------------------------------------------------------------------------------- 1 | const { ApolloServer } = require('apollo-server'); 2 | const typeDefs = require('./schema'); 3 | const CarAPI = require('./car-rest-consumer'); 4 | const resolvers = require('./resolvers'); 5 | 6 | const dataSources = () => ({ 7 | carAPI: new CarAPI(), 8 | }); 9 | 10 | const server = new ApolloServer({ 11 | typeDefs, 12 | resolvers, 13 | dataSources 14 | }); 15 | 16 | server.listen().then(({ url }) => { 17 | console.info(`Server is listening on ${url} 🎉`); 18 | }); -------------------------------------------------------------------------------- /basic/backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "apollo-datasource-rest": "^0.4.0", 14 | "apollo-server": "^2.5.0", 15 | "bcrypt": "^3.0.6", 16 | "body-parser": "^1.19.0", 17 | "cors": "^2.8.5", 18 | "dotenv": "^8.0.0", 19 | "express": "^4.16.4", 20 | "graphql": "^14.3.0", 21 | "jsonwebtoken": "^8.5.1", 22 | "knex": "^0.16.5", 23 | "lokijs": "^1.5.6", 24 | "mysql": "^2.17.1", 25 | "mysql2": "^1.6.5", 26 | "sequelize": "^5.8.6" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /basic/backend/resolvers.js: -------------------------------------------------------------------------------- 1 | const { paginateResults } = require('./utils'); 2 | 3 | module.exports = { 4 | Query: { 5 | cars: async (_, { pageSize = 10, after }, { dataSources }) => { 6 | const allCars = await dataSources.carAPI.getCars(); 7 | 8 | const cars = paginateResults({ 9 | after, 10 | pageSize, 11 | results: allCars 12 | }); 13 | 14 | return { 15 | cars, 16 | cursor: cars.length ? cars[cars.length - 1].cursor : null, 17 | hasMore: cars.length ? cars[cars.length - 1].cursor !== allCars[allCars.length - 1].cursor : false 18 | } 19 | }, 20 | car: (_, { id }, { dataSources }) => dataSources.carAPI.getCar({ id }) 21 | } 22 | }; 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | // cars: (_, __, { dataSources }) => dataSources.carAPI.getCars(), 42 | // cars: (_, __, { dataSources }) => dataSources.carAPI.getCars(), 43 | // cars: async (_, { pageSize = 500, after }, { dataSources }) => { 44 | // const allCars = await dataSources.carAPI.getCars(); 45 | 46 | // const cars = paginateResults({ 47 | // after, 48 | // pageSize, 49 | // results: allCars 50 | // }); 51 | 52 | // return { 53 | // cars, 54 | // cursor: cars.length ? cars[cars.length - 1].cursor : null, 55 | // hasMore: cars.length ? cars[cars.length - 1].cursor !== allCars[allCars.length - 1].cursor : false 56 | // } 57 | // }, -------------------------------------------------------------------------------- /basic/backend/schema.js: -------------------------------------------------------------------------------- 1 | const { gql } = require('apollo-server'); 2 | 3 | const typeDefs = gql` 4 | type Query { 5 | cars(pageSize: Int, after: String): CarConnection! 6 | car(id: ID!): Car 7 | } 8 | 9 | type CarConnection { 10 | cursor: String! 11 | hasMore: Boolean! 12 | cars: [Car]! 13 | } 14 | 15 | type Car { 16 | id: ID! 17 | make: String 18 | model: String 19 | year: Int 20 | colour: String 21 | speed: Int 22 | } 23 | ` 24 | 25 | module.exports = typeDefs; 26 | 27 | 28 | // cars: [Car] 29 | 30 | 31 | // type CarConnection { 32 | // cursor: String! 33 | // hasMore: Boolean! 34 | // cars: [Car]! 35 | // } 36 | 37 | 38 | 39 | // cars(pageSize: Int, after: String): CarConnection! 40 | //cars(pageSize: Int, after: String): CarConnection! -------------------------------------------------------------------------------- /basic/backend/utils.js: -------------------------------------------------------------------------------- 1 | module.exports.paginateResults = ({ 2 | after: cursor, 3 | pageSize = 20, 4 | results, 5 | getCursor = () => null, 6 | }) => { 7 | if (pageSize < 1) return []; 8 | 9 | if (!cursor) return results.slice(0, pageSize); 10 | const cursorIndex = results.findIndex(item => { 11 | let itemCursor = item.cursor ? item.cursor : getCursor(item); 12 | return itemCursor ? cursor === itemCursor : false; 13 | }); 14 | 15 | return cursorIndex >= 0 16 | ? cursorIndex === results.length - 1 17 | ? [] 18 | : results.slice( 19 | cursorIndex + 1, 20 | Math.min(results.length, cursorIndex + 1 + pageSize), 21 | ) 22 | : results.slice(0, pageSize); 23 | }; -------------------------------------------------------------------------------- /basic/frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /basic/frontend/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /basic/frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@emotion/core": "^10.0.10", 7 | "@emotion/styled": "^10.0.11", 8 | "@reach/router": "^1.2.1", 9 | "apollo-boost": "^0.3.1", 10 | "apollo-cache-inmemory": "^1.5.1", 11 | "apollo-client": "^2.5.1", 12 | "apollo-link": "^1.2.11", 13 | "apollo-link-error": "^1.1.10", 14 | "apollo-link-http": "^1.5.14", 15 | "apollo-link-state": "^0.4.2", 16 | "graphql": "^14.3.0", 17 | "graphql-tag": "^2.10.1", 18 | "react": "^16.8.6", 19 | "react-apollo": "^2.5.5", 20 | "react-dom": "^16.8.6", 21 | "react-scripts": "3.0.1" 22 | }, 23 | "scripts": { 24 | "start": "react-scripts start", 25 | "build": "react-scripts build", 26 | "test": "react-scripts test", 27 | "eject": "react-scripts eject" 28 | }, 29 | "eslintConfig": { 30 | "extends": "react-app" 31 | }, 32 | "browserslist": { 33 | "production": [ 34 | ">0.2%", 35 | "not dead", 36 | "not op_mini all" 37 | ], 38 | "development": [ 39 | "last 1 chrome version", 40 | "last 1 firefox version", 41 | "last 1 safari version" 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /basic/frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fullstacktraining/oreilly-react-graphql/9748e24f9b9261812d4035de32ab9fd39264460c/basic/frontend/public/favicon.ico -------------------------------------------------------------------------------- /basic/frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 26 |
27 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /basic/frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /basic/frontend/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | pointer-events: none; 9 | } 10 | 11 | .App-header { 12 | background-color: #282c34; 13 | min-height: 100vh; 14 | display: flex; 15 | flex-direction: column; 16 | align-items: center; 17 | justify-content: center; 18 | font-size: calc(10px + 2vmin); 19 | color: white; 20 | } 21 | 22 | .App-link { 23 | color: #61dafb; 24 | } 25 | 26 | @keyframes App-logo-spin { 27 | from { 28 | transform: rotate(0deg); 29 | } 30 | to { 31 | transform: rotate(360deg); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /basic/frontend/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | 5 | function App() { 6 | return ( 7 |
8 |
9 | logo 10 |

11 | Edit src/App.js and save to reload. 12 |

13 | 19 | Learn React 20 | 21 |
22 |
23 | ); 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /basic/frontend/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /basic/frontend/src/components/container.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import styled from '@emotion/styled' 3 | 4 | export default function PageContainer(props) { 5 | return ( 6 | 7 | {props.children} 8 | 9 | ); 10 | }; 11 | 12 | const Container = styled('div')({ 13 | display: 'flex', 14 | flexDirection: 'column', 15 | flexGrow: 1, 16 | width: '100%', 17 | maxWidth: 600, 18 | margin: '0 auto', 19 | padding: 30, 20 | paddingBottom: 50, 21 | }); -------------------------------------------------------------------------------- /basic/frontend/src/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as PageContainer } from './container'; -------------------------------------------------------------------------------- /basic/frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import Pages from './pages'; 4 | import * as serviceWorker from './serviceWorker'; 5 | 6 | import { ApolloClient } from 'apollo-client'; 7 | import { InMemoryCache } from 'apollo-cache-inmemory'; 8 | import { HttpLink } from 'apollo-link-http'; 9 | import { ApolloProvider } from 'react-apollo'; 10 | 11 | const cache = new InMemoryCache(); 12 | const httpLink = new HttpLink({ 13 | uri: 'http://localhost:4000/graphql' 14 | }); 15 | 16 | const client = new ApolloClient({ 17 | cache, 18 | link: httpLink 19 | }); 20 | 21 | ReactDOM.render( 22 | 23 | 24 | , 25 | document.getElementById('root'), 26 | ); 27 | 28 | // If you want your app to work offline and load faster, you can change 29 | // unregister() to register() below. Note this comes with some pitfalls. 30 | // Learn more about service workers: https://bit.ly/CRA-PWA 31 | serviceWorker.unregister(); 32 | -------------------------------------------------------------------------------- /basic/frontend/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /basic/frontend/src/pages/car.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import { Query } from 'react-apollo'; 3 | import gql from 'graphql-tag'; 4 | 5 | export const CAR_DETAIL = gql` 6 | query CarDetail($carId: ID!) { 7 | car(id: $carId) { 8 | make 9 | model 10 | colour 11 | year 12 | speed 13 | } 14 | } 15 | `; 16 | 17 | export default function Car({ carId }) { 18 | return ( 19 | 20 | {({ data, loading, error }) => { 21 | if (loading) return

Loading ...

; 22 | if (error) return

Error ...

; 23 | return ( 24 | 25 |

{ data.car.make } - { data.car.model } 🚗

26 |

Year of production: { data.car.year }

27 |

Maximum speed: { data.car.speed }

28 |

Colour: { data.car.colour }

29 | Go back 30 |
31 | ); 32 | }} 33 |
34 | ); 35 | } -------------------------------------------------------------------------------- /basic/frontend/src/pages/cars.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import { Query } from 'react-apollo'; 3 | import gql from 'graphql-tag'; 4 | import { Link } from '@reach/router'; 5 | 6 | // export const GET_CARS = gql` 7 | // { 8 | // cars { 9 | // id 10 | // make 11 | // model 12 | // } 13 | // } 14 | // ` 15 | 16 | export const GET_CARS = gql` 17 | query GetCars($after: String) { 18 | cars(after: $after) { 19 | cursor 20 | hasMore 21 | cars { 22 | id 23 | make 24 | model 25 | } 26 | } 27 | } 28 | `; 29 | 30 | 31 | export default function Cars() { 32 | return ( 33 | 34 | {({ data, loading, error, fetchMore }) => { 35 | if (loading) return

Loading ...

; 36 | if (error) return

ERROR

; 37 | return ( 38 | 39 |

A list of cars 🚗

40 | {data.cars && 41 | data.cars.cars && 42 | data.cars.cars.map(car => ( 43 |

{ car.make } - { car.model } >> View more

44 | ))} 45 | {data.cars && 46 | data.cars.hasMore && ( 47 | 71 | )} 72 |
73 | ); 74 | }} 75 |
76 | ); 77 | } 78 | 79 | // export default function Cars() { 80 | // return ( 81 | // 82 | // {({ data, loading, error, fetchMore }) => { 83 | // if (loading) return

Loading ...

; 84 | // if (error) return

ERROR

; 85 | // return ( 86 | // 87 | //

A list of cars 🚗

88 | // {data.cars && data.cars.map(car => ( 89 | //

{ car.make } - { car.model } >> View more

90 | // ))} 91 | //
92 | // ) 93 | // }} 94 | //
95 | // ) 96 | // } 97 | 98 | // export const GET_CARS = gql` 99 | // query GetCars($after: String) { 100 | // cars(after: $after) { 101 | // cursor 102 | // hasMore 103 | // cars { 104 | // id 105 | // make 106 | // model 107 | // } 108 | // } 109 | // } 110 | // `; -------------------------------------------------------------------------------- /basic/frontend/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import { Router } from '@reach/router'; 3 | import Cars from './cars'; 4 | import Car from './car'; 5 | import { PageContainer } from '../components'; 6 | 7 | export default function Pages() { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | } -------------------------------------------------------------------------------- /basic/frontend/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /basic/hooks-frontend/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /basic/hooks-frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@apollo/react-hooks": "^3.0.1", 7 | "@emotion/core": "^10.0.10", 8 | "@emotion/styled": "^10.0.11", 9 | "@reach/router": "^1.2.1", 10 | "apollo-boost": "^0.3.1", 11 | "apollo-cache-inmemory": "^1.5.1", 12 | "apollo-client": "^2.5.1", 13 | "apollo-link": "^1.2.11", 14 | "apollo-link-error": "^1.1.10", 15 | "apollo-link-http": "^1.5.14", 16 | "apollo-link-state": "^0.4.2", 17 | "graphql": "^14.3.0", 18 | "graphql-tag": "^2.10.1", 19 | "react": "^16.8.6", 20 | "react-apollo": "^2.5.5", 21 | "react-dom": "^16.8.6", 22 | "react-scripts": "3.0.1" 23 | }, 24 | "scripts": { 25 | "start": "react-scripts start", 26 | "build": "react-scripts build", 27 | "test": "react-scripts test", 28 | "eject": "react-scripts eject" 29 | }, 30 | "eslintConfig": { 31 | "extends": "react-app" 32 | }, 33 | "browserslist": { 34 | "production": [ 35 | ">0.2%", 36 | "not dead", 37 | "not op_mini all" 38 | ], 39 | "development": [ 40 | "last 1 chrome version", 41 | "last 1 firefox version", 42 | "last 1 safari version" 43 | ] 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /basic/hooks-frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fullstacktraining/oreilly-react-graphql/9748e24f9b9261812d4035de32ab9fd39264460c/basic/hooks-frontend/public/favicon.ico -------------------------------------------------------------------------------- /basic/hooks-frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React App 23 | 24 | 25 | 26 |
27 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /basic/hooks-frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /basic/hooks-frontend/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | pointer-events: none; 9 | } 10 | 11 | .App-header { 12 | background-color: #282c34; 13 | min-height: 100vh; 14 | display: flex; 15 | flex-direction: column; 16 | align-items: center; 17 | justify-content: center; 18 | font-size: calc(10px + 2vmin); 19 | color: white; 20 | } 21 | 22 | .App-link { 23 | color: #61dafb; 24 | } 25 | 26 | @keyframes App-logo-spin { 27 | from { 28 | transform: rotate(0deg); 29 | } 30 | to { 31 | transform: rotate(360deg); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /basic/hooks-frontend/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | 5 | function App() { 6 | return ( 7 |
8 |
9 | logo 10 |

11 | Edit src/App.js and save to reload. 12 |

13 | 19 | Learn React 20 | 21 |
22 |
23 | ); 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /basic/hooks-frontend/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /basic/hooks-frontend/src/components/container.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import styled from '@emotion/styled' 3 | 4 | export default function PageContainer(props) { 5 | return ( 6 | 7 | {props.children} 8 | 9 | ); 10 | }; 11 | 12 | const Container = styled('div')({ 13 | display: 'flex', 14 | flexDirection: 'column', 15 | flexGrow: 1, 16 | width: '100%', 17 | maxWidth: 600, 18 | margin: '0 auto', 19 | padding: 30, 20 | paddingBottom: 50, 21 | }); -------------------------------------------------------------------------------- /basic/hooks-frontend/src/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as PageContainer } from './container'; -------------------------------------------------------------------------------- /basic/hooks-frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import Pages from './pages'; 4 | import * as serviceWorker from './serviceWorker'; 5 | 6 | import { ApolloClient } from 'apollo-client'; 7 | import { InMemoryCache } from 'apollo-cache-inmemory'; 8 | import { HttpLink } from 'apollo-link-http'; 9 | import { ApolloProvider } from '@apollo/react-hooks'; 10 | 11 | const cache = new InMemoryCache(); 12 | const httpLink = new HttpLink({ 13 | uri: 'http://localhost:4000/graphql' 14 | }); 15 | 16 | const client = new ApolloClient({ 17 | cache, 18 | link: httpLink 19 | }); 20 | 21 | ReactDOM.render( 22 | 23 | 24 | , 25 | document.getElementById('root'), 26 | ); 27 | 28 | // If you want your app to work offline and load faster, you can change 29 | // unregister() to register() below. Note this comes with some pitfalls. 30 | // Learn more about service workers: https://bit.ly/CRA-PWA 31 | serviceWorker.unregister(); 32 | -------------------------------------------------------------------------------- /basic/hooks-frontend/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /basic/hooks-frontend/src/pages/car.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import { Query } from 'react-apollo'; 3 | import gql from 'graphql-tag'; 4 | 5 | export const CAR_DETAIL = gql` 6 | query CarDetail($carId: ID!) { 7 | car(id: $carId) { 8 | make 9 | model 10 | colour 11 | year 12 | speed 13 | } 14 | } 15 | `; 16 | 17 | export default function Car({ carId }) { 18 | return ( 19 | 20 | {({ data, loading, error }) => { 21 | if (loading) return

Loading ...

; 22 | if (error) return

Error ...

; 23 | return ( 24 | 25 |

{ data.car.make } - { data.car.model } 🚗

26 |

Year of production: { data.car.year }

27 |

Maximum speed: { data.car.speed }

28 |

Colour: { data.car.colour }

29 | Go back 30 |
31 | ); 32 | }} 33 |
34 | ); 35 | } -------------------------------------------------------------------------------- /basic/hooks-frontend/src/pages/cars.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import { useQuery } from '@apollo/react-hooks'; 3 | import gql from 'graphql-tag'; 4 | import { Link } from '@reach/router'; 5 | 6 | // export const GET_CARS = gql` 7 | // query GetCars($after: String) { 8 | // cars(after: $after) { 9 | // cursor 10 | // hasMore 11 | // cars { 12 | // id 13 | // make 14 | // model 15 | // } 16 | // } 17 | // } 18 | // `; 19 | 20 | export const GET_CARS = gql` 21 | { 22 | cars { 23 | id 24 | make 25 | model 26 | } 27 | } 28 | ` 29 | 30 | export default function Cars() { 31 | const { data, loading, error } = useQuery(GET_CARS); 32 | if (loading) return

Loading ...

; 33 | if (error) return

ERROR

; 34 | return ( 35 | 36 |

A list of cars 🚗

37 | {data.cars && data.cars.map(car => ( 38 |

{ car.make } - { car.model } >> View more

39 | ))} 40 |
41 | ); 42 | } 43 | 44 | 45 | 46 | // return ( 47 | // 48 | //

A list of cars 🚗

49 | // {data.cars && data.cars.map(car => ( 50 | //

{ car.make } - { car.model } >> View more

51 | // ))} 52 | //
53 | // ) -------------------------------------------------------------------------------- /basic/hooks-frontend/src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import { Router } from '@reach/router'; 3 | import Cars from './cars'; 4 | import Car from './car'; 5 | import { PageContainer } from '../components'; 6 | 7 | export default function Pages() { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | } -------------------------------------------------------------------------------- /basic/hooks-frontend/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /links.txt: -------------------------------------------------------------------------------- 1 | React & GraphQL at Stripe 2 | https://www.slideshare.net/sashko1/react-and-graphql-at-stripe 3 | 4 | (A very gentle) Introduction to GraphQL 5 | https://blog.fullstacktraining.com/introduction-to-graphql/ 6 | 7 | Manage images via GraphQL 8 | https://blog.fullstacktraining.com/image-management-via-graphql/ 9 | 10 | Gatsby and GraphQL 11 | https://www.gatsbyjs.org/docs/graphql/ 12 | 13 | Apollo GraphQL’s website 14 | https://www.apollographql.com 15 | 16 | Link to the material on GitHub 17 | https://github.com/fullstacktraining/oreilly-react-graphql 18 | 19 | GraphQL Course 20 | https://courses.fullstacktraining.com/courses/practical-graphql-become-a-graphql-ninja 21 | 22 | GraphQL Spec 23 | https://graphql.org --------------------------------------------------------------------------------