├── .circleci └── config.yml ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── LICENSE ├── README.md ├── backend ├── .env.example ├── .gcloudignore ├── .gitignore ├── app.yaml ├── docker-compose.yml ├── package.json ├── prisma │ ├── datamodel.prisma │ ├── prisma.yml │ └── seed.ts ├── src │ ├── auth.ts │ ├── index.ts │ ├── mutation.ts │ ├── permissions.ts │ ├── postConnection.ts │ ├── query.ts │ ├── rules.ts │ ├── schemas.ts │ ├── types │ │ └── GraphQLServerContext.ts │ └── yupSchemas.ts ├── tsconfig.json ├── yarn-error.log └── yarn.lock ├── frontend ├── .env.example ├── .firebase │ └── hosting.YnVpbGQ.cache ├── .firebaserc ├── .gitignore ├── README.md ├── firebase.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json ├── src │ ├── App.css │ ├── App.test.tsx │ ├── App.tsx │ ├── components │ │ ├── AuthRoute.tsx │ │ ├── NoAuthRoute.tsx │ │ ├── NotFound.tsx │ │ ├── auth │ │ │ ├── Login.tsx │ │ │ └── Signup.tsx │ │ ├── layout │ │ │ ├── AuthLayout.tsx │ │ │ ├── Drawer.tsx │ │ │ ├── Header.tsx │ │ │ ├── HeaderMenu.tsx │ │ │ └── Layout.tsx │ │ ├── post │ │ │ ├── DialogConfirmDelete.tsx │ │ │ ├── Drafts.tsx │ │ │ ├── Feed.tsx │ │ │ ├── Post.tsx │ │ │ ├── PostCreate.tsx │ │ │ ├── PostDetail.tsx │ │ │ ├── PostEdit.tsx │ │ │ └── PostList.tsx │ │ └── user │ │ │ └── Profile.tsx │ ├── constants │ │ └── auth.ts │ ├── context │ │ └── MeQueryContext.ts │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ ├── react-app-env.d.ts │ ├── routes │ │ ├── GlobalRoutes.tsx │ │ └── RoutesAuth.tsx │ ├── serviceWorker.ts │ └── types │ │ ├── Post.ts │ │ └── User.ts ├── tsconfig.json └── yarn.lock ├── package.json ├── prettier.config.js └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | useNode: &useNode 2 | docker: 3 | - image: circleci/node:lts 4 | 5 | useGcloud: &useGcloud 6 | docker: 7 | - image: google/cloud-sdk 8 | 9 | useFirebase: &useFirebase 10 | docker: 11 | - image: devillex/docker-firebase 12 | 13 | version: 2.1 14 | jobs: 15 | install: 16 | <<: *useNode 17 | steps: 18 | - checkout 19 | - run: 20 | name: Import Backend ENV 21 | command: | 22 | export BRANCH_NAME_UPPERCASE=$(echo "${CIRCLE_BRANCH}" | tr a-z A-Z) 23 | export BACKEND_ENV=$( 24 | if [ "$BRANCH_NAME_UPPERCASE" != "PREPROD" ]; 25 | then 26 | printf '%s' "$(eval echo \"\$BACKEND_ENV_${BRANCH_NAME_UPPERCASE}\")"; 27 | else 28 | printf '%s' "${BACKEND_ENV_PROD}"; 29 | fi 30 | ) 31 | if [ "$BACKEND_ENV" != "" ]; 32 | then 33 | printf '%s' "$(echo "$BACKEND_ENV" | base64 --decode)" > ./backend/.env; 34 | fi 35 | - run: 36 | name: Import Frontend ENV 37 | command: | 38 | export BRANCH_NAME_UPPERCASE=$(echo "${CIRCLE_BRANCH}" | tr a-z A-Z) 39 | export FRONTEND_ENV=$( 40 | if [ "$BRANCH_NAME_UPPERCASE" != "PREPROD" ]; 41 | then 42 | printf '%s' "$(eval echo \"\$FRONTEND_ENV_${BRANCH_NAME_UPPERCASE}\")"; 43 | else 44 | printf '%s' "${FRONTEND_ENV_PROD}"; 45 | fi 46 | ) 47 | if [ "$FRONTEND_ENV" != "" ]; 48 | then 49 | printf '%s' "$(echo "$FRONTEND_ENV" | base64 --decode)" > ./frontend/.env; 50 | fi 51 | - run: 52 | name: DEBUG 53 | command: | 54 | cat ./backend/.env 55 | cat ./frontend/.env 56 | - restore_cache: 57 | name: Restore Yarn Package Cache 58 | keys: 59 | - ${CACHE_VERSION}-yarn-packages-{{ checksum "yarn.lock" }}-{{ checksum "./frontend/yarn.lock" }}-{{ checksum "./backend/yarn.lock" }} 60 | - run: 61 | name: Install Dependencies 62 | command: yarn install --frozen-lockfile 63 | - save_cache: 64 | name: Save Yarn Package Cache 65 | key: ${CACHE_VERSION}-yarn-packages-{{ checksum "yarn.lock" }}-{{ checksum "./frontend/yarn.lock" }}-{{ checksum "./backend/yarn.lock" }} 66 | paths: 67 | - ~/.cache/yarn 68 | - persist_to_workspace: 69 | root: . 70 | paths: 71 | - node_modules 72 | - backend/node_modules 73 | - frontend/node_modules 74 | - backend/.env 75 | - frontend/.env 76 | 77 | test-frontend: 78 | <<: *useNode 79 | steps: 80 | - checkout 81 | - attach_workspace: 82 | at: . 83 | - run: 84 | name: Test Frontend 85 | command: cd frontend && yarn test 86 | build-frontend: 87 | <<: *useNode 88 | steps: 89 | - checkout 90 | - attach_workspace: 91 | at: . 92 | - run: 93 | name: Build Frontend 94 | command: cd frontend && yarn build 95 | - persist_to_workspace: 96 | root: . 97 | paths: 98 | - frontend/build 99 | deploy-frontend: 100 | <<: *useFirebase 101 | steps: 102 | - checkout 103 | - attach_workspace: 104 | at: . 105 | - run: | 106 | cd frontend 107 | eval $(cat .env | sed 's/^/export /') 108 | firebase deploy --token "$FIREBASE_TOKEN" 109 | 110 | test-backend: 111 | <<: *useNode 112 | steps: 113 | - checkout 114 | - attach_workspace: 115 | at: . 116 | - run: 117 | name: Test Backend 118 | command: cd backend && yarn test 119 | deploy-prisma: 120 | <<: *useNode 121 | steps: 122 | - checkout 123 | - attach_workspace: 124 | at: . 125 | - run: 126 | name: Install prisma 127 | command: yarn global add prisma 128 | - run: 129 | name: Deploy prisma 130 | command: cd backend && yarn prisma:deploy 131 | - persist_to_workspace: 132 | root: . 133 | paths: 134 | - backend/src/generated 135 | deploy-backend: 136 | <<: *useGcloud 137 | steps: 138 | - checkout 139 | - attach_workspace: 140 | at: . 141 | - run: | 142 | cd backend 143 | eval $(cat .env | sed 's/^/export /') 144 | printf '%s' "$GCLOUD_SERVICE_KEY" 145 | printf '%s' "$GCLOUD_SERVICE_KEY" | gcloud auth activate-service-account --key-file=- 146 | gcloud --quiet config set project ${GCLOUD_PROJECT_ID} 147 | gcloud --quiet config set compute/zone ${GCLOUD_COMPUTE_ZONE} 148 | gcloud app deploy -v $CIRCLE_SHA1 149 | 150 | onlyEnvBranches: &onlyEnvBranches 151 | filters: 152 | branches: 153 | only: 154 | - dev 155 | - preprod 156 | - prod 157 | 158 | workflows: 159 | version: 2 160 | default: 161 | jobs: 162 | - install 163 | 164 | - test-frontend: 165 | requires: 166 | - install 167 | - build-frontend: 168 | requires: 169 | - install 170 | - deploy-frontend: 171 | <<: *onlyEnvBranches 172 | requires: 173 | - test-frontend 174 | - build-frontend 175 | 176 | - test-backend: 177 | requires: 178 | - install 179 | - deploy-prisma: 180 | <<: *onlyEnvBranches 181 | requires: 182 | - test-backend 183 | - deploy-backend: 184 | <<: *onlyEnvBranches 185 | requires: 186 | - deploy-prisma 187 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/build 2 | **/generated -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | parserOptions: { 4 | ecmaVersion: 2018, 5 | sourceType: 'module', 6 | ecmaFeatures: { 7 | jsx: true, 8 | }, 9 | }, 10 | plugins: ['@typescript-eslint'], 11 | extends: [ 12 | 'react-app', 13 | 'plugin:@typescript-eslint/recommended', 14 | 'prettier/@typescript-eslint', 15 | 'plugin:prettier/recommended', 16 | ], 17 | rules: { 18 | 'arrow-parens': ['error', 'always'], 19 | '@typescript-eslint/no-empty-interface': 'off', 20 | '@typescript-eslint/no-use-before-define': 'off', 21 | '@typescript-eslint/explicit-function-return-type': 'off', 22 | indent: 'off', 23 | '@typescript-eslint/indent': 'off', 24 | semi: 'off', 25 | '@typescript-eslint/semi': ['error', 'never'], 26 | 'comma-dangle': [ 27 | 'error', 28 | { 29 | arrays: 'always-multiline', 30 | objects: 'always-multiline', 31 | imports: 'always-multiline', 32 | exports: 'always-multiline', 33 | functions: 'always-multiline', 34 | }, 35 | ], 36 | 'prefer-arrow-callback': 'error', 37 | quotes: ['error', 'single'], 38 | }, 39 | overrides: { 40 | files: ['**/*.ts'], 41 | parser: '@typescript-eslint/parser', 42 | rules: { 43 | 'no-undef': 'off', //https://github.com/eslint/typescript-eslint-parser/issues/437 44 | }, 45 | }, 46 | } 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .vscode 3 | yarn-error.log -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Dylan Merigaud 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Prisma Typescript Fullstack 2 | 3 | ### Backend 4 | 5 | - [Express](https://www.npmjs.com/package/express) 6 | - [Prisma](https://github.com/prisma/prisma) & [Nexus](https://www.npmjs.com/package/nexus) for generating schemas and resolvers 7 | - [Yup](https://github.com/jquense/yup) for schema validation 8 | 9 | ### Frontend 10 | 11 | - [Create-React-App](https://github.com/facebook/create-react-app) 12 | - [Material-UI v4](https://www.npmjs.com/package/@material-ui/core), [AtomicCSS using Box](https://material-ui.com/components/box/) 13 | - [React-apollo](https://www.npmjs.com/package/react-apollo), [react-apollo-hooks](https://www.npmjs.com/package/react-apollo-hooks) 14 | - [Formik](https://www.npmjs.com/package/formik) for forms 15 | - [Yup](https://github.com/jquense/yup) for form schema validation 16 | - [React-Router](https://reacttraining.com/react-router/web/guides/quick-start) with route authentication verification 17 | 18 | ### Installation 19 | 20 | - `yarn install` 21 | - `cd backend` 22 | - `yarn docker:up` 23 | 24 | _in a new terminal / window_ 25 | 26 | - `yarn prisma:deploy` 27 | 28 | ### Usage 29 | 30 | - `cd backend` 31 | - `yarn dev` 32 | 33 | _in a new terminal / window_ 34 | 35 | - `cd frontend` 36 | - `yarn start` 37 | 38 | ### Hosting 39 | 40 | - Front is hosted on [Firebase Hosting](https://firebase.google.com/docs/hosting) 41 | - Back is hosted on [Google Cloud App Engine](https://cloud.google.com/appengine/) 42 | 43 | ### Workspace 44 | 45 | - [Yarn Workspace](https://yarnpkg.com/en/docs/workspaces) 46 | 47 | ### Licence 48 | 49 | MIT 50 | -------------------------------------------------------------------------------- /backend/.env.example: -------------------------------------------------------------------------------- 1 | PRISMA_ENDPOINT=http://localhost:4466 2 | PRISMA_MANAGEMENT_API_SECRET=secret -------------------------------------------------------------------------------- /backend/.gcloudignore: -------------------------------------------------------------------------------- 1 | # This file specifies files that are *not* uploaded to Google Cloud Platform 2 | # using gcloud. It follows the same syntax as .gitignore, with the addition of 3 | # "#!include" directives (which insert the entries of the given .gitignore-style 4 | # file at that point). 5 | # 6 | # For more information, run: 7 | # $ gcloud topic gcloudignore 8 | # 9 | .gcloudignore 10 | # If you would like to upload your .git directory, .gitignore file or files 11 | # from your .gitignore file, remove the corresponding line 12 | # below: 13 | .git 14 | .gitignore 15 | 16 | # Node.js dependencies: 17 | node_modules/ -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | generated/ -------------------------------------------------------------------------------- /backend/app.yaml: -------------------------------------------------------------------------------- 1 | runtime: nodejs10 2 | instance_class: F4 3 | 4 | handlers: 5 | - url: /.* 6 | secure: always 7 | redirect_http_response_code: 301 8 | script: auto 9 | -------------------------------------------------------------------------------- /backend/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | prisma: 4 | image: prismagraphql/prisma:1.33 5 | restart: always 6 | ports: 7 | - "4466:4466" 8 | environment: 9 | PRISMA_CONFIG: | 10 | port: 4466 11 | managementApiSecret: "${PRISMA_MANAGEMENT_API_SECRET}" 12 | databases: 13 | default: 14 | connector: postgres 15 | host: postgres 16 | user: prisma 17 | password: prisma 18 | rawAccess: true 19 | port: 5432 20 | migrations: true 21 | postgres: 22 | image: postgres 23 | restart: always 24 | # Uncomment the next two lines to connect to your your database from outside the Docker environment, e.g. using a database GUI like Postico 25 | # ports: 26 | # - "5432:5432" 27 | environment: 28 | POSTGRES_USER: prisma 29 | POSTGRES_PASSWORD: prisma 30 | volumes: 31 | - postgres:/var/lib/postgresql/data 32 | volumes: 33 | postgres: 34 | -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 0", 8 | "start": "dotenv ts-node src/index.ts", 9 | "dev": "dotenv ts-node-dev --no-notify src/index.ts", 10 | "build": "yarn run prisma:generate", 11 | "prisma:generate": "prisma generate --env-file .env", 12 | "prisma:deploy": "prisma deploy --env-file .env", 13 | "prisma:seed": "prisma seed --env-file .env", 14 | "docker:up": "docker-compose up" 15 | }, 16 | "keywords": [], 17 | "author": "", 18 | "license": "ISC", 19 | "dependencies": { 20 | "bcrypt": "^3.0.6", 21 | "cors": "^2.8.5", 22 | "dotenv-cli": "^2.0.0", 23 | "graphql": "^14.3.0", 24 | "graphql-shield": "^5.3.5", 25 | "graphql-yoga": "^1.17.4", 26 | "graphql-yup-middleware": "^0.0.1", 27 | "jsonwebtoken": "^8.5.1", 28 | "nexus": "^0.11.7", 29 | "nexus-prisma": "^0.3.7", 30 | "prisma-client-lib": "^1.33.0", 31 | "ts-node": "^8.1.0", 32 | "yup": "^0.27.0" 33 | }, 34 | "devDependencies": { 35 | "@types/cors": "^2.8.5", 36 | "@types/dotenv": "^6.1.1", 37 | "@types/graphql": "^14.2.0", 38 | "@types/yup": "^0.26.13", 39 | "ts-node-dev": "^1.0.0-pre.38", 40 | "typescript": "^3.4.5" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /backend/prisma/datamodel.prisma: -------------------------------------------------------------------------------- 1 | 2 | enum Role { 3 | ADMIN 4 | USER 5 | } 6 | 7 | type User { 8 | id: ID! @id 9 | email: String @unique 10 | verifiedEmail: Boolean! @default(value: false) 11 | name: String! 12 | posts: [Post!]! 13 | password: String! 14 | role: Role! 15 | } 16 | 17 | type Post { 18 | id: ID! @id 19 | title: String! 20 | published: Boolean! @default(value: false) 21 | author: User @relation(link: INLINE) 22 | } 23 | 24 | type Test { 25 | id: ID! @id 26 | lol: String! 27 | } -------------------------------------------------------------------------------- /backend/prisma/prisma.yml: -------------------------------------------------------------------------------- 1 | endpoint: ${env:PRISMA_ENDPOINT} 2 | datamodel: datamodel.prisma 3 | databaseType: document 4 | 5 | generate: 6 | - generator: typescript-client 7 | output: ../src/generated/prisma-client/ 8 | 9 | hooks: 10 | post-deploy: 11 | - yarn prisma:generate 12 | - npx nexus-prisma-generate --client ./src/generated/prisma-client --output ./src/generated/nexus-prisma 13 | 14 | seed: 15 | run: yarn ts-node ./prisma/seed.ts 16 | -------------------------------------------------------------------------------- /backend/prisma/seed.ts: -------------------------------------------------------------------------------- 1 | import { prisma } from '../src/generated/prisma-client' 2 | 3 | async function main() { 4 | await prisma.createUser({ 5 | name: 'Admin', 6 | email: 'admin@adminadminadminadminadmin.admin', 7 | password: 'admin', 8 | role: 'ADMIN', 9 | }) 10 | } 11 | 12 | main() 13 | -------------------------------------------------------------------------------- /backend/src/auth.ts: -------------------------------------------------------------------------------- 1 | import { prisma } from './generated/prisma-client' 2 | import { ContextParameters } from 'graphql-yoga/dist/types' 3 | import * as jwt from 'jsonwebtoken' 4 | import { stringArg } from 'nexus' 5 | import * as bcrypt from 'bcrypt' 6 | import { PrismaObjectDefinitionBlock } from 'nexus-prisma/dist/blocks/objectType' 7 | import GraphQLServerContext from './types/GraphQLServerContext' 8 | 9 | export const getUser = async (req: ContextParameters) => { 10 | const auth = req.request.get('Authorization') 11 | 12 | if (auth) { 13 | const token = auth.replace('Bearer ', '') 14 | try { 15 | const { userId } = jwt.verify(token, 'APP_SECRET') 16 | // TO FIX: prisma.user ne retourne pas .role 17 | return prisma.user({ id: userId }) 18 | } catch (error) { 19 | console.log('getUser error', error) 20 | return null 21 | } 22 | } else { 23 | return null 24 | } 25 | } 26 | 27 | export const query = (t: PrismaObjectDefinitionBlock<'Query'>) => { 28 | t.field('me', { 29 | type: 'User', 30 | args: {}, 31 | resolve: async (_, { email }, ctx: GraphQLServerContext) => { 32 | const user = await ctx.user 33 | console.log('/me: ', { user }) 34 | if (!user) throw new Error('Not auth.') 35 | return user 36 | }, 37 | }) 38 | } 39 | 40 | export const mutation = (t: PrismaObjectDefinitionBlock<'Mutation'>) => { 41 | t.field('login', { 42 | type: 'AuthPayload', 43 | args: { 44 | email: stringArg({ nullable: false }), 45 | password: stringArg({ nullable: false }), 46 | }, 47 | resolve: async (_, { email, password }, ctx: GraphQLServerContext) => { 48 | const user = await ctx.prisma.user({ email }) 49 | console.log({ user }) 50 | if (!user) throw new Error('User not in db.') 51 | 52 | const valid = await bcrypt.compare(password, user.password) 53 | console.log({ valid }) 54 | if (!valid) throw new Error('Wrong password.') 55 | 56 | return { 57 | token: jwt.sign({ userId: user.id }, 'APP_SECRET'), 58 | user, 59 | } 60 | }, 61 | }) 62 | t.field('signup', { 63 | type: 'AuthPayload', 64 | args: { 65 | name: stringArg({ nullable: false }), 66 | email: stringArg({ nullable: false }), 67 | password: stringArg({ nullable: false }), 68 | }, 69 | resolve: async ( 70 | _, 71 | { name, email, password }, 72 | ctx: GraphQLServerContext, 73 | ) => { 74 | const password2 = await bcrypt.hash(password, 10) 75 | 76 | const user = await ctx.prisma.createUser({ 77 | name, 78 | email, 79 | password: password2, 80 | role: 'USER', 81 | }) 82 | 83 | console.log({ user }) 84 | 85 | return { 86 | token: jwt.sign({ userId: user.id }, 'APP_SECRET'), 87 | user, 88 | } 89 | }, 90 | }) 91 | } 92 | -------------------------------------------------------------------------------- /backend/src/index.ts: -------------------------------------------------------------------------------- 1 | import { prisma, User } from './generated/prisma-client' 2 | import datamodelInfo from './generated/nexus-prisma' 3 | import * as path from 'path' 4 | import { makePrismaSchema } from 'nexus-prisma' 5 | import { GraphQLServer } from 'graphql-yoga' 6 | import { ContextParameters } from 'graphql-yoga/dist/types' 7 | 8 | import Query from './query' 9 | import Mutation from './mutation' 10 | 11 | import permissions from './permissions' 12 | 13 | import { Aliment, AuthPayload } from './schemas' 14 | 15 | import { getUser } from './auth' 16 | 17 | import * as cors from 'cors' 18 | 19 | import PostConnection from './postConnection' 20 | 21 | const schema = makePrismaSchema({ 22 | types: [Query, Mutation, Aliment, AuthPayload, PostConnection], 23 | prisma: { 24 | datamodelInfo, 25 | client: prisma, 26 | }, 27 | outputs: { 28 | schema: path.join(__dirname, './generated/schema.graphql'), 29 | typegen: path.join(__dirname, './generated/nexus.ts'), 30 | }, 31 | }) 32 | 33 | const server = new GraphQLServer({ 34 | schema, 35 | context: (req: ContextParameters) => ({ 36 | ...req, 37 | user: getUser(req), 38 | prisma, 39 | }), 40 | middlewares: [permissions], 41 | }) 42 | 43 | const options = { 44 | port: process.env.PORT || 4000, 45 | endpoint: '/graphql', 46 | subscriptions: '/subscriptions', 47 | playground: '/playground', 48 | } 49 | 50 | server.express.use(cors()) 51 | 52 | server.express.get('/', (req, res) => { 53 | res.send('Hello world!') 54 | }) 55 | 56 | server.start(options, ({ port, playground }) => 57 | console.log( 58 | `Server started, listening on port ${port} for incoming requests.\nYou can test the playground at http://localhost:4000${playground}`, 59 | ), 60 | ) 61 | 62 | server.express.use((req, res) => { 63 | res.status(404) 64 | res.send('404 not found') 65 | }) 66 | -------------------------------------------------------------------------------- /backend/src/mutation.ts: -------------------------------------------------------------------------------- 1 | import { arg, stringArg, idArg } from 'nexus' 2 | import { prismaObjectType } from 'nexus-prisma' 3 | 4 | import { AlimentYupSchema } from './yupSchemas' 5 | 6 | import { mutation as authMutation } from './auth' 7 | import GraphQLServerContext from './types/GraphQLServerContext' 8 | 9 | const Mutation = prismaObjectType({ 10 | name: 'Mutation', 11 | definition: (t) => { 12 | t.prismaFields(['createUser', 'deletePost', 'updatePost']) 13 | t.field('createDraft', { 14 | type: 'Post', 15 | args: { 16 | title: stringArg(), 17 | authorId: idArg({ nullable: true }), 18 | }, 19 | resolve: (_, { title, authorId }, ctx: GraphQLServerContext) => 20 | ctx.prisma.createPost({ 21 | title, 22 | author: { connect: { id: authorId } }, 23 | }), 24 | }) 25 | t.field('publish', { 26 | type: 'Post', 27 | nullable: true, 28 | args: { id: idArg() }, 29 | resolve: (_, { id }, ctx: GraphQLServerContext) => 30 | ctx.prisma.updatePost({ 31 | where: { id }, 32 | data: { published: true }, 33 | }), 34 | }) 35 | t.field('testoss', { 36 | type: 'Test', 37 | args: { 38 | aliment: arg({ 39 | type: 'Aliment', 40 | }), 41 | }, 42 | resolve: (_, { aliment }, ctx) => { 43 | console.log('aliment: ' + aliment) 44 | // const yupVal = 45 | AlimentYupSchema.validateSync(aliment) 46 | 47 | // console.log({ yupVal }) 48 | 49 | return { 50 | id: '', 51 | lol: aliment, 52 | } 53 | }, 54 | }) 55 | authMutation(t) 56 | }, 57 | }) 58 | 59 | export default Mutation 60 | -------------------------------------------------------------------------------- /backend/src/permissions.ts: -------------------------------------------------------------------------------- 1 | import { shield } from 'graphql-shield' 2 | import { isAuthenticated, isAdmin } from './rules' 3 | 4 | const permissions = shield( 5 | { 6 | Query: { 7 | // feed: isAuthenticated, 8 | }, 9 | Mutation: { 10 | testoss: isAuthenticated, 11 | }, 12 | Test: isAdmin, 13 | Aliment: isAuthenticated, 14 | // Post: isAdmin 15 | }, 16 | { debug: true }, 17 | ) 18 | 19 | export default permissions 20 | -------------------------------------------------------------------------------- /backend/src/postConnection.ts: -------------------------------------------------------------------------------- 1 | import { prismaObjectType } from 'nexus-prisma' 2 | 3 | const PostsConnection = prismaObjectType({ 4 | name: 'PostConnection', 5 | definition: (t) => { 6 | t.prismaFields(['*']) 7 | t.field('aggregate', { 8 | ...t.prismaType.aggregate, 9 | resolve: async (_, args, ctx) => { 10 | const posts = await ctx.prisma.posts() 11 | const count = posts.length 12 | return { count } 13 | }, 14 | }) 15 | }, 16 | }) 17 | 18 | export default PostsConnection 19 | -------------------------------------------------------------------------------- /backend/src/query.ts: -------------------------------------------------------------------------------- 1 | import { stringArg } from 'nexus' 2 | import { prismaObjectType } from 'nexus-prisma' 3 | 4 | import { query as authQuery } from './auth' 5 | import GraphQLServerContext from './types/GraphQLServerContext' 6 | 7 | const Query = prismaObjectType({ 8 | name: 'Query', 9 | definition: (t) => { 10 | t.prismaFields(['post']) 11 | t.field('feed', { 12 | type: 'PostConnection', 13 | args: t.prismaType.postsConnection.args, 14 | resolve: (_, args, ctx: GraphQLServerContext) => { 15 | console.log({ args }) 16 | 17 | return ctx.prisma.postsConnection({ 18 | ...args, 19 | where: { ...args.where, published: true }, 20 | }) 21 | }, 22 | }) 23 | t.field('drafts', { 24 | type: 'PostConnection', 25 | args: t.prismaType.postsConnection.args, 26 | resolve: async (_, args, ctx: GraphQLServerContext) => { 27 | const user = await ctx.user 28 | if (!user) throw Error('Not auth.') 29 | return ctx.prisma.postsConnection({ 30 | ...args, 31 | where: { ...args.where, published: false, author: { id: user.id } }, 32 | }) 33 | }, 34 | }) 35 | t.list.field('postsByUser', { 36 | type: 'Post', 37 | args: { email: stringArg() }, 38 | resolve: (_, { email }, ctx: GraphQLServerContext) => 39 | ctx.prisma.posts({ where: { author: { email } } }), 40 | }) 41 | authQuery(t) 42 | }, 43 | }) 44 | 45 | export default Query 46 | -------------------------------------------------------------------------------- /backend/src/rules.ts: -------------------------------------------------------------------------------- 1 | import { rule } from 'graphql-shield' 2 | 3 | export const isAuthenticated = rule()(async (parent, args, ctx, info) => { 4 | const user = await ctx.user 5 | 6 | console.log('isAuth: ', { user }) 7 | 8 | return user !== null && user.id !== undefined 9 | }) 10 | 11 | export const isAdmin = rule()(async (parent, args, ctx, info) => { 12 | const user = await ctx.user 13 | return user.role === 'ADMIN' 14 | }) 15 | 16 | export const isUser = rule()(async (parent, args, ctx, info) => { 17 | const user = await ctx.user 18 | return user.role === 'USER' 19 | }) 20 | -------------------------------------------------------------------------------- /backend/src/schemas.ts: -------------------------------------------------------------------------------- 1 | import { enumType, objectType } from 'nexus' 2 | 3 | export const Aliment = enumType({ 4 | name: 'Aliment', 5 | members: ['Poulet', 'Frites', 'Error'], 6 | description: 'A boufer !', 7 | }) 8 | 9 | export const AuthPayload = objectType({ 10 | name: 'AuthPayload', 11 | definition: (t) => { 12 | t.string('token') 13 | t.field('user', { 14 | type: 'User', 15 | }) 16 | }, 17 | }) 18 | -------------------------------------------------------------------------------- /backend/src/types/GraphQLServerContext.ts: -------------------------------------------------------------------------------- 1 | import { User } from '../generated/prisma-client' 2 | import { PrismaClient } from 'nexus-prisma/dist/types' 3 | 4 | interface GraphQLServerContext { 5 | user: User 6 | prisma: PrismaClient 7 | } 8 | 9 | export default GraphQLServerContext 10 | -------------------------------------------------------------------------------- /backend/src/yupSchemas.ts: -------------------------------------------------------------------------------- 1 | import * as yup from 'yup' 2 | 3 | export const AlimentYupSchema = yup.mixed().oneOf(['Poulet', 'Frites']) 4 | 5 | export const EmailYupSchema = null 6 | 7 | export const PasswordYupSchema = null 8 | -------------------------------------------------------------------------------- /backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2016", "esnext.asynciterable"] 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /backend/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/runtime@^7.0.0": 6 | version "7.4.4" 7 | resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.4.tgz#dc2e34982eb236803aa27a07fea6857af1b9171d" 8 | dependencies: 9 | regenerator-runtime "^0.13.2" 10 | 11 | "@types/bcrypt@^3.0.0": 12 | version "3.0.0" 13 | resolved "https://registry.yarnpkg.com/@types/bcrypt/-/bcrypt-3.0.0.tgz#851489a9065a067cb7f3c9cbe4ce9bed8bba0876" 14 | 15 | "@types/body-parser@*": 16 | version "1.17.0" 17 | resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c" 18 | dependencies: 19 | "@types/connect" "*" 20 | "@types/node" "*" 21 | 22 | "@types/concat-stream@^1.6.0": 23 | version "1.6.0" 24 | resolved "https://registry.yarnpkg.com/@types/concat-stream/-/concat-stream-1.6.0.tgz#394dbe0bb5fee46b38d896735e8b68ef2390d00d" 25 | dependencies: 26 | "@types/node" "*" 27 | 28 | "@types/connect@*": 29 | version "3.4.32" 30 | resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28" 31 | dependencies: 32 | "@types/node" "*" 33 | 34 | "@types/cors@^2.8.4": 35 | version "2.8.5" 36 | resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.5.tgz#c0c54c4e643e1d943d447292f2baf9dc82cfc8ec" 37 | dependencies: 38 | "@types/express" "*" 39 | 40 | "@types/express-serve-static-core@*": 41 | version "4.16.4" 42 | resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.4.tgz#56bb8be4559401d68af4a3624ae9dd3166103e60" 43 | dependencies: 44 | "@types/node" "*" 45 | "@types/range-parser" "*" 46 | 47 | "@types/express@*", "@types/express@^4.11.1": 48 | version "4.16.1" 49 | resolved "https://registry.yarnpkg.com/@types/express/-/express-4.16.1.tgz#d756bd1a85c34d87eaf44c888bad27ba8a4b7cf0" 50 | dependencies: 51 | "@types/body-parser" "*" 52 | "@types/express-serve-static-core" "*" 53 | "@types/serve-static" "*" 54 | 55 | "@types/form-data@0.0.33": 56 | version "0.0.33" 57 | resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-0.0.33.tgz#c9ac85b2a5fd18435b8c85d9ecb50e6d6c893ff8" 58 | dependencies: 59 | "@types/node" "*" 60 | 61 | "@types/graphql-deduplicator@^2.0.0": 62 | version "2.0.0" 63 | resolved "https://registry.yarnpkg.com/@types/graphql-deduplicator/-/graphql-deduplicator-2.0.0.tgz#9e577b8f3feb3d067b0ca756f4a1fb356d533922" 64 | 65 | "@types/graphql@0.13.4": 66 | version "0.13.4" 67 | resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.13.4.tgz#55ae9c29f0fd6b85ee536f5c72b4769d5c5e06b1" 68 | 69 | "@types/graphql@^14.0.0", "@types/graphql@^14.2.0": 70 | version "14.2.0" 71 | resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-14.2.0.tgz#74e1da5f2a4a744ac6eb3ed57b48242ea9367202" 72 | 73 | "@types/jsonwebtoken@^8.3.2": 74 | version "8.3.2" 75 | resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.3.2.tgz#e3d5245197152346fae7ee87d5541aa5a92d0362" 76 | dependencies: 77 | "@types/node" "*" 78 | 79 | "@types/lodash.groupby@^4.6.4": 80 | version "4.6.6" 81 | resolved "https://registry.yarnpkg.com/@types/lodash.groupby/-/lodash.groupby-4.6.6.tgz#4d9b61a4d8b0d83d384975cabfed4c1769d6792e" 82 | dependencies: 83 | "@types/lodash" "*" 84 | 85 | "@types/lodash@*": 86 | version "4.14.126" 87 | resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.126.tgz#47cff3ea014aa083194f8ca3ec351136c3786613" 88 | 89 | "@types/methods@^1.1.0": 90 | version "1.1.0" 91 | resolved "https://registry.yarnpkg.com/@types/methods/-/methods-1.1.0.tgz#fa0c8c81992257903f724651ec2500ec427dc32d" 92 | 93 | "@types/mime@*": 94 | version "2.0.1" 95 | resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" 96 | 97 | "@types/node@*": 98 | version "12.0.0" 99 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.0.tgz#d11813b9c0ff8aaca29f04cbc12817f4c7d656e5" 100 | 101 | "@types/node@^10.12.0": 102 | version "10.14.6" 103 | resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.6.tgz#9cbfcb62c50947217f4d88d4d274cc40c22625a9" 104 | 105 | "@types/prettier@^1.13.2": 106 | version "1.16.3" 107 | resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.16.3.tgz#141bdf4dcbaac06fd2b3f05e233ff23b66866f9f" 108 | 109 | "@types/range-parser@*": 110 | version "1.2.3" 111 | resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" 112 | 113 | "@types/serve-static@*": 114 | version "1.13.2" 115 | resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48" 116 | dependencies: 117 | "@types/express-serve-static-core" "*" 118 | "@types/mime" "*" 119 | 120 | "@types/strip-bom@^3.0.0": 121 | version "3.0.0" 122 | resolved "https://registry.yarnpkg.com/@types/strip-bom/-/strip-bom-3.0.0.tgz#14a8ec3956c2e81edb7520790aecf21c290aebd2" 123 | 124 | "@types/strip-json-comments@0.0.30": 125 | version "0.0.30" 126 | resolved "https://registry.yarnpkg.com/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz#9aa30c04db212a9a0649d6ae6fd50accc40748a1" 127 | 128 | "@types/tough-cookie@^2.3.0": 129 | version "2.3.5" 130 | resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.5.tgz#9da44ed75571999b65c37b60c9b2b88db54c585d" 131 | 132 | "@types/yup@0.26.13", "@types/yup@^0.26.13": 133 | version "0.26.13" 134 | resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.26.13.tgz#0aeeba85231a34ddc68c74b3a2c64eeb2ccf68bf" 135 | 136 | "@types/yup@^0.24.9": 137 | version "0.24.9" 138 | resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.24.9.tgz#da98f4b38eec7ca72146e7042679c8c8628896fa" 139 | 140 | "@types/zen-observable@^0.5.3": 141 | version "0.5.4" 142 | resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.5.4.tgz#b863a4191e525206819e008097ebf0fb2e3a1cdc" 143 | 144 | abbrev@1: 145 | version "1.1.1" 146 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 147 | 148 | accepts@~1.3.5: 149 | version "1.3.7" 150 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" 151 | dependencies: 152 | mime-types "~2.1.24" 153 | negotiator "0.6.2" 154 | 155 | ansi-regex@^2.0.0: 156 | version "2.1.1" 157 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 158 | 159 | ansi-regex@^3.0.0: 160 | version "3.0.0" 161 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 162 | 163 | apollo-cache-control@^0.1.0: 164 | version "0.1.1" 165 | resolved "https://registry.yarnpkg.com/apollo-cache-control/-/apollo-cache-control-0.1.1.tgz#173d14ceb3eb9e7cb53de7eb8b61bee6159d4171" 166 | dependencies: 167 | graphql-extensions "^0.0.x" 168 | 169 | apollo-link@^1.2.3: 170 | version "1.2.11" 171 | resolved "https://registry.yarnpkg.com/apollo-link/-/apollo-link-1.2.11.tgz#493293b747ad3237114ccd22e9f559e5e24a194d" 172 | dependencies: 173 | apollo-utilities "^1.2.1" 174 | ts-invariant "^0.3.2" 175 | tslib "^1.9.3" 176 | zen-observable-ts "^0.8.18" 177 | 178 | apollo-server-core@^1.3.6, apollo-server-core@^1.4.0: 179 | version "1.4.0" 180 | resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-1.4.0.tgz#4faff7f110bfdd6c3f47008302ae24140f94c592" 181 | dependencies: 182 | apollo-cache-control "^0.1.0" 183 | apollo-tracing "^0.1.0" 184 | graphql-extensions "^0.0.x" 185 | 186 | apollo-server-express@^1.3.6: 187 | version "1.4.0" 188 | resolved "https://registry.yarnpkg.com/apollo-server-express/-/apollo-server-express-1.4.0.tgz#7d7c58d6d6f9892b83fe575669093bb66738b125" 189 | dependencies: 190 | apollo-server-core "^1.4.0" 191 | apollo-server-module-graphiql "^1.4.0" 192 | 193 | apollo-server-lambda@1.3.6: 194 | version "1.3.6" 195 | resolved "https://registry.yarnpkg.com/apollo-server-lambda/-/apollo-server-lambda-1.3.6.tgz#bdaac37f143c6798e40b8ae75580ba673cea260e" 196 | dependencies: 197 | apollo-server-core "^1.3.6" 198 | apollo-server-module-graphiql "^1.3.4" 199 | 200 | apollo-server-module-graphiql@^1.3.4, apollo-server-module-graphiql@^1.4.0: 201 | version "1.4.0" 202 | resolved "https://registry.yarnpkg.com/apollo-server-module-graphiql/-/apollo-server-module-graphiql-1.4.0.tgz#c559efa285578820709f1769bb85d3b3eed3d8ec" 203 | 204 | apollo-tracing@^0.1.0: 205 | version "0.1.4" 206 | resolved "https://registry.yarnpkg.com/apollo-tracing/-/apollo-tracing-0.1.4.tgz#5b8ae1b01526b160ee6e552a7f131923a9aedcc7" 207 | dependencies: 208 | graphql-extensions "~0.0.9" 209 | 210 | apollo-upload-server@^7.0.0: 211 | version "7.1.0" 212 | resolved "https://registry.yarnpkg.com/apollo-upload-server/-/apollo-upload-server-7.1.0.tgz#21e07b52252b3749b913468599813e13cfca805f" 213 | dependencies: 214 | busboy "^0.2.14" 215 | fs-capacitor "^1.0.0" 216 | http-errors "^1.7.0" 217 | object-path "^0.11.4" 218 | 219 | apollo-utilities@^1.0.1, apollo-utilities@^1.2.1: 220 | version "1.2.1" 221 | resolved "https://registry.yarnpkg.com/apollo-utilities/-/apollo-utilities-1.2.1.tgz#1c3a1ebf5607d7c8efe7636daaf58e7463b41b3c" 222 | dependencies: 223 | fast-json-stable-stringify "^2.0.0" 224 | ts-invariant "^0.2.1" 225 | tslib "^1.9.3" 226 | 227 | aproba@^1.0.3: 228 | version "1.2.0" 229 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" 230 | 231 | are-we-there-yet@~1.1.2: 232 | version "1.1.5" 233 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" 234 | dependencies: 235 | delegates "^1.0.0" 236 | readable-stream "^2.0.6" 237 | 238 | arg@^4.1.0: 239 | version "4.1.0" 240 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.0.tgz#583c518199419e0037abb74062c37f8519e575f0" 241 | 242 | array-find-index@^1.0.1: 243 | version "1.0.2" 244 | resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" 245 | 246 | array-flatten@1.1.1: 247 | version "1.1.1" 248 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 249 | 250 | async-limiter@~1.0.0: 251 | version "1.0.0" 252 | resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" 253 | 254 | asynckit@^0.4.0: 255 | version "0.4.0" 256 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 257 | 258 | aws-lambda@^0.1.2: 259 | version "0.1.2" 260 | resolved "https://registry.yarnpkg.com/aws-lambda/-/aws-lambda-0.1.2.tgz#19b1585075df31679597b976a5f1def61f12ccee" 261 | dependencies: 262 | aws-sdk "^*" 263 | commander "^2.5.0" 264 | dotenv "^0.4.0" 265 | 266 | aws-sdk@^*: 267 | version "2.452.0" 268 | resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.452.0.tgz#b33c29c4250d45a803f9b8b26dedacc96f60699d" 269 | dependencies: 270 | buffer "4.9.1" 271 | events "1.1.1" 272 | ieee754 "1.1.8" 273 | jmespath "0.15.0" 274 | querystring "0.2.0" 275 | sax "1.2.1" 276 | url "0.10.3" 277 | uuid "3.3.2" 278 | xml2js "0.4.19" 279 | 280 | backo2@^1.0.2: 281 | version "1.0.2" 282 | resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" 283 | 284 | balanced-match@^1.0.0: 285 | version "1.0.0" 286 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 287 | 288 | base64-js@^1.0.2: 289 | version "1.3.0" 290 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" 291 | 292 | bcrypt@^3.0.6: 293 | version "3.0.6" 294 | resolved "https://registry.yarnpkg.com/bcrypt/-/bcrypt-3.0.6.tgz#f607846df62d27e60d5e795612c4f67d70206eb2" 295 | dependencies: 296 | nan "2.13.2" 297 | node-pre-gyp "0.12.0" 298 | 299 | body-parser-graphql@1.1.0: 300 | version "1.1.0" 301 | resolved "https://registry.yarnpkg.com/body-parser-graphql/-/body-parser-graphql-1.1.0.tgz#80a80353c7cb623562fd375750dfe018d75f0f7c" 302 | dependencies: 303 | body-parser "^1.18.2" 304 | 305 | body-parser@1.18.3: 306 | version "1.18.3" 307 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4" 308 | dependencies: 309 | bytes "3.0.0" 310 | content-type "~1.0.4" 311 | debug "2.6.9" 312 | depd "~1.1.2" 313 | http-errors "~1.6.3" 314 | iconv-lite "0.4.23" 315 | on-finished "~2.3.0" 316 | qs "6.5.2" 317 | raw-body "2.3.3" 318 | type-is "~1.6.16" 319 | 320 | body-parser@^1.18.2: 321 | version "1.19.0" 322 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" 323 | dependencies: 324 | bytes "3.1.0" 325 | content-type "~1.0.4" 326 | debug "2.6.9" 327 | depd "~1.1.2" 328 | http-errors "1.7.2" 329 | iconv-lite "0.4.24" 330 | on-finished "~2.3.0" 331 | qs "6.7.0" 332 | raw-body "2.4.0" 333 | type-is "~1.6.17" 334 | 335 | brace-expansion@^1.1.7: 336 | version "1.1.11" 337 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 338 | dependencies: 339 | balanced-match "^1.0.0" 340 | concat-map "0.0.1" 341 | 342 | buffer-equal-constant-time@1.0.1: 343 | version "1.0.1" 344 | resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" 345 | 346 | buffer-from@^1.0.0: 347 | version "1.1.1" 348 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" 349 | 350 | buffer@4.9.1: 351 | version "4.9.1" 352 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" 353 | dependencies: 354 | base64-js "^1.0.2" 355 | ieee754 "^1.1.4" 356 | isarray "^1.0.0" 357 | 358 | busboy@^0.2.14: 359 | version "0.2.14" 360 | resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" 361 | dependencies: 362 | dicer "0.2.5" 363 | readable-stream "1.1.x" 364 | 365 | bytes@3.0.0: 366 | version "3.0.0" 367 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" 368 | 369 | bytes@3.1.0: 370 | version "3.1.0" 371 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" 372 | 373 | camelcase-keys@^2.0.0: 374 | version "2.1.0" 375 | resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" 376 | dependencies: 377 | camelcase "^2.0.0" 378 | map-obj "^1.0.0" 379 | 380 | camelcase@^2.0.0: 381 | version "2.1.1" 382 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" 383 | 384 | camelcase@^4.1.0: 385 | version "4.1.0" 386 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" 387 | 388 | chownr@^1.1.1: 389 | version "1.1.1" 390 | resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" 391 | 392 | code-point-at@^1.0.0: 393 | version "1.1.0" 394 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 395 | 396 | combined-stream@^1.0.6: 397 | version "1.0.7" 398 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" 399 | dependencies: 400 | delayed-stream "~1.0.0" 401 | 402 | commander@^2.5.0: 403 | version "2.20.0" 404 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" 405 | 406 | concat-map@0.0.1: 407 | version "0.0.1" 408 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 409 | 410 | concat-stream@^1.4.7: 411 | version "1.6.2" 412 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" 413 | dependencies: 414 | buffer-from "^1.0.0" 415 | inherits "^2.0.3" 416 | readable-stream "^2.2.2" 417 | typedarray "^0.0.6" 418 | 419 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: 420 | version "1.1.0" 421 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 422 | 423 | content-disposition@0.5.2: 424 | version "0.5.2" 425 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 426 | 427 | content-type@~1.0.4: 428 | version "1.0.4" 429 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 430 | 431 | cookie-signature@1.0.6: 432 | version "1.0.6" 433 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 434 | 435 | cookie@0.3.1: 436 | version "0.3.1" 437 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" 438 | 439 | core-js@^2.5.3: 440 | version "2.6.5" 441 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" 442 | 443 | core-util-is@~1.0.0: 444 | version "1.0.2" 445 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 446 | 447 | cors@^2.8.4: 448 | version "2.8.5" 449 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" 450 | dependencies: 451 | object-assign "^4" 452 | vary "^1" 453 | 454 | cross-fetch@2.2.2: 455 | version "2.2.2" 456 | resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.2.tgz#a47ff4f7fc712daba8f6a695a11c948440d45723" 457 | dependencies: 458 | node-fetch "2.1.2" 459 | whatwg-fetch "2.0.4" 460 | 461 | cross-spawn@^4.0.0: 462 | version "4.0.2" 463 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" 464 | dependencies: 465 | lru-cache "^4.0.1" 466 | which "^1.2.9" 467 | 468 | currently-unhandled@^0.4.1: 469 | version "0.4.1" 470 | resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" 471 | dependencies: 472 | array-find-index "^1.0.1" 473 | 474 | dataloader@^1.4.0: 475 | version "1.4.0" 476 | resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-1.4.0.tgz#bca11d867f5d3f1b9ed9f737bd15970c65dff5c8" 477 | 478 | dateformat@~1.0.4-1.2.3: 479 | version "1.0.12" 480 | resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.12.tgz#9f124b67594c937ff706932e4a642cca8dbbfee9" 481 | dependencies: 482 | get-stdin "^4.0.1" 483 | meow "^3.3.0" 484 | 485 | debounce@^1.0.0: 486 | version "1.2.0" 487 | resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.0.tgz#44a540abc0ea9943018dc0eaa95cce87f65cd131" 488 | 489 | debug@2.6.9: 490 | version "2.6.9" 491 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 492 | dependencies: 493 | ms "2.0.0" 494 | 495 | debug@^3.2.6: 496 | version "3.2.6" 497 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 498 | dependencies: 499 | ms "^2.1.1" 500 | 501 | debug@^4.1.0: 502 | version "4.1.1" 503 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" 504 | dependencies: 505 | ms "^2.1.1" 506 | 507 | decamelize@^1.1.2: 508 | version "1.2.0" 509 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 510 | 511 | deep-extend@^0.6.0: 512 | version "0.6.0" 513 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" 514 | 515 | delayed-stream@~1.0.0: 516 | version "1.0.0" 517 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 518 | 519 | delegates@^1.0.0: 520 | version "1.0.0" 521 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 522 | 523 | depd@~1.1.2: 524 | version "1.1.2" 525 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 526 | 527 | deprecated-decorator@^0.1.6: 528 | version "0.1.6" 529 | resolved "https://registry.yarnpkg.com/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz#00966317b7a12fe92f3cc831f7583af329b86c37" 530 | 531 | destroy@~1.0.4: 532 | version "1.0.4" 533 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 534 | 535 | detect-libc@^1.0.2: 536 | version "1.0.3" 537 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" 538 | 539 | dicer@0.2.5: 540 | version "0.2.5" 541 | resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" 542 | dependencies: 543 | readable-stream "1.1.x" 544 | streamsearch "0.1.2" 545 | 546 | diff@^3.1.0: 547 | version "3.5.0" 548 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 549 | 550 | dotenv-cli@^2.0.0: 551 | version "2.0.0" 552 | resolved "https://registry.yarnpkg.com/dotenv-cli/-/dotenv-cli-2.0.0.tgz#2d519e06fd08bbd1bea82e60689e4a9947155d0e" 553 | dependencies: 554 | cross-spawn "^4.0.0" 555 | dotenv "^7.0.0" 556 | dotenv-expand "^5.0.0" 557 | minimist "^1.1.3" 558 | 559 | dotenv-expand@^5.0.0: 560 | version "5.1.0" 561 | resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0" 562 | 563 | dotenv@^0.4.0: 564 | version "0.4.0" 565 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-0.4.0.tgz#f6fb351363c2d92207245c737802c9ab5ae1495a" 566 | 567 | dotenv@^7.0.0: 568 | version "7.0.0" 569 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c" 570 | 571 | dynamic-dedupe@^0.3.0: 572 | version "0.3.0" 573 | resolved "https://registry.yarnpkg.com/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz#06e44c223f5e4e94d78ef9db23a6515ce2f962a1" 574 | dependencies: 575 | xtend "^4.0.0" 576 | 577 | ecdsa-sig-formatter@1.0.11: 578 | version "1.0.11" 579 | resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" 580 | dependencies: 581 | safe-buffer "^5.0.1" 582 | 583 | ee-first@1.1.1: 584 | version "1.1.1" 585 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 586 | 587 | encodeurl@~1.0.2: 588 | version "1.0.2" 589 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 590 | 591 | error-ex@^1.2.0: 592 | version "1.3.2" 593 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" 594 | dependencies: 595 | is-arrayish "^0.2.1" 596 | 597 | escape-html@~1.0.3: 598 | version "1.0.3" 599 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 600 | 601 | etag@~1.8.1: 602 | version "1.8.1" 603 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 604 | 605 | eventemitter3@^3.1.0: 606 | version "3.1.2" 607 | resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" 608 | 609 | events@1.1.1: 610 | version "1.1.1" 611 | resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" 612 | 613 | express@^4.16.3: 614 | version "4.16.4" 615 | resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e" 616 | dependencies: 617 | accepts "~1.3.5" 618 | array-flatten "1.1.1" 619 | body-parser "1.18.3" 620 | content-disposition "0.5.2" 621 | content-type "~1.0.4" 622 | cookie "0.3.1" 623 | cookie-signature "1.0.6" 624 | debug "2.6.9" 625 | depd "~1.1.2" 626 | encodeurl "~1.0.2" 627 | escape-html "~1.0.3" 628 | etag "~1.8.1" 629 | finalhandler "1.1.1" 630 | fresh "0.5.2" 631 | merge-descriptors "1.0.1" 632 | methods "~1.1.2" 633 | on-finished "~2.3.0" 634 | parseurl "~1.3.2" 635 | path-to-regexp "0.1.7" 636 | proxy-addr "~2.0.4" 637 | qs "6.5.2" 638 | range-parser "~1.2.0" 639 | safe-buffer "5.1.2" 640 | send "0.16.2" 641 | serve-static "1.13.2" 642 | setprototypeof "1.1.0" 643 | statuses "~1.4.0" 644 | type-is "~1.6.16" 645 | utils-merge "1.0.1" 646 | vary "~1.1.2" 647 | 648 | fast-json-stable-stringify@^2.0.0: 649 | version "2.0.0" 650 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" 651 | 652 | filewatcher@~3.0.0: 653 | version "3.0.1" 654 | resolved "https://registry.yarnpkg.com/filewatcher/-/filewatcher-3.0.1.tgz#f4a1957355ddaf443ccd78a895f3d55e23c8a034" 655 | dependencies: 656 | debounce "^1.0.0" 657 | 658 | finalhandler@1.1.1: 659 | version "1.1.1" 660 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" 661 | dependencies: 662 | debug "2.6.9" 663 | encodeurl "~1.0.2" 664 | escape-html "~1.0.3" 665 | on-finished "~2.3.0" 666 | parseurl "~1.3.2" 667 | statuses "~1.4.0" 668 | unpipe "~1.0.0" 669 | 670 | find-up@^1.0.0: 671 | version "1.1.2" 672 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" 673 | dependencies: 674 | path-exists "^2.0.0" 675 | pinkie-promise "^2.0.0" 676 | 677 | flow-bin@^0.87.0: 678 | version "0.87.0" 679 | resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.87.0.tgz#fab7f984d8cc767e93fa9eb01cf7d57ed744f19d" 680 | 681 | fn-name@~2.0.1: 682 | version "2.0.1" 683 | resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7" 684 | 685 | form-data@^2.0.0: 686 | version "2.3.3" 687 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" 688 | dependencies: 689 | asynckit "^0.4.0" 690 | combined-stream "^1.0.6" 691 | mime-types "^2.1.12" 692 | 693 | forwarded@~0.1.2: 694 | version "0.1.2" 695 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" 696 | 697 | fresh@0.5.2: 698 | version "0.5.2" 699 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 700 | 701 | fs-capacitor@^1.0.0: 702 | version "1.0.1" 703 | resolved "https://registry.yarnpkg.com/fs-capacitor/-/fs-capacitor-1.0.1.tgz#ff9dbfa14dfaf4472537720f19c3088ed9278df0" 704 | 705 | fs-minipass@^1.2.5: 706 | version "1.2.5" 707 | resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" 708 | dependencies: 709 | minipass "^2.2.1" 710 | 711 | fs.realpath@^1.0.0: 712 | version "1.0.0" 713 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 714 | 715 | gauge@~2.7.3: 716 | version "2.7.4" 717 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" 718 | dependencies: 719 | aproba "^1.0.3" 720 | console-control-strings "^1.0.0" 721 | has-unicode "^2.0.0" 722 | object-assign "^4.1.0" 723 | signal-exit "^3.0.0" 724 | string-width "^1.0.1" 725 | strip-ansi "^3.0.1" 726 | wide-align "^1.1.0" 727 | 728 | get-stdin@^4.0.1: 729 | version "4.0.1" 730 | resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" 731 | 732 | glob@^7.1.3: 733 | version "7.1.4" 734 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" 735 | dependencies: 736 | fs.realpath "^1.0.0" 737 | inflight "^1.0.4" 738 | inherits "2" 739 | minimatch "^3.0.4" 740 | once "^1.3.0" 741 | path-is-absolute "^1.0.0" 742 | 743 | graceful-fs@^4.1.2: 744 | version "4.1.15" 745 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" 746 | 747 | graphql-deduplicator@^2.0.1: 748 | version "2.0.2" 749 | resolved "https://registry.yarnpkg.com/graphql-deduplicator/-/graphql-deduplicator-2.0.2.tgz#d8608161cf6be97725e178df0c41f6a1f9f778f3" 750 | 751 | graphql-extensions@^0.0.x, graphql-extensions@~0.0.9: 752 | version "0.0.10" 753 | resolved "https://registry.yarnpkg.com/graphql-extensions/-/graphql-extensions-0.0.10.tgz#34bdb2546d43f6a5bc89ab23c295ec0466c6843d" 754 | dependencies: 755 | core-js "^2.5.3" 756 | source-map-support "^0.5.1" 757 | 758 | graphql-import@^0.7.0: 759 | version "0.7.1" 760 | resolved "https://registry.yarnpkg.com/graphql-import/-/graphql-import-0.7.1.tgz#4add8d91a5f752d764b0a4a7a461fcd93136f223" 761 | dependencies: 762 | lodash "^4.17.4" 763 | resolve-from "^4.0.0" 764 | 765 | graphql-middleware@3.0.2: 766 | version "3.0.2" 767 | resolved "https://registry.yarnpkg.com/graphql-middleware/-/graphql-middleware-3.0.2.tgz#c8cdb67615eec02aec237b455e679f5fc973ddc4" 768 | dependencies: 769 | graphql-tools "^4.0.4" 770 | 771 | graphql-playground-html@1.6.12: 772 | version "1.6.12" 773 | resolved "https://registry.yarnpkg.com/graphql-playground-html/-/graphql-playground-html-1.6.12.tgz#8b3b34ab6013e2c877f0ceaae478fafc8ca91b85" 774 | 775 | graphql-playground-middleware-express@1.7.11: 776 | version "1.7.11" 777 | resolved "https://registry.yarnpkg.com/graphql-playground-middleware-express/-/graphql-playground-middleware-express-1.7.11.tgz#bbffd784a37133bfa7165bdd8f429081dbf4bcf6" 778 | dependencies: 779 | graphql-playground-html "1.6.12" 780 | 781 | graphql-playground-middleware-lambda@1.7.12: 782 | version "1.7.12" 783 | resolved "https://registry.yarnpkg.com/graphql-playground-middleware-lambda/-/graphql-playground-middleware-lambda-1.7.12.tgz#1b06440a288dbcd53f935b43e5b9ca2738a06305" 784 | dependencies: 785 | graphql-playground-html "1.6.12" 786 | 787 | graphql-shield@^5.3.5: 788 | version "5.3.5" 789 | resolved "https://registry.yarnpkg.com/graphql-shield/-/graphql-shield-5.3.5.tgz#cba409f4c1714e107212cff0a1cb2d934273392b" 790 | dependencies: 791 | "@types/yup" "0.26.13" 792 | lightercollective "^0.3.0" 793 | object-hash "^1.3.1" 794 | yup "^0.27.0" 795 | 796 | graphql-subscriptions@^0.5.8: 797 | version "0.5.8" 798 | resolved "https://registry.yarnpkg.com/graphql-subscriptions/-/graphql-subscriptions-0.5.8.tgz#13a6143c546bce390404657dc73ca501def30aa7" 799 | dependencies: 800 | iterall "^1.2.1" 801 | 802 | graphql-tag@^2.10.0: 803 | version "2.10.1" 804 | resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.10.1.tgz#10aa41f1cd8fae5373eaf11f1f67260a3cad5e02" 805 | 806 | graphql-tools@^4.0.0, graphql-tools@^4.0.4: 807 | version "4.0.4" 808 | resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-4.0.4.tgz#ca08a63454221fdde825fe45fbd315eb2a6d566b" 809 | dependencies: 810 | apollo-link "^1.2.3" 811 | apollo-utilities "^1.0.1" 812 | deprecated-decorator "^0.1.6" 813 | iterall "^1.1.3" 814 | uuid "^3.1.0" 815 | 816 | graphql-yoga@^1.17.4: 817 | version "1.17.4" 818 | resolved "https://registry.yarnpkg.com/graphql-yoga/-/graphql-yoga-1.17.4.tgz#6d325a6270399edf0776fb5f60a2e9e19512e63c" 819 | dependencies: 820 | "@types/cors" "^2.8.4" 821 | "@types/express" "^4.11.1" 822 | "@types/graphql" "^14.0.0" 823 | "@types/graphql-deduplicator" "^2.0.0" 824 | "@types/zen-observable" "^0.5.3" 825 | apollo-server-express "^1.3.6" 826 | apollo-server-lambda "1.3.6" 827 | apollo-upload-server "^7.0.0" 828 | aws-lambda "^0.1.2" 829 | body-parser-graphql "1.1.0" 830 | cors "^2.8.4" 831 | express "^4.16.3" 832 | graphql "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0" 833 | graphql-deduplicator "^2.0.1" 834 | graphql-import "^0.7.0" 835 | graphql-middleware "3.0.2" 836 | graphql-playground-middleware-express "1.7.11" 837 | graphql-playground-middleware-lambda "1.7.12" 838 | graphql-subscriptions "^0.5.8" 839 | graphql-tools "^4.0.0" 840 | subscriptions-transport-ws "^0.9.8" 841 | 842 | graphql-yup-middleware@^0.0.1: 843 | version "0.0.1" 844 | resolved "https://registry.yarnpkg.com/graphql-yup-middleware/-/graphql-yup-middleware-0.0.1.tgz#f14895b001d7636dbc82787c8cdf2c0df1e898e9" 845 | dependencies: 846 | "@types/graphql" "0.13.4" 847 | "@types/lodash.groupby" "^4.6.4" 848 | "@types/yup" "^0.24.9" 849 | lodash.groupby "^4.6.0" 850 | 851 | "graphql@^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0", graphql@^14.0.2, graphql@^14.3.0: 852 | version "14.3.0" 853 | resolved "https://registry.yarnpkg.com/graphql/-/graphql-14.3.0.tgz#34dd36faa489ff642bcd25df6c3b4f988a1a2f3e" 854 | dependencies: 855 | iterall "^1.2.2" 856 | 857 | growly@^1.3.0: 858 | version "1.3.0" 859 | resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" 860 | 861 | has-unicode@^2.0.0: 862 | version "2.0.1" 863 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 864 | 865 | hosted-git-info@^2.1.4: 866 | version "2.7.1" 867 | resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" 868 | 869 | http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3: 870 | version "1.6.3" 871 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" 872 | dependencies: 873 | depd "~1.1.2" 874 | inherits "2.0.3" 875 | setprototypeof "1.1.0" 876 | statuses ">= 1.4.0 < 2" 877 | 878 | http-errors@1.7.2, http-errors@^1.7.0: 879 | version "1.7.2" 880 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" 881 | dependencies: 882 | depd "~1.1.2" 883 | inherits "2.0.3" 884 | setprototypeof "1.1.1" 885 | statuses ">= 1.5.0 < 2" 886 | toidentifier "1.0.0" 887 | 888 | http-link-dataloader@^0.1.6: 889 | version "0.1.6" 890 | resolved "https://registry.yarnpkg.com/http-link-dataloader/-/http-link-dataloader-0.1.6.tgz#ad87d6b5cb6c2745b14b21ffd9cf476c13976c4f" 891 | dependencies: 892 | apollo-link "^1.2.3" 893 | cross-fetch "2.2.2" 894 | dataloader "^1.4.0" 895 | 896 | iconv-lite@0.4.23: 897 | version "0.4.23" 898 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" 899 | dependencies: 900 | safer-buffer ">= 2.1.2 < 3" 901 | 902 | iconv-lite@0.4.24, iconv-lite@^0.4.4: 903 | version "0.4.24" 904 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 905 | dependencies: 906 | safer-buffer ">= 2.1.2 < 3" 907 | 908 | ieee754@1.1.8: 909 | version "1.1.8" 910 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" 911 | 912 | ieee754@^1.1.4: 913 | version "1.1.13" 914 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" 915 | 916 | ignore-walk@^3.0.1: 917 | version "3.0.1" 918 | resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" 919 | dependencies: 920 | minimatch "^3.0.4" 921 | 922 | indent-string@^2.1.0: 923 | version "2.1.0" 924 | resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" 925 | dependencies: 926 | repeating "^2.0.0" 927 | 928 | inflight@^1.0.4: 929 | version "1.0.6" 930 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 931 | dependencies: 932 | once "^1.3.0" 933 | wrappy "1" 934 | 935 | inherits@2, inherits@2.0.3, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: 936 | version "2.0.3" 937 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 938 | 939 | ini@~1.3.0: 940 | version "1.3.5" 941 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" 942 | 943 | ipaddr.js@1.9.0: 944 | version "1.9.0" 945 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" 946 | 947 | is-arrayish@^0.2.1: 948 | version "0.2.1" 949 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 950 | 951 | is-finite@^1.0.0: 952 | version "1.0.2" 953 | resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" 954 | dependencies: 955 | number-is-nan "^1.0.0" 956 | 957 | is-fullwidth-code-point@^1.0.0: 958 | version "1.0.0" 959 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 960 | dependencies: 961 | number-is-nan "^1.0.0" 962 | 963 | is-fullwidth-code-point@^2.0.0: 964 | version "2.0.0" 965 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 966 | 967 | is-utf8@^0.2.0: 968 | version "0.2.1" 969 | resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" 970 | 971 | is-wsl@^1.1.0: 972 | version "1.1.0" 973 | resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" 974 | 975 | isarray@0.0.1: 976 | version "0.0.1" 977 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 978 | 979 | isarray@^1.0.0, isarray@~1.0.0: 980 | version "1.0.0" 981 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 982 | 983 | isexe@^2.0.0: 984 | version "2.0.0" 985 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 986 | 987 | iterall@^1.1.3, iterall@^1.2.1, iterall@^1.2.2: 988 | version "1.2.2" 989 | resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.2.2.tgz#92d70deb8028e0c39ff3164fdbf4d8b088130cd7" 990 | 991 | jmespath@0.15.0: 992 | version "0.15.0" 993 | resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.15.0.tgz#a3f222a9aae9f966f5d27c796510e28091764217" 994 | 995 | jsonwebtoken@^8.3.0, jsonwebtoken@^8.5.1: 996 | version "8.5.1" 997 | resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" 998 | dependencies: 999 | jws "^3.2.2" 1000 | lodash.includes "^4.3.0" 1001 | lodash.isboolean "^3.0.3" 1002 | lodash.isinteger "^4.0.4" 1003 | lodash.isnumber "^3.0.3" 1004 | lodash.isplainobject "^4.0.6" 1005 | lodash.isstring "^4.0.1" 1006 | lodash.once "^4.0.0" 1007 | ms "^2.1.1" 1008 | semver "^5.6.0" 1009 | 1010 | jwa@^1.4.1: 1011 | version "1.4.1" 1012 | resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" 1013 | dependencies: 1014 | buffer-equal-constant-time "1.0.1" 1015 | ecdsa-sig-formatter "1.0.11" 1016 | safe-buffer "^5.0.1" 1017 | 1018 | jws@^3.2.2: 1019 | version "3.2.2" 1020 | resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" 1021 | dependencies: 1022 | jwa "^1.4.1" 1023 | safe-buffer "^5.0.1" 1024 | 1025 | lightercollective@^0.3.0: 1026 | version "0.3.0" 1027 | resolved "https://registry.yarnpkg.com/lightercollective/-/lightercollective-0.3.0.tgz#1f07638642ec645d70bdb69ab2777676f35a28f0" 1028 | 1029 | load-json-file@^1.0.0: 1030 | version "1.1.0" 1031 | resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" 1032 | dependencies: 1033 | graceful-fs "^4.1.2" 1034 | parse-json "^2.2.0" 1035 | pify "^2.0.0" 1036 | pinkie-promise "^2.0.0" 1037 | strip-bom "^2.0.0" 1038 | 1039 | lodash.flatten@^4.4.0: 1040 | version "4.4.0" 1041 | resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" 1042 | 1043 | lodash.groupby@^4.6.0: 1044 | version "4.6.0" 1045 | resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1" 1046 | 1047 | lodash.includes@^4.3.0: 1048 | version "4.3.0" 1049 | resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" 1050 | 1051 | lodash.isboolean@^3.0.3: 1052 | version "3.0.3" 1053 | resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" 1054 | 1055 | lodash.isinteger@^4.0.4: 1056 | version "4.0.4" 1057 | resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" 1058 | 1059 | lodash.isnumber@^3.0.3: 1060 | version "3.0.3" 1061 | resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" 1062 | 1063 | lodash.isplainobject@^4.0.6: 1064 | version "4.0.6" 1065 | resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" 1066 | 1067 | lodash.isstring@^4.0.1: 1068 | version "4.0.1" 1069 | resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" 1070 | 1071 | lodash.once@^4.0.0: 1072 | version "4.1.1" 1073 | resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" 1074 | 1075 | lodash@^4.17.11, lodash@^4.17.4: 1076 | version "4.17.11" 1077 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" 1078 | 1079 | loud-rejection@^1.0.0: 1080 | version "1.6.0" 1081 | resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" 1082 | dependencies: 1083 | currently-unhandled "^0.4.1" 1084 | signal-exit "^3.0.0" 1085 | 1086 | lru-cache@^4.0.1: 1087 | version "4.1.5" 1088 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" 1089 | dependencies: 1090 | pseudomap "^1.0.2" 1091 | yallist "^2.1.2" 1092 | 1093 | make-error-cause@^1.2.1: 1094 | version "1.2.2" 1095 | resolved "https://registry.yarnpkg.com/make-error-cause/-/make-error-cause-1.2.2.tgz#df0388fcd0b37816dff0a5fb8108939777dcbc9d" 1096 | dependencies: 1097 | make-error "^1.2.0" 1098 | 1099 | make-error@^1.1.1, make-error@^1.2.0: 1100 | version "1.3.5" 1101 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" 1102 | 1103 | map-obj@^1.0.0, map-obj@^1.0.1: 1104 | version "1.0.1" 1105 | resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" 1106 | 1107 | media-typer@0.3.0: 1108 | version "0.3.0" 1109 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 1110 | 1111 | meow@^3.3.0: 1112 | version "3.7.0" 1113 | resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" 1114 | dependencies: 1115 | camelcase-keys "^2.0.0" 1116 | decamelize "^1.1.2" 1117 | loud-rejection "^1.0.0" 1118 | map-obj "^1.0.1" 1119 | minimist "^1.1.3" 1120 | normalize-package-data "^2.3.4" 1121 | object-assign "^4.0.1" 1122 | read-pkg-up "^1.0.1" 1123 | redent "^1.0.0" 1124 | trim-newlines "^1.0.0" 1125 | 1126 | merge-descriptors@1.0.1: 1127 | version "1.0.1" 1128 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 1129 | 1130 | methods@~1.1.2: 1131 | version "1.1.2" 1132 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 1133 | 1134 | mime-db@1.40.0: 1135 | version "1.40.0" 1136 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" 1137 | 1138 | mime-types@^2.1.12, mime-types@~2.1.24: 1139 | version "2.1.24" 1140 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" 1141 | dependencies: 1142 | mime-db "1.40.0" 1143 | 1144 | mime@1.4.1: 1145 | version "1.4.1" 1146 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" 1147 | 1148 | minimatch@^3.0.4: 1149 | version "3.0.4" 1150 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 1151 | dependencies: 1152 | brace-expansion "^1.1.7" 1153 | 1154 | minimist@0.0.8: 1155 | version "0.0.8" 1156 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 1157 | 1158 | minimist@^1.1.3, minimist@^1.2.0: 1159 | version "1.2.0" 1160 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 1161 | 1162 | minipass@^2.2.1, minipass@^2.3.4: 1163 | version "2.3.5" 1164 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" 1165 | dependencies: 1166 | safe-buffer "^5.1.2" 1167 | yallist "^3.0.0" 1168 | 1169 | minizlib@^1.1.1: 1170 | version "1.2.1" 1171 | resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" 1172 | dependencies: 1173 | minipass "^2.2.1" 1174 | 1175 | mkdirp@^0.5.0, mkdirp@^0.5.1: 1176 | version "0.5.1" 1177 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 1178 | dependencies: 1179 | minimist "0.0.8" 1180 | 1181 | ms@2.0.0: 1182 | version "2.0.0" 1183 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 1184 | 1185 | ms@^2.1.1: 1186 | version "2.1.1" 1187 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 1188 | 1189 | nan@2.13.2: 1190 | version "2.13.2" 1191 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7" 1192 | 1193 | needle@^2.2.1: 1194 | version "2.4.0" 1195 | resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" 1196 | dependencies: 1197 | debug "^3.2.6" 1198 | iconv-lite "^0.4.4" 1199 | sax "^1.2.4" 1200 | 1201 | negotiator@0.6.2: 1202 | version "0.6.2" 1203 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" 1204 | 1205 | nexus-prisma@^0.3.7: 1206 | version "0.3.7" 1207 | resolved "https://registry.yarnpkg.com/nexus-prisma/-/nexus-prisma-0.3.7.tgz#d2a556616bb6d100c1a0b9daff89fd4394666a29" 1208 | 1209 | nexus@^0.11.7: 1210 | version "0.11.7" 1211 | resolved "https://registry.yarnpkg.com/nexus/-/nexus-0.11.7.tgz#db580f1d6feb5e590fe395d9cd218c969c46b9ed" 1212 | dependencies: 1213 | tslib "^1.9.3" 1214 | 1215 | node-fetch@2.1.2: 1216 | version "2.1.2" 1217 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.1.2.tgz#ab884e8e7e57e38a944753cec706f788d1768bb5" 1218 | 1219 | node-notifier@^5.4.0: 1220 | version "5.4.0" 1221 | resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.0.tgz#7b455fdce9f7de0c63538297354f3db468426e6a" 1222 | dependencies: 1223 | growly "^1.3.0" 1224 | is-wsl "^1.1.0" 1225 | semver "^5.5.0" 1226 | shellwords "^0.1.1" 1227 | which "^1.3.0" 1228 | 1229 | node-pre-gyp@0.12.0: 1230 | version "0.12.0" 1231 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" 1232 | dependencies: 1233 | detect-libc "^1.0.2" 1234 | mkdirp "^0.5.1" 1235 | needle "^2.2.1" 1236 | nopt "^4.0.1" 1237 | npm-packlist "^1.1.6" 1238 | npmlog "^4.0.2" 1239 | rc "^1.2.7" 1240 | rimraf "^2.6.1" 1241 | semver "^5.3.0" 1242 | tar "^4" 1243 | 1244 | nopt@^4.0.1: 1245 | version "4.0.1" 1246 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" 1247 | dependencies: 1248 | abbrev "1" 1249 | osenv "^0.1.4" 1250 | 1251 | normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: 1252 | version "2.5.0" 1253 | resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" 1254 | dependencies: 1255 | hosted-git-info "^2.1.4" 1256 | resolve "^1.10.0" 1257 | semver "2 || 3 || 4 || 5" 1258 | validate-npm-package-license "^3.0.1" 1259 | 1260 | npm-bundled@^1.0.1: 1261 | version "1.0.6" 1262 | resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" 1263 | 1264 | npm-packlist@^1.1.6: 1265 | version "1.4.1" 1266 | resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc" 1267 | dependencies: 1268 | ignore-walk "^3.0.1" 1269 | npm-bundled "^1.0.1" 1270 | 1271 | npmlog@^4.0.2: 1272 | version "4.1.2" 1273 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" 1274 | dependencies: 1275 | are-we-there-yet "~1.1.2" 1276 | console-control-strings "~1.1.0" 1277 | gauge "~2.7.3" 1278 | set-blocking "~2.0.0" 1279 | 1280 | number-is-nan@^1.0.0: 1281 | version "1.0.1" 1282 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 1283 | 1284 | object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0: 1285 | version "4.1.1" 1286 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 1287 | 1288 | object-hash@^1.3.1: 1289 | version "1.3.1" 1290 | resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df" 1291 | 1292 | object-path@^0.11.4: 1293 | version "0.11.4" 1294 | resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.11.4.tgz#370ae752fbf37de3ea70a861c23bba8915691949" 1295 | 1296 | on-finished@~2.3.0: 1297 | version "2.3.0" 1298 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 1299 | dependencies: 1300 | ee-first "1.1.1" 1301 | 1302 | once@^1.3.0: 1303 | version "1.4.0" 1304 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1305 | dependencies: 1306 | wrappy "1" 1307 | 1308 | os-homedir@^1.0.0: 1309 | version "1.0.2" 1310 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 1311 | 1312 | os-tmpdir@^1.0.0: 1313 | version "1.0.2" 1314 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 1315 | 1316 | osenv@^0.1.4: 1317 | version "0.1.5" 1318 | resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" 1319 | dependencies: 1320 | os-homedir "^1.0.0" 1321 | os-tmpdir "^1.0.0" 1322 | 1323 | parse-json@^2.2.0: 1324 | version "2.2.0" 1325 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" 1326 | dependencies: 1327 | error-ex "^1.2.0" 1328 | 1329 | parseurl@~1.3.2: 1330 | version "1.3.3" 1331 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 1332 | 1333 | path-exists@^2.0.0: 1334 | version "2.1.0" 1335 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" 1336 | dependencies: 1337 | pinkie-promise "^2.0.0" 1338 | 1339 | path-is-absolute@^1.0.0: 1340 | version "1.0.1" 1341 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1342 | 1343 | path-parse@^1.0.6: 1344 | version "1.0.6" 1345 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 1346 | 1347 | path-to-regexp@0.1.7: 1348 | version "0.1.7" 1349 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 1350 | 1351 | path-type@^1.0.0: 1352 | version "1.1.0" 1353 | resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" 1354 | dependencies: 1355 | graceful-fs "^4.1.2" 1356 | pify "^2.0.0" 1357 | pinkie-promise "^2.0.0" 1358 | 1359 | pify@^2.0.0: 1360 | version "2.3.0" 1361 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 1362 | 1363 | pinkie-promise@^2.0.0: 1364 | version "2.0.1" 1365 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 1366 | dependencies: 1367 | pinkie "^2.0.0" 1368 | 1369 | pinkie@^2.0.0: 1370 | version "2.0.4" 1371 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 1372 | 1373 | pluralize@^7.0.0: 1374 | version "7.0.0" 1375 | resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" 1376 | 1377 | popsicle@10: 1378 | version "10.0.1" 1379 | resolved "https://registry.yarnpkg.com/popsicle/-/popsicle-10.0.1.tgz#2abd36130560647c74eaf08400d473ae25c4486f" 1380 | dependencies: 1381 | "@types/concat-stream" "^1.6.0" 1382 | "@types/form-data" "0.0.33" 1383 | "@types/methods" "^1.1.0" 1384 | "@types/tough-cookie" "^2.3.0" 1385 | concat-stream "^1.4.7" 1386 | form-data "^2.0.0" 1387 | make-error-cause "^1.2.1" 1388 | tough-cookie "^2.0.0" 1389 | 1390 | prettier@1.16.4: 1391 | version "1.16.4" 1392 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.4.tgz#73e37e73e018ad2db9c76742e2647e21790c9717" 1393 | 1394 | prisma-client-lib@^1.33.0: 1395 | version "1.33.0" 1396 | resolved "https://registry.yarnpkg.com/prisma-client-lib/-/prisma-client-lib-1.33.0.tgz#e446c85ffd926283230ba98d0ee8dd6ba3988782" 1397 | dependencies: 1398 | "@types/node" "^10.12.0" 1399 | "@types/prettier" "^1.13.2" 1400 | debug "^4.1.0" 1401 | flow-bin "^0.87.0" 1402 | graphql-tag "^2.10.0" 1403 | http-link-dataloader "^0.1.6" 1404 | jsonwebtoken "^8.3.0" 1405 | lodash.flatten "^4.4.0" 1406 | prettier "1.16.4" 1407 | prisma-datamodel "1.33.0" 1408 | prisma-generate-schema "1.33.0" 1409 | subscriptions-transport-ws "^0.9.15" 1410 | uppercamelcase "^3.0.0" 1411 | ws "^6.1.0" 1412 | zen-observable "^0.8.10" 1413 | 1414 | prisma-datamodel@1.33.0: 1415 | version "1.33.0" 1416 | resolved "https://registry.yarnpkg.com/prisma-datamodel/-/prisma-datamodel-1.33.0.tgz#64d8b4cc78ada8c60cc31d7fda51d060b202886f" 1417 | dependencies: 1418 | graphql "^14.0.2" 1419 | pluralize "^7.0.0" 1420 | popsicle "10" 1421 | 1422 | prisma-generate-schema@1.33.0: 1423 | version "1.33.0" 1424 | resolved "https://registry.yarnpkg.com/prisma-generate-schema/-/prisma-generate-schema-1.33.0.tgz#d966240de5e0c925d7e4ae7f64cb0f476115e51e" 1425 | dependencies: 1426 | graphql "^14.0.2" 1427 | pluralize "^7.0.0" 1428 | popsicle "10" 1429 | prisma-datamodel "1.33.0" 1430 | 1431 | process-nextick-args@~2.0.0: 1432 | version "2.0.0" 1433 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" 1434 | 1435 | property-expr@^1.5.0: 1436 | version "1.5.1" 1437 | resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.5.1.tgz#22e8706894a0c8e28d58735804f6ba3a3673314f" 1438 | 1439 | proxy-addr@~2.0.4: 1440 | version "2.0.5" 1441 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" 1442 | dependencies: 1443 | forwarded "~0.1.2" 1444 | ipaddr.js "1.9.0" 1445 | 1446 | pseudomap@^1.0.2: 1447 | version "1.0.2" 1448 | resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" 1449 | 1450 | psl@^1.1.28: 1451 | version "1.1.31" 1452 | resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" 1453 | 1454 | punycode@1.3.2: 1455 | version "1.3.2" 1456 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" 1457 | 1458 | punycode@^2.1.1: 1459 | version "2.1.1" 1460 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" 1461 | 1462 | qs@6.5.2: 1463 | version "6.5.2" 1464 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" 1465 | 1466 | qs@6.7.0: 1467 | version "6.7.0" 1468 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" 1469 | 1470 | querystring@0.2.0: 1471 | version "0.2.0" 1472 | resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" 1473 | 1474 | range-parser@~1.2.0: 1475 | version "1.2.0" 1476 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" 1477 | 1478 | raw-body@2.3.3: 1479 | version "2.3.3" 1480 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3" 1481 | dependencies: 1482 | bytes "3.0.0" 1483 | http-errors "1.6.3" 1484 | iconv-lite "0.4.23" 1485 | unpipe "1.0.0" 1486 | 1487 | raw-body@2.4.0: 1488 | version "2.4.0" 1489 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" 1490 | dependencies: 1491 | bytes "3.1.0" 1492 | http-errors "1.7.2" 1493 | iconv-lite "0.4.24" 1494 | unpipe "1.0.0" 1495 | 1496 | rc@^1.2.7: 1497 | version "1.2.8" 1498 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" 1499 | dependencies: 1500 | deep-extend "^0.6.0" 1501 | ini "~1.3.0" 1502 | minimist "^1.2.0" 1503 | strip-json-comments "~2.0.1" 1504 | 1505 | read-pkg-up@^1.0.1: 1506 | version "1.0.1" 1507 | resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" 1508 | dependencies: 1509 | find-up "^1.0.0" 1510 | read-pkg "^1.0.0" 1511 | 1512 | read-pkg@^1.0.0: 1513 | version "1.1.0" 1514 | resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" 1515 | dependencies: 1516 | load-json-file "^1.0.0" 1517 | normalize-package-data "^2.3.2" 1518 | path-type "^1.0.0" 1519 | 1520 | readable-stream@1.1.x: 1521 | version "1.1.14" 1522 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" 1523 | dependencies: 1524 | core-util-is "~1.0.0" 1525 | inherits "~2.0.1" 1526 | isarray "0.0.1" 1527 | string_decoder "~0.10.x" 1528 | 1529 | readable-stream@^2.0.6, readable-stream@^2.2.2: 1530 | version "2.3.6" 1531 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" 1532 | dependencies: 1533 | core-util-is "~1.0.0" 1534 | inherits "~2.0.3" 1535 | isarray "~1.0.0" 1536 | process-nextick-args "~2.0.0" 1537 | safe-buffer "~5.1.1" 1538 | string_decoder "~1.1.1" 1539 | util-deprecate "~1.0.1" 1540 | 1541 | redent@^1.0.0: 1542 | version "1.0.0" 1543 | resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" 1544 | dependencies: 1545 | indent-string "^2.1.0" 1546 | strip-indent "^1.0.1" 1547 | 1548 | regenerator-runtime@^0.13.2: 1549 | version "0.13.2" 1550 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" 1551 | 1552 | repeating@^2.0.0: 1553 | version "2.0.1" 1554 | resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" 1555 | dependencies: 1556 | is-finite "^1.0.0" 1557 | 1558 | resolve-from@^4.0.0: 1559 | version "4.0.0" 1560 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" 1561 | 1562 | resolve@^1.0.0, resolve@^1.10.0: 1563 | version "1.10.1" 1564 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.10.1.tgz#664842ac960795bbe758221cdccda61fb64b5f18" 1565 | dependencies: 1566 | path-parse "^1.0.6" 1567 | 1568 | rimraf@^2.6.1: 1569 | version "2.6.3" 1570 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" 1571 | dependencies: 1572 | glob "^7.1.3" 1573 | 1574 | safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1575 | version "5.1.2" 1576 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1577 | 1578 | "safer-buffer@>= 2.1.2 < 3": 1579 | version "2.1.2" 1580 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 1581 | 1582 | sax@1.2.1: 1583 | version "1.2.1" 1584 | resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" 1585 | 1586 | sax@>=0.6.0, sax@^1.2.4: 1587 | version "1.2.4" 1588 | resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" 1589 | 1590 | "semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.6.0: 1591 | version "5.7.0" 1592 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" 1593 | 1594 | send@0.16.2: 1595 | version "0.16.2" 1596 | resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" 1597 | dependencies: 1598 | debug "2.6.9" 1599 | depd "~1.1.2" 1600 | destroy "~1.0.4" 1601 | encodeurl "~1.0.2" 1602 | escape-html "~1.0.3" 1603 | etag "~1.8.1" 1604 | fresh "0.5.2" 1605 | http-errors "~1.6.2" 1606 | mime "1.4.1" 1607 | ms "2.0.0" 1608 | on-finished "~2.3.0" 1609 | range-parser "~1.2.0" 1610 | statuses "~1.4.0" 1611 | 1612 | serve-static@1.13.2: 1613 | version "1.13.2" 1614 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" 1615 | dependencies: 1616 | encodeurl "~1.0.2" 1617 | escape-html "~1.0.3" 1618 | parseurl "~1.3.2" 1619 | send "0.16.2" 1620 | 1621 | set-blocking@~2.0.0: 1622 | version "2.0.0" 1623 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 1624 | 1625 | setprototypeof@1.1.0: 1626 | version "1.1.0" 1627 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" 1628 | 1629 | setprototypeof@1.1.1: 1630 | version "1.1.1" 1631 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" 1632 | 1633 | shellwords@^0.1.1: 1634 | version "0.1.1" 1635 | resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" 1636 | 1637 | signal-exit@^3.0.0: 1638 | version "3.0.2" 1639 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 1640 | 1641 | source-map-support@^0.5.1, source-map-support@^0.5.6: 1642 | version "0.5.12" 1643 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" 1644 | dependencies: 1645 | buffer-from "^1.0.0" 1646 | source-map "^0.6.0" 1647 | 1648 | source-map@^0.6.0: 1649 | version "0.6.1" 1650 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 1651 | 1652 | spdx-correct@^3.0.0: 1653 | version "3.1.0" 1654 | resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" 1655 | dependencies: 1656 | spdx-expression-parse "^3.0.0" 1657 | spdx-license-ids "^3.0.0" 1658 | 1659 | spdx-exceptions@^2.1.0: 1660 | version "2.2.0" 1661 | resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" 1662 | 1663 | spdx-expression-parse@^3.0.0: 1664 | version "3.0.0" 1665 | resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" 1666 | dependencies: 1667 | spdx-exceptions "^2.1.0" 1668 | spdx-license-ids "^3.0.0" 1669 | 1670 | spdx-license-ids@^3.0.0: 1671 | version "3.0.4" 1672 | resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1" 1673 | 1674 | "statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2": 1675 | version "1.5.0" 1676 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 1677 | 1678 | statuses@~1.4.0: 1679 | version "1.4.0" 1680 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" 1681 | 1682 | streamsearch@0.1.2: 1683 | version "0.1.2" 1684 | resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" 1685 | 1686 | string-width@^1.0.1: 1687 | version "1.0.2" 1688 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 1689 | dependencies: 1690 | code-point-at "^1.0.0" 1691 | is-fullwidth-code-point "^1.0.0" 1692 | strip-ansi "^3.0.0" 1693 | 1694 | "string-width@^1.0.2 || 2": 1695 | version "2.1.1" 1696 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 1697 | dependencies: 1698 | is-fullwidth-code-point "^2.0.0" 1699 | strip-ansi "^4.0.0" 1700 | 1701 | string_decoder@~0.10.x: 1702 | version "0.10.31" 1703 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 1704 | 1705 | string_decoder@~1.1.1: 1706 | version "1.1.1" 1707 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 1708 | dependencies: 1709 | safe-buffer "~5.1.0" 1710 | 1711 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 1712 | version "3.0.1" 1713 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1714 | dependencies: 1715 | ansi-regex "^2.0.0" 1716 | 1717 | strip-ansi@^4.0.0: 1718 | version "4.0.0" 1719 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 1720 | dependencies: 1721 | ansi-regex "^3.0.0" 1722 | 1723 | strip-bom@^2.0.0: 1724 | version "2.0.0" 1725 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" 1726 | dependencies: 1727 | is-utf8 "^0.2.0" 1728 | 1729 | strip-bom@^3.0.0: 1730 | version "3.0.0" 1731 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 1732 | 1733 | strip-indent@^1.0.1: 1734 | version "1.0.1" 1735 | resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" 1736 | dependencies: 1737 | get-stdin "^4.0.1" 1738 | 1739 | strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: 1740 | version "2.0.1" 1741 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1742 | 1743 | subscriptions-transport-ws@^0.9.15, subscriptions-transport-ws@^0.9.8: 1744 | version "0.9.16" 1745 | resolved "https://registry.yarnpkg.com/subscriptions-transport-ws/-/subscriptions-transport-ws-0.9.16.tgz#90a422f0771d9c32069294c08608af2d47f596ec" 1746 | dependencies: 1747 | backo2 "^1.0.2" 1748 | eventemitter3 "^3.1.0" 1749 | iterall "^1.2.1" 1750 | symbol-observable "^1.0.4" 1751 | ws "^5.2.0" 1752 | 1753 | symbol-observable@^1.0.4: 1754 | version "1.2.0" 1755 | resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" 1756 | 1757 | synchronous-promise@^2.0.6: 1758 | version "2.0.7" 1759 | resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.7.tgz#3574b3d2fae86b145356a4b89103e1577f646fe3" 1760 | 1761 | tar@^4: 1762 | version "4.4.8" 1763 | resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" 1764 | dependencies: 1765 | chownr "^1.1.1" 1766 | fs-minipass "^1.2.5" 1767 | minipass "^2.3.4" 1768 | minizlib "^1.1.1" 1769 | mkdirp "^0.5.0" 1770 | safe-buffer "^5.1.2" 1771 | yallist "^3.0.2" 1772 | 1773 | toidentifier@1.0.0: 1774 | version "1.0.0" 1775 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" 1776 | 1777 | toposort@^2.0.2: 1778 | version "2.0.2" 1779 | resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" 1780 | 1781 | tough-cookie@^2.0.0: 1782 | version "2.5.0" 1783 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" 1784 | dependencies: 1785 | psl "^1.1.28" 1786 | punycode "^2.1.1" 1787 | 1788 | tree-kill@^1.2.1: 1789 | version "1.2.1" 1790 | resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a" 1791 | 1792 | trim-newlines@^1.0.0: 1793 | version "1.0.0" 1794 | resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" 1795 | 1796 | ts-invariant@^0.2.1: 1797 | version "0.2.1" 1798 | resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.2.1.tgz#3d587f9d6e3bded97bf9ec17951dd9814d5a9d3f" 1799 | dependencies: 1800 | tslib "^1.9.3" 1801 | 1802 | ts-invariant@^0.3.2: 1803 | version "0.3.3" 1804 | resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.3.3.tgz#b5742b1885ecf9e29c31a750307480f045ec0b16" 1805 | dependencies: 1806 | tslib "^1.9.3" 1807 | 1808 | ts-node-dev@^1.0.0-pre.38: 1809 | version "1.0.0-pre.38" 1810 | resolved "https://registry.yarnpkg.com/ts-node-dev/-/ts-node-dev-1.0.0-pre.38.tgz#5cbeececf19d6de2a750f947e0bdef5ec8d330c1" 1811 | dependencies: 1812 | dateformat "~1.0.4-1.2.3" 1813 | dynamic-dedupe "^0.3.0" 1814 | filewatcher "~3.0.0" 1815 | minimist "^1.1.3" 1816 | mkdirp "^0.5.1" 1817 | node-notifier "^5.4.0" 1818 | resolve "^1.0.0" 1819 | rimraf "^2.6.1" 1820 | tree-kill "^1.2.1" 1821 | ts-node "*" 1822 | tsconfig "^7.0.0" 1823 | 1824 | ts-node@*, ts-node@^8.1.0: 1825 | version "8.1.0" 1826 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.1.0.tgz#8c4b37036abd448577db22a061fd7a67d47e658e" 1827 | dependencies: 1828 | arg "^4.1.0" 1829 | diff "^3.1.0" 1830 | make-error "^1.1.1" 1831 | source-map-support "^0.5.6" 1832 | yn "^3.0.0" 1833 | 1834 | tsconfig@^7.0.0: 1835 | version "7.0.0" 1836 | resolved "https://registry.yarnpkg.com/tsconfig/-/tsconfig-7.0.0.tgz#84538875a4dc216e5c4a5432b3a4dec3d54e91b7" 1837 | dependencies: 1838 | "@types/strip-bom" "^3.0.0" 1839 | "@types/strip-json-comments" "0.0.30" 1840 | strip-bom "^3.0.0" 1841 | strip-json-comments "^2.0.0" 1842 | 1843 | tslib@^1.9.3: 1844 | version "1.9.3" 1845 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" 1846 | 1847 | type-is@~1.6.16, type-is@~1.6.17: 1848 | version "1.6.18" 1849 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 1850 | dependencies: 1851 | media-typer "0.3.0" 1852 | mime-types "~2.1.24" 1853 | 1854 | typedarray@^0.0.6: 1855 | version "0.0.6" 1856 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 1857 | 1858 | typescript@^3.4.5: 1859 | version "3.4.5" 1860 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" 1861 | 1862 | unpipe@1.0.0, unpipe@~1.0.0: 1863 | version "1.0.0" 1864 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 1865 | 1866 | uppercamelcase@^3.0.0: 1867 | version "3.0.0" 1868 | resolved "https://registry.yarnpkg.com/uppercamelcase/-/uppercamelcase-3.0.0.tgz#380b321b8d73cba16fec4d752a575152d1ef7317" 1869 | dependencies: 1870 | camelcase "^4.1.0" 1871 | 1872 | url@0.10.3: 1873 | version "0.10.3" 1874 | resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" 1875 | dependencies: 1876 | punycode "1.3.2" 1877 | querystring "0.2.0" 1878 | 1879 | util-deprecate@~1.0.1: 1880 | version "1.0.2" 1881 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1882 | 1883 | utils-merge@1.0.1: 1884 | version "1.0.1" 1885 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 1886 | 1887 | uuid@3.3.2, uuid@^3.1.0: 1888 | version "3.3.2" 1889 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" 1890 | 1891 | validate-npm-package-license@^3.0.1: 1892 | version "3.0.4" 1893 | resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" 1894 | dependencies: 1895 | spdx-correct "^3.0.0" 1896 | spdx-expression-parse "^3.0.0" 1897 | 1898 | vary@^1, vary@~1.1.2: 1899 | version "1.1.2" 1900 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 1901 | 1902 | whatwg-fetch@2.0.4: 1903 | version "2.0.4" 1904 | resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" 1905 | 1906 | which@^1.2.9, which@^1.3.0: 1907 | version "1.3.1" 1908 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 1909 | dependencies: 1910 | isexe "^2.0.0" 1911 | 1912 | wide-align@^1.1.0: 1913 | version "1.1.3" 1914 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 1915 | dependencies: 1916 | string-width "^1.0.2 || 2" 1917 | 1918 | wrappy@1: 1919 | version "1.0.2" 1920 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1921 | 1922 | ws@^5.2.0: 1923 | version "5.2.2" 1924 | resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" 1925 | dependencies: 1926 | async-limiter "~1.0.0" 1927 | 1928 | ws@^6.1.0: 1929 | version "6.2.1" 1930 | resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" 1931 | dependencies: 1932 | async-limiter "~1.0.0" 1933 | 1934 | xml2js@0.4.19: 1935 | version "0.4.19" 1936 | resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" 1937 | dependencies: 1938 | sax ">=0.6.0" 1939 | xmlbuilder "~9.0.1" 1940 | 1941 | xmlbuilder@~9.0.1: 1942 | version "9.0.7" 1943 | resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" 1944 | 1945 | xtend@^4.0.0: 1946 | version "4.0.1" 1947 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 1948 | 1949 | yallist@^2.1.2: 1950 | version "2.1.2" 1951 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" 1952 | 1953 | yallist@^3.0.0, yallist@^3.0.2: 1954 | version "3.0.3" 1955 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" 1956 | 1957 | yn@^3.0.0: 1958 | version "3.1.0" 1959 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.0.tgz#fcbe2db63610361afcc5eb9e0ac91e976d046114" 1960 | 1961 | yup@^0.27.0: 1962 | version "0.27.0" 1963 | resolved "https://registry.yarnpkg.com/yup/-/yup-0.27.0.tgz#f8cb198c8e7dd2124beddc2457571329096b06e7" 1964 | dependencies: 1965 | "@babel/runtime" "^7.0.0" 1966 | fn-name "~2.0.1" 1967 | lodash "^4.17.11" 1968 | property-expr "^1.5.0" 1969 | synchronous-promise "^2.0.6" 1970 | toposort "^2.0.2" 1971 | 1972 | zen-observable-ts@^0.8.18: 1973 | version "0.8.18" 1974 | resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.18.tgz#ade44b1060cc4a800627856ec10b9c67f5f639c8" 1975 | dependencies: 1976 | tslib "^1.9.3" 1977 | zen-observable "^0.8.0" 1978 | 1979 | zen-observable@^0.8.0, zen-observable@^0.8.10: 1980 | version "0.8.14" 1981 | resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.14.tgz#d33058359d335bc0db1f0af66158b32872af3bf7" 1982 | -------------------------------------------------------------------------------- /frontend/.env.example: -------------------------------------------------------------------------------- 1 | REACT_APP_GRAPHQL_URI=http://localhost:4000/graphql 2 | FIREBASE_TOKEN=********** -------------------------------------------------------------------------------- /frontend/.firebase/hosting.YnVpbGQ.cache: -------------------------------------------------------------------------------- 1 | asset-manifest.json,1557915089138,0ceb80e31ebfb0fb739fc276a1da8bf3df25862d8ad850a9bf1cb96cb4b995d0 2 | index.html,1557915089138,7b01e852faea7027fb849568becbc6f2c2e180f94c035f9af03c7190277e7a77 3 | manifest.json,1557915083227,ed7b98046be74c7d1476b73ebb8cd1f00c2b34443af1525af60b9dd20be9fb9a 4 | favicon.ico,1557915083227,c599b7a91ab3627e3538125d9f40adc2d4bf949046984262670545dc7738af06 5 | precache-manifest.054774adbe886ee6e3c29227ef1745b5.js,1557915089138,710ceb1056fa5141d012d9f2e25e19d2c606f42ab88b1428d79409bfe26bd324 6 | static/css/main.2cce8147.chunk.css,1557915089141,b9c69d66cd84115e1b35024ac47b97d62c87a897e11ff2fdbd6fe6b78e7f6714 7 | service-worker.js,1557915089138,e8867d9f497f4f875b05eb6a3ff41efcbe2f19d7f61a614cb73c8daea68ffbb7 8 | static/css/main.2cce8147.chunk.css.map,1557915089140,7871a4f9bddf7b4113ed375a13d42f9d23f2917b7648f96ba6e6e2c11d99b064 9 | static/js/main.28647029.chunk.js,1557915089141,5385710edd60715c8b50a1435523ae0be8d839bd42531641131070cfec2f2ca7 10 | static/js/runtime~main.a8a9905a.js,1557915089139,5b0313db8c475761662a933e703f2a6bd16847cdfc34b81915f5dd56862e4e77 11 | static/media/logo.5d5d9eef.svg,1557915089139,414f02d8e5eb2008c3a2411956a98e4913cade810cb6b474882dd41b2271fd6b 12 | static/js/main.28647029.chunk.js.map,1557915089141,7475927cf21000dc05fab1f08acdba98616090ba69e12e640da13ba569ca8d34 13 | static/js/runtime~main.a8a9905a.js.map,1557915089141,2510643041ce395196dfc3f9ae31cd72d7127dbd8457479959c6e22dd1b1eaeb 14 | static/js/2.b41502e9.chunk.js,1557915089142,490286ef5f4efb50af47996fdc9ecec5234631646f51583a19b45d4bba3749ae 15 | static/js/2.b41502e9.chunk.js.map,1557915089143,49c2db8ab19d6f4b4702a4bbe0b0e588958073316eed09f328efaecc3eeeec66 16 | -------------------------------------------------------------------------------- /frontend/.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "messenger-application-240708" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /frontend/firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "build", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "/index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@material-ui/core": "^4.0.0-rc.0", 7 | "@material-ui/icons": "^4.0.0-rc.0", 8 | "apollo-cache-inmemory": "^1.6.0", 9 | "apollo-client": "^2.6.0", 10 | "apollo-link": "^1.2.11", 11 | "apollo-link-error": "^1.1.10", 12 | "apollo-link-http": "^1.5.14", 13 | "apollo-link-state": "^0.4.2", 14 | "apollo-link-ws": "^1.0.17", 15 | "apollo-utilities": "^1.3.0", 16 | "clsx": "^1.0.4", 17 | "formik": "^1.5.7", 18 | "lodash.get": "^4.4.2", 19 | "react": "^16.8.6", 20 | "react-apollo": "^2.5.5", 21 | "react-apollo-hooks": "^0.4.5", 22 | "react-dom": "^16.8.6", 23 | "react-router": "^5.0.0", 24 | "react-router-dom": "^5.0.0", 25 | "react-scripts": "3.0.1", 26 | "typescript": "3.4.5", 27 | "use-react-router": "^1.0.6" 28 | }, 29 | "scripts": { 30 | "start": "react-scripts start", 31 | "build": "react-scripts build", 32 | "test": "react-scripts test", 33 | "eject": "react-scripts eject" 34 | }, 35 | "eslintConfig": { 36 | "extends": "../.eslintrc.js" 37 | }, 38 | "browserslist": { 39 | "production": [ 40 | ">0.2%", 41 | "not dead", 42 | "not op_mini all" 43 | ], 44 | "development": [ 45 | "last 1 chrome version", 46 | "last 1 firefox version", 47 | "last 1 safari version" 48 | ] 49 | }, 50 | "devDependencies": { 51 | "@types/lodash.get": "^4.4.6", 52 | "@types/jest": "24.0.13", 53 | "@types/node": "12.0.2", 54 | "@types/react": "16.8.18", 55 | "@types/react-dom": "16.8.4", 56 | "@types/react-router-dom": "^4.3.3" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DylanMerigaud/react-prisma-typescript-fullstack/936d90e266571588aee4fbfc480eddc5284e9775/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 22 | React Prisma Typescript Fullstack 23 | 24 | 25 | 26 |
27 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /frontend/src/App.test.tsx: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /frontend/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { ApolloClient } from 'apollo-client' 4 | import { InMemoryCache } from 'apollo-cache-inmemory' 5 | import { HttpLink } from 'apollo-link-http' 6 | import { onError } from 'apollo-link-error' 7 | import { withClientState } from 'apollo-link-state' 8 | import { ApolloLink, Observable, Operation } from 'apollo-link' 9 | 10 | import { ApolloProvider } from 'react-apollo' 11 | 12 | import { ApolloProvider as ApolloHooksProvider } from 'react-apollo-hooks' 13 | 14 | import Layout from './components/layout/Layout' 15 | 16 | const cache = new InMemoryCache({ 17 | cacheRedirects: { 18 | Query: { 19 | movie: (_, { id }, { getCacheKey }) => 20 | getCacheKey({ __typename: 'Movie', id }), 21 | }, 22 | }, 23 | }) 24 | 25 | const request = async (operation: Operation) => { 26 | const token = localStorage.getItem('token') 27 | operation.setContext({ 28 | headers: { 29 | authorization: 'Bearer ' + token, 30 | }, 31 | }) 32 | } 33 | 34 | const requestLink = new ApolloLink( 35 | (operation, forward) => 36 | new Observable((observer) => { 37 | let handle: ZenObservable.Subscription | undefined 38 | Promise.resolve(operation) 39 | .then((oper) => request(oper)) 40 | .then(() => { 41 | handle = !!forward 42 | ? forward(operation).subscribe({ 43 | next: observer.next.bind(observer), 44 | error: observer.error.bind(observer), 45 | complete: observer.complete.bind(observer), 46 | }) 47 | : undefined 48 | }) 49 | .catch(observer.error.bind(observer)) 50 | 51 | return () => { 52 | if (handle) handle.unsubscribe() 53 | } 54 | }), 55 | ) 56 | 57 | const client = new ApolloClient({ 58 | link: ApolloLink.from([ 59 | onError(({ graphQLErrors, networkError }) => { 60 | if (graphQLErrors) { 61 | // sendToLoggingService(graphQLErrors); 62 | } 63 | if (networkError) { 64 | // logoutUser(); 65 | } 66 | }), 67 | requestLink, 68 | withClientState({ 69 | defaults: { 70 | isConnected: true, 71 | }, 72 | resolvers: { 73 | Mutation: { 74 | updateNetworkStatus: ( 75 | _: undefined, 76 | { isConnected }: { isConnected: boolean }, 77 | { 78 | cache, 79 | }: { 80 | cache: { 81 | writeData: (data: { data: { isConnected: boolean } }) => void 82 | } 83 | }, 84 | ) => { 85 | cache.writeData({ data: { isConnected } }) 86 | return null 87 | }, 88 | }, 89 | }, 90 | cache, 91 | }), 92 | new HttpLink({ 93 | uri: process.env.REACT_APP_GRAPHQL_URI || 'http://localhost:4000/graphql', 94 | // credentials: 'include' TODO: what is include 95 | }), 96 | ]), 97 | cache, 98 | }) 99 | 100 | const App: React.FC = () => { 101 | return ( 102 | 103 | 104 | 108 | 109 | 110 | 111 | ) 112 | } 113 | 114 | export default App 115 | -------------------------------------------------------------------------------- /frontend/src/components/AuthRoute.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Route, Redirect } from 'react-router-dom' 3 | 4 | const AuthRoute = ({ ...rest }) => { 5 | const token = localStorage.getItem('token') 6 | return token ? : 7 | } 8 | 9 | export default AuthRoute 10 | -------------------------------------------------------------------------------- /frontend/src/components/NoAuthRoute.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Route, Redirect } from 'react-router-dom' 3 | 4 | const PrivateRoute = ({ ...rest }) => { 5 | const token = localStorage.getItem('token') 6 | return !token ? : 7 | } 8 | 9 | export default PrivateRoute 10 | -------------------------------------------------------------------------------- /frontend/src/components/NotFound.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Redirect } from 'react-router' 3 | 4 | const NotFound: React.FC = (props) => { 5 | if (!localStorage.getItem('token')) return 6 | 7 | return
Not Found
8 | } 9 | 10 | export default NotFound 11 | -------------------------------------------------------------------------------- /frontend/src/components/auth/Login.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useCallback } from 'react' 2 | import { Formik, FormikActions } from 'formik' 3 | 4 | import TextField from '@material-ui/core/TextField' 5 | import Box from '@material-ui/core/Box' 6 | import Paper from '@material-ui/core/Paper' 7 | import Button from '@material-ui/core/Button' 8 | 9 | import gql from 'graphql-tag' 10 | import { useMutation } from 'react-apollo-hooks' 11 | 12 | import * as Yup from 'yup' 13 | 14 | import useReactRouter from 'use-react-router' 15 | 16 | import UserType from './../../types/User' 17 | 18 | const LoginSchema = Yup.object().shape({ 19 | email: Yup.string() 20 | .min(2, 'Too Short!') 21 | .max(50, 'Too Long!') 22 | .email('Not a email.') 23 | .required('Required'), 24 | password: Yup.string() 25 | .min(2, 'Too Short!') 26 | .max(50, 'Too Long!') 27 | .required('Required'), 28 | }) 29 | 30 | interface Props {} 31 | 32 | interface Form { 33 | email: string 34 | password: string 35 | } 36 | type FormValues = Record 37 | 38 | interface LoginMutationResponse { 39 | login: { 40 | token: string 41 | user: UserType 42 | } 43 | } 44 | 45 | const Login: React.FC = () => { 46 | const loginMutation = useMutation(LOGIN_MUTATION) 47 | const { history } = useReactRouter() 48 | const [error, setError] = useState() 49 | 50 | const handleSubmit = useCallback( 51 | (values: FormValues, { setSubmitting }: FormikActions) => { 52 | setError(undefined) 53 | loginMutation({ 54 | variables: { 55 | email: values.email, 56 | password: values.password, 57 | }, 58 | }) 59 | .then((res) => { 60 | if (!res.data) return 61 | // console.log('login success: ', res.data.login) 62 | 63 | localStorage.setItem('token', res.data.login.token) 64 | history.push('/') 65 | }) 66 | .catch((e) => { 67 | console.error(e) 68 | setError(e.message) 69 | setSubmitting(false) 70 | }) 71 | }, 72 | [history, loginMutation], 73 | ) 74 | 75 | return ( 76 | 85 | 86 | 87 |

Login

88 | 93 | {({ 94 | values, 95 | errors, 96 | touched, 97 | handleChange, 98 | handleBlur, 99 | handleSubmit, 100 | isSubmitting, 101 | }) => ( 102 | 103 |
104 | 112 | {errors.email && touched.email && errors.email} 113 | 121 | {errors.password && touched.password && errors.password} 122 | 123 | 131 | 132 | 133 |
134 | )} 135 |
136 | 137 | 138 | 139 | {error} 140 |
141 |
142 |
143 | ) 144 | } 145 | 146 | const LOGIN_MUTATION = gql` 147 | mutation Login($email: String!, $password: String!) { 148 | login(email: $email, password: $password) { 149 | token 150 | user { 151 | id 152 | name 153 | role 154 | } 155 | } 156 | } 157 | ` 158 | 159 | export default Login 160 | -------------------------------------------------------------------------------- /frontend/src/components/auth/Signup.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useCallback } from 'react' 2 | import { Formik, FormikActions } from 'formik' 3 | 4 | import TextField from '@material-ui/core/TextField' 5 | import Box from '@material-ui/core/Box' 6 | import Paper from '@material-ui/core/Paper' 7 | import Button from '@material-ui/core/Button' 8 | 9 | import gql from 'graphql-tag' 10 | import { useMutation } from 'react-apollo-hooks' 11 | 12 | import UserType from './../../types/User' 13 | 14 | import * as Yup from 'yup' 15 | 16 | import useReactRouter from 'use-react-router' 17 | 18 | const SignupSchema = Yup.object().shape({ 19 | name: Yup.string() 20 | .min(2, 'Too Short!') 21 | .max(50, 'Too Long!') 22 | .required('Required'), 23 | email: Yup.string() 24 | .min(2, 'Too Short!') 25 | .max(50, 'Too Long!') 26 | .email('Not a email.') 27 | .required('Required'), 28 | password: Yup.string() 29 | .min(2, 'Too Short!') 30 | .max(50, 'Too Long!') 31 | .required('Required'), 32 | }) 33 | 34 | interface Props {} 35 | 36 | interface Form { 37 | name: string 38 | email: string 39 | password: string 40 | } 41 | type FormValues = Record 42 | 43 | interface SignupMutationResponse { 44 | signup: { 45 | token: string 46 | user: UserType 47 | } 48 | } 49 | 50 | const Signup: React.FC = () => { 51 | const signupMutation = useMutation(SIGNUP_MUTATION) 52 | const { history } = useReactRouter() 53 | const [error, setError] = useState() 54 | 55 | const handleSubmit = useCallback( 56 | (values: FormValues, { setSubmitting }: FormikActions) => { 57 | setError(undefined) 58 | signupMutation({ 59 | variables: { 60 | name: values.name, 61 | email: values.email, 62 | password: values.password, 63 | }, 64 | }) 65 | .then((res) => { 66 | if (!res.data) throw Error() 67 | // console.log('signup success: ', res.data.login) 68 | 69 | localStorage.setItem('token', res.data.signup.token) 70 | history.push('/') 71 | }) 72 | .catch((e) => { 73 | console.error(e) 74 | setError(e.message) 75 | setSubmitting(false) 76 | }) 77 | }, 78 | [history, signupMutation], 79 | ) 80 | 81 | return ( 82 | 91 | 92 | 93 |

Signup

94 | 99 | {({ 100 | values, 101 | errors, 102 | touched, 103 | handleChange, 104 | handleBlur, 105 | handleSubmit, 106 | isSubmitting, 107 | }) => ( 108 | 109 |
110 | 118 | {errors.name && touched.name && errors.name} 119 | 127 | {errors.email && touched.email && errors.email} 128 | 136 | {errors.password && touched.password && errors.password} 137 | 138 | 146 | 147 | 148 |
149 | )} 150 |
151 | 152 | 153 | 154 | {error} 155 |
156 |
157 |
158 | ) 159 | } 160 | 161 | const SIGNUP_MUTATION = gql` 162 | mutation Signup($name: String!, $email: String!, $password: String!) { 163 | signup(name: $name, email: $email, password: $password) { 164 | token 165 | user { 166 | id 167 | name 168 | role 169 | } 170 | } 171 | } 172 | ` 173 | 174 | export default Signup 175 | -------------------------------------------------------------------------------- /frontend/src/components/layout/AuthLayout.tsx: -------------------------------------------------------------------------------- 1 | import React, { 2 | useState, 3 | useEffect, 4 | useCallback, 5 | ReactChild, 6 | useRef, 7 | } from 'react' 8 | import { makeStyles, Theme } from '@material-ui/core/styles' 9 | import clsx from 'clsx' 10 | 11 | import Header from './../layout/Header' 12 | import Drawer from './../layout/Drawer' 13 | 14 | const initialState = { 15 | isDrawerOpen: true, 16 | isMobile: false, 17 | } 18 | 19 | const drawerWidth = 240 20 | 21 | const useStyles = makeStyles((theme: Theme) => ({ 22 | content: { 23 | flexGrow: 1, 24 | padding: theme.spacing(4), 25 | transition: theme.transitions.create('margin', { 26 | easing: theme.transitions.easing.sharp, 27 | duration: theme.transitions.duration.leavingScreen, 28 | }), 29 | marginLeft: -drawerWidth, 30 | }, 31 | contentMobile: { 32 | marginLeft: 0, 33 | }, 34 | contentShift: { 35 | transition: theme.transitions.create('margin', { 36 | easing: theme.transitions.easing.easeOut, 37 | duration: theme.transitions.duration.enteringScreen, 38 | }), 39 | marginLeft: 0, 40 | }, 41 | drawerHeader: { 42 | display: 'flex', 43 | alignItems: 'center', 44 | padding: '0 8px', 45 | ...theme.mixins.toolbar, 46 | justifyContent: 'flex-end', 47 | }, 48 | })) 49 | 50 | const AuthLayout: React.FC = ({ children }) => { 51 | const [state, setState] = useState(initialState) 52 | const classes = useStyles({}) 53 | const checkIsMobile = useCallback( 54 | () => (window.innerWidth < 600 ? true : false), 55 | [], 56 | ) 57 | 58 | const resize = useCallback(() => { 59 | setState((currentState) => ({ 60 | ...currentState, 61 | isMobile: checkIsMobile(), 62 | isDrawerOpen: checkIsMobile() ? false : true, 63 | })) 64 | }, [checkIsMobile]) 65 | 66 | const initialResizeCalled = useRef(false) 67 | useEffect(() => { 68 | window.addEventListener('resize', resize) 69 | if (!initialResizeCalled.current) { 70 | resize() 71 | initialResizeCalled.current = true 72 | } 73 | return () => { 74 | window.removeEventListener('resize', resize) 75 | } 76 | }, [resize]) 77 | 78 | const handleDrawerClose = useCallback( 79 | () => 80 | setState((currentState) => ({ ...currentState, isDrawerOpen: false })), 81 | [], 82 | ) 83 | const handleDrawerOpen = useCallback( 84 | () => setState((currentState) => ({ ...currentState, isDrawerOpen: true })), 85 | [], 86 | ) 87 | 88 | return ( 89 | 90 | 96 |
101 |
107 |
108 | {children} 109 |
110 | 111 | ) 112 | } 113 | 114 | interface Props { 115 | children: ReactChild 116 | } 117 | 118 | export default AuthLayout 119 | -------------------------------------------------------------------------------- /frontend/src/components/layout/Drawer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { makeStyles, Theme } from '@material-ui/core/styles' 3 | import Drawer from '@material-ui/core/Drawer' 4 | import IconButton from '@material-ui/core/IconButton' 5 | import ListItem from '@material-ui/core/ListItem' 6 | import ListItemText from '@material-ui/core/ListItemText' 7 | import ChevronLeftIcon from '@material-ui/icons/ChevronLeft' 8 | import Divider from '@material-ui/core/Divider' 9 | import List from '@material-ui/core/List' 10 | import { Link } from 'react-router-dom' 11 | import useReactRouter from 'use-react-router' 12 | 13 | const drawerWidth = 240 14 | 15 | const useStyles = makeStyles((theme: Theme) => ({ 16 | drawer: { 17 | width: drawerWidth, 18 | flexShrink: 0, 19 | }, 20 | drawerPaper: { 21 | width: drawerWidth, 22 | }, 23 | drawerHeader: { 24 | display: 'flex', 25 | alignItems: 'center', 26 | padding: '0 8px', 27 | ...theme.mixins.toolbar, 28 | justifyContent: 'flex-end', 29 | }, 30 | })) 31 | 32 | const items = [ 33 | { 34 | name: 'Feed', 35 | href: '/', 36 | }, 37 | { 38 | name: 'Drafts', 39 | href: '/drafts', 40 | }, 41 | { 42 | name: 'Create Draft', 43 | href: '/create', 44 | }, 45 | ] 46 | 47 | interface Props { 48 | open: boolean 49 | onDrawerClose: () => void 50 | isMobile: boolean 51 | onClose: () => void 52 | } 53 | 54 | const MyDrawer: React.FC = ({ 55 | open, 56 | onDrawerClose, 57 | isMobile, 58 | onClose, 59 | }) => { 60 | const classes = useStyles({}) 61 | 62 | const { history } = useReactRouter() 63 | 64 | return ( 65 | 75 |
76 | 77 | 78 | 79 |
80 | 81 | 82 | {items.map((item, index) => ( 83 | 90 | {/* {index % 2 === 0 ? : } */} 91 | 92 | 93 | ))} 94 | 95 | 96 |
97 | ) 98 | } 99 | 100 | export default MyDrawer 101 | -------------------------------------------------------------------------------- /frontend/src/components/layout/Header.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useCallback } from 'react' 2 | 3 | import { makeStyles, Theme } from '@material-ui/core/styles' 4 | import IconButton from '@material-ui/core/IconButton' 5 | import AppBar from '@material-ui/core/AppBar' 6 | import Toolbar from '@material-ui/core/Toolbar' 7 | import MenuIcon from '@material-ui/icons/Menu' 8 | import Typography from '@material-ui/core/Typography' 9 | import MoreVertIcon from '@material-ui/icons/MoreVert' 10 | 11 | import clsx from 'clsx' 12 | import useReactRouter from 'use-react-router' 13 | 14 | import HeaderMenu from './HeaderMenu' 15 | 16 | const drawerWidth = 240 17 | 18 | const useStyles = makeStyles((theme: Theme) => ({ 19 | appBar: { 20 | transition: theme.transitions.create(['margin', 'width'], { 21 | easing: theme.transitions.easing.sharp, 22 | duration: theme.transitions.duration.leavingScreen, 23 | }), 24 | }, 25 | appBarShift: { 26 | width: `calc(100% - ${drawerWidth}px)`, 27 | marginLeft: drawerWidth, 28 | transition: theme.transitions.create(['margin', 'width'], { 29 | easing: theme.transitions.easing.easeOut, 30 | duration: theme.transitions.duration.enteringScreen, 31 | }), 32 | }, 33 | menuButton: { 34 | marginRight: theme.spacing(2), 35 | }, 36 | hide: { 37 | display: 'none', 38 | }, 39 | title: { 40 | flexGrow: 1, 41 | }, 42 | moreVert: { 43 | color: 'white', 44 | }, 45 | })) 46 | 47 | interface Props { 48 | isDrawerOpen: boolean 49 | onDrawerOpen: () => void 50 | isMobile: boolean 51 | } 52 | 53 | const Header: React.FC = ({ isDrawerOpen, onDrawerOpen, isMobile }) => { 54 | const [menuAnchorEl, setMenuAnchorEl] = useState(null) 55 | const classes = useStyles({}) 56 | 57 | const { history } = useReactRouter() 58 | 59 | const handleMenuOpen = useCallback( 60 | (e: any) => { 61 | setMenuAnchorEl(e.currentTarget) 62 | }, 63 | [setMenuAnchorEl], 64 | ) 65 | 66 | const handleMenuClose = useCallback(() => { 67 | setMenuAnchorEl(null) 68 | }, [setMenuAnchorEl]) 69 | 70 | const handleLogout = useCallback(() => { 71 | handleMenuClose() 72 | localStorage.removeItem('token') 73 | history.push('/login') 74 | }, [handleMenuClose, history]) 75 | 76 | const handleToProfile = useCallback(() => { 77 | handleMenuClose() 78 | history.push('/profile') 79 | }, [handleMenuClose, history]) 80 | 81 | return ( 82 | 88 | 89 | 99 | 100 | 101 | 102 | React Prisma Typescript Fullstack 103 | 104 | 110 | 111 | 112 | 118 | 119 | 120 | ) 121 | } 122 | 123 | export default Header 124 | -------------------------------------------------------------------------------- /frontend/src/components/layout/HeaderMenu.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Menu from '@material-ui/core/Menu' 4 | import MenuItem from '@material-ui/core/MenuItem' 5 | 6 | interface Props { 7 | anchorEl: Element | null 8 | onClose: () => void 9 | onLogout: () => void 10 | onToProfile: () => void 11 | } 12 | 13 | const HeaderMenu: React.FC = ({ 14 | anchorEl, 15 | onClose, 16 | onLogout, 17 | onToProfile, 18 | }) => { 19 | return ( 20 | 21 | Profile 22 | Logout 23 | 24 | ) 25 | } 26 | 27 | export default HeaderMenu 28 | -------------------------------------------------------------------------------- /frontend/src/components/layout/Layout.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { BrowserRouter as Router } from 'react-router-dom' 3 | 4 | import GlobalRoutes from './../../routes/GlobalRoutes' 5 | import Box from '@material-ui/core/Box' 6 | 7 | const Layout: React.FC = () => { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | ) 15 | } 16 | 17 | export default Layout 18 | -------------------------------------------------------------------------------- /frontend/src/components/post/DialogConfirmDelete.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Dialog from '@material-ui/core/Dialog' 4 | import DialogActions from '@material-ui/core/DialogActions' 5 | import DialogContent from '@material-ui/core/DialogContent' 6 | import DialogContentText from '@material-ui/core/DialogContentText' 7 | import DialogTitle from '@material-ui/core/DialogTitle' 8 | import Button from '@material-ui/core/Button' 9 | 10 | interface Props { 11 | open: boolean 12 | title: string 13 | onClose: () => void 14 | onConfirm: () => void 15 | } 16 | 17 | const DialogConfirmDelete: React.FC = ({ 18 | open, 19 | title, 20 | onClose, 21 | onConfirm, 22 | }) => { 23 | return ( 24 | 30 | 31 | {'Delete `' + title + '` ?'} 32 | 33 | 34 | 35 | This action is not reversible. 36 | 37 | 38 | 39 | 42 | 45 | 46 | 47 | ) 48 | } 49 | 50 | export default DialogConfirmDelete 51 | -------------------------------------------------------------------------------- /frontend/src/components/post/Drafts.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback } from 'react' 2 | import { useQuery } from 'react-apollo-hooks' 3 | 4 | import Button from '@material-ui/core/Button' 5 | 6 | import gql from 'graphql-tag' 7 | import get from 'lodash.get' 8 | 9 | import PostType from './../../types/Post' 10 | 11 | import PostList from './PostList' 12 | 13 | interface FeedQueryResponse { 14 | drafts: { 15 | pageInfo: { 16 | hasNextPage: boolean 17 | endCursor: string 18 | } 19 | edges: { 20 | node: PostType 21 | }[] 22 | aggregate: { 23 | count: number 24 | } 25 | } 26 | } 27 | 28 | interface DraftsQueryResponse { 29 | drafts: { 30 | pageInfo: { 31 | hasNextPage: boolean 32 | endCursor: string 33 | } 34 | edges: { 35 | node: PostType 36 | }[] 37 | aggregate: { 38 | count: number 39 | } 40 | } 41 | } 42 | 43 | const Drafts: React.FC = () => { 44 | const draftsQuery = useQuery(DRAFTS_QUERY) 45 | 46 | const handleLoadMore = useCallback(() => { 47 | if (!draftsQuery || !draftsQuery.data || !draftsQuery.data.drafts) return 48 | draftsQuery.fetchMore({ 49 | variables: { 50 | after: draftsQuery.data.drafts.pageInfo.endCursor, 51 | }, 52 | updateQuery: (previousResult, { fetchMoreResult }) => { 53 | if (!fetchMoreResult) { 54 | return previousResult 55 | } 56 | return { 57 | drafts: { 58 | __typename: 'PostConnection', 59 | aggregate: fetchMoreResult.drafts.aggregate, 60 | pageInfo: fetchMoreResult.drafts.pageInfo, 61 | edges: [ 62 | ...previousResult.drafts.edges, 63 | ...fetchMoreResult.drafts.edges, 64 | ], 65 | }, 66 | } 67 | }, 68 | }) 69 | }, [draftsQuery]) 70 | 71 | return ( 72 |
73 |

Drafts

74 | {draftsQuery && draftsQuery.data && draftsQuery.data.drafts && ( 75 | e.node)} 77 | /> 78 | )} 79 | {get(draftsQuery, 'data.drafts.pageInfo.hasNextPage') && ( 80 | 81 | )} 82 |
83 | ) 84 | } 85 | 86 | const DRAFTS_QUERY = gql` 87 | query Drafts( 88 | $after: String 89 | $orderBy: PostOrderByInput 90 | $where: PostWhereInput 91 | $skip: Int 92 | ) { 93 | drafts( 94 | after: $after 95 | orderBy: $orderBy 96 | where: $where 97 | first: 5 98 | skip: $skip 99 | ) { 100 | pageInfo { 101 | hasNextPage 102 | endCursor 103 | } 104 | edges { 105 | node { 106 | id 107 | title 108 | author { 109 | id 110 | name 111 | } 112 | } 113 | } 114 | aggregate { 115 | count 116 | } 117 | } 118 | } 119 | ` 120 | 121 | export default Drafts 122 | -------------------------------------------------------------------------------- /frontend/src/components/post/Feed.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback } from 'react' 2 | import { useQuery } from 'react-apollo-hooks' 3 | 4 | import Button from '@material-ui/core/Button' 5 | 6 | import gql from 'graphql-tag' 7 | import get from 'lodash.get' 8 | 9 | import PostType from './../../types/Post' 10 | 11 | import PostList from './PostList' 12 | 13 | interface FeedQueryResponse { 14 | feed: { 15 | pageInfo: { 16 | hasNextPage: boolean 17 | endCursor: string 18 | } 19 | edges: { 20 | node: PostType 21 | }[] 22 | aggregate: { 23 | count: number 24 | } 25 | } 26 | } 27 | 28 | const Feed: React.FC = () => { 29 | const feedQuery = useQuery(FEED_QUERY) 30 | 31 | const handleLoadMore = useCallback(() => { 32 | if (!feedQuery || !feedQuery.data || !feedQuery.data.feed) return 33 | feedQuery.fetchMore({ 34 | variables: { 35 | after: feedQuery.data.feed.pageInfo.endCursor, 36 | }, 37 | updateQuery: (previousResult, { fetchMoreResult }) => { 38 | if (!fetchMoreResult) { 39 | return previousResult 40 | } 41 | return { 42 | feed: { 43 | __typename: 'PostConnection', 44 | aggregate: fetchMoreResult.feed.aggregate, 45 | pageInfo: fetchMoreResult.feed.pageInfo, 46 | edges: [ 47 | ...previousResult.feed.edges, 48 | ...fetchMoreResult.feed.edges, 49 | ], 50 | }, 51 | } 52 | }, 53 | }) 54 | }, [feedQuery]) 55 | 56 | return ( 57 |
58 |

Feed

59 | {feedQuery.data && feedQuery.data.feed && ( 60 | e.node)} /> 61 | )} 62 | {get(feedQuery, 'data.feed.pageInfo.hasNextPage') && ( 63 | 64 | )} 65 |
66 | ) 67 | } 68 | 69 | const FEED_QUERY = gql` 70 | query Feed( 71 | $after: String 72 | $orderBy: PostOrderByInput 73 | $where: PostWhereInput 74 | $skip: Int 75 | ) { 76 | feed( 77 | after: $after 78 | orderBy: $orderBy 79 | where: $where 80 | first: 5 81 | skip: $skip 82 | ) { 83 | pageInfo { 84 | hasNextPage 85 | endCursor 86 | } 87 | edges { 88 | node { 89 | id 90 | title 91 | author { 92 | id 93 | name 94 | } 95 | } 96 | } 97 | aggregate { 98 | count 99 | } 100 | } 101 | } 102 | ` 103 | 104 | export default Feed 105 | -------------------------------------------------------------------------------- /frontend/src/components/post/Post.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import PostType from './../../types/Post' 4 | 5 | import ListItem from '@material-ui/core/ListItem' 6 | import ListItemText from '@material-ui/core/ListItemText' 7 | 8 | import { Link } from 'react-router-dom' 9 | 10 | interface Props { 11 | post: PostType 12 | } 13 | 14 | const PostList: React.FC = ({ post }) => { 15 | return ( 16 | 17 | 18 | 19 | ) 20 | } 21 | 22 | export default PostList 23 | -------------------------------------------------------------------------------- /frontend/src/components/post/PostCreate.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useContext, useCallback } from 'react' 2 | import { Formik, FormikActions } from 'formik' 3 | 4 | import TextField from '@material-ui/core/TextField' 5 | import Box from '@material-ui/core/Box' 6 | import Paper from '@material-ui/core/Paper' 7 | import Button from '@material-ui/core/Button' 8 | 9 | import gql from 'graphql-tag' 10 | import { useMutation, useApolloClient } from 'react-apollo-hooks' 11 | 12 | import * as Yup from 'yup' 13 | 14 | import useReactRouter from 'use-react-router' 15 | 16 | import PostType from './../../types/Post' 17 | 18 | import MeQueryContext from './../../context/MeQueryContext' 19 | 20 | const PostCreateSchema = Yup.object().shape({ 21 | title: Yup.string() 22 | .min(2, 'Too Short!') 23 | .max(50, 'Too Long!') 24 | .required('Required'), 25 | }) 26 | 27 | interface Props {} 28 | 29 | interface Form { 30 | title: string 31 | } 32 | type FormValues = Record 33 | 34 | interface CreateDraftMutationResponse { 35 | createDraft: PostType 36 | } 37 | 38 | const Login: React.FC = () => { 39 | const createDraftMutation = useMutation( 40 | CREATE_DRAFT_MUTATION, 41 | ) 42 | const { history } = useReactRouter() 43 | const [error, setError] = useState() 44 | 45 | const meQuery = useContext(MeQueryContext) 46 | const client = useApolloClient() 47 | 48 | const handleSubmit = useCallback( 49 | (values: FormValues, { setSubmitting }: FormikActions) => { 50 | if (!meQuery || !meQuery.data) return 51 | 52 | setError(undefined) 53 | createDraftMutation({ 54 | variables: { 55 | title: values.title, 56 | authorId: meQuery.data.me.id, 57 | }, 58 | }) 59 | .then((res) => { 60 | if (!res.data) return 61 | client.resetStore().then(() => history.push('/drafts')) 62 | }) 63 | .catch((e) => { 64 | console.error(e) 65 | setError(e.message) 66 | setSubmitting(false) 67 | }) 68 | }, 69 | [client, createDraftMutation, history, meQuery], 70 | ) 71 | 72 | return ( 73 | 74 | 75 |

Create Draft

76 | 81 | {({ 82 | values, 83 | errors, 84 | touched, 85 | handleChange, 86 | handleBlur, 87 | handleSubmit, 88 | isSubmitting, 89 | /* and other goodies */ 90 | }) => ( 91 | 92 |
93 | 101 | {errors.title && touched.title && errors.title} 102 | 103 | 106 | 107 | 108 |
109 | )} 110 |
111 | {error} 112 |
113 |
114 | ) 115 | } 116 | 117 | const CREATE_DRAFT_MUTATION = gql` 118 | mutation CreateDraft($authorId: ID!, $title: String!) { 119 | createDraft(authorId: $authorId, title: $title) { 120 | id 121 | title 122 | author { 123 | id 124 | name 125 | } 126 | } 127 | } 128 | ` 129 | 130 | export default Login 131 | -------------------------------------------------------------------------------- /frontend/src/components/post/PostDetail.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useContext, useCallback } from 'react' 2 | 3 | import PostType from './../../types/Post' 4 | 5 | import Button from '@material-ui/core/Button' 6 | 7 | import { Link } from 'react-router-dom' 8 | 9 | import { useMutation, useApolloClient, useQuery } from 'react-apollo-hooks' 10 | import gql from 'graphql-tag' 11 | 12 | import useReactRouter from 'use-react-router' 13 | import MeQueryContext from '../../context/MeQueryContext' 14 | import DialogConfirmDelete from './DialogConfirmDelete' 15 | 16 | interface PostQueryResponse { 17 | post: PostType 18 | } 19 | 20 | interface PublishMutationResponse { 21 | publish: PostType 22 | } 23 | 24 | interface DeleteMutationResponse { 25 | deletePost: PostType 26 | } 27 | 28 | interface MatchParam { 29 | id: string 30 | } 31 | 32 | const PostDetail: React.FC = () => { 33 | const [error, setError] = useState() 34 | const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false) 35 | const { match, history } = useReactRouter() 36 | const client = useApolloClient() 37 | const meQuery = useContext(MeQueryContext) 38 | 39 | const postQuery = useQuery(POST_QUERY, { 40 | variables: { 41 | where: { id: match.params.id }, 42 | }, 43 | }) 44 | 45 | const publishMutation = useMutation(PUBLISH_MUTATION) 46 | 47 | const deleteMutation = useMutation(DELETE_MUTATION) 48 | 49 | const handlePublish = useCallback(() => { 50 | if (!postQuery.data) return 51 | 52 | publishMutation({ 53 | variables: { 54 | id: postQuery.data.post.id, 55 | }, 56 | }) 57 | .then(() => { 58 | client.resetStore().then(() => history.push('/')) 59 | }) 60 | .catch((e) => { 61 | setError(e.message) 62 | }) 63 | }, [client, history, postQuery.data, publishMutation]) 64 | 65 | const handleDeleteDialogClose = useCallback(() => { 66 | setIsDeleteDialogOpen(false) 67 | }, []) 68 | 69 | const handleDelete = useCallback(() => { 70 | if (!postQuery.data) return 71 | 72 | deleteMutation({ 73 | variables: { 74 | where: { id: postQuery.data.post.id }, 75 | }, 76 | }) 77 | .then(() => { 78 | client.resetStore().then(() => { 79 | handleDeleteDialogClose() 80 | history.push( 81 | postQuery.data && postQuery.data.post.published ? '/' : '/drafts', 82 | ) 83 | }) 84 | }) 85 | .catch((e) => { 86 | setError(e.message) 87 | }) 88 | }, [client, deleteMutation, handleDeleteDialogClose, history, postQuery.data]) 89 | 90 | const handleDeleteDialogOpen = useCallback(() => { 91 | setIsDeleteDialogOpen(true) 92 | }, []) 93 | 94 | if (!meQuery || !meQuery.data || !postQuery || !postQuery.data) 95 | return
ERROR
96 | if (meQuery.loading || postQuery.loading) return
Loading
97 | if (postQuery.error) 98 | return
Post query error: {postQuery.error.message}
99 | if (meQuery.error) return
Me query error: {meQuery.error.message}
100 | if (!postQuery.data.post) return
Post not found
101 | 102 | const isOwner = postQuery.data.post.author.id === meQuery.data.me.id 103 | 104 | return ( 105 |
106 |

{postQuery.data.post.title}

107 | {isOwner && ( 108 | 114 | )} 115 | {isOwner && !postQuery.data.post.published && ( 116 | 117 | )} 118 | {isOwner && } 119 | {error} 120 | 126 |
127 | ) 128 | } 129 | 130 | const PUBLISH_MUTATION = gql` 131 | mutation Publish($id: ID!) { 132 | publish(id: $id) { 133 | id 134 | title 135 | } 136 | } 137 | ` 138 | 139 | const DELETE_MUTATION = gql` 140 | mutation DeletePost($where: PostWhereUniqueInput!) { 141 | deletePost(where: $where) { 142 | id 143 | } 144 | } 145 | ` 146 | 147 | const POST_QUERY = gql` 148 | query Post($where: PostWhereUniqueInput!) { 149 | post(where: $where) { 150 | id 151 | title 152 | published 153 | author { 154 | id 155 | name 156 | } 157 | } 158 | } 159 | ` 160 | 161 | export default PostDetail 162 | -------------------------------------------------------------------------------- /frontend/src/components/post/PostEdit.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useCallback } from 'react' 2 | import { Formik, FormikActions } from 'formik' 3 | 4 | import TextField from '@material-ui/core/TextField' 5 | import Box from '@material-ui/core/Box' 6 | import Paper from '@material-ui/core/Paper' 7 | import Button from '@material-ui/core/Button' 8 | 9 | import gql from 'graphql-tag' 10 | import { useMutation, useApolloClient, useQuery } from 'react-apollo-hooks' 11 | 12 | import * as Yup from 'yup' 13 | 14 | import useReactRouter from 'use-react-router' 15 | 16 | import PostType from './../../types/Post' 17 | 18 | const PostCreateSchema = Yup.object().shape({ 19 | title: Yup.string() 20 | .min(2, 'Too Short!') 21 | .max(50, 'Too Long!') 22 | .required('Required'), 23 | }) 24 | 25 | interface Props {} 26 | 27 | interface Form { 28 | title: string 29 | } 30 | type FormValues = Record 31 | 32 | interface PostQueryResponse { 33 | post: PostType 34 | } 35 | 36 | interface UpdatePostMutationResponse { 37 | updatePost: PostType 38 | } 39 | 40 | interface MatchParam { 41 | id: string 42 | } 43 | 44 | const PostEdit: React.FC = () => { 45 | const createDraftMutation = useMutation( 46 | UPDATE_POST_MUTATION, 47 | ) 48 | const { history, match } = useReactRouter() 49 | const [error, setError] = useState() 50 | 51 | const client = useApolloClient() 52 | const postQuery = useQuery(POST_QUERY, { 53 | variables: { 54 | where: { 55 | id: match.params.id, 56 | }, 57 | }, 58 | }) 59 | 60 | const handleSubmit = useCallback( 61 | (values: FormValues, { setSubmitting }: FormikActions) => { 62 | if (!postQuery || !postQuery.data || !postQuery.data.post) return 63 | 64 | setError(undefined) 65 | createDraftMutation({ 66 | variables: { 67 | data: { 68 | title: values.title, 69 | }, 70 | where: { 71 | id: postQuery.data.post.id, 72 | }, 73 | }, 74 | }) 75 | .then((res) => { 76 | if (!res.data) return 77 | client 78 | .resetStore() 79 | .then(() => 80 | history.push( 81 | postQuery.data && postQuery.data.post.published 82 | ? '/' 83 | : '/drafts', 84 | ), 85 | ) // TODO wtf typescript 86 | }) 87 | .catch((e) => { 88 | console.error(e) 89 | setError(e.message) 90 | setSubmitting(false) 91 | }) 92 | }, 93 | [client, createDraftMutation, history, postQuery], 94 | ) 95 | 96 | if (!postQuery || !postQuery.data) return
ERROR
97 | if (postQuery.loading) return
Loading
98 | if (postQuery.error) 99 | return
Post query error: {postQuery.error.message}
// TODO Error || Loading 100 | if (!postQuery.data.post) return
Post not found
101 | 102 | return ( 103 | 104 | 105 |

Update {postQuery.data.post.published ? 'Post' : 'Draft'}

106 | 111 | {({ 112 | values, 113 | errors, 114 | touched, 115 | handleChange, 116 | handleBlur, 117 | handleSubmit, 118 | isSubmitting, 119 | /* and other goodies */ 120 | }) => ( 121 | 122 |
123 | 131 | {errors.title && touched.title && errors.title} 132 | 133 | 136 | 137 | 138 |
139 | )} 140 |
141 | {error} 142 |
143 |
144 | ) 145 | } 146 | 147 | const POST_QUERY = gql` 148 | query Post($where: PostWhereUniqueInput!) { 149 | post(where: $where) { 150 | id 151 | title 152 | author { 153 | id 154 | name 155 | } 156 | published 157 | } 158 | } 159 | ` 160 | 161 | const UPDATE_POST_MUTATION = gql` 162 | mutation UpdatePost($data: PostUpdateInput!, $where: PostWhereUniqueInput!) { 163 | updatePost(data: $data, where: $where) { 164 | id 165 | title 166 | author { 167 | id 168 | name 169 | } 170 | } 171 | } 172 | ` 173 | 174 | export default PostEdit 175 | -------------------------------------------------------------------------------- /frontend/src/components/post/PostList.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import PostType from './../../types/Post' 4 | 5 | import List from '@material-ui/core/List' 6 | 7 | import Post from './Post' 8 | 9 | interface Props { 10 | posts: PostType[] 11 | } 12 | 13 | const PostList: React.FC = ({ posts }) => { 14 | return ( 15 | 16 | {posts.map((post) => ( 17 | 18 | ))} 19 | 20 | ) 21 | } 22 | 23 | export default PostList 24 | -------------------------------------------------------------------------------- /frontend/src/components/user/Profile.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | import MeQueryContext from '../../context/MeQueryContext' 3 | 4 | const Profile = () => { 5 | const meQuery = useContext(MeQueryContext) 6 | 7 | if (!meQuery || !meQuery.data) return
Error
8 | if (meQuery.loading) return
Loading
9 | if (meQuery.error) return
{meQuery.error.message}
10 | 11 | return ( 12 |
13 |

{meQuery.data.me.name}

14 |

{meQuery.data.me.email}

15 |
16 | ) 17 | } 18 | 19 | export default Profile 20 | -------------------------------------------------------------------------------- /frontend/src/constants/auth.ts: -------------------------------------------------------------------------------- 1 | export const AUTH_TOKEN = 'auth-token' 2 | export const USER_TOKEN = 'userToken' 3 | -------------------------------------------------------------------------------- /frontend/src/context/MeQueryContext.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { QueryHookResult } from 'react-apollo-hooks' 3 | import { OperationVariables } from 'apollo-client' 4 | 5 | import UserType from './../types/User' 6 | 7 | export interface MeQueryResponse { 8 | me: UserType 9 | } 10 | 11 | export default React.createContext< 12 | QueryHookResult | undefined 13 | >(undefined) 14 | -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 4 | 'Droid Sans', 'Helvetica Neue', sans-serif; 5 | -webkit-font-smoothing: antialiased; 6 | -moz-osx-font-smoothing: grayscale; 7 | } 8 | 9 | code { 10 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; 11 | } 12 | 13 | a { 14 | text-decoration: none; 15 | /* color: black; */ 16 | } 17 | -------------------------------------------------------------------------------- /frontend/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import './index.css' 4 | import App from './App' 5 | import * as serviceWorker from './serviceWorker' 6 | 7 | ReactDOM.render(, document.getElementById('root')) 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: https://bit.ly/CRA-PWA 12 | serviceWorker.unregister() 13 | -------------------------------------------------------------------------------- /frontend/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /frontend/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /frontend/src/routes/GlobalRoutes.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Switch } from 'react-router-dom' 3 | 4 | import RoutesAuth from './RoutesAuth' 5 | 6 | import Login from './../components/auth/Login' 7 | import Signup from './../components/auth/Signup' 8 | 9 | import NoAuthRoute from './../components/NoAuthRoute' 10 | 11 | const GlobalRoutes: React.FC = () => { 12 | return ( 13 | 14 | 15 | 16 | 17 | 18 | ) 19 | } 20 | 21 | export default GlobalRoutes 22 | -------------------------------------------------------------------------------- /frontend/src/routes/RoutesAuth.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import { Route, Switch } from 'react-router-dom' 4 | import NotFound from './../components/NotFound' 5 | 6 | import { useQuery } from 'react-apollo-hooks' 7 | 8 | import gql from 'graphql-tag' 9 | 10 | import AuthRoute from './../components/AuthRoute' 11 | import AuthLayout from './../components/layout/AuthLayout' 12 | 13 | import Feed from './../components/post/Feed' 14 | import Drafts from './../components/post/Drafts' 15 | import PostCreate from './../components/post/PostCreate' 16 | import PostDetail from './../components/post/PostDetail' 17 | import PostEdit from './../components/post/PostEdit' 18 | import Profile from './../components/user/Profile' 19 | 20 | import MeQueryContext, { MeQueryResponse } from './../context/MeQueryContext' 21 | 22 | const RoutesAuth: React.FC = () => { 23 | const meQuery = useQuery(ME_QUERY) 24 | 25 | return ( 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | ) 40 | } 41 | 42 | const ME_QUERY = gql` 43 | query Me { 44 | me { 45 | id 46 | name 47 | email 48 | role 49 | } 50 | } 51 | ` 52 | 53 | export default RoutesAuth 54 | -------------------------------------------------------------------------------- /frontend/src/serviceWorker.ts: -------------------------------------------------------------------------------- 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 | interface Config { 24 | onSuccess?: (registration: ServiceWorkerRegistration) => void 25 | onUpdate?: (registration: ServiceWorkerRegistration) => void 26 | } 27 | 28 | export function register(config?: Config) { 29 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 30 | // The URL constructor is available in all browsers that support SW. 31 | const publicUrl = new URL( 32 | (process as { env: { [key: string]: string } }).env.PUBLIC_URL, 33 | window.location.href, 34 | ) 35 | if (publicUrl.origin !== window.location.origin) { 36 | // Our service worker won't work if PUBLIC_URL is on a different origin 37 | // from what our page is served on. This might happen if a CDN is used to 38 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 39 | return 40 | } 41 | 42 | window.addEventListener('load', () => { 43 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js` 44 | 45 | if (isLocalhost) { 46 | // This is running on localhost. Let's check if a service worker still exists or not. 47 | checkValidServiceWorker(swUrl, config) 48 | 49 | // Add some additional logging to localhost, pointing developers to the 50 | // service worker/PWA documentation. 51 | navigator.serviceWorker.ready.then(() => { 52 | console.log( 53 | 'This web app is being served cache-first by a service ' + 54 | 'worker. To learn more, visit https://bit.ly/CRA-PWA', 55 | ) 56 | }) 57 | } else { 58 | // Is not localhost. Just register service worker 59 | registerValidSW(swUrl, config) 60 | } 61 | }) 62 | } 63 | } 64 | 65 | function registerValidSW(swUrl: string, config?: Config) { 66 | navigator.serviceWorker 67 | .register(swUrl) 68 | .then((registration) => { 69 | registration.onupdatefound = () => { 70 | const installingWorker = registration.installing 71 | if (installingWorker == null) { 72 | return 73 | } 74 | installingWorker.onstatechange = () => { 75 | if (installingWorker.state === 'installed') { 76 | if (navigator.serviceWorker.controller) { 77 | // At this point, the updated precached content has been fetched, 78 | // but the previous service worker will still serve the older 79 | // content until all client tabs are closed. 80 | console.log( 81 | 'New content is available and will be used when all ' + 82 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.', 83 | ) 84 | 85 | // Execute callback 86 | if (config && config.onUpdate) { 87 | config.onUpdate(registration) 88 | } 89 | } else { 90 | // At this point, everything has been precached. 91 | // It's the perfect time to display a 92 | // "Content is cached for offline use." message. 93 | console.log('Content is cached for offline use.') 94 | 95 | // Execute callback 96 | if (config && config.onSuccess) { 97 | config.onSuccess(registration) 98 | } 99 | } 100 | } 101 | } 102 | } 103 | }) 104 | .catch((error) => { 105 | console.error('Error during service worker registration:', error) 106 | }) 107 | } 108 | 109 | function checkValidServiceWorker(swUrl: string, config?: Config) { 110 | // Check if the service worker can be found. If it can't reload the page. 111 | fetch(swUrl) 112 | .then((response) => { 113 | // Ensure service worker exists, and that we really are getting a JS file. 114 | const contentType = response.headers.get('content-type') 115 | if ( 116 | response.status === 404 || 117 | (contentType != null && contentType.indexOf('javascript') === -1) 118 | ) { 119 | // No service worker found. Probably a different app. Reload the page. 120 | navigator.serviceWorker.ready.then((registration) => { 121 | registration.unregister().then(() => { 122 | window.location.reload() 123 | }) 124 | }) 125 | } else { 126 | // Service worker found. Proceed as normal. 127 | registerValidSW(swUrl, config) 128 | } 129 | }) 130 | .catch(() => { 131 | console.log( 132 | 'No internet connection found. App is running in offline mode.', 133 | ) 134 | }) 135 | } 136 | 137 | export function unregister() { 138 | if ('serviceWorker' in navigator) { 139 | navigator.serviceWorker.ready.then((registration) => { 140 | registration.unregister() 141 | }) 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /frontend/src/types/Post.ts: -------------------------------------------------------------------------------- 1 | import UserType from './User' 2 | 3 | interface Post { 4 | id: string 5 | title: string 6 | published: boolean 7 | author: UserType 8 | } 9 | 10 | export default Post 11 | -------------------------------------------------------------------------------- /frontend/src/types/User.ts: -------------------------------------------------------------------------------- 1 | interface User { 2 | name: string 3 | id: string 4 | email: string 5 | role: Role 6 | } 7 | 8 | enum Role { 9 | USER, 10 | ADMIN, 11 | } 12 | 13 | export default User 14 | -------------------------------------------------------------------------------- /frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "module": "esnext", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "isolatedModules": true, 19 | "noEmit": true, 20 | "jsx": "preserve" 21 | }, 22 | "include": [ 23 | "src" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-prisma-typescript-fullstack", 3 | "version": "1.0.0", 4 | "repository": "git@github.com:DylanMerigaud/messenger-project.git", 5 | "author": "DylanMerigaud ", 6 | "contributors": [ 7 | "Léopold Szabatura " 8 | ], 9 | "license": "MIT", 10 | "workspaces": { 11 | "packages": [ 12 | "backend", 13 | "frontend" 14 | ] 15 | }, 16 | "private": true, 17 | "devDependencies": { 18 | "@typescript-eslint/eslint-plugin": "^1.9.0", 19 | "@typescript-eslint/parser": "^1.9.0", 20 | "babel-eslint": "^10.0.1", 21 | "eslint": "^5.16.0", 22 | "eslint-config-prettier": "^4.3.0", 23 | "eslint-config-react-app": "^4.0.1", 24 | "eslint-plugin-flowtype": "^3.9.0", 25 | "eslint-plugin-import": "^2.17.2", 26 | "eslint-plugin-jsx-a11y": "^6.2.1", 27 | "eslint-plugin-prettier": "^3.1.0", 28 | "eslint-plugin-react": "^7.13.0", 29 | "eslint-plugin-react-hooks": "^1.6.0", 30 | "husky": "^2.3.0", 31 | "lint-staged": "^8.1.7", 32 | "prettier": "^1.17.1", 33 | "tslint": "^5.16.0" 34 | }, 35 | "husky": { 36 | "hooks": { 37 | "pre-commit": "lint-staged" 38 | } 39 | }, 40 | "lint-staged": { 41 | "*.{js,jsx,ts,tsx,css,json,md}": [ 42 | "prettier --write", 43 | "git add" 44 | ], 45 | "*.{js,jsx,ts,tsx}": [ 46 | "eslint --fix", 47 | "git add" 48 | ] 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: 'all', 3 | tabWidth: 2, 4 | semi: false, 5 | singleQuote: true, 6 | arrowParens: 'always', 7 | } 8 | --------------------------------------------------------------------------------