├── .DS_Store ├── .gitignore ├── .nowignore ├── .vscode └── settings.json ├── README.md ├── lerna.json ├── now.json ├── package.json ├── packages ├── app │ ├── .babelrc │ ├── .buckconfig │ ├── .flowconfig │ ├── .gitattributes │ ├── .gitignore │ ├── .watchmanconfig │ ├── App.js │ ├── App.tsx │ ├── LICENSE │ ├── README.md │ ├── android │ │ ├── app │ │ │ ├── BUCK │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── assets │ │ │ │ └── fonts │ │ │ │ │ ├── AntDesign.ttf │ │ │ │ │ ├── Entypo.ttf │ │ │ │ │ ├── EvilIcons.ttf │ │ │ │ │ ├── Feather.ttf │ │ │ │ │ ├── FontAwesome.ttf │ │ │ │ │ ├── FontAwesome5_Brands.ttf │ │ │ │ │ ├── FontAwesome5_Regular.ttf │ │ │ │ │ ├── FontAwesome5_Solid.ttf │ │ │ │ │ ├── Foundation.ttf │ │ │ │ │ ├── Ionicons.ttf │ │ │ │ │ ├── MaterialCommunityIcons.ttf │ │ │ │ │ ├── MaterialIcons.ttf │ │ │ │ │ ├── Octicons.ttf │ │ │ │ │ ├── SimpleLineIcons.ttf │ │ │ │ │ └── Zocial.ttf │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── app │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ └── MainApplication.java │ │ │ │ └── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ └── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ ├── keystores │ │ │ ├── BUCK │ │ │ └── debug.keystore.properties │ │ └── settings.gradle │ ├── app.json │ ├── index.js │ ├── ios │ │ ├── app-tvOS │ │ │ └── Info.plist │ │ ├── app-tvOSTests │ │ │ └── Info.plist │ │ ├── app.xcodeproj │ │ │ ├── project.pbxproj │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ ├── app-tvOS.xcscheme │ │ │ │ └── app.xcscheme │ │ ├── app │ │ │ ├── AppDelegate.h │ │ │ ├── AppDelegate.m │ │ │ ├── Base.lproj │ │ │ │ └── LaunchScreen.xib │ │ │ ├── Images.xcassets │ │ │ │ ├── AppIcon.appiconset │ │ │ │ │ └── Contents.json │ │ │ │ └── Contents.json │ │ │ ├── Info.plist │ │ │ └── main.m │ │ └── appTests │ │ │ ├── Info.plist │ │ │ └── appTests.m │ ├── package.json │ ├── package.json~ │ ├── redirect_ports.sh │ ├── setup.js │ ├── src │ │ ├── App.tsx │ │ ├── assets │ │ │ ├── backArrow.png │ │ │ ├── correctSign.png │ │ │ ├── hang.jpg │ │ │ └── index.tsx │ │ ├── components │ │ │ ├── ActionButton.tsx │ │ │ ├── Button.tsx │ │ │ ├── Checkbox.tsx │ │ │ ├── Header.tsx │ │ │ ├── HeaderHome.tsx │ │ │ ├── Input.tsx │ │ │ ├── Loading.tsx │ │ │ ├── LowerIOSAdaption.tsx │ │ │ ├── PetItem.tsx │ │ │ ├── Shimmer.tsx │ │ │ └── Text.tsx │ │ ├── config │ │ │ ├── ApolloEnv.tsx │ │ │ ├── Router.tsx │ │ │ └── theme.tsx │ │ ├── screens │ │ │ ├── Chat.tsx │ │ │ ├── Home.tsx │ │ │ ├── Login.tsx │ │ │ └── SignUp.tsx │ │ └── utils.js │ ├── tsconfig.json │ └── yarn.lock ├── server │ ├── .babelrc │ ├── .env │ ├── .env.example │ ├── .eslintrc │ ├── .flowconfig │ ├── .gitignore │ ├── .yarnclean │ ├── Dockerfile │ ├── README.md │ ├── circle.yml │ ├── data │ │ ├── schema.graphql │ │ └── schema.json │ ├── dist │ │ ├── TypeDefinition.js │ │ ├── app.js │ │ ├── auth.js │ │ ├── config.js │ │ ├── connection │ │ │ ├── ConversationConnection.js │ │ │ ├── MessageConnection.js │ │ │ ├── PetConnection.js │ │ │ └── UserConnection.js │ │ ├── database.js │ │ ├── index.js │ │ ├── interface │ │ │ └── NodeInterface.js │ │ ├── loader │ │ │ ├── ConversationLoader.js │ │ │ ├── MessageLoader.js │ │ │ ├── PetLoader.js │ │ │ ├── UserLoader.js │ │ │ └── index.js │ │ ├── model │ │ │ ├── Conversation.js │ │ │ ├── Message.js │ │ │ ├── Pet.js │ │ │ ├── User.js │ │ │ └── index.js │ │ ├── mutation │ │ │ ├── AddMessageMutation.js │ │ │ ├── ChangePasswordMutation.js │ │ │ ├── ConversationAddMutation.js │ │ │ ├── LoginEmailMutation.js │ │ │ ├── PetAddMutation.js │ │ │ ├── PetDeleteMutation.js │ │ │ ├── RegisterEmailMutation.js │ │ │ └── StartConversationMutation.js │ │ ├── schema.js │ │ └── type │ │ │ ├── ConversationType.js │ │ │ ├── MessageType.js │ │ │ ├── MutationType.js │ │ │ ├── PetType.js │ │ │ ├── QueryType.js │ │ │ └── UserType.js │ ├── docker-compose.test.yml │ ├── docker-compose.yml │ ├── flow-typed │ │ └── npm │ │ │ ├── babel-cli_vx.x.x.js │ │ │ ├── babel-eslint_vx.x.x.js │ │ │ ├── babel-polyfill_vx.x.x.js │ │ │ ├── babel-preset-es2015_vx.x.x.js │ │ │ ├── babel-preset-flow_vx.x.x.js │ │ │ ├── babel-preset-stage-0_vx.x.x.js │ │ │ ├── bcrypt-as-promised_vx.x.x.js │ │ │ ├── bcryptjs_vx.x.x.js │ │ │ ├── dotenv-safe_vx.x.x.js │ │ │ ├── eslint-config-airbnb_vx.x.x.js │ │ │ ├── eslint-plugin-import_vx.x.x.js │ │ │ ├── eslint_vx.x.x.js │ │ │ ├── flow-bin_v0.x.x.js │ │ │ ├── graphql-relay_vx.x.x.js │ │ │ ├── isomorphic-fetch_v2.x.x.js │ │ │ ├── jest-cli_vx.x.x.js │ │ │ ├── jest_v20.x.x.js │ │ │ ├── jsonwebtoken_vx.x.x.js │ │ │ ├── koa-bodyparser_vx.x.x.js │ │ │ ├── koa-compose_vx.x.x.js │ │ │ ├── koa-convert_vx.x.x.js │ │ │ ├── koa-cors_vx.x.x.js │ │ │ ├── koa-graphql-batch_vx.x.x.js │ │ │ ├── koa-graphql_vx.x.x.js │ │ │ ├── koa-logger_vx.x.x.js │ │ │ ├── koa-router_vx.x.x.js │ │ │ ├── koa_v2.x.x.js │ │ │ ├── koa_vx.x.x.js │ │ │ ├── mongoose_vx.x.x.js │ │ │ ├── nodemon_vx.x.x.js │ │ │ ├── reify_vx.x.x.js │ │ │ ├── repl-promised_vx.x.x.js │ │ │ ├── repl.history_vx.x.x.js │ │ │ ├── repl_vx.x.x.js │ │ │ └── rimraf_vx.x.x.js │ ├── package.json │ ├── repl.js │ ├── repl │ │ └── nodemon.json │ ├── scripts │ │ └── updateSchema.js │ ├── src │ │ ├── TypeDefinition.js │ │ ├── __tests__ │ │ │ └── auth.spec.js │ │ ├── app.js │ │ ├── auth.js │ │ ├── config.js │ │ ├── connection │ │ │ ├── ConversationConnection.js │ │ │ ├── MessageConnection.js │ │ │ ├── PetConnection.js │ │ │ └── UserConnection.js │ │ ├── database.js │ │ ├── index.js │ │ ├── interface │ │ │ ├── NodeInterface.js │ │ │ └── __tests__ │ │ │ │ └── NodeInterface.spec.js │ │ ├── loader │ │ │ ├── ConversationLoader.js │ │ │ ├── MessageLoader.js │ │ │ ├── PetLoader.js │ │ │ ├── UserLoader.js │ │ │ └── index.js │ │ ├── model │ │ │ ├── Conversation.js │ │ │ ├── Message.js │ │ │ ├── Pet.js │ │ │ ├── User.js │ │ │ └── index.js │ │ ├── mutation │ │ │ ├── AddMessageMutation.js │ │ │ ├── ChangePasswordMutation.js │ │ │ ├── ConversationAddMutation.js │ │ │ ├── LoginEmailMutation.js │ │ │ ├── PetAddMutation.js │ │ │ ├── PetDeleteMutation.js │ │ │ ├── RegisterEmailMutation.js │ │ │ ├── StartConversationMutation.js │ │ │ └── __tests__ │ │ │ │ ├── ChangePasswordMutation.spec.js │ │ │ │ ├── LoginEmailMutation.spec.js │ │ │ │ └── RegisterEmailMutation.spec.js │ │ ├── schema.js │ │ └── type │ │ │ ├── ConversationType.js │ │ │ ├── MessageType.js │ │ │ ├── MutationType.js │ │ │ ├── PetType.js │ │ │ ├── QueryType.js │ │ │ ├── UserType.js │ │ │ └── __tests__ │ │ │ └── UserType.spec.js │ ├── test │ │ ├── helper.js │ │ └── mongooseConnection.js │ └── yarn.lock └── web │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json │ ├── src │ ├── App.css │ ├── App.test.tsx │ ├── App.tsx │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ ├── react-app-env.d.ts │ └── serviceWorker.ts │ ├── tsconfig.json │ └── yarn.lock ├── yarn-error.log └── yarn.lock /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | */node_modules 2 | node_modules -------------------------------------------------------------------------------- /.nowignore: -------------------------------------------------------------------------------- 1 | packages/app 2 | packages/server/node_modules 3 | packages/web/node_modules 4 | packages/web/build 5 | .vscode 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[javascript]": { 3 | "editor.formatOnSave": false 4 | }, 5 | "editor.formatOnPaste": false, 6 | "eslint.autoFixOnSave": true, 7 | "editor.tabSize": 2, 8 | "editor.renderWhitespace": "all", 9 | "extensions.ignoreRecommendations": false, 10 | "editor.formatOnSave": true, 11 | "eslint.alwaysShowStatus": true, 12 | "prettier.disableLanguages": ["js"], 13 | "prettier.requireConfig": true, 14 | "javascript.updateImportsOnFileMove.enabled": "never", 15 | "tslint.autoFixOnSave": true, 16 | "tslint.alwaysShowStatus": true 17 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Foton Chat 2 | 3 | ## Why? 4 | Foton chat is an experimental application for the following stuffs we wanna try on Foton projects: 5 | - Hooks 6 | - Apollo Hooks 7 | - Subscriptions 8 | - Optimistic Update 9 | - Apollo link state 10 | - Chat Application 11 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmClient": "yarn", 3 | "packages": [ 4 | "packages/*" 5 | ], 6 | "version": "0.0.1" 7 | } 8 | -------------------------------------------------------------------------------- /now.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "name": "foton-chat", 4 | "public": true, 5 | "builds": [{ 6 | "src": "packages/web/package.json", 7 | "use": "@now/static-build", 8 | "config": { 9 | "distDir": "build" 10 | } 11 | }, 12 | { 13 | "src": "packages/server/dist/index.js", 14 | "use": "@now/node-server" 15 | } 16 | ], 17 | "routes": [{ 18 | "src": "^/graphql", 19 | "dest": "/packages/server/dist/index.js" 20 | }, 21 | { 22 | "src": "^/static/(.*)", 23 | "dest": "/packages/web/static/$1" 24 | }, 25 | { 26 | "src": "^/favicon.ico", 27 | "dest": "/packages/web/favicon.ico" 28 | }, 29 | { 30 | "src": "^/asset-manifest.json", 31 | "dest": "/packages/web/asset-manifest.json" 32 | }, 33 | { 34 | "src": "^/manifest.json", 35 | "dest": "/packages/web/manifest.json" 36 | }, 37 | { 38 | "src": "^/service-worker.js", 39 | "headers": { 40 | "cache-control": "s-maxage=0" 41 | }, 42 | "dest": "/packages/web/service-worker.js" 43 | }, 44 | { 45 | "src": "^/precache-manifest.(.*)", 46 | "dest": "/packages/web/precache-manifest.$1" 47 | }, 48 | { 49 | "src": "^/(.*)", 50 | "dest": "/packages/web/index.html" 51 | } 52 | ], 53 | "env": { 54 | "NODE_ENV": "development", 55 | "GRAPHQL_PORT": "5000", 56 | "JWT_KEY": "awesome_secret_key", 57 | "MONGO_URL": "mongodb://foton:foton123@ds151354.mlab.com:51354/fotonchat" 58 | } 59 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "devDependencies": { 5 | "lerna": "^3.8.5" 6 | }, 7 | "scripts": { 8 | "start:server": "lerna run watch --scope @foton/server --stream", 9 | "start:app": "lerna run start --scope @foton/app --stream" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/app/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["module:metro-react-native-babel-preset"] 3 | } 4 | -------------------------------------------------------------------------------- /packages/app/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /packages/app/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | 16 | ; Ignore polyfills 17 | .*/Libraries/polyfills/.* 18 | 19 | ; Ignore metro 20 | .*/node_modules/metro/.* 21 | 22 | [include] 23 | 24 | [libs] 25 | node_modules/react-native/Libraries/react-native/react-native-interface.js 26 | node_modules/react-native/flow/ 27 | node_modules/react-native/flow-github/ 28 | 29 | [options] 30 | emoji=true 31 | 32 | esproposal.optional_chaining=enable 33 | esproposal.nullish_coalescing=enable 34 | 35 | module.system=haste 36 | module.system.haste.use_name_reducers=true 37 | # get basename 38 | module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' 39 | # strip .js or .js.flow suffix 40 | module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' 41 | # strip .ios suffix 42 | module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' 43 | module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' 44 | module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' 45 | module.system.haste.paths.blacklist=.*/__tests__/.* 46 | module.system.haste.paths.blacklist=.*/__mocks__/.* 47 | module.system.haste.paths.blacklist=/node_modules/react-native/Libraries/Animated/src/polyfills/.* 48 | module.system.haste.paths.whitelist=/node_modules/react-native/Libraries/.* 49 | 50 | munge_underscores=true 51 | 52 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 53 | 54 | module.file_ext=.js 55 | module.file_ext=.jsx 56 | module.file_ext=.json 57 | module.file_ext=.native.js 58 | 59 | suppress_type=$FlowIssue 60 | suppress_type=$FlowFixMe 61 | suppress_type=$FlowFixMeProps 62 | suppress_type=$FlowFixMeState 63 | 64 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 65 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 66 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 67 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 68 | 69 | [version] 70 | ^0.78.0 71 | -------------------------------------------------------------------------------- /packages/app/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /packages/app/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # Visual Studio Code 34 | # 35 | .vscode/ 36 | 37 | # node.js 38 | # 39 | node_modules/ 40 | npm-debug.log 41 | yarn-error.log 42 | 43 | # BUCK 44 | buck-out/ 45 | \.buckd/ 46 | *.keystore 47 | 48 | # fastlane 49 | # 50 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 51 | # screenshots whenever they are needed. 52 | # For more information about the recommended setup visit: 53 | # https://docs.fastlane.tools/best-practices/source-control/ 54 | 55 | */fastlane/report.xml 56 | */fastlane/Preview.html 57 | */fastlane/screenshots 58 | 59 | # Bundle artifact 60 | *.jsbundle 61 | -------------------------------------------------------------------------------- /packages/app/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /packages/app/App.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | * @flow 7 | */ 8 | 9 | import React, {Component} from 'react'; 10 | import {Platform, StyleSheet, Text, View} from 'react-native'; 11 | 12 | const instructions = Platform.select({ 13 | ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu', 14 | android: 15 | 'Double tap R on your keyboard to reload,\n' + 16 | 'Shake or press menu button for dev menu', 17 | }); 18 | 19 | type Props = {}; 20 | export default class App extends Component { 21 | render() { 22 | return ( 23 | 24 | Welcome to React Native! 25 | To get started, edit App.js 26 | {instructions} 27 | 28 | ); 29 | } 30 | } 31 | 32 | const styles = StyleSheet.create({ 33 | container: { 34 | flex: 1, 35 | justifyContent: 'center', 36 | alignItems: 'center', 37 | backgroundColor: '#F5FCFF', 38 | }, 39 | welcome: { 40 | fontSize: 20, 41 | textAlign: 'center', 42 | margin: 10, 43 | }, 44 | instructions: { 45 | textAlign: 'center', 46 | color: '#333333', 47 | marginBottom: 5, 48 | }, 49 | }); 50 | -------------------------------------------------------------------------------- /packages/app/App.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * 5 | * Generated with the TypeScript template 6 | * https://github.com/emin93/react-native-template-typescript 7 | * 8 | * @format 9 | */ 10 | 11 | import React, {Component} from 'react'; 12 | import {Platform, StyleSheet, Text, View} from 'react-native'; 13 | 14 | const instructions = Platform.select({ 15 | ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu', 16 | android: 17 | 'Double tap R on your keyboard to reload,\n' + 18 | 'Shake or press menu button for dev menu', 19 | }); 20 | 21 | interface Props {} 22 | export default class App extends Component { 23 | render() { 24 | return ( 25 | 26 | Welcome to React Native! 27 | To get started, edit App.tsx 28 | {instructions} 29 | 30 | ); 31 | } 32 | } 33 | 34 | const styles = StyleSheet.create({ 35 | container: { 36 | flex: 1, 37 | justifyContent: 'center', 38 | alignItems: 'center', 39 | backgroundColor: '#F5FCFF', 40 | }, 41 | welcome: { 42 | fontSize: 20, 43 | textAlign: 'center', 44 | margin: 10, 45 | }, 46 | instructions: { 47 | textAlign: 'center', 48 | color: '#333333', 49 | marginBottom: 5, 50 | }, 51 | }); 52 | -------------------------------------------------------------------------------- /packages/app/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Emin Khateeb 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 | -------------------------------------------------------------------------------- /packages/app/android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | lib_deps = [] 12 | 13 | for jarfile in glob(['libs/*.jar']): 14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] 15 | lib_deps.append(':' + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | 21 | for aarfile in glob(['libs/*.aar']): 22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] 23 | lib_deps.append(':' + name) 24 | android_prebuilt_aar( 25 | name = name, 26 | aar = aarfile, 27 | ) 28 | 29 | android_library( 30 | name = "all-libs", 31 | exported_deps = lib_deps, 32 | ) 33 | 34 | android_library( 35 | name = "app-code", 36 | srcs = glob([ 37 | "src/main/java/**/*.java", 38 | ]), 39 | deps = [ 40 | ":all-libs", 41 | ":build_config", 42 | ":res", 43 | ], 44 | ) 45 | 46 | android_build_config( 47 | name = "build_config", 48 | package = "com.app", 49 | ) 50 | 51 | android_resource( 52 | name = "res", 53 | package = "com.app", 54 | res = "src/main/res", 55 | ) 56 | 57 | android_binary( 58 | name = "app", 59 | keystore = "//android/keystores:debug", 60 | manifest = "src/main/AndroidManifest.xml", 61 | package_type = "debug", 62 | deps = [ 63 | ":app-code", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /packages/app/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /packages/app/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 13 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/AntDesign.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/AntDesign.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/Entypo.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/Entypo.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/EvilIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/EvilIcons.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/Feather.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/Feather.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/FontAwesome.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/FontAwesome.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/FontAwesome5_Brands.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/FontAwesome5_Brands.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/FontAwesome5_Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/FontAwesome5_Regular.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/FontAwesome5_Solid.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/FontAwesome5_Solid.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/Foundation.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/Foundation.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/Ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/Ionicons.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/MaterialCommunityIcons.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/MaterialIcons.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/Octicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/Octicons.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/SimpleLineIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/SimpleLineIcons.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/assets/fonts/Zocial.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/assets/fonts/Zocial.ttf -------------------------------------------------------------------------------- /packages/app/android/app/src/main/java/com/app/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.app; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "app"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/app/android/app/src/main/java/com/app/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.app; 2 | 3 | import android.app.Application; 4 | 5 | import com.facebook.react.ReactApplication; 6 | import com.oblador.vectoricons.VectorIconsPackage; 7 | import com.facebook.react.ReactNativeHost; 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.shell.MainReactPackage; 10 | import com.facebook.soloader.SoLoader; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class MainApplication extends Application implements ReactApplication { 16 | 17 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 18 | @Override 19 | public boolean getUseDeveloperSupport() { 20 | return BuildConfig.DEBUG; 21 | } 22 | 23 | @Override 24 | protected List getPackages() { 25 | return Arrays.asList( 26 | new MainReactPackage(), 27 | new VectorIconsPackage() 28 | ); 29 | } 30 | 31 | @Override 32 | protected String getJSMainModuleName() { 33 | return "index"; 34 | } 35 | }; 36 | 37 | @Override 38 | public ReactNativeHost getReactNativeHost() { 39 | return mReactNativeHost; 40 | } 41 | 42 | @Override 43 | public void onCreate() { 44 | super.onCreate(); 45 | SoLoader.init(this, /* native exopackage */ false); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /packages/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /packages/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /packages/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /packages/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /packages/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/app/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | app 3 | 4 | -------------------------------------------------------------------------------- /packages/app/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/app/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "27.0.3" 6 | minSdkVersion = 16 7 | compileSdkVersion = 27 8 | targetSdkVersion = 26 9 | supportLibVersion = "27.1.1" 10 | } 11 | repositories { 12 | google() 13 | jcenter() 14 | } 15 | dependencies { 16 | classpath 'com.android.tools.build:gradle:3.1.4' 17 | 18 | // NOTE: Do not place your application dependencies here; they belong 19 | // in the individual module build.gradle files 20 | } 21 | } 22 | 23 | allprojects { 24 | repositories { 25 | mavenLocal() 26 | google() 27 | jcenter() 28 | maven { 29 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 30 | url "$rootDir/../node_modules/react-native/android" 31 | } 32 | } 33 | } 34 | 35 | 36 | task wrapper(type: Wrapper) { 37 | gradleVersion = '4.4' 38 | distributionUrl = distributionUrl.replace("bin", "all") 39 | } 40 | -------------------------------------------------------------------------------- /packages/app/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | -------------------------------------------------------------------------------- /packages/app/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /packages/app/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 6 | -------------------------------------------------------------------------------- /packages/app/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /packages/app/android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = "debug", 3 | properties = "debug.keystore.properties", 4 | store = "debug.keystore", 5 | visibility = [ 6 | "PUBLIC", 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /packages/app/android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /packages/app/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'app' 2 | include ':react-native-vector-icons' 3 | project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android') 4 | 5 | include ':app' 6 | -------------------------------------------------------------------------------- /packages/app/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "displayName": "app" 4 | } -------------------------------------------------------------------------------- /packages/app/index.js: -------------------------------------------------------------------------------- 1 | /** @format */ 2 | 3 | import {AppRegistry} from 'react-native'; 4 | import App from './src/App'; 5 | import {name as appName} from './app.json'; 6 | 7 | AppRegistry.registerComponent(appName, () => App); 8 | -------------------------------------------------------------------------------- /packages/app/ios/app-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | NSLocationWhenInUseUsageDescription 40 | 41 | NSAppTransportSecurity 42 | 43 | 44 | NSExceptionDomains 45 | 46 | localhost 47 | 48 | NSExceptionAllowsInsecureHTTPLoads 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /packages/app/ios/app-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /packages/app/ios/app/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | 10 | @interface AppDelegate : UIResponder 11 | 12 | @property (nonatomic, strong) UIWindow *window; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /packages/app/ios/app/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import "AppDelegate.h" 9 | 10 | #import 11 | #import 12 | 13 | @implementation AppDelegate 14 | 15 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 16 | { 17 | NSURL *jsCodeLocation; 18 | 19 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 20 | 21 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 22 | moduleName:@"app" 23 | initialProperties:nil 24 | launchOptions:launchOptions]; 25 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 26 | 27 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 28 | UIViewController *rootViewController = [UIViewController new]; 29 | rootViewController.view = rootView; 30 | self.window.rootViewController = rootViewController; 31 | [self.window makeKeyAndVisible]; 32 | return YES; 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /packages/app/ios/app/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /packages/app/ios/app/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/app/ios/app/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | app 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSLocationWhenInUseUsageDescription 28 | 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UIViewControllerBasedStatusBarAppearance 42 | 43 | NSAppTransportSecurity 44 | 45 | NSAllowsArbitraryLoads 46 | 47 | NSExceptionDomains 48 | 49 | localhost 50 | 51 | NSExceptionAllowsInsecureHTTPLoads 52 | 53 | 54 | 55 | 56 | UIAppFonts 57 | 58 | AntDesign.ttf 59 | Entypo.ttf 60 | EvilIcons.ttf 61 | Feather.ttf 62 | FontAwesome.ttf 63 | FontAwesome5_Brands.ttf 64 | FontAwesome5_Regular.ttf 65 | FontAwesome5_Solid.ttf 66 | Foundation.ttf 67 | Ionicons.ttf 68 | MaterialCommunityIcons.ttf 69 | MaterialIcons.ttf 70 | Octicons.ttf 71 | SimpleLineIcons.ttf 72 | Zocial.ttf 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /packages/app/ios/app/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/app/ios/appTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /packages/app/ios/appTests/appTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | #import 12 | #import 13 | 14 | #define TIMEOUT_SECONDS 600 15 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 16 | 17 | @interface appTests : XCTestCase 18 | 19 | @end 20 | 21 | @implementation appTests 22 | 23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 24 | { 25 | if (test(view)) { 26 | return YES; 27 | } 28 | for (UIView *subview in [view subviews]) { 29 | if ([self findSubviewInView:subview matching:test]) { 30 | return YES; 31 | } 32 | } 33 | return NO; 34 | } 35 | 36 | - (void)testRendersWelcomeScreen 37 | { 38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 40 | BOOL foundElement = NO; 41 | 42 | __block NSString *redboxError = nil; 43 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 44 | if (level >= RCTLogLevelError) { 45 | redboxError = message; 46 | } 47 | }); 48 | 49 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 50 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 51 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 52 | 53 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 54 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 55 | return YES; 56 | } 57 | return NO; 58 | }]; 59 | } 60 | 61 | RCTSetLogFunction(RCTDefaultLogFunction); 62 | 63 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 64 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 65 | } 66 | 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /packages/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@foton/app", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start", 7 | "test": "jest", 8 | "prettier": "prettier --write --single-quote true --trailing-comma all --print-width 120", 9 | "android:install": "adb install android/app/build/outputs/apk/app-release.apk", 10 | "clear": "node node_modules/react-native/local-cli/cli.js start --reset-cache", 11 | "lint": "eslint src", 12 | "lint:staged": "lint-staged", 13 | "prettier:all": "prettier --write --single-quote true --trailing-comma all --print-width 120 --write './**/*.js'" 14 | }, 15 | "dependencies": { 16 | "@types/yup": "^0.26.2", 17 | "apollo-boost": "^0.1.19", 18 | "apollo-cache-inmemory": "^1.3.8", 19 | "apollo-client": "^2.4.5", 20 | "apollo-link-context": "^1.0.9", 21 | "apollo-link-http": "^1.5.5", 22 | "formik": "^1.3.2", 23 | "graphql": "^0.13.2", 24 | "idx": "^2.4.0", 25 | "react": "16.7.0-alpha.0", 26 | "react-apollo": "^2.2.4", 27 | "react-apollo-hooks": "^0.2.1", 28 | "react-native": "https://github.com/expo/react-native/archive/sdk-31-with-hooks-dangerzone.tar.gz", 29 | "react-native-animatable": "^1.3.0", 30 | "react-native-gifted-chat": "^0.5.0", 31 | "react-native-text-input-mask": "^0.8.0", 32 | "react-native-textinput-effects": "^0.4.2", 33 | "react-native-typography": "^1.4.0", 34 | "react-native-vector-icons": "^6.1.0", 35 | "react-navigation": "^2.6.2", 36 | "react-navigation-fluid-transitions": "^0.2.2", 37 | "styled-components": "^4.1.2", 38 | "yup": "^0.26.6" 39 | }, 40 | "devDependencies": { 41 | "@types/jest": "^23.3.10", 42 | "@types/react": "^16.7.11", 43 | "@types/react-native": "^0.57.15", 44 | "@types/react-navigation": "^2.6.2", 45 | "@types/react-test-renderer": "^16.0.3", 46 | "@types/styled-components": "^4.1.3", 47 | "babel-jest": "23.6.0", 48 | "eslint-plugin-jsx-a11y": "^6.0.3", 49 | "eslint-plugin-react": "^7.7.0", 50 | "eslint-plugin-react-native": "^3.2.1", 51 | "jest": "23.6.0", 52 | "lint-staged": "^3.4.0", 53 | "metro-react-native-babel-preset": "0.50.0", 54 | "pre-commit": "^1.2.2", 55 | "prettier": "^1.2.2", 56 | "react-test-renderer": "16.6.1", 57 | "typescript": "^3.2.1" 58 | }, 59 | "lint-staged": { 60 | "*.js": [ 61 | "prettier --write --single-quote true --trailing-comma all --print-width 120", 62 | "eslint --fix", 63 | "git add" 64 | ] 65 | }, 66 | "pre-commit": "lint:staged", 67 | "jest": { 68 | "preset": "react-native" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /packages/app/package.json~: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start", 7 | "test": "jest", 8 | "prettier": "prettier --write --single-quote true --trailing-comma all --print-width 120", 9 | "android:install": "adb install android/app/build/outputs/apk/app-release.apk", 10 | "clear": "node node_modules/react-native/local-cli/cli.js start --reset-cache", 11 | "lint": "eslint src", 12 | "lint:staged": "lint-staged", 13 | "prettier:all": "prettier --write --single-quote true --trailing-comma all --print-width 120 --write './**/*.js'" 14 | }, 15 | "dependencies": { 16 | "@types/yup": "^0.26.2", 17 | "apollo-boost": "^0.1.19", 18 | "apollo-cache-inmemory": "^1.3.8", 19 | "apollo-client": "^2.4.5", 20 | "apollo-link-context": "^1.0.9", 21 | "apollo-link-http": "^1.5.5", 22 | "formik": "^1.3.2", 23 | "graphql": "^0.13.2", 24 | "idx": "^2.4.0", 25 | "react": "16.7.0-alpha.0", 26 | "react-apollo": "^2.2.4", 27 | "react-apollo-hooks": "^0.2.1", 28 | "react-native": "https://github.com/expo/react-native/archive/sdk-31-with-hooks-dangerzone.tar.gz", 29 | "react-native-animatable": "^1.3.0", 30 | "react-native-gifted-chat": "^0.5.0", 31 | "react-native-text-input-mask": "^0.8.0", 32 | "react-native-textinput-effects": "^0.4.2", 33 | "react-native-typography": "^1.4.0", 34 | "react-native-vector-icons": "^6.1.0", 35 | "react-navigation": "^2.6.2", 36 | "react-navigation-fluid-transitions": "^0.2.2", 37 | "styled-components": "^4.1.2", 38 | "yup": "^0.26.6" 39 | }, 40 | "devDependencies": { 41 | "@types/jest": "^23.3.10", 42 | "@types/react": "^16.7.11", 43 | "@types/react-native": "^0.57.15", 44 | "@types/react-navigation": "^2.6.2", 45 | "@types/react-test-renderer": "^16.0.3", 46 | "@types/styled-components": "^4.1.3", 47 | "babel-jest": "23.6.0", 48 | "eslint-plugin-jsx-a11y": "^6.0.3", 49 | "eslint-plugin-react": "^7.7.0", 50 | "eslint-plugin-react-native": "^3.2.1", 51 | "jest": "23.6.0", 52 | "lint-staged": "^3.4.0", 53 | "metro-react-native-babel-preset": "0.50.0", 54 | "pre-commit": "^1.2.2", 55 | "prettier": "^1.2.2", 56 | "react-test-renderer": "16.6.1", 57 | "typescript": "^3.2.1" 58 | }, 59 | "lint-staged": { 60 | "*.js": [ 61 | "prettier --write --single-quote true --trailing-comma all --print-width 120", 62 | "eslint --fix", 63 | "git add" 64 | ] 65 | }, 66 | "pre-commit": "lint:staged", 67 | "jest": { 68 | "preset": "react-native" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /packages/app/redirect_ports.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # packager 4 | adb reverse tcp:8081 tcp:8081 5 | adb -d reverse tcp:8081 tcp:8081 6 | adb -e reverse tcp:8081 tcp:8081 7 | 8 | # Storybooks 9 | adb reverse tcp:7007 tcp:7007 10 | adb -d reverse tcp:7007 tcp:7007 11 | adb -e reverse tcp:7007 tcp:7007 12 | 13 | # GraphQL 14 | adb reverse tcp:5001 tcp:5001 15 | adb -d reverse tcp:5001 tcp:5001 16 | adb -e reverse tcp:5001 tcp:5001 -------------------------------------------------------------------------------- /packages/app/setup.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | 4 | const packageJson = require('./package.json') 5 | 6 | const deleteFile = fileName => fs.unlinkSync(path.join(__dirname, fileName)) 7 | const writeFile = (fileName, data) => fs.writeFileSync(path.join(__dirname, fileName), data) 8 | 9 | console.log('🔄 Setting up...') 10 | 11 | packageJson.scripts.tsc = 'tsc' 12 | 13 | writeFile('package.json', JSON.stringify(packageJson, null, 2)) 14 | 15 | deleteFile('.flowconfig') 16 | deleteFile('App.js') 17 | deleteFile('LICENSE') 18 | deleteFile('README.md') 19 | deleteFile('setup.js') 20 | 21 | console.log(`✅ Setup completed!`) 22 | -------------------------------------------------------------------------------- /packages/app/src/App.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React, { Component } from 'react'; 3 | import { AsyncStorage } from 'react-native'; 4 | import { createRootNavigator } from './config/Router'; 5 | import styled, { ThemeProvider } from 'styled-components'; 6 | import { ApolloProvider } from 'react-apollo'; 7 | import { ApolloProvider as ApolloHooksProvider } from 'react-apollo-hooks'; 8 | 9 | import client from './config/ApolloEnv'; 10 | import theme from './config/theme'; 11 | 12 | console.disableYellowBox = true; 13 | 14 | const LoadingWrapper = styled.View` 15 | flex: 1; 16 | align-items: center; 17 | justify-content: center; 18 | background-color: ${p => p.theme.colors.primaryBackground}; 19 | `; 20 | 21 | const WelcomeText = styled.Text` 22 | font-size: 83; 23 | `; 24 | 25 | const Zap = () => ( 26 | 27 | ) 28 | 29 | interface Props {}; 30 | 31 | interface State { 32 | token: string | null 33 | loading: boolean 34 | }; 35 | 36 | class App extends Component { 37 | state = { 38 | token: '', 39 | loading: true, 40 | }; 41 | 42 | componentDidMount() { 43 | // AsyncStorage.clear(); 44 | setTimeout(() => { 45 | AsyncStorage.getItem('token').then(value => { 46 | this.setState({ 47 | loading: false, 48 | token: value, 49 | }); 50 | }); 51 | }, 1000); 52 | } 53 | render() { 54 | const { token, loading } = this.state; 55 | 56 | const Router = createRootNavigator(token); 57 | 58 | if (loading) { 59 | return ( 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | ); 70 | } 71 | 72 | return ( 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | ); 81 | } 82 | } 83 | 84 | export default App; 85 | -------------------------------------------------------------------------------- /packages/app/src/assets/backArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/src/assets/backArrow.png -------------------------------------------------------------------------------- /packages/app/src/assets/correctSign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/src/assets/correctSign.png -------------------------------------------------------------------------------- /packages/app/src/assets/hang.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/app/src/assets/hang.jpg -------------------------------------------------------------------------------- /packages/app/src/assets/index.tsx: -------------------------------------------------------------------------------- 1 | export const images = { 2 | backArrow: require('./backArrow.png'), 3 | correctSign: require('./correctSign.png'), 4 | hang: require('./hang.jpg'), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/app/src/components/ActionButton.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react'; 3 | import { Platform } from 'react-native'; 4 | import styled, { css, StyledComponentClass } from 'styled-components'; 5 | 6 | const Wrapper = styled.TouchableOpacity` 7 | height: 65px; 8 | width: 65px; 9 | background-color: ${props => (props.disabled ? 'grey' : '#404040')}; 10 | border-radius: 35; 11 | align-items: center; 12 | justify-content: center; 13 | ${Platform.select({ 14 | ios: css` 15 | shadow-color: grey; 16 | shadow-offset: 0px 2px; 17 | shadow-radius: 2px; 18 | shadow-opacity: 2px; 19 | `, 20 | android: css` 21 | elevation: 5; 22 | `, 23 | })}; 24 | position: absolute; 25 | bottom: 25px; 26 | right: 25px; 27 | `; 28 | 29 | const Text = styled.Text` 30 | color: white; 31 | 32 | font-size: 25px; 33 | `; 34 | 35 | type Props = { 36 | text: string, 37 | onPress: () => any, 38 | disabled?: boolean, 39 | }; 40 | 41 | const Button = ({ onPress, disabled }: Props) => ( 42 | 43 | + 44 | 45 | ); 46 | 47 | export default Button; 48 | -------------------------------------------------------------------------------- /packages/app/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react'; 3 | import { ActivityIndicator } from 'react-native'; 4 | import styled from 'styled-components/native'; 5 | import Text from './Text' 6 | 7 | const Wrapper = styled.TouchableOpacity` 8 | padding: 15px 65px; 9 | background-color: ${props => (props.disabled ? 'grey' : '#ffffff')}; 10 | border-radius: 25; 11 | align-items: center; 12 | justify-content: center; 13 | margin-top: 20; 14 | `; 15 | 16 | 17 | interface Props { 18 | text: string 19 | onPress: () => any 20 | disabled?: boolean 21 | isLoading?: boolean 22 | }; 23 | 24 | const Button = ({ text, onPress, disabled, isLoading }: Props) => ( 25 | 26 | {isLoading ? () : ({text})} 27 | 28 | ); 29 | 30 | export default Button; 31 | -------------------------------------------------------------------------------- /packages/app/src/components/Checkbox.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react'; 3 | import { Dimensions, Switch } from 'react-native'; 4 | import styled from 'styled-components/native'; 5 | 6 | const { width } = Dimensions.get('window'); 7 | 8 | const Wrapper = styled.View` 9 | margin-top: 20; 10 | padding: 10px; 11 | border-bottom-color: black; 12 | border-bottom-width: 2; 13 | width: ${width - 40}; 14 | flex-direction: row; 15 | justify-content: space-between; 16 | align-items: center; 17 | `; 18 | 19 | const Text = styled.Text` 20 | font-size: 16; 21 | font-weight: 600; 22 | 23 | `; 24 | 25 | type Props = { 26 | placeholder: string, 27 | value: string, 28 | secureTextEntry: boolean, 29 | onChangeText: (value: string) => void, 30 | }; 31 | 32 | const Checkbox = ({ placeholder, value, onValueChange }: Props) => ( 33 | 34 | {placeholder} 35 | 36 | 37 | ); 38 | 39 | export default Checkbox; 40 | -------------------------------------------------------------------------------- /packages/app/src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | 2 | import * as React from 'react'; 3 | import { View } from 'react-native'; 4 | import styled from 'styled-components/native'; 5 | import { SafeArea } from '../utils'; 6 | import { images } from '../assets/index'; 7 | import { withNavigation } from 'react-navigation'; 8 | 9 | const LeftArrow = styled.Image.attrs({ 10 | source: images.backArrow, 11 | })` 12 | width: 25; 13 | height: 25; 14 | `; 15 | 16 | const CorrectSign = styled.Image.attrs({ 17 | source: images.correctSign, 18 | })` 19 | width: 25; 20 | height: 25; 21 | `; 22 | 23 | const Wrapper = styled.View` 24 | flex-direction: row; 25 | padding: 16px; 26 | align-items: center; 27 | justify-content: flex-start; 28 | width: 100%; 29 | `; 30 | 31 | const TextWrapper = styled.View` 32 | flex-direction: column; 33 | margin-left: 16px; 34 | `; 35 | 36 | const HeaderSmallText = styled.Text` 37 | color: #c0c0c0; 38 | font-size: 16; 39 | 40 | font-weight: 500; 41 | `; 42 | 43 | const HeaderLargeText = styled.Text` 44 | color: black; 45 | font-size: 24; 46 | font-weight: 500; 47 | 48 | `; 49 | 50 | const RightAvatar = styled.TouchableOpacity` 51 | width: 50; 52 | height: 50; 53 | border-radius: ${50 / 2}; 54 | background-color: #404040; 55 | align-items: center; 56 | justify-content: center; 57 | margin-left: auto; 58 | `; 59 | const LeftAvatar = styled.TouchableOpacity` 60 | width: 50; 61 | height: 50; 62 | align-items: center; 63 | justify-content: center; 64 | `; 65 | 66 | const Initials = styled.Text` 67 | 68 | color: white; 69 | font-size: 20; 70 | font-weight: 500; 71 | `; 72 | 73 | type Props = { 74 | description: string, 75 | title: string, 76 | userInitials: string, 77 | onPress?: () => void, 78 | }; 79 | 80 | const Header = ({ title, description, userInitials, onPress, ...rest }: Props) => ( 81 | 82 | 83 | 84 | rest.navigation.goBack()}> 85 | 86 | 87 | 88 | {description} 89 | {title} 90 | 91 | 92 | 93 | 94 | 95 | 96 | ); 97 | 98 | export default withNavigation(Header); 99 | -------------------------------------------------------------------------------- /packages/app/src/components/HeaderHome.tsx: -------------------------------------------------------------------------------- 1 | 2 | import * as React from 'react'; 3 | import { View } from 'react-native'; 4 | import styled from 'styled-components/native'; 5 | import { SafeArea } from '../utils'; 6 | 7 | const Wrapper = styled.View` 8 | flex-direction: row; 9 | padding: 16px; 10 | align-items: center; 11 | justify-content: space-between; 12 | `; 13 | 14 | const TextWrapper = styled.View` 15 | flex-direction: column; 16 | `; 17 | 18 | const HeaderSmallText = styled.Text` 19 | color: #c0c0c0; 20 | font-size: 16; 21 | 22 | font-weight: 500; 23 | `; 24 | 25 | const HeaderLargeText = styled.Text` 26 | color: black; 27 | font-size: 24; 28 | font-weight: 500; 29 | 30 | `; 31 | 32 | const Avatar = styled.TouchableOpacity` 33 | width: 50; 34 | height: 50; 35 | border-radius: ${50 / 2}; 36 | background-color: #404040; 37 | align-items: center; 38 | justify-content: center; 39 | `; 40 | 41 | const Initials = styled.Text` 42 | 43 | color: white; 44 | font-size: 20; 45 | font-weight: 500; 46 | `; 47 | 48 | type Props = { 49 | description: string, 50 | title: string, 51 | userInitials: string, 52 | onClickAvatar?: () => void, 53 | }; 54 | 55 | const HeaderHome = ({ title, description, userInitials, onClickAvatar }: Props) => ( 56 | 57 | 58 | 59 | 60 | {description} 61 | {title} 62 | 63 | 64 | {userInitials} 65 | 66 | 67 | 68 | ); 69 | 70 | export default HeaderHome; 71 | -------------------------------------------------------------------------------- /packages/app/src/components/Loading.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react'; 3 | import { ActivityIndicator } from 'react-native'; 4 | import styled from 'styled-components'; 5 | 6 | const Wrapper = styled.View` 7 | height: 100%; 8 | width: 100%; 9 | justify-content: center; 10 | align-items: center; 11 | position: absolute; 12 | `; 13 | 14 | const Button = ({ onPress, disabled }: Props) => ( 15 | 16 | 17 | 18 | ); 19 | 20 | export default Button; 21 | -------------------------------------------------------------------------------- /packages/app/src/components/LowerIOSAdaption.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react'; 3 | import { Dimensions } from 'react-native'; 4 | import styled from 'styled-components/native'; 5 | 6 | const { height } = Dimensions.get('window'); 7 | 8 | const Wrapper = styled.View` 9 | margin-bottom: ${height === 812 ? 44 : 20}; 10 | `; 11 | 12 | const LoweriOSAdaption = () => ; 13 | 14 | export default LoweriOSAdaption; 15 | -------------------------------------------------------------------------------- /packages/app/src/components/PetItem.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import styled from 'styled-components/native'; 3 | 4 | const Wrapper = styled.TouchableOpacity` 5 | height: 44px; 6 | border-radius: 8px; 7 | border: 1px solid rgba(174, 174, 174, 0.5); 8 | flex-direction: row; 9 | justify-content: space-between; 10 | align-items: center; 11 | margin: 8px 16px; 12 | ` 13 | 14 | const Text = styled.Text` 15 | color: black; 16 | font-size: 15px; 17 | margin-left: 16px; 18 | `; 19 | 20 | 21 | const Icon = styled.Image` 22 | width: 25; 23 | height: 25; 24 | margin-right: 16px; 25 | `; 26 | 27 | export default ({ onPress, text, icon }) => ( 28 | 29 | {text} 30 | 31 | 32 | ) -------------------------------------------------------------------------------- /packages/app/src/components/Shimmer.tsx: -------------------------------------------------------------------------------- 1 | import { Animated } from 'react-native'; 2 | import styled from 'styled-components/native'; 3 | 4 | 5 | const CardsShimmer = styled(Animated.View)` 6 | height: 120; 7 | width: ${width - 30}; 8 | border-radius: 10; 9 | margin: 10px 15px; 10 | `; 11 | const HeaderNameShimmer = styled(Animated.View)` 12 | height: 50; 13 | width: ${width - 100}; 14 | border-radius: 10; 15 | `; 16 | 17 | const HeaderRowShimmer = styled.View` 18 | flex-direction: row; 19 | padding: 15px; 20 | justify-content: space-between; 21 | `; 22 | 23 | const HeaderProfileImageShimmer = styled(Animated.View)` 24 | width: 50; 25 | height: 50; 26 | border-radius: ${50 / 2}; 27 | `; 28 | 29 | const animateShimmer = () => { 30 | Animated.sequence([ 31 | Animated.timing(this.state.animatedValue, { 32 | toValue: 150, 33 | duration: 500, 34 | }), 35 | Animated.timing(this.state.animatedValue, { 36 | toValue: 0, 37 | duration: 600, 38 | }), 39 | ]).start(() => { 40 | this.animateShimmer(); 41 | }); 42 | }; 43 | 44 | 45 | -------------------------------------------------------------------------------- /packages/app/src/components/Text.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import styled, { css } from 'styled-components/native'; 3 | 4 | 5 | interface ThemeProps { 6 | theme: any 7 | } 8 | 9 | interface Props extends ThemeProps { 10 | size: 'small' | 'normal' | 'big' | 'huge' 11 | tint: 'primary' | 'secondary' | 'disabled' 12 | strong: boolean 13 | } 14 | 15 | export default styled.Text` 16 | font-size: ${(p: Props) => { 17 | switch(p.size) { 18 | case 'small': 19 | return p.theme.fontSizes.small 20 | case 'normal': 21 | return p.theme.fontSizes.normal 22 | case 'big': 23 | return p.theme.fontSizes.big 24 | case 'huge': 25 | return p.theme.fontSizes.huge 26 | } 27 | }}; 28 | color: ${(p: Props) => { 29 | switch(p.tint) { 30 | case 'primary': 31 | return p.theme.colors.primaryText 32 | case 'secondary': 33 | return p.theme.colors.secondaryText 34 | case 'disabled': 35 | return p.theme.colors.disabled 36 | } 37 | }}; 38 | ${(p: Props) => { 39 | return p.strong && `font-weight: bold` 40 | }}; 41 | 42 | ` -------------------------------------------------------------------------------- /packages/app/src/config/ApolloEnv.tsx: -------------------------------------------------------------------------------- 1 | import { AsyncStorage } from 'react-native'; 2 | import { ApolloClient } from 'apollo-client'; 3 | import { createHttpLink } from 'apollo-link-http'; 4 | import { setContext } from 'apollo-link-context'; 5 | import { InMemoryCache } from 'apollo-cache-inmemory'; 6 | 7 | const httpLink = new createHttpLink({ uri: 'http://localhost:5000/graphql' }); 8 | 9 | const authLink = setContext(async (_, { headers }) => { 10 | // return the headers to the context so httpLink can read them 11 | return { 12 | headers: { 13 | ...headers, 14 | Authorization: await AsyncStorage.getItem('token'), 15 | }, 16 | }; 17 | }); 18 | 19 | const client = new ApolloClient({ 20 | link: authLink.concat(httpLink), 21 | cache: new InMemoryCache(), 22 | }); 23 | 24 | export default client; 25 | -------------------------------------------------------------------------------- /packages/app/src/config/Router.tsx: -------------------------------------------------------------------------------- 1 | import { StackNavigator, createSwitchNavigator } from 'react-navigation'; 2 | import Login from '../screens/Login'; 3 | import SignUp from '../screens/SignUp'; 4 | import Home from '../screens/Home'; 5 | import Chat from '../screens/Chat'; 6 | 7 | export const RouteNames = { 8 | Login: 'Login', 9 | SignUp: 'SignUp', 10 | Home: 'Home', 11 | Chat: 'Chat', 12 | Logged: 'Logged', 13 | NonLogged: 'NonLogged', 14 | }; 15 | 16 | const NonLoggedAppRouter = StackNavigator( 17 | { 18 | [RouteNames.Login]: { screen: Login }, 19 | [RouteNames.SignUp]: { screen: SignUp }, 20 | }, 21 | { 22 | initialRouteName: RouteNames.Login, 23 | navigationOptions: { 24 | header: null, 25 | }, 26 | }, 27 | ); 28 | 29 | const LoggedAppRouter = StackNavigator( 30 | { 31 | [RouteNames.Home]: { screen: Home }, 32 | [RouteNames.Chat]: { screen: Chat }, 33 | }, 34 | { 35 | initialRouteName: RouteNames.Home, 36 | navigationOptions: { 37 | header: null, 38 | }, 39 | }, 40 | ); 41 | 42 | export const createRootNavigator = (token: string) => 43 | createSwitchNavigator( 44 | { 45 | [RouteNames.Logged]: LoggedAppRouter, 46 | [RouteNames.NonLogged]: NonLoggedAppRouter, 47 | }, 48 | { 49 | initialRouteName: token ? RouteNames.Logged : RouteNames.NonLogged, 50 | }, 51 | ); 52 | -------------------------------------------------------------------------------- /packages/app/src/config/theme.tsx: -------------------------------------------------------------------------------- 1 | export default { 2 | colors: { 3 | primaryText: '#ffffff', 4 | secondaryText: '#7F00FF', 5 | disabled: 'grey', 6 | primaryBackground: '#7F00FF', 7 | error: 'red', 8 | }, 9 | fontSizes: { 10 | small: 13, 11 | normal: 16, 12 | medium: 20, 13 | big: 25, 14 | huge: 53, 15 | } 16 | } -------------------------------------------------------------------------------- /packages/app/src/screens/Chat.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Text, FlatList, ActivityIndicator, SafeAreaView } from 'react-native'; 3 | import styled from 'styled-components/native'; 4 | import { useMutation } from 'react-apollo-hooks'; 5 | 6 | import idx from 'idx'; 7 | import gql from 'graphql-tag'; 8 | import { graphql } from 'react-apollo'; 9 | import Loading from '../components/Loading' 10 | import { GiftedChat } from 'react-native-gifted-chat' 11 | 12 | const Chat = (props) => { 13 | 14 | 15 | const onSend = () => { 16 | 17 | } 18 | return ( 19 | onSend(messages)} 22 | user={{ 23 | _id: 1, 24 | }} 25 | /> 26 | ) 27 | } 28 | 29 | 30 | const MESSAGES_QUERY = gql` 31 | query messages($first: Int = 10, $conversation: ID) { 32 | messages(first: $first, conversation: $conversation) { 33 | pageInfo { 34 | hasNextPage 35 | endCursor 36 | } 37 | edges { 38 | node { 39 | id 40 | owner { 41 | id 42 | name 43 | } 44 | text 45 | createdAt 46 | } 47 | } 48 | } 49 | me { 50 | id 51 | name 52 | } 53 | } 54 | ` 55 | 56 | const ADD_MESSAGE = gql` 57 | mutation AddMessageMutation($input: AddMessageInput!) { 58 | AddMessage(input: $input) { 59 | error 60 | status 61 | text 62 | owner 63 | } 64 | } 65 | `; 66 | 67 | export default graphql(MESSAGES_QUERY)(Chat) -------------------------------------------------------------------------------- /packages/app/src/utils.js: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react'; 3 | import { Platform } from 'react-native'; 4 | import LoweriOSAdaption from './components/LowerIOSAdaption'; 5 | 6 | export const iosVersion = parseInt(Platform.Version, 10); 7 | 8 | export const SafeArea = () => { 9 | return ; 10 | }; 11 | 12 | export const getInitials = (name: string): string => { 13 | return name 14 | ? name 15 | .split(' ') 16 | .slice(0, 2) 17 | .map(namePart => namePart.charAt(0).toUpperCase()) 18 | .join('') 19 | : ''; 20 | }; 21 | -------------------------------------------------------------------------------- /packages/app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "allowSyntheticDefaultImports": true, 5 | "esModuleInterop": true, 6 | "isolatedModules": true, 7 | "jsx": "react-native", 8 | "lib": ["es6"], 9 | "moduleResolution": "node", 10 | "noEmit": true, 11 | "strict": true, 12 | "target": "esnext" 13 | }, 14 | "exclude": ["node_modules"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/server/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["flow", "es2015", "stage-0"] 3 | } 4 | 5 | -------------------------------------------------------------------------------- /packages/server/.env: -------------------------------------------------------------------------------- 1 | #Enviroment 2 | NODE_ENV=development 3 | 4 | #GraphQL settings 5 | GRAPHQL_PORT=5000 6 | 7 | #Security 8 | JWT_KEY=awesome_secret_key 9 | MONGO_URL=mongodb://foton:foton123@ds151354.mlab.com:51354/fotonchat -------------------------------------------------------------------------------- /packages/server/.env.example: -------------------------------------------------------------------------------- 1 | #Enviroment 2 | NODE_ENV=development 3 | 4 | #GraphQL settings 5 | GRAPHQL_PORT=5000 6 | 7 | #Security 8 | JWT_KEY=awesome_secret_key 9 | -------------------------------------------------------------------------------- /packages/server/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb/base", 3 | "parser": "babel-eslint", 4 | "rules": { 5 | "no-console": 0, 6 | "max-len": [1, 120, 2], 7 | "no-param-reassign": [2, { "props": false }], 8 | "no-continue": 0, 9 | "no-underscore-dangle": 0, 10 | "generator-star-spacing": 0, 11 | "import/no-named-as-default": 0, 12 | "no-return-await": 0, 13 | "no-shadow": 0, 14 | "object-curly-newline": 0, 15 | "import/prefer-default-export": 0, 16 | }, 17 | "env": { 18 | "jest": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/server/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | 7 | [options] 8 | -------------------------------------------------------------------------------- /packages/server/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.sublime-project 3 | *.sublime-workspace 4 | .idea/ 5 | .vscode/ 6 | package-lock.json 7 | 8 | lib-cov 9 | *.seed 10 | *.log 11 | *.csv 12 | *.dat 13 | *.out 14 | *.pid 15 | *.gz 16 | *.map 17 | 18 | pids 19 | logs 20 | results 21 | 22 | node_modules 23 | npm-debug.log 24 | 25 | dump.rdb 26 | bundle.js 27 | 28 | dist 29 | coverage 30 | .nyc_output 31 | flow-coverage 32 | -------------------------------------------------------------------------------- /packages/server/.yarnclean: -------------------------------------------------------------------------------- 1 | # test directories 2 | __tests__ 3 | test 4 | tests 5 | powered-test 6 | 7 | # asset directories 8 | docs 9 | doc 10 | website 11 | images 12 | assets 13 | !istanbul-reports/lib/html/assets 14 | 15 | # examples 16 | example 17 | examples 18 | 19 | # code coverage directories 20 | coverage 21 | .nyc_output 22 | 23 | # build scripts 24 | Makefile 25 | Gulpfile.js 26 | Gruntfile.js 27 | 28 | # configs 29 | appveyor.yml 30 | circle.yml 31 | codeship-services.yml 32 | codeship-steps.yml 33 | wercker.yml 34 | .tern-project 35 | .gitattributes 36 | .editorconfig 37 | .*ignore 38 | .eslintrc 39 | .jshintrc 40 | .flowconfig 41 | .documentup.json 42 | .yarn-metadata.json 43 | .travis.yml 44 | 45 | # misc 46 | *.md 47 | -------------------------------------------------------------------------------- /packages/server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8 2 | 3 | MAINTAINER Entria 4 | 5 | RUN mkdir -p /app 6 | WORKDIR /app 7 | 8 | COPY package.json /app 9 | RUN npm i 10 | 11 | COPY . /app 12 | 13 | #cachable 14 | RUN npm run build 15 | 16 | CMD ["npm", "start"] 17 | -------------------------------------------------------------------------------- /packages/server/circle.yml: -------------------------------------------------------------------------------- 1 | 2 | # Javascript Node CircleCI 2.0 configuration file 3 | # 4 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 5 | # 6 | version: 2 7 | 8 | jobs: 9 | build: 10 | docker: 11 | # specify the version you desire here 12 | - image: circleci/node 13 | 14 | # Specify service dependencies here if necessary 15 | # CircleCI maintains a library of pre-built images 16 | # documented at https://circleci.com/docs/2.0/circleci-images/ 17 | # - image: circleci/mongo:3.4.4 18 | 19 | working_directory: ~/repo 20 | 21 | steps: 22 | - checkout 23 | 24 | # Download and cache dependencies 25 | - restore_cache: 26 | keys: 27 | - v1-dependencies-{{ checksum "package.json" }} 28 | # fallback to using the latest cache if no exact match is found 29 | - v1-dependencies- 30 | 31 | - run: yarn install 32 | 33 | - save_cache: 34 | paths: 35 | - node_modules 36 | key: v1-dependencies-{{ checksum "package.json" }} 37 | 38 | # run tests! commented 39 | - run: yarn lint 40 | -------------------------------------------------------------------------------- /packages/server/dist/TypeDefinition.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _UserLoader = require('./loader/UserLoader'); -------------------------------------------------------------------------------- /packages/server/dist/auth.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.getUser = undefined; 7 | 8 | var getUser = exports.getUser = function () { 9 | var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(token) { 10 | var decodedToken, user; 11 | return regeneratorRuntime.wrap(function _callee$(_context) { 12 | while (1) { 13 | switch (_context.prev = _context.next) { 14 | case 0: 15 | if (token) { 16 | _context.next = 2; 17 | break; 18 | } 19 | 20 | return _context.abrupt('return', { user: null }); 21 | 22 | case 2: 23 | _context.prev = 2; 24 | decodedToken = _jsonwebtoken2.default.verify(token.substring(4), _config.jwtSecret); 25 | _context.next = 6; 26 | return _model.User.findOne({ _id: decodedToken.id }); 27 | 28 | case 6: 29 | user = _context.sent; 30 | return _context.abrupt('return', { 31 | user: user 32 | }); 33 | 34 | case 10: 35 | _context.prev = 10; 36 | _context.t0 = _context['catch'](2); 37 | return _context.abrupt('return', { user: null }); 38 | 39 | case 13: 40 | case 'end': 41 | return _context.stop(); 42 | } 43 | } 44 | }, _callee, this, [[2, 10]]); 45 | })); 46 | 47 | return function getUser(_x) { 48 | return _ref.apply(this, arguments); 49 | }; 50 | }(); 51 | 52 | exports.generateToken = generateToken; 53 | 54 | var _jsonwebtoken = require('jsonwebtoken'); 55 | 56 | var _jsonwebtoken2 = _interopRequireDefault(_jsonwebtoken); 57 | 58 | var _model = require('./model'); 59 | 60 | var _config = require('./config'); 61 | 62 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 63 | 64 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } 65 | 66 | function generateToken(user) { 67 | return 'JWT ' + _jsonwebtoken2.default.sign({ id: user._id }, _config.jwtSecret); 68 | } -------------------------------------------------------------------------------- /packages/server/dist/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.jwtSecret = exports.graphqlPort = exports.databaseConfig = undefined; 7 | 8 | var _path = require('path'); 9 | 10 | var _path2 = _interopRequireDefault(_path); 11 | 12 | var _dotenvSafe = require('dotenv-safe'); 13 | 14 | var _dotenvSafe2 = _interopRequireDefault(_dotenvSafe); 15 | 16 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 17 | 18 | var root = _path2.default.join.bind(null, __dirname); 19 | 20 | if (!process.env.NOW_REGION) { 21 | _dotenvSafe2.default.load({ 22 | path: root('.env'), 23 | sample: root('.env.example') 24 | }); 25 | } 26 | 27 | // Database Settings 28 | var dBdevelopment = process.env.MONGO_URL || 'mongodb://localhost/fotonChat'; 29 | var dBproduction = process.env.MONGO_URL || 'mongodb://localhost/fotonChat'; 30 | 31 | console.log('dBdevelopment', dBdevelopment); 32 | console.log('dBproduction', dBproduction); 33 | // Test Database Settings 34 | // const test = 'mongodb://localhost/awesome-test'; 35 | 36 | // Export DB Settings 37 | var databaseConfig = exports.databaseConfig = process.env.NODE_ENV === 'production' ? dBproduction : dBdevelopment; 38 | 39 | // Export GraphQL Server settings 40 | var graphqlPort = exports.graphqlPort = process.env.GRAPHQL_PORT || 5000; 41 | var jwtSecret = exports.jwtSecret = process.env.JWT_KEY || 'secret_key'; -------------------------------------------------------------------------------- /packages/server/dist/connection/ConversationConnection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _graphql = require('graphql'); 8 | 9 | var _graphqlRelay = require('graphql-relay'); 10 | 11 | var _ConversationType = require('../type/ConversationType'); 12 | 13 | var _ConversationType2 = _interopRequireDefault(_ConversationType); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | exports.default = (0, _graphqlRelay.connectionDefinitions)({ 18 | name: 'Conversation', 19 | nodeType: _ConversationType2.default, 20 | connectionFields: { 21 | count: { 22 | type: _graphql.GraphQLInt 23 | } 24 | } 25 | }); -------------------------------------------------------------------------------- /packages/server/dist/connection/MessageConnection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _graphql = require('graphql'); 8 | 9 | var _graphqlRelay = require('graphql-relay'); 10 | 11 | var _MessageType = require('../type/MessageType'); 12 | 13 | var _MessageType2 = _interopRequireDefault(_MessageType); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | exports.default = (0, _graphqlRelay.connectionDefinitions)({ 18 | name: 'Message', 19 | nodeType: _MessageType2.default, 20 | connectionFields: { 21 | count: { 22 | type: _graphql.GraphQLInt 23 | } 24 | } 25 | }); -------------------------------------------------------------------------------- /packages/server/dist/connection/PetConnection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _graphql = require('graphql'); 8 | 9 | var _graphqlRelay = require('graphql-relay'); 10 | 11 | var _PetType = require('../type/PetType'); 12 | 13 | var _PetType2 = _interopRequireDefault(_PetType); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | exports.default = (0, _graphqlRelay.connectionDefinitions)({ 18 | name: 'Pet', 19 | nodeType: _PetType2.default, 20 | connectionFields: { 21 | count: { 22 | type: _graphql.GraphQLInt 23 | } 24 | } 25 | }); -------------------------------------------------------------------------------- /packages/server/dist/connection/UserConnection.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _graphql = require('graphql'); 8 | 9 | var _graphqlRelay = require('graphql-relay'); 10 | 11 | var _UserType = require('../type/UserType'); 12 | 13 | var _UserType2 = _interopRequireDefault(_UserType); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | exports.default = (0, _graphqlRelay.connectionDefinitions)({ 18 | name: 'User', 19 | nodeType: _UserType2.default, 20 | connectionFields: { 21 | count: { 22 | type: _graphql.GraphQLInt 23 | } 24 | } 25 | }); -------------------------------------------------------------------------------- /packages/server/dist/database.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = connectDatabase; 7 | 8 | var _mongoose = require('mongoose'); 9 | 10 | var _mongoose2 = _interopRequireDefault(_mongoose); 11 | 12 | var _config = require('./config'); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | function connectDatabase() { 17 | return new Promise(function (resolve, reject) { 18 | _mongoose2.default.Promise = global.Promise; 19 | _mongoose2.default.connection.on('error', function (error) { 20 | return reject(error); 21 | }).on('close', function () { 22 | return console.log('Database connection closed.'); 23 | }).once('open', function () { 24 | return resolve(_mongoose2.default.connections[0]); 25 | }); 26 | 27 | _mongoose2.default.connect(_config.databaseConfig, { useNewUrlParser: true }); 28 | }); 29 | } -------------------------------------------------------------------------------- /packages/server/dist/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('babel-polyfill'); 4 | 5 | var _app = require('./app'); 6 | 7 | var _app2 = _interopRequireDefault(_app); 8 | 9 | var _database = require('./database'); 10 | 11 | var _database2 = _interopRequireDefault(_database); 12 | 13 | var _config = require('./config'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } 18 | 19 | _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() { 20 | var info; 21 | return regeneratorRuntime.wrap(function _callee$(_context) { 22 | while (1) { 23 | switch (_context.prev = _context.next) { 24 | case 0: 25 | _context.prev = 0; 26 | _context.next = 3; 27 | return (0, _database2.default)(); 28 | 29 | case 3: 30 | info = _context.sent; 31 | 32 | console.log('Connected to ' + info.host + ':' + info.port + '/' + info.name); 33 | _context.next = 11; 34 | break; 35 | 36 | case 7: 37 | _context.prev = 7; 38 | _context.t0 = _context['catch'](0); 39 | 40 | console.error('Unable to connect to database'); 41 | process.exit(1); 42 | 43 | case 11: 44 | _context.next = 13; 45 | return _app2.default.listen(_config.graphqlPort); 46 | 47 | case 13: 48 | console.log('Server started on port ' + _config.graphqlPort); 49 | 50 | case 14: 51 | case 'end': 52 | return _context.stop(); 53 | } 54 | } 55 | }, _callee, undefined, [[0, 7]]); 56 | }))(); -------------------------------------------------------------------------------- /packages/server/dist/interface/NodeInterface.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.NodeField = exports.NodeInterface = undefined; 7 | 8 | var _graphqlRelay = require('graphql-relay'); 9 | 10 | var _UserLoader = require('../loader/UserLoader'); 11 | 12 | var _UserLoader2 = _interopRequireDefault(_UserLoader); 13 | 14 | var _loader = require('../loader'); 15 | 16 | var _UserType = require('../type/UserType'); 17 | 18 | var _UserType2 = _interopRequireDefault(_UserType); 19 | 20 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 21 | 22 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } 23 | 24 | var _nodeDefinitions = (0, _graphqlRelay.nodeDefinitions)( 25 | // A method that maps from a global id to an object 26 | function () { 27 | var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(globalId, context) { 28 | var _fromGlobalId, id, type; 29 | 30 | return regeneratorRuntime.wrap(function _callee$(_context) { 31 | while (1) { 32 | switch (_context.prev = _context.next) { 33 | case 0: 34 | _fromGlobalId = (0, _graphqlRelay.fromGlobalId)(globalId), id = _fromGlobalId.id, type = _fromGlobalId.type; 35 | 36 | // console.log('id, type: ', type, id, globalId); 37 | 38 | if (!(type === 'User')) { 39 | _context.next = 5; 40 | break; 41 | } 42 | 43 | _context.next = 4; 44 | return _loader.UserLoader.load(context, id); 45 | 46 | case 4: 47 | return _context.abrupt('return', _context.sent); 48 | 49 | case 5: 50 | return _context.abrupt('return', null); 51 | 52 | case 6: 53 | case 'end': 54 | return _context.stop(); 55 | } 56 | } 57 | }, _callee, undefined); 58 | })); 59 | 60 | return function (_x, _x2) { 61 | return _ref.apply(this, arguments); 62 | }; 63 | }(), 64 | // A method that maps from an object to a type 65 | function (obj) { 66 | // console.log('obj: ', typeof obj, obj.constructor); 67 | if (obj instanceof _UserLoader2.default) { 68 | return _UserType2.default; 69 | } 70 | return null; 71 | }), 72 | nodeField = _nodeDefinitions.nodeField, 73 | nodeInterface = _nodeDefinitions.nodeInterface; 74 | 75 | var NodeInterface = exports.NodeInterface = nodeInterface; 76 | var NodeField = exports.NodeField = nodeField; -------------------------------------------------------------------------------- /packages/server/dist/loader/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.MessageLoader = exports.ConversationLoader = exports.PetLoader = exports.UserLoader = undefined; 7 | 8 | var _UserLoader2 = require('./UserLoader'); 9 | 10 | var _UserLoader = _interopRequireWildcard(_UserLoader2); 11 | 12 | var _PetLoader2 = require('./PetLoader'); 13 | 14 | var _PetLoader = _interopRequireWildcard(_PetLoader2); 15 | 16 | var _ConversationLoader2 = require('./ConversationLoader'); 17 | 18 | var _ConversationLoader = _interopRequireWildcard(_ConversationLoader2); 19 | 20 | var _MessageLoader2 = require('./MessageLoader'); 21 | 22 | var _MessageLoader = _interopRequireWildcard(_MessageLoader2); 23 | 24 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } 25 | 26 | exports.UserLoader = _UserLoader; 27 | exports.PetLoader = _PetLoader; 28 | exports.ConversationLoader = _ConversationLoader; 29 | exports.MessageLoader = _MessageLoader; -------------------------------------------------------------------------------- /packages/server/dist/model/Conversation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _mongoose = require('mongoose'); 8 | 9 | var _mongoose2 = _interopRequireDefault(_mongoose); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | var Schema = _mongoose2.default.Schema({ 14 | messages: { 15 | type: [_mongoose2.default.Schema.ObjectId], 16 | ref: 'Message', 17 | required: false 18 | }, 19 | owner: { 20 | type: _mongoose2.default.Schema.ObjectId, 21 | ref: 'User', 22 | required: true 23 | }, 24 | otherUser: { 25 | type: _mongoose2.default.Schema.ObjectId, 26 | ref: 'User', 27 | required: true 28 | }, 29 | lastMessage: { 30 | type: String, 31 | required: false 32 | } 33 | }, { 34 | collection: 'conversation', 35 | timestamps: { 36 | createdAt: 'createdAt', 37 | updatedAt: 'updatedAt' 38 | } 39 | }); 40 | 41 | exports.default = _mongoose2.default.model('Conversation', Schema); -------------------------------------------------------------------------------- /packages/server/dist/model/Message.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _mongoose = require('mongoose'); 8 | 9 | var _mongoose2 = _interopRequireDefault(_mongoose); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | var Schema = _mongoose2.default.Schema({ 14 | text: { 15 | type: String, 16 | required: true 17 | }, 18 | owner: { 19 | type: _mongoose2.default.Schema.ObjectId, 20 | ref: 'User', 21 | required: true 22 | }, 23 | conversation: { 24 | type: _mongoose2.default.Schema.ObjectId, 25 | ref: 'Conversation', 26 | required: true 27 | } 28 | }, { 29 | collection: 'message', 30 | timestamps: { 31 | createdAt: 'createdAt', 32 | updatedAt: 'updatedAt' 33 | } 34 | }); 35 | 36 | exports.default = _mongoose2.default.model('Message', Schema); -------------------------------------------------------------------------------- /packages/server/dist/model/Pet.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _mongoose = require('mongoose'); 8 | 9 | var _mongoose2 = _interopRequireDefault(_mongoose); 10 | 11 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 12 | 13 | var Schema = _mongoose2.default.Schema({ 14 | image: { 15 | type: String, 16 | required: false 17 | }, 18 | name: { 19 | type: String, 20 | required: true 21 | }, 22 | gender: { 23 | type: String, 24 | required: true 25 | }, 26 | port: { 27 | type: String, 28 | required: true 29 | }, 30 | birthDate: { 31 | type: String, 32 | required: true 33 | }, 34 | owner: { 35 | type: String, 36 | required: true 37 | }, 38 | castrated: { 39 | type: Boolean, 40 | required: true 41 | }, 42 | color: { 43 | type: String, 44 | required: true 45 | }, 46 | alergic: { 47 | type: [String], 48 | required: false, 49 | default: [] 50 | }, 51 | doctor: { 52 | type: String, 53 | required: false 54 | }, 55 | race: { 56 | type: String, 57 | required: true 58 | }, 59 | type: { 60 | type: String, 61 | required: true 62 | }, 63 | active: { 64 | type: Boolean, 65 | default: true, 66 | required: true 67 | } 68 | }, { 69 | collection: 'pet', 70 | timestamps: { 71 | createdAt: 'createdAt', 72 | updatedAt: 'updatedAt' 73 | } 74 | }); 75 | 76 | exports.default = _mongoose2.default.model('Pet', Schema); -------------------------------------------------------------------------------- /packages/server/dist/model/User.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _mongoose = require('mongoose'); 8 | 9 | var _mongoose2 = _interopRequireDefault(_mongoose); 10 | 11 | var _bcryptjs = require('bcryptjs'); 12 | 13 | var _bcryptjs2 = _interopRequireDefault(_bcryptjs); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | var Schema = new _mongoose2.default.Schema({ 18 | name: { 19 | type: String, 20 | required: true 21 | }, 22 | password: { 23 | type: String, 24 | hidden: true 25 | }, 26 | email: { 27 | type: String, 28 | required: false, 29 | index: true 30 | }, 31 | active: { 32 | type: Boolean, 33 | default: true 34 | } 35 | }, { 36 | timestamps: { 37 | createdAt: 'createdAt', 38 | updatedAt: 'updatedAt' 39 | }, 40 | collection: 'user' 41 | }); 42 | 43 | Schema.pre('save', function (next) { 44 | if (this.isModified('password')) { 45 | this.password = this.encryptPassword(this.password); 46 | } 47 | 48 | return next(); 49 | }); 50 | 51 | Schema.methods = { 52 | authenticate: function authenticate(plainTextPassword) { 53 | return _bcryptjs2.default.compareSync(plainTextPassword, this.password); 54 | }, 55 | encryptPassword: function encryptPassword(password) { 56 | return _bcryptjs2.default.hashSync(password, 8); 57 | } 58 | }; 59 | 60 | exports.default = _mongoose2.default.model('User', Schema); -------------------------------------------------------------------------------- /packages/server/dist/model/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.Message = exports.Conversation = exports.Pet = exports.User = undefined; 7 | 8 | var _User2 = require('./User'); 9 | 10 | var _User3 = _interopRequireDefault(_User2); 11 | 12 | var _Pet2 = require('./Pet'); 13 | 14 | var _Pet3 = _interopRequireDefault(_Pet2); 15 | 16 | var _Conversation2 = require('./Conversation'); 17 | 18 | var _Conversation3 = _interopRequireDefault(_Conversation2); 19 | 20 | var _Message2 = require('./Message'); 21 | 22 | var _Message3 = _interopRequireDefault(_Message2); 23 | 24 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 25 | 26 | exports.User = _User3.default; 27 | exports.Pet = _Pet3.default; 28 | exports.Conversation = _Conversation3.default; 29 | exports.Message = _Message3.default; -------------------------------------------------------------------------------- /packages/server/dist/schema.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.schema = undefined; 7 | 8 | var _graphql = require('graphql'); 9 | 10 | var _QueryType = require('./type/QueryType'); 11 | 12 | var _QueryType2 = _interopRequireDefault(_QueryType); 13 | 14 | var _MutationType = require('./type/MutationType'); 15 | 16 | var _MutationType2 = _interopRequireDefault(_MutationType); 17 | 18 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 19 | 20 | var schema = exports.schema = new _graphql.GraphQLSchema({ 21 | query: _QueryType2.default, 22 | mutation: _MutationType2.default 23 | }); -------------------------------------------------------------------------------- /packages/server/dist/type/ConversationType.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _graphql = require('graphql'); 8 | 9 | var _graphqlRelay = require('graphql-relay'); 10 | 11 | var _NodeInterface = require('../interface/NodeInterface'); 12 | 13 | var _UserType = require('./UserType'); 14 | 15 | var _UserType2 = _interopRequireDefault(_UserType); 16 | 17 | var _MessageType = require('./MessageType'); 18 | 19 | var _MessageType2 = _interopRequireDefault(_MessageType); 20 | 21 | var _loader = require('../loader'); 22 | 23 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 24 | 25 | exports.default = new _graphql.GraphQLObjectType({ 26 | name: 'Conversation', 27 | description: 'Conversation data', 28 | fields: function fields() { 29 | return { 30 | id: (0, _graphqlRelay.globalIdField)('Conversation'), 31 | _id: { 32 | type: _graphql.GraphQLString, 33 | resolve: function resolve(conversation) { 34 | return conversation._id; 35 | } 36 | }, 37 | owner: { 38 | type: _UserType2.default, 39 | resolve: function resolve(_ref, args, context) { 40 | var owner = _ref.owner; 41 | return _loader.UserLoader.load(context, owner); 42 | } 43 | }, 44 | otherUser: { 45 | type: _UserType2.default, 46 | resolve: function resolve(_ref2, args, context) { 47 | var otherUser = _ref2.otherUser; 48 | return _loader.UserLoader.load(context, otherUser); 49 | } 50 | }, 51 | lastMessage: { 52 | type: _graphql.GraphQLString, 53 | resolve: function resolve(conversation) { 54 | return conversation.lastMessage; 55 | } 56 | }, 57 | updatedAt: { 58 | type: _graphql.GraphQLString, 59 | resolve: function resolve(conversation) { 60 | return conversation.updatedAt; 61 | } 62 | }, 63 | messages: { 64 | type: _MessageType2.default, 65 | resolve: function resolve(_ref3, args, context) { 66 | var owner = _ref3.owner; 67 | return _loader.MessageLoader.load(context, owner); 68 | } 69 | } 70 | }; 71 | }, 72 | interfaces: function interfaces() { 73 | return [_NodeInterface.NodeInterface]; 74 | } 75 | }); -------------------------------------------------------------------------------- /packages/server/dist/type/MessageType.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _graphql = require('graphql'); 8 | 9 | var _graphqlRelay = require('graphql-relay'); 10 | 11 | var _NodeInterface = require('../interface/NodeInterface'); 12 | 13 | var _UserType = require('./UserType'); 14 | 15 | var _UserType2 = _interopRequireDefault(_UserType); 16 | 17 | var _loader = require('../loader'); 18 | 19 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 20 | 21 | exports.default = new _graphql.GraphQLObjectType({ 22 | name: 'Message', 23 | description: 'message data', 24 | fields: function fields() { 25 | return { 26 | id: (0, _graphqlRelay.globalIdField)('Message'), 27 | _id: { 28 | type: _graphql.GraphQLString, 29 | resolve: function resolve(message) { 30 | return message._id; 31 | } 32 | }, 33 | owner: { 34 | type: _UserType2.default, 35 | resolve: function resolve(_ref, args, context) { 36 | var owner = _ref.owner; 37 | return _loader.UserLoader.load(context, owner); 38 | } 39 | }, 40 | text: { 41 | type: _graphql.GraphQLString, 42 | resolve: function resolve(message) { 43 | return message.text; 44 | } 45 | } 46 | }; 47 | }, 48 | interfaces: function interfaces() { 49 | return [_NodeInterface.NodeInterface]; 50 | } 51 | }); -------------------------------------------------------------------------------- /packages/server/dist/type/MutationType.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _graphql = require('graphql'); 8 | 9 | var _LoginEmailMutation = require('../mutation/LoginEmailMutation'); 10 | 11 | var _LoginEmailMutation2 = _interopRequireDefault(_LoginEmailMutation); 12 | 13 | var _RegisterEmailMutation = require('../mutation/RegisterEmailMutation'); 14 | 15 | var _RegisterEmailMutation2 = _interopRequireDefault(_RegisterEmailMutation); 16 | 17 | var _ChangePasswordMutation = require('../mutation/ChangePasswordMutation'); 18 | 19 | var _ChangePasswordMutation2 = _interopRequireDefault(_ChangePasswordMutation); 20 | 21 | var _PetAddMutation = require('../mutation/PetAddMutation'); 22 | 23 | var _PetAddMutation2 = _interopRequireDefault(_PetAddMutation); 24 | 25 | var _StartConversationMutation = require('../mutation/StartConversationMutation'); 26 | 27 | var _StartConversationMutation2 = _interopRequireDefault(_StartConversationMutation); 28 | 29 | var _PetDeleteMutation = require('../mutation/PetDeleteMutation'); 30 | 31 | var _PetDeleteMutation2 = _interopRequireDefault(_PetDeleteMutation); 32 | 33 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 34 | 35 | exports.default = new _graphql.GraphQLObjectType({ 36 | name: 'Mutation', 37 | fields: function fields() { 38 | return { 39 | // auth 40 | LoginEmail: _LoginEmailMutation2.default, 41 | RegisterEmail: _RegisterEmailMutation2.default, 42 | ChangePassword: _ChangePasswordMutation2.default, 43 | 44 | // conversation 45 | StartConversation: _StartConversationMutation2.default, 46 | 47 | // pet 48 | PetAdd: _PetAddMutation2.default, 49 | PetDelete: _PetDeleteMutation2.default 50 | }; 51 | } 52 | }); -------------------------------------------------------------------------------- /packages/server/dist/type/UserType.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _graphql = require('graphql'); 8 | 9 | var _graphqlRelay = require('graphql-relay'); 10 | 11 | var _NodeInterface = require('../interface/NodeInterface'); 12 | 13 | exports.default = new _graphql.GraphQLObjectType({ 14 | name: 'User', 15 | description: 'User data', 16 | fields: function fields() { 17 | return { 18 | id: (0, _graphqlRelay.globalIdField)('User'), 19 | _id: { 20 | type: _graphql.GraphQLString, 21 | resolve: function resolve(user) { 22 | return user._id; 23 | } 24 | }, 25 | name: { 26 | type: _graphql.GraphQLString, 27 | resolve: function resolve(user) { 28 | return user.name; 29 | } 30 | }, 31 | email: { 32 | type: _graphql.GraphQLString, 33 | resolve: function resolve(user) { 34 | return user.email; 35 | } 36 | }, 37 | active: { 38 | type: _graphql.GraphQLBoolean, 39 | resolve: function resolve(user) { 40 | return user.active; 41 | } 42 | } 43 | }; 44 | }, 45 | interfaces: function interfaces() { 46 | return [_NodeInterface.NodeInterface]; 47 | } 48 | }); -------------------------------------------------------------------------------- /packages/server/docker-compose.test.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | test-jest: 4 | build: . 5 | depends_on: 6 | - mongo 7 | links: 8 | - mongo 9 | environment: 10 | NODE_ENV: test 11 | MONGO_URL: mongodb://mongo/test 12 | volumes: 13 | - "./src:/app/src" 14 | entrypoint: "npm run test:watch" 15 | mongo: 16 | image: mongo 17 | -------------------------------------------------------------------------------- /packages/server/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | graph-api: 4 | build: . 5 | depends_on: 6 | - mongo 7 | links: 8 | - mongo 9 | environment: 10 | NODE_ENV: development 11 | MONGO_URL: mongodb://mongo/database 12 | ports: 13 | - "5000:5000" 14 | volumes: 15 | - "./src:/app/src" 16 | - "./dist:/app/dist" 17 | entrypoint: "npm run watch" 18 | 19 | mongo: 20 | image: mongo 21 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/babel-eslint_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 588520259adb70f153ddadc72115a81c 2 | // flow-typed version: <>/babel-eslint_v^7.2.2/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-eslint' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'babel-eslint' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-eslint/babylon-to-espree/attachComments' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'babel-eslint/babylon-to-espree/convertComments' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'babel-eslint/babylon-to-espree/convertTemplateType' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'babel-eslint/babylon-to-espree/index' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'babel-eslint/babylon-to-espree/toAST' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'babel-eslint/babylon-to-espree/toToken' { 46 | declare module.exports: any; 47 | } 48 | 49 | declare module 'babel-eslint/babylon-to-espree/toTokens' { 50 | declare module.exports: any; 51 | } 52 | 53 | // Filename aliases 54 | declare module 'babel-eslint/babylon-to-espree/attachComments.js' { 55 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/attachComments'>; 56 | } 57 | declare module 'babel-eslint/babylon-to-espree/convertComments.js' { 58 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/convertComments'>; 59 | } 60 | declare module 'babel-eslint/babylon-to-espree/convertTemplateType.js' { 61 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/convertTemplateType'>; 62 | } 63 | declare module 'babel-eslint/babylon-to-espree/index.js' { 64 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/index'>; 65 | } 66 | declare module 'babel-eslint/babylon-to-espree/toAST.js' { 67 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/toAST'>; 68 | } 69 | declare module 'babel-eslint/babylon-to-espree/toToken.js' { 70 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/toToken'>; 71 | } 72 | declare module 'babel-eslint/babylon-to-espree/toTokens.js' { 73 | declare module.exports: $Exports<'babel-eslint/babylon-to-espree/toTokens'>; 74 | } 75 | declare module 'babel-eslint/index' { 76 | declare module.exports: $Exports<'babel-eslint'>; 77 | } 78 | declare module 'babel-eslint/index.js' { 79 | declare module.exports: $Exports<'babel-eslint'>; 80 | } 81 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/babel-polyfill_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: c6f558fc8ba25b565b624d19c1c0f1d1 2 | // flow-typed version: <>/babel-polyfill_v^6.23.0/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-polyfill' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'babel-polyfill' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-polyfill/browser' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'babel-polyfill/dist/polyfill' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'babel-polyfill/dist/polyfill.min' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'babel-polyfill/lib/index' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'babel-polyfill/scripts/postpublish' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'babel-polyfill/scripts/prepublish' { 46 | declare module.exports: any; 47 | } 48 | 49 | // Filename aliases 50 | declare module 'babel-polyfill/browser.js' { 51 | declare module.exports: $Exports<'babel-polyfill/browser'>; 52 | } 53 | declare module 'babel-polyfill/dist/polyfill.js' { 54 | declare module.exports: $Exports<'babel-polyfill/dist/polyfill'>; 55 | } 56 | declare module 'babel-polyfill/dist/polyfill.min.js' { 57 | declare module.exports: $Exports<'babel-polyfill/dist/polyfill.min'>; 58 | } 59 | declare module 'babel-polyfill/lib/index.js' { 60 | declare module.exports: $Exports<'babel-polyfill/lib/index'>; 61 | } 62 | declare module 'babel-polyfill/scripts/postpublish.js' { 63 | declare module.exports: $Exports<'babel-polyfill/scripts/postpublish'>; 64 | } 65 | declare module 'babel-polyfill/scripts/prepublish.js' { 66 | declare module.exports: $Exports<'babel-polyfill/scripts/prepublish'>; 67 | } 68 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/babel-preset-es2015_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: cc52b4874d48c8e5eeafb8fade9fbdbd 2 | // flow-typed version: <>/babel-preset-es2015_v^6.24.1/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-preset-es2015' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'babel-preset-es2015' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-preset-es2015/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-preset-es2015/lib/index.js' { 31 | declare module.exports: $Exports<'babel-preset-es2015/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/babel-preset-flow_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: c39acea7c78146fcb5cc8be37f7ea134 2 | // flow-typed version: <>/babel-preset-flow_v^6.23.0/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-preset-flow' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'babel-preset-flow' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-preset-flow/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-preset-flow/lib/index.js' { 31 | declare module.exports: $Exports<'babel-preset-flow/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/babel-preset-stage-0_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 1dc8e15c75f281dffdace778720e0eab 2 | // flow-typed version: <>/babel-preset-stage-0_v^6.24.1/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'babel-preset-stage-0' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'babel-preset-stage-0' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'babel-preset-stage-0/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'babel-preset-stage-0/lib/index.js' { 31 | declare module.exports: $Exports<'babel-preset-stage-0/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/bcrypt-as-promised_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 1337b7210d228fc438075ecd083ad4d2 2 | // flow-typed version: <>/bcrypt-as-promised_v^1.1.0/flow_v0.44.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'bcrypt-as-promised' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'bcrypt-as-promised' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'bcrypt-as-promised/test/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'bcrypt-as-promised/index' { 31 | declare module.exports: $Exports<'bcrypt-as-promised'>; 32 | } 33 | declare module 'bcrypt-as-promised/index.js' { 34 | declare module.exports: $Exports<'bcrypt-as-promised'>; 35 | } 36 | declare module 'bcrypt-as-promised/test/index.js' { 37 | declare module.exports: $Exports<'bcrypt-as-promised/test/index'>; 38 | } 39 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/dotenv-safe_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 73472b296fb6b664764cf68ecb14ed35 2 | // flow-typed version: <>/dotenv-safe_v^4.0.4/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'dotenv-safe' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'dotenv-safe' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'dotenv-safe/config' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'dotenv-safe/MissingEnvVarsError' { 30 | declare module.exports: any; 31 | } 32 | 33 | // Filename aliases 34 | declare module 'dotenv-safe/config.js' { 35 | declare module.exports: $Exports<'dotenv-safe/config'>; 36 | } 37 | declare module 'dotenv-safe/index' { 38 | declare module.exports: $Exports<'dotenv-safe'>; 39 | } 40 | declare module 'dotenv-safe/index.js' { 41 | declare module.exports: $Exports<'dotenv-safe'>; 42 | } 43 | declare module 'dotenv-safe/MissingEnvVarsError.js' { 44 | declare module.exports: $Exports<'dotenv-safe/MissingEnvVarsError'>; 45 | } 46 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/eslint-config-airbnb_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 216e3488c87bcd849b648fbf5c48e83b 2 | // flow-typed version: <>/eslint-config-airbnb_v^15.0.1/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'eslint-config-airbnb' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'eslint-config-airbnb' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'eslint-config-airbnb/base' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'eslint-config-airbnb/legacy' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'eslint-config-airbnb/rules/react-a11y' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'eslint-config-airbnb/rules/react' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'eslint-config-airbnb/test/test-base' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'eslint-config-airbnb/test/test-react-order' { 46 | declare module.exports: any; 47 | } 48 | 49 | // Filename aliases 50 | declare module 'eslint-config-airbnb/base.js' { 51 | declare module.exports: $Exports<'eslint-config-airbnb/base'>; 52 | } 53 | declare module 'eslint-config-airbnb/index' { 54 | declare module.exports: $Exports<'eslint-config-airbnb'>; 55 | } 56 | declare module 'eslint-config-airbnb/index.js' { 57 | declare module.exports: $Exports<'eslint-config-airbnb'>; 58 | } 59 | declare module 'eslint-config-airbnb/legacy.js' { 60 | declare module.exports: $Exports<'eslint-config-airbnb/legacy'>; 61 | } 62 | declare module 'eslint-config-airbnb/rules/react-a11y.js' { 63 | declare module.exports: $Exports<'eslint-config-airbnb/rules/react-a11y'>; 64 | } 65 | declare module 'eslint-config-airbnb/rules/react.js' { 66 | declare module.exports: $Exports<'eslint-config-airbnb/rules/react'>; 67 | } 68 | declare module 'eslint-config-airbnb/test/test-base.js' { 69 | declare module.exports: $Exports<'eslint-config-airbnb/test/test-base'>; 70 | } 71 | declare module 'eslint-config-airbnb/test/test-react-order.js' { 72 | declare module.exports: $Exports<'eslint-config-airbnb/test/test-react-order'>; 73 | } 74 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/flow-bin_v0.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 6a5610678d4b01e13bbfbbc62bdaf583 2 | // flow-typed version: 3817bc6980/flow-bin_v0.x.x/flow_>=v0.25.x 3 | 4 | declare module "flow-bin" { 5 | declare module.exports: string; 6 | } 7 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/graphql-relay_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 1a203c9536ec8469be9ca5d234428f2c 2 | // flow-typed version: <>/graphql-relay_v^0.5.1/flow_v0.44.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'graphql-relay' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'graphql-relay' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'graphql-relay/lib/connection/arrayconnection' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'graphql-relay/lib/connection/connection' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'graphql-relay/lib/connection/connectiontypes' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'graphql-relay/lib/index' { 38 | declare module.exports: any; 39 | } 40 | 41 | declare module 'graphql-relay/lib/mutation/mutation' { 42 | declare module.exports: any; 43 | } 44 | 45 | declare module 'graphql-relay/lib/node/node' { 46 | declare module.exports: any; 47 | } 48 | 49 | declare module 'graphql-relay/lib/node/plural' { 50 | declare module.exports: any; 51 | } 52 | 53 | declare module 'graphql-relay/lib/utils/base64' { 54 | declare module.exports: any; 55 | } 56 | 57 | // Filename aliases 58 | declare module 'graphql-relay/lib/connection/arrayconnection.js' { 59 | declare module.exports: $Exports<'graphql-relay/lib/connection/arrayconnection'>; 60 | } 61 | declare module 'graphql-relay/lib/connection/connection.js' { 62 | declare module.exports: $Exports<'graphql-relay/lib/connection/connection'>; 63 | } 64 | declare module 'graphql-relay/lib/connection/connectiontypes.js' { 65 | declare module.exports: $Exports<'graphql-relay/lib/connection/connectiontypes'>; 66 | } 67 | declare module 'graphql-relay/lib/index.js' { 68 | declare module.exports: $Exports<'graphql-relay/lib/index'>; 69 | } 70 | declare module 'graphql-relay/lib/mutation/mutation.js' { 71 | declare module.exports: $Exports<'graphql-relay/lib/mutation/mutation'>; 72 | } 73 | declare module 'graphql-relay/lib/node/node.js' { 74 | declare module.exports: $Exports<'graphql-relay/lib/node/node'>; 75 | } 76 | declare module 'graphql-relay/lib/node/plural.js' { 77 | declare module.exports: $Exports<'graphql-relay/lib/node/plural'>; 78 | } 79 | declare module 'graphql-relay/lib/utils/base64.js' { 80 | declare module.exports: $Exports<'graphql-relay/lib/utils/base64'>; 81 | } 82 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/isomorphic-fetch_v2.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 28ad27471ba2cb831af6a1f17b7f0cf0 2 | // flow-typed version: f3161dc07c/isomorphic-fetch_v2.x.x/flow_>=v0.25.x 3 | 4 | 5 | declare module 'isomorphic-fetch' { 6 | declare module.exports: (input: string | Request, init?: RequestOptions) => Promise; 7 | } 8 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/koa-bodyparser_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: ef2abddb0428f9283902c978fcf7025c 2 | // flow-typed version: <>/koa-bodyparser_v^2.2.0/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'koa-bodyparser' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'koa-bodyparser' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | 26 | 27 | // Filename aliases 28 | declare module 'koa-bodyparser/index' { 29 | declare module.exports: $Exports<'koa-bodyparser'>; 30 | } 31 | declare module 'koa-bodyparser/index.js' { 32 | declare module.exports: $Exports<'koa-bodyparser'>; 33 | } 34 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/koa-compose_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: ecfb1138a666eba69173c6cfe3f1bac2 2 | // flow-typed version: <>/koa-compose_v^4.0.0/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'koa-compose' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'koa-compose' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | 26 | 27 | // Filename aliases 28 | declare module 'koa-compose/index' { 29 | declare module.exports: $Exports<'koa-compose'>; 30 | } 31 | declare module 'koa-compose/index.js' { 32 | declare module.exports: $Exports<'koa-compose'>; 33 | } 34 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/koa-convert_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 35ee626f330ad40d82f15951426b6bd3 2 | // flow-typed version: <>/koa-convert_v^1.2.0/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'koa-convert' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'koa-convert' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'koa-convert/test' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'koa-convert/index' { 31 | declare module.exports: $Exports<'koa-convert'>; 32 | } 33 | declare module 'koa-convert/index.js' { 34 | declare module.exports: $Exports<'koa-convert'>; 35 | } 36 | declare module 'koa-convert/test.js' { 37 | declare module.exports: $Exports<'koa-convert/test'>; 38 | } 39 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/koa-cors_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 02d812c520427cb211b82d27b5865a9e 2 | // flow-typed version: <>/koa-cors_v0.0.16/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'koa-cors' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'koa-cors' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'koa-cors/examples/basic-auth-and-cors' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'koa-cors/examples/custom-options' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'koa-cors/examples/defaults-options' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'koa-cors/test/index' { 38 | declare module.exports: any; 39 | } 40 | 41 | // Filename aliases 42 | declare module 'koa-cors/examples/basic-auth-and-cors.js' { 43 | declare module.exports: $Exports<'koa-cors/examples/basic-auth-and-cors'>; 44 | } 45 | declare module 'koa-cors/examples/custom-options.js' { 46 | declare module.exports: $Exports<'koa-cors/examples/custom-options'>; 47 | } 48 | declare module 'koa-cors/examples/defaults-options.js' { 49 | declare module.exports: $Exports<'koa-cors/examples/defaults-options'>; 50 | } 51 | declare module 'koa-cors/index' { 52 | declare module.exports: $Exports<'koa-cors'>; 53 | } 54 | declare module 'koa-cors/index.js' { 55 | declare module.exports: $Exports<'koa-cors'>; 56 | } 57 | declare module 'koa-cors/test/index.js' { 58 | declare module.exports: $Exports<'koa-cors/test/index'>; 59 | } 60 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/koa-graphql-batch_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 8b1a206c18e12996dff61f8a245048fa 2 | // flow-typed version: <>/koa-graphql-batch_v^1.1.0/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'koa-graphql-batch' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'koa-graphql-batch' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'koa-graphql-batch/lib/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | // Filename aliases 30 | declare module 'koa-graphql-batch/lib/index.js' { 31 | declare module.exports: $Exports<'koa-graphql-batch/lib/index'>; 32 | } 33 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/koa-graphql_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 2716bccab7716f0d52a5be0ffe60bf84 2 | // flow-typed version: <>/koa-graphql_v^0.6.2/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'koa-graphql' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'koa-graphql' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'koa-graphql/dist/index' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'koa-graphql/dist/renderGraphiQL' { 30 | declare module.exports: any; 31 | } 32 | 33 | // Filename aliases 34 | declare module 'koa-graphql/dist/index.js' { 35 | declare module.exports: $Exports<'koa-graphql/dist/index'>; 36 | } 37 | declare module 'koa-graphql/dist/renderGraphiQL.js' { 38 | declare module.exports: $Exports<'koa-graphql/dist/renderGraphiQL'>; 39 | } 40 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/koa-logger_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: a9c7f49a73f83723d24c91bb87b3b15b 2 | // flow-typed version: <>/koa-logger_v^2.0.1/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'koa-logger' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'koa-logger' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | 26 | 27 | // Filename aliases 28 | declare module 'koa-logger/index' { 29 | declare module.exports: $Exports<'koa-logger'>; 30 | } 31 | declare module 'koa-logger/index.js' { 32 | declare module.exports: $Exports<'koa-logger'>; 33 | } 34 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/koa-router_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 9b38c1239716a494c252fe5f4ed23e92 2 | // flow-typed version: <>/koa-router_v^7.1.1/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'koa-router' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'koa-router' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'koa-router/lib/layer' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'koa-router/lib/router' { 30 | declare module.exports: any; 31 | } 32 | 33 | // Filename aliases 34 | declare module 'koa-router/lib/layer.js' { 35 | declare module.exports: $Exports<'koa-router/lib/layer'>; 36 | } 37 | declare module 'koa-router/lib/router.js' { 38 | declare module.exports: $Exports<'koa-router/lib/router'>; 39 | } 40 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/koa_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: ae61fc7076a2b7f9238d0ee175b2e90c 2 | // flow-typed version: <>/koa_v^2.2.0/flow_v0.44.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'koa' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'koa' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'koa/lib/application' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'koa/lib/context' { 30 | declare module.exports: any; 31 | } 32 | 33 | declare module 'koa/lib/request' { 34 | declare module.exports: any; 35 | } 36 | 37 | declare module 'koa/lib/response' { 38 | declare module.exports: any; 39 | } 40 | 41 | // Filename aliases 42 | declare module 'koa/lib/application.js' { 43 | declare module.exports: $Exports<'koa/lib/application'>; 44 | } 45 | declare module 'koa/lib/context.js' { 46 | declare module.exports: $Exports<'koa/lib/context'>; 47 | } 48 | declare module 'koa/lib/request.js' { 49 | declare module.exports: $Exports<'koa/lib/request'>; 50 | } 51 | declare module 'koa/lib/response.js' { 52 | declare module.exports: $Exports<'koa/lib/response'>; 53 | } 54 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/repl-promised_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 706d69a61911e3538005b850629cf0ec 2 | // flow-typed version: <>/repl-promised_v^0.1.0/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'repl-promised' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'repl-promised' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | 26 | 27 | // Filename aliases 28 | declare module 'repl-promised/index' { 29 | declare module.exports: $Exports<'repl-promised'>; 30 | } 31 | declare module 'repl-promised/index.js' { 32 | declare module.exports: $Exports<'repl-promised'>; 33 | } 34 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/repl.history_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 2e8e406a416c4adee333aeab14221385 2 | // flow-typed version: <>/repl.history_v^0.1.4/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'repl.history' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'repl.history' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | 26 | 27 | // Filename aliases 28 | declare module 'repl.history/index' { 29 | declare module.exports: $Exports<'repl.history'>; 30 | } 31 | declare module 'repl.history/index.js' { 32 | declare module.exports: $Exports<'repl.history'>; 33 | } 34 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/repl_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 6628a14954ed2d7f4be14b3124b0fb07 2 | // flow-typed version: <>/repl_v^0.1.3/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'repl' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'repl' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'repl/lib/repl' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'repl/test' { 30 | declare module.exports: any; 31 | } 32 | 33 | // Filename aliases 34 | declare module 'repl/index' { 35 | declare module.exports: $Exports<'repl'>; 36 | } 37 | declare module 'repl/index.js' { 38 | declare module.exports: $Exports<'repl'>; 39 | } 40 | declare module 'repl/lib/repl.js' { 41 | declare module.exports: $Exports<'repl/lib/repl'>; 42 | } 43 | declare module 'repl/test.js' { 44 | declare module.exports: $Exports<'repl/test'>; 45 | } 46 | -------------------------------------------------------------------------------- /packages/server/flow-typed/npm/rimraf_vx.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 3ebb7dc9640f087ab46c79a1c365e10a 2 | // flow-typed version: <>/rimraf_v^2.6.1/flow_v0.48.0 3 | 4 | /** 5 | * This is an autogenerated libdef stub for: 6 | * 7 | * 'rimraf' 8 | * 9 | * Fill this stub out by replacing all the `any` types. 10 | * 11 | * Once filled out, we encourage you to share your work with the 12 | * community by sending a pull request to: 13 | * https://github.com/flowtype/flow-typed 14 | */ 15 | 16 | declare module 'rimraf' { 17 | declare module.exports: any; 18 | } 19 | 20 | /** 21 | * We include stubs for each file inside this npm package in case you need to 22 | * require those files directly. Feel free to delete any files that aren't 23 | * needed. 24 | */ 25 | declare module 'rimraf/bin' { 26 | declare module.exports: any; 27 | } 28 | 29 | declare module 'rimraf/rimraf' { 30 | declare module.exports: any; 31 | } 32 | 33 | // Filename aliases 34 | declare module 'rimraf/bin.js' { 35 | declare module.exports: $Exports<'rimraf/bin'>; 36 | } 37 | declare module 'rimraf/rimraf.js' { 38 | declare module.exports: $Exports<'rimraf/rimraf'>; 39 | } 40 | -------------------------------------------------------------------------------- /packages/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@foton/server", 3 | "version": "0.0.1", 4 | "dependencies": { 5 | "@entria/graphql-mongoose-loader": "^1.1.1", 6 | "babel-polyfill": "^6.26.0", 7 | "bcryptjs": "^2.4.3", 8 | "dataloader": "^1.3.0", 9 | "dotenv-safe": "^4.0.4", 10 | "graphql": "^0.12.3", 11 | "graphql-relay": "^0.5.4", 12 | "idx": "^2.4.0", 13 | "isomorphic-fetch": "^2.2.1", 14 | "jsonwebtoken": "^8.1.0", 15 | "kcors": "^2.2.1", 16 | "koa": "^2.4.1", 17 | "koa-bodyparser": "^4.2.0", 18 | "koa-compose": "^4.0.0", 19 | "koa-convert": "^1.2.0", 20 | "koa-graphql": "^0.7.3", 21 | "koa-graphql-batch": "^1.1.0", 22 | "koa-logger": "^3.1.0", 23 | "koa-router": "^7.3.0", 24 | "moment": "^2.22.2", 25 | "mongoose": "^5.0.0-rc2" 26 | }, 27 | "devDependencies": { 28 | "babel-cli": "^6.26.0", 29 | "babel-eslint": "^8.1.2", 30 | "babel-preset-es2015": "^6.24.1", 31 | "babel-preset-flow": "^6.23.0", 32 | "babel-preset-stage-0": "^6.24.1", 33 | "eslint": "^4.14.0", 34 | "eslint-config-airbnb": "^16.1.0", 35 | "eslint-plugin-import": "^2.8.0", 36 | "flow-bin": "^0.62.0", 37 | "husky": "^0.14.3", 38 | "jest": "22.0.4", 39 | "jest-cli": "22.0.4", 40 | "lint-staged": "6.0.0", 41 | "nodemon": "^1.14.7", 42 | "now-env": "^3.1.0", 43 | "prettier": "^1.9.2", 44 | "reify": "^0.13.5", 45 | "repl": "^0.1.3", 46 | "repl-promised": "^0.1.0", 47 | "repl.history": "^0.1.4", 48 | "rimraf": "^2.6.2" 49 | }, 50 | "jest": { 51 | "testEnvironment": "node", 52 | "testPathIgnorePatterns": [ 53 | "/node_modules/", 54 | "./dist" 55 | ], 56 | "coverageReporters": [ 57 | "lcov", 58 | "html" 59 | ], 60 | "coverageDirectory": "./coverage/", 61 | "collectCoverage": true, 62 | "moduleNameMapper": { 63 | "^mongoose$": "/node_modules/mongoose" 64 | }, 65 | "setupFiles": [ 66 | "babel-polyfill" 67 | ] 68 | }, 69 | "license": "MIT", 70 | "main": "index.js", 71 | "repository": { 72 | "type": "git", 73 | "url": "https://github.com/entria/graphql-dataloader-boilerplate" 74 | }, 75 | "lint-staged": { 76 | "*.js": [ 77 | "prettier --write --single-quote true --trailing-comma all --print-width 120", 78 | "eslint --fix", 79 | "git add" 80 | ] 81 | }, 82 | "scripts": { 83 | "build": "npm run clear && babel src --ignore *.spec.js --out-dir dist --copy-files", 84 | "clear": "rimraf ./dist", 85 | "flow": "flow; test $? -eq 0 -o $? -eq 2", 86 | "lint": "eslint src/**", 87 | "precommit": "lint-staged", 88 | "repl": "nodemon --config ./repl/nodemon.json ./repl.js --exec babel-node", 89 | "start": "node dist/index.js", 90 | "test": "jest --coverage --forceExit --runInBand", 91 | "test:watch": "jest --watch --coverage", 92 | "update-schema": "npx babel-node ./scripts/updateSchema.js", 93 | "watch": "nodemon src/index.js --exec babel-node" 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /packages/server/repl.js: -------------------------------------------------------------------------------- 1 | import 'reify/repl'; 2 | import 'isomorphic-fetch'; 3 | import 'babel-polyfill'; 4 | import REPL from 'repl'; 5 | import replPromised from 'repl-promised'; 6 | import history from 'repl.history'; 7 | // import babel from 'babel-core'; 8 | const babel = require('babel-core'); 9 | 10 | import connectDatabase from './src/database'; 11 | import * as M from './src/model'; 12 | import { generateToken } from './src/auth'; 13 | 14 | // based on https://gist.github.com/princejwesley/a66d514d86ea174270210561c44b71ba 15 | /** 16 | * Preprocess repl command to wrap await inside an async function if needed 17 | * @param input 18 | * @returns {*} 19 | */ 20 | function preprocess(input) { 21 | const awaitMatcher = /^(?:\s*(?:(?:let|var|const)\s)?\s*([^=]+)=\s*|^\s*)(await\s[\s\S]*)/; 22 | const asyncWrapper = (code, binder) => { 23 | let assign = binder ? `global.${binder} = ` : ''; 24 | return `(function(){ async function _wrap() { return ${assign}${code} } return _wrap();})()`; 25 | }; 26 | 27 | // match & transform 28 | const match = input.match(awaitMatcher); 29 | if (match) { 30 | input = `${asyncWrapper(match[2], match[1])}`; 31 | } 32 | return input; 33 | } 34 | 35 | function myEval(cmd, context, filename, callback) { 36 | const code = babel.transform(preprocess(cmd), { 37 | plugins: [ 38 | ['transform-flow-strip-types'], 39 | ], 40 | presets: ['es2015', 'stage-0'], 41 | }).code; 42 | _eval(code, context, filename, callback); 43 | } 44 | 45 | let _eval; 46 | 47 | (async () => { 48 | try { 49 | const info = await connectDatabase(); 50 | console.log(`Connected to ${info.host}:${info.port}/${info.name}`); 51 | 52 | const repl = REPL.start({ 53 | prompt: 'awesome > ', 54 | }); 55 | _eval = repl.eval; 56 | repl.eval = myEval; 57 | 58 | repl.context.M = M; 59 | repl.context.generateToken = generateToken; 60 | 61 | history(repl, `${process.env.HOME}/.node_history`); 62 | 63 | replPromised.promisify(repl); 64 | } catch (error) { 65 | console.error('Unable to connect to database'); 66 | process.exit(1); 67 | } 68 | })(); 69 | 70 | 71 | -------------------------------------------------------------------------------- /packages/server/repl/nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "restartable": false 3 | } 4 | -------------------------------------------------------------------------------- /packages/server/scripts/updateSchema.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env babel-node --optional es7.asyncFunctions 2 | /** 3 | * This file provided by Facebook is for non-commercial testing and evaluation 4 | * purposes only. Facebook reserves all rights not expressly granted. 5 | * 6 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 7 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 8 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 9 | * FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 10 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 11 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 12 | */ 13 | 14 | import fs from 'fs'; 15 | import path from 'path'; 16 | import { schema } from '../src/schema'; 17 | import { graphql } from 'graphql'; 18 | import { introspectionQuery, printSchema } from 'graphql/utilities'; 19 | 20 | // Save JSON of full schema introspection for Babel Relay Plugin to use 21 | (async () => { 22 | const result = await (graphql(schema, introspectionQuery)); 23 | if (result.errors) { 24 | console.error( 25 | 'ERROR introspecting schema: ', 26 | JSON.stringify(result.errors, null, 2) 27 | ); 28 | } else { 29 | fs.writeFileSync( 30 | path.join(__dirname, '../data/schema.json'), 31 | JSON.stringify(result, null, 2) 32 | ); 33 | 34 | process.exit(0); 35 | } 36 | })(); 37 | 38 | // Save user readable type system shorthand of schema 39 | fs.writeFileSync( 40 | path.join(__dirname, '../data/schema.graphql'), 41 | printSchema(schema) 42 | ); 43 | -------------------------------------------------------------------------------- /packages/server/src/TypeDefinition.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | import type Dataloader from 'dataloader'; 3 | import { UserType } from './loader/UserLoader'; 4 | 5 | type Key = string; 6 | 7 | export type Dataloaders = { 8 | UserLoader: Dataloader, 9 | PetLoader: Dataloader, 10 | ContactLoader: Dataloader, 11 | ExamLoader: Dataloader, 12 | MedicineLoader: Dataloader, 13 | AppointmentLoader: Dataloader, 14 | VermifugeLoader: Dataloader, 15 | }; 16 | 17 | export interface GraphQLContext { 18 | user?: UserType; 19 | dataloaders: Dataloaders; 20 | } 21 | 22 | export type ConnectionArguments = { 23 | first: number, 24 | after: string, 25 | before: string, 26 | search: string, 27 | }; 28 | 29 | export type ConnectionPayload = { 30 | pageInfo: { 31 | hasNextPage: Boolean, 32 | hasPreviousPage: Boolean, 33 | startCursor: string, 34 | endcursor: string, 35 | }, 36 | count: number, 37 | edges: Array, 38 | }; 39 | -------------------------------------------------------------------------------- /packages/server/src/__tests__/auth.spec.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose'; 2 | import { User } from '../model'; 3 | import { setupTest } from '../../test/helper'; 4 | 5 | import { getUser, generateToken } from '../auth'; 6 | 7 | const { ObjectId } = mongoose.Types; 8 | 9 | beforeEach(async () => await setupTest()); 10 | 11 | describe('getUser', () => { 12 | it('should return an user null when token is null', async () => { 13 | const token = null; 14 | const { user } = await getUser(token); 15 | 16 | expect(user).toBe(null); 17 | }); 18 | 19 | it('should return null when token is invalid', async () => { 20 | const token = 'invalid token'; 21 | const { user } = await getUser(token); 22 | 23 | expect(user).toBe(null); 24 | }); 25 | 26 | it('should return null when token do not represent a valid user', async () => { 27 | const token = generateToken({ _id: new ObjectId() }); 28 | const { user } = await getUser(token); 29 | 30 | expect(user).toBe(null); 31 | }); 32 | 33 | it('should return user from a valid token', async () => { 34 | const me = new User({ 35 | name: 'user', 36 | email: 'user@example.com', 37 | password: '123', 38 | }); 39 | await me.save(); 40 | 41 | const token = generateToken(me); 42 | const { user } = await getUser(token); 43 | 44 | expect(user.name).toBe(me.name); 45 | expect(user.email).toBe(me.email); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /packages/server/src/app.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import 'isomorphic-fetch'; 4 | 5 | import Koa from 'koa'; 6 | import bodyParser from 'koa-bodyparser'; 7 | import convert from 'koa-convert'; 8 | import cors from 'kcors'; 9 | import graphqlHttp from 'koa-graphql'; 10 | import graphqlBatchHttpWrapper from 'koa-graphql-batch'; 11 | import logger from 'koa-logger'; 12 | import Router from 'koa-router'; 13 | import { print } from 'graphql/language'; 14 | 15 | import { schema } from './schema'; 16 | import { jwtSecret } from './config'; 17 | import { getUser } from './auth'; 18 | import * as loaders from './loader'; 19 | 20 | const app = new Koa(); 21 | const router = new Router(); 22 | 23 | app.keys = jwtSecret; 24 | 25 | const graphqlSettingsPerReq = async (req) => { 26 | const { user } = await getUser(req.header.authorization); 27 | 28 | const dataloaders = Object.keys(loaders).reduce( 29 | (dataloaders, loaderKey) => ({ 30 | ...dataloaders, 31 | [loaderKey]: loaders[loaderKey].getLoader(), 32 | }), 33 | {}, 34 | ); 35 | 36 | return { 37 | graphiql: process.env.NODE_ENV !== 'production', 38 | schema, 39 | context: { 40 | user, 41 | req, 42 | dataloaders, 43 | }, 44 | // eslint-disable-next-line 45 | extensions: ({ document, variables, operationName, result }) => { 46 | console.log(print(document)); 47 | console.log(variables); 48 | console.log(result); 49 | }, 50 | formatError: (error) => { 51 | console.log(error.message); 52 | console.log(error.locations); 53 | console.log(error.stack); 54 | 55 | return { 56 | message: error.message, 57 | locations: error.locations, 58 | stack: error.stack, 59 | }; 60 | }, 61 | }; 62 | }; 63 | 64 | const graphqlServer = convert(graphqlHttp(graphqlSettingsPerReq)); 65 | 66 | // graphql batch query route 67 | router.all('/graphql/batch', bodyParser(), graphqlBatchHttpWrapper(graphqlServer)); 68 | 69 | // graphql standard route 70 | router.all('/graphql', graphqlServer); 71 | 72 | app.use(logger()); 73 | app.use(cors()); 74 | app.use(router.routes()).use(router.allowedMethods()); 75 | 76 | export default app; 77 | -------------------------------------------------------------------------------- /packages/server/src/auth.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import jwt from 'jsonwebtoken'; 4 | import { User } from './model'; 5 | import { jwtSecret } from './config'; 6 | 7 | export async function getUser(token: string) { 8 | if (!token) return { user: null }; 9 | 10 | try { 11 | const decodedToken = jwt.verify(token.substring(4), jwtSecret); 12 | 13 | const user = await User.findOne({ _id: decodedToken.id }); 14 | 15 | return { 16 | user, 17 | }; 18 | } catch (err) { 19 | return { user: null }; 20 | } 21 | } 22 | 23 | type UserType = { 24 | _id: string, 25 | } 26 | 27 | export function generateToken(user: UserType) { 28 | return `JWT ${jwt.sign({ id: user._id }, jwtSecret)}`; 29 | } 30 | -------------------------------------------------------------------------------- /packages/server/src/config.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import dotenvSafe from 'dotenv-safe'; 3 | 4 | const root = path.join.bind(null, __dirname); 5 | 6 | if (!process.env.NOW_REGION) { 7 | dotenvSafe.load({ 8 | path: root('.env'), 9 | sample: root('.env.example'), 10 | }); 11 | } 12 | 13 | // Database Settings 14 | const dBdevelopment = process.env.MONGO_URL || 'mongodb://localhost/fotonChat'; 15 | const dBproduction = process.env.MONGO_URL || 'mongodb://localhost/fotonChat'; 16 | 17 | console.log('dBdevelopment', dBdevelopment); 18 | console.log('dBproduction', dBproduction); 19 | // Test Database Settings 20 | // const test = 'mongodb://localhost/awesome-test'; 21 | 22 | // Export DB Settings 23 | export const databaseConfig = process.env.NODE_ENV === 'production' ? dBproduction : dBdevelopment; 24 | 25 | // Export GraphQL Server settings 26 | export const graphqlPort = process.env.GRAPHQL_PORT || 5000; 27 | export const jwtSecret = process.env.JWT_KEY || 'secret_key'; 28 | -------------------------------------------------------------------------------- /packages/server/src/connection/ConversationConnection.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLInt } from 'graphql'; 4 | 5 | import { connectionDefinitions } from 'graphql-relay'; 6 | 7 | import ConversationType from '../type/ConversationType'; 8 | 9 | export default connectionDefinitions({ 10 | name: 'Conversation', 11 | nodeType: ConversationType, 12 | connectionFields: { 13 | count: { 14 | type: GraphQLInt, 15 | }, 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /packages/server/src/connection/MessageConnection.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLInt } from 'graphql'; 4 | 5 | import { connectionDefinitions } from 'graphql-relay'; 6 | 7 | import MessageType from '../type/MessageType'; 8 | 9 | export default connectionDefinitions({ 10 | name: 'Message', 11 | nodeType: MessageType, 12 | connectionFields: { 13 | count: { 14 | type: GraphQLInt, 15 | }, 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /packages/server/src/connection/PetConnection.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLInt } from 'graphql'; 4 | 5 | import { connectionDefinitions } from 'graphql-relay'; 6 | 7 | import PetType from '../type/PetType'; 8 | 9 | export default connectionDefinitions({ 10 | name: 'Pet', 11 | nodeType: PetType, 12 | connectionFields: { 13 | count: { 14 | type: GraphQLInt, 15 | }, 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /packages/server/src/connection/UserConnection.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLInt } from 'graphql'; 4 | 5 | import { connectionDefinitions } from 'graphql-relay'; 6 | 7 | import UserType from '../type/UserType'; 8 | 9 | export default connectionDefinitions({ 10 | name: 'User', 11 | nodeType: UserType, 12 | connectionFields: { 13 | count: { 14 | type: GraphQLInt, 15 | }, 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /packages/server/src/database.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import mongoose from 'mongoose'; 4 | import { databaseConfig } from './config'; 5 | 6 | export default function connectDatabase() { 7 | return new Promise((resolve, reject) => { 8 | mongoose.Promise = global.Promise; 9 | mongoose.connection 10 | .on('error', error => reject(error)) 11 | .on('close', () => console.log('Database connection closed.')) 12 | .once('open', () => resolve(mongoose.connections[0])); 13 | 14 | mongoose.connect(databaseConfig, { useNewUrlParser: true }); 15 | }); 16 | } 17 | -------------------------------------------------------------------------------- /packages/server/src/index.js: -------------------------------------------------------------------------------- 1 | 2 | import 'babel-polyfill'; 3 | import app from './app'; 4 | import connectDatabase from './database'; 5 | import { graphqlPort } from './config'; 6 | 7 | (async () => { 8 | try { 9 | const info = await connectDatabase(); 10 | console.log(`Connected to ${info.host}:${info.port}/${info.name}`); 11 | } catch (error) { 12 | console.error('Unable to connect to database'); 13 | process.exit(1); 14 | } 15 | 16 | await app.listen(graphqlPort); 17 | console.log(`Server started on port ${graphqlPort}`); 18 | })(); 19 | -------------------------------------------------------------------------------- /packages/server/src/interface/NodeInterface.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { nodeDefinitions, fromGlobalId } from 'graphql-relay'; 4 | 5 | import User from '../loader/UserLoader'; 6 | import { UserLoader } from '../loader'; 7 | 8 | import UserType from '../type/UserType'; 9 | 10 | const { nodeField, nodeInterface } = nodeDefinitions( 11 | // A method that maps from a global id to an object 12 | async (globalId, context) => { 13 | const { id, type } = fromGlobalId(globalId); 14 | 15 | // console.log('id, type: ', type, id, globalId); 16 | if (type === 'User') { 17 | return await UserLoader.load(context, id); 18 | } 19 | return null; 20 | }, 21 | // A method that maps from an object to a type 22 | (obj) => { 23 | // console.log('obj: ', typeof obj, obj.constructor); 24 | if (obj instanceof User) { 25 | return UserType; 26 | } 27 | return null; 28 | }, 29 | ); 30 | 31 | export const NodeInterface = nodeInterface; 32 | export const NodeField = nodeField; 33 | -------------------------------------------------------------------------------- /packages/server/src/interface/__tests__/NodeInterface.spec.js: -------------------------------------------------------------------------------- 1 | import { graphql } from 'graphql'; 2 | import { toGlobalId } from 'graphql-relay'; 3 | import { schema } from '../../schema'; 4 | import { User } from '../../model'; 5 | import { getContext, setupTest } from '../../../test/helper'; 6 | 7 | beforeEach(async () => await setupTest()); 8 | 9 | it('should load User', async () => { 10 | const user = new User({ 11 | name: 'user', 12 | email: 'user@example.com', 13 | password: '123', 14 | }); 15 | await user.save(); 16 | 17 | const query = ` 18 | query Q { 19 | node(id: "${toGlobalId('User', user._id)}") { 20 | ... on User { 21 | name 22 | } 23 | } 24 | } 25 | `; 26 | 27 | const rootValue = {}; 28 | const context = getContext(); 29 | 30 | const result = await graphql(schema, query, rootValue, context); 31 | const { node } = result.data; 32 | 33 | expect(node.name).toBe(user.name); 34 | }); 35 | -------------------------------------------------------------------------------- /packages/server/src/loader/ConversationLoader.js: -------------------------------------------------------------------------------- 1 | 2 | import DataLoader from 'dataloader'; 3 | import type { ConnectionArguments } from 'graphql-relay'; 4 | import { connectionFromMongoCursor, mongooseLoader } from '@entria/graphql-mongoose-loader'; 5 | import { Conversation as ConversationModel } from '../model'; 6 | import type { GraphQLContext, ConnectionPayload } from '../TypeDefinition'; 7 | import type { ConversationType } from '../type/ConversationType'; 8 | 9 | type ConversationConnectionArgs = { 10 | search: string, 11 | } & ConnectionArguments; 12 | 13 | export type ConversationConnection = ConnectionPayload; 14 | 15 | export default class Conversation { 16 | id: string; 17 | _id: string; 18 | name: string; 19 | owner: string; 20 | castrated: boolean; 21 | alergic: Array; 22 | image: string; 23 | doctor: string; 24 | race: string; 25 | type: string; 26 | active: Boolean; 27 | gender: string; 28 | port: string; 29 | birthDate: string; 30 | color: string; 31 | 32 | constructor(data: ConversationType, { user }: GraphQLContext) { 33 | if (user) { 34 | this.id = data.id; 35 | this._id = data._id; 36 | this.owner = data.owner; 37 | this.otherUser = data.otherUser; 38 | this.lastMessage = data.lastMessage; 39 | this.messages = data.messages; 40 | } 41 | } 42 | } 43 | 44 | export const getLoader = () => new DataLoader(ids => mongooseLoader(ConversationModel, ids)); 45 | 46 | const viewerCanSee = () => true; 47 | 48 | export const load = async (context: GraphQLContext, id: string): Promise => { 49 | if (!id) { 50 | return null; 51 | } 52 | 53 | let data; 54 | try { 55 | data = await context.dataloaders.ConversationLoader.load(id); 56 | } catch (err) { 57 | return null; 58 | } 59 | return viewerCanSee() ? new Conversation(data, context) : null; 60 | }; 61 | 62 | export const clearCache = ({ dataloaders }: GraphQLContext, id: string) => dataloaders.ConversationLoader.clear(id.toString()); 63 | 64 | export const loadConversations = async (context: GraphQLContext, args: ConversationConnectionArgs): Promise => { 65 | const { user } = context; 66 | const Conversations = ConversationModel.find({ owner: user._id }).sort({ createdAt: -1 }); 67 | 68 | return connectionFromMongoCursor({ 69 | cursor: Conversations, 70 | context, 71 | args, 72 | loader: load, 73 | }); 74 | }; 75 | -------------------------------------------------------------------------------- /packages/server/src/loader/MessageLoader.js: -------------------------------------------------------------------------------- 1 | 2 | import DataLoader from 'dataloader'; 3 | import type { ConnectionArguments } from 'graphql-relay'; 4 | import { connectionFromMongoCursor, mongooseLoader } from '@entria/graphql-mongoose-loader'; 5 | import { Message as MessageModel } from '../model'; 6 | import type { GraphQLContext, ConnectionPayload } from '../TypeDefinition'; 7 | import type { MessageType } from '../type/MessageType'; 8 | 9 | type MessageConnectionArgs = { 10 | search: string, 11 | } & ConnectionArguments; 12 | 13 | export type MessageConnection = ConnectionPayload; 14 | 15 | export default class Message { 16 | id: string; 17 | _id: string; 18 | owner: string; 19 | text: string; 20 | conversation: string; 21 | 22 | constructor(data: MessageType, { user }: GraphQLContext) { 23 | if (user) { 24 | this.id = data.id; 25 | this._id = data._id; 26 | this.owner = data.owner; 27 | this.text = data.text; 28 | this.conversation = data.conversation; 29 | } 30 | } 31 | } 32 | 33 | export const getLoader = () => new DataLoader(ids => mongooseLoader(MessageModel, ids)); 34 | 35 | const viewerCanSee = () => true; 36 | 37 | export const load = async (context: GraphQLContext, id: string): Promise => { 38 | if (!id) { 39 | return null; 40 | } 41 | 42 | let data; 43 | try { 44 | data = await context.dataloaders.MessageLoader.load(id); 45 | } catch (err) { 46 | return null; 47 | } 48 | return viewerCanSee() ? new Message(data, context) : null; 49 | }; 50 | 51 | export const clearCache = ({ dataloaders }: GraphQLContext, id: string) => dataloaders.MessageLoader.clear(id.toString()); 52 | 53 | export const loadMessages = async (context: GraphQLContext, args: MessageConnectionArgs): Promise => { 54 | const { conversation } = args; 55 | const Messages = MessageModel.find({ conversation }).sort({ createdAt: -1 }); 56 | 57 | return connectionFromMongoCursor({ 58 | cursor: Messages, 59 | context, 60 | args, 61 | loader: load, 62 | }); 63 | }; 64 | -------------------------------------------------------------------------------- /packages/server/src/loader/PetLoader.js: -------------------------------------------------------------------------------- 1 | 2 | import DataLoader from 'dataloader'; 3 | import type { ConnectionArguments } from 'graphql-relay'; 4 | import { connectionFromMongoCursor, mongooseLoader } from '@entria/graphql-mongoose-loader'; 5 | import { Pet as PetModel } from '../model'; 6 | import type { GraphQLContext, ConnectionPayload } from '../TypeDefinition'; 7 | import type { PetType } from '../type/PetType'; 8 | 9 | type PetConnectionArgs = { 10 | search: string, 11 | } & ConnectionArguments; 12 | 13 | export type PetConnection = ConnectionPayload; 14 | 15 | export default class Pet { 16 | id: string; 17 | _id: string; 18 | name: string; 19 | owner: string; 20 | castrated: boolean; 21 | alergic: Array; 22 | image: string; 23 | doctor: string; 24 | race: string; 25 | type: string; 26 | active: Boolean; 27 | gender: string; 28 | port: string; 29 | birthDate: string; 30 | color: string; 31 | 32 | constructor(data: PetType, { user }: GraphQLContext) { 33 | if (user) { 34 | this.id = data.id; 35 | this._id = data._id; 36 | this.name = data.name; 37 | this.image = data.image; 38 | this.port = data.port; 39 | this.owner = data.owner; 40 | this.castrated = data.castrated; 41 | this.alergic = data.alergic; 42 | this.doctor = data.doctor; 43 | this.race = data.race; 44 | this.type = data.type; 45 | this.active = data.active; 46 | this.gender = data.gender; 47 | this.birthDate = data.birthDate; 48 | this.color = data.color; 49 | } 50 | } 51 | } 52 | 53 | export const getLoader = () => new DataLoader(ids => mongooseLoader(PetModel, ids)); 54 | 55 | const viewerCanSee = () => true; 56 | 57 | export const load = async (context: GraphQLContext, id: string): Promise => { 58 | if (!id) { 59 | return null; 60 | } 61 | 62 | let data; 63 | try { 64 | data = await context.dataloaders.PetLoader.load(id); 65 | } catch (err) { 66 | return null; 67 | } 68 | return viewerCanSee() ? new Pet(data, context) : null; 69 | }; 70 | 71 | export const clearCache = ({ dataloaders }: GraphQLContext, id: string) => dataloaders.PetLoader.clear(id.toString()); 72 | 73 | export const loadPets = async (context: GraphQLContext, args: PetConnectionArgs): Promise => { 74 | const { user } = context; 75 | const where = args.search 76 | ? { name: { $regex: new RegExp(`^${args.search}`, 'ig') }, owner: user._id, active: true } 77 | : { owner: user._id, active: true }; 78 | const pets = PetModel.find(where, { _id: 1 }).sort({ createdAt: -1 }); 79 | 80 | console.log(pets); 81 | 82 | return connectionFromMongoCursor({ 83 | cursor: pets, 84 | context, 85 | args, 86 | loader: load, 87 | }); 88 | }; 89 | -------------------------------------------------------------------------------- /packages/server/src/loader/UserLoader.js: -------------------------------------------------------------------------------- 1 | 2 | import DataLoader from 'dataloader'; 3 | import type { ConnectionArguments } from 'graphql-relay'; 4 | import { connectionFromMongoCursor, mongooseLoader } from '@entria/graphql-mongoose-loader'; 5 | import { User as UserModel } from '../model'; 6 | import type { GraphQLContext } from '../TypeDefinition'; 7 | 8 | export type UserType = { 9 | id: string, 10 | _id: string, 11 | name: string, 12 | password: string, 13 | email: string, 14 | active: boolean, 15 | }; 16 | 17 | export type UserConnection = { 18 | search: string, 19 | } & ConnectionArguments; 20 | 21 | export default class User { 22 | id: string; 23 | _id: string; 24 | name: string; 25 | email: string; 26 | active: boolean; 27 | 28 | constructor(data: UserType, { user }: GraphQLContext) { 29 | this.id = data.id; 30 | this._id = data._id; 31 | this.name = data.name; 32 | 33 | // you can only see your own email, and your active status 34 | if (user && user._id.equals(data._id)) { 35 | this.email = data.email; 36 | this.active = data.active; 37 | } 38 | } 39 | } 40 | 41 | export const getLoader = () => new DataLoader(ids => mongooseLoader(UserModel, ids)); 42 | 43 | const viewerCanSee = () => true; 44 | 45 | export const load = async (context: GraphQLContext, id: string): Promise => { 46 | if (!id) { 47 | return null; 48 | } 49 | 50 | let data; 51 | try { 52 | data = await context.dataloaders.UserLoader.load(id); 53 | } catch (err) { 54 | return null; 55 | } 56 | return viewerCanSee() ? new User(data, context) : null; 57 | }; 58 | 59 | export const clearCache = ({ dataloaders }: GraphQLContext, id: string) => dataloaders.UserLoader.clear(id.toString()); 60 | 61 | export const loadUsers = async (context: GraphQLContext, args: UserConnection) => { 62 | const where = args.search ? { name: { $regex: new RegExp(`^${args.search}`, 'ig') } } : {}; 63 | const users = UserModel.find(where, { _id: 1 }).sort({ createdAt: -1 }); 64 | 65 | return connectionFromMongoCursor({ 66 | cursor: users, 67 | context, 68 | args, 69 | loader: load, 70 | }); 71 | }; 72 | -------------------------------------------------------------------------------- /packages/server/src/loader/index.js: -------------------------------------------------------------------------------- 1 | export * as UserLoader from './UserLoader'; 2 | export * as PetLoader from './PetLoader'; 3 | export * as ConversationLoader from './ConversationLoader'; 4 | export * as MessageLoader from './MessageLoader'; 5 | -------------------------------------------------------------------------------- /packages/server/src/model/Conversation.js: -------------------------------------------------------------------------------- 1 | 2 | import mongoose from 'mongoose'; 3 | 4 | const Schema: mongoose.SchemaType = mongoose.Schema( 5 | { 6 | messages: { 7 | type: [mongoose.Schema.ObjectId], 8 | ref: 'Message', 9 | required: false, 10 | }, 11 | owner: { 12 | type: mongoose.Schema.ObjectId, 13 | ref: 'User', 14 | required: true, 15 | }, 16 | otherUser: { 17 | type: mongoose.Schema.ObjectId, 18 | ref: 'User', 19 | required: true, 20 | }, 21 | lastMessage: { 22 | type: String, 23 | required: false, 24 | }, 25 | }, 26 | { 27 | collection: 'conversation', 28 | timestamps: { 29 | createdAt: 'createdAt', 30 | updatedAt: 'updatedAt', 31 | }, 32 | }, 33 | ); 34 | 35 | export default mongoose.model('Conversation', Schema); 36 | -------------------------------------------------------------------------------- /packages/server/src/model/Message.js: -------------------------------------------------------------------------------- 1 | 2 | import mongoose from 'mongoose'; 3 | 4 | const Schema: mongoose.SchemaType = mongoose.Schema( 5 | { 6 | text: { 7 | type: String, 8 | required: true, 9 | }, 10 | owner: { 11 | type: mongoose.Schema.ObjectId, 12 | ref: 'User', 13 | required: true, 14 | }, 15 | conversation: { 16 | type: mongoose.Schema.ObjectId, 17 | ref: 'Conversation', 18 | required: true, 19 | }, 20 | }, 21 | { 22 | collection: 'message', 23 | timestamps: { 24 | createdAt: 'createdAt', 25 | updatedAt: 'updatedAt', 26 | }, 27 | }, 28 | ); 29 | 30 | export default mongoose.model('Message', Schema); 31 | -------------------------------------------------------------------------------- /packages/server/src/model/Pet.js: -------------------------------------------------------------------------------- 1 | 2 | import mongoose from 'mongoose'; 3 | 4 | const Schema: mongoose.SchemaType = mongoose.Schema( 5 | { 6 | image: { 7 | type: String, 8 | required: false, 9 | }, 10 | name: { 11 | type: String, 12 | required: true, 13 | }, 14 | gender: { 15 | type: String, 16 | required: true, 17 | }, 18 | port: { 19 | type: String, 20 | required: true, 21 | }, 22 | birthDate: { 23 | type: String, 24 | required: true, 25 | }, 26 | owner: { 27 | type: String, 28 | required: true, 29 | }, 30 | castrated: { 31 | type: Boolean, 32 | required: true, 33 | }, 34 | color: { 35 | type: String, 36 | required: true, 37 | }, 38 | alergic: { 39 | type: [String], 40 | required: false, 41 | default: [], 42 | }, 43 | doctor: { 44 | type: String, 45 | required: false, 46 | }, 47 | race: { 48 | type: String, 49 | required: true, 50 | }, 51 | type: { 52 | type: String, 53 | required: true, 54 | }, 55 | active: { 56 | type: Boolean, 57 | default: true, 58 | required: true, 59 | }, 60 | }, 61 | { 62 | collection: 'pet', 63 | timestamps: { 64 | createdAt: 'createdAt', 65 | updatedAt: 'updatedAt', 66 | }, 67 | }, 68 | ); 69 | 70 | export default mongoose.model('Pet', Schema); 71 | -------------------------------------------------------------------------------- /packages/server/src/model/User.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import mongoose from 'mongoose'; 4 | import bcrypt from 'bcryptjs'; 5 | 6 | const Schema = new mongoose.Schema( 7 | { 8 | name: { 9 | type: String, 10 | required: true, 11 | }, 12 | password: { 13 | type: String, 14 | hidden: true, 15 | }, 16 | email: { 17 | type: String, 18 | required: false, 19 | index: true, 20 | }, 21 | active: { 22 | type: Boolean, 23 | default: true, 24 | }, 25 | }, 26 | { 27 | timestamps: { 28 | createdAt: 'createdAt', 29 | updatedAt: 'updatedAt', 30 | }, 31 | collection: 'user', 32 | }, 33 | ); 34 | 35 | Schema.pre('save', function (next) { 36 | if (this.isModified('password')) { 37 | this.password = this.encryptPassword(this.password); 38 | } 39 | 40 | return next(); 41 | }); 42 | 43 | Schema.methods = { 44 | authenticate(plainTextPassword) { 45 | return bcrypt.compareSync(plainTextPassword, this.password); 46 | }, 47 | encryptPassword(password) { 48 | return bcrypt.hashSync(password, 8); 49 | }, 50 | }; 51 | 52 | export default mongoose.model('User', Schema); 53 | -------------------------------------------------------------------------------- /packages/server/src/model/index.js: -------------------------------------------------------------------------------- 1 | export User from './User'; 2 | export Pet from './Pet'; 3 | export Conversation from './Conversation'; 4 | export Message from './Message'; 5 | -------------------------------------------------------------------------------- /packages/server/src/mutation/AddMessageMutation.js: -------------------------------------------------------------------------------- 1 | import { GraphQLString, GraphQLNonNull, GraphQLID, GraphQLBoolean } from 'graphql'; 2 | import { mutationWithClientMutationId } from 'graphql-relay'; 3 | 4 | import { Message, Conversation } from '../model'; 5 | import MessageType from '../type/MessageType'; 6 | 7 | export default mutationWithClientMutationId({ 8 | name: 'AddMessage', 9 | inputFields: { 10 | conversation: { 11 | type: new GraphQLNonNull(GraphQLID), 12 | }, 13 | text: { 14 | type: new GraphQLNonNull(GraphQLString), 15 | }, 16 | }, 17 | mutateAndGetPayload: async ({ conversation, text }, { user }) => { 18 | const currentConversation = await Conversation.findOne({ id: conversation }); 19 | 20 | 21 | if (Message) { 22 | return { 23 | error: 'Message already exists', 24 | id: Message._id, 25 | }; 26 | } 27 | 28 | const newMessage = new Message({ 29 | owner: user._id, 30 | text, 31 | conversation, 32 | }); 33 | await newMessage.save(); 34 | 35 | await Conversation.findByIdAndUpdate( 36 | { id: conversation }, 37 | { messages: [newMessage, ...currentConversation.messages] }, 38 | ); 39 | const { _id } = newMessage; 40 | 41 | return { 42 | error: null, 43 | status: true, 44 | Message: await Message.findOne({ _id }), 45 | }; 46 | }, 47 | outputFields: { 48 | status: { 49 | type: GraphQLBoolean, 50 | resolve: ({ status }) => status, 51 | }, 52 | error: { 53 | type: GraphQLString, 54 | resolve: ({ error }) => error, 55 | }, 56 | message: { 57 | type: MessageType, 58 | resolve: ({ Message }) => Message, 59 | }, 60 | }, 61 | }); 62 | -------------------------------------------------------------------------------- /packages/server/src/mutation/ChangePasswordMutation.js: -------------------------------------------------------------------------------- 1 | import { GraphQLString, GraphQLNonNull } from 'graphql'; 2 | import { mutationWithClientMutationId } from 'graphql-relay'; 3 | 4 | import UserType from '../type/UserType'; 5 | import { UserLoader } from '../loader'; 6 | 7 | export default mutationWithClientMutationId({ 8 | name: 'ChangePassword', 9 | inputFields: { 10 | oldPassword: { 11 | type: new GraphQLNonNull(GraphQLString), 12 | }, 13 | password: { 14 | type: new GraphQLNonNull(GraphQLString), 15 | description: 'user new password', 16 | }, 17 | }, 18 | mutateAndGetPayload: async ({ oldPassword, password }, { user }) => { 19 | if (!user) { 20 | throw new Error('invalid user'); 21 | } 22 | 23 | const correctPassword = user.authenticate(oldPassword); 24 | 25 | if (!correctPassword) { 26 | return { 27 | error: 'INVALID_PASSWORD', 28 | }; 29 | } 30 | 31 | user.password = password; 32 | await user.save(); 33 | 34 | return { 35 | error: null, 36 | }; 37 | }, 38 | outputFields: { 39 | error: { 40 | type: GraphQLString, 41 | resolve: ({ error }) => error, 42 | }, 43 | me: { 44 | type: UserType, 45 | resolve: (obj, args, context) => UserLoader.load(context, context.user.id), 46 | }, 47 | }, 48 | }); 49 | -------------------------------------------------------------------------------- /packages/server/src/mutation/ConversationAddMutation.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLString, GraphQLNonNull, GraphQLBoolean, GraphQLList, GraphQLID } from 'graphql'; 4 | import { mutationWithClientMutationId } from 'graphql-relay'; 5 | import { Conversation } from '../model'; 6 | import PetType from '../type/PetType'; 7 | import type { PetType as PetFlowTypes } from '../type/PetType'; 8 | import type { GraphQLContext } from '../TypeDefinition'; 9 | 10 | type MutationReturn = { 11 | error: string | null, 12 | message: string, 13 | status: boolean, 14 | pet: PetFlowTypes | null, 15 | }; 16 | 17 | export default mutationWithClientMutationId({ 18 | name: 'ConversationAdd', 19 | inputFields: { 20 | owner: { 21 | type: new GraphQLNonNull(GraphQLID), 22 | }, 23 | otherUser: { 24 | type: new GraphQLNonNull(GraphQLID), 25 | }, 26 | message: { 27 | type: new GraphQLNonNull(GraphQLString), 28 | }, 29 | }, 30 | mutateAndGetPayload: async ( 31 | { owner, otherUser, message }, 32 | { user }: GraphQLContext, 33 | ): Promise => { 34 | if (!user) { 35 | return { 36 | error: 'Unauthenticated', 37 | message: 'Oops me parece que você não esta logado! Por Favor Refaça o Login', 38 | status: false, 39 | pet: null, 40 | }; 41 | } 42 | 43 | const conversation = new Conversation({ 44 | owner, 45 | otherUser, 46 | messages: [message], 47 | }); 48 | await conversation.save(); 49 | 50 | const { _id } = conversation; 51 | 52 | return { 53 | error: null, 54 | message: 'Your new conversation was created', 55 | status: true, 56 | conversation: await Conversation.findOne({ _id }), 57 | }; 58 | }, 59 | outputFields: { 60 | status: { 61 | type: GraphQLBoolean, 62 | resolve: ({ status }: MutationReturn) => status, 63 | }, 64 | message: { 65 | type: GraphQLString, 66 | resolve: ({ message }: MutationReturn) => message, 67 | }, 68 | error: { 69 | type: GraphQLString, 70 | resolve: ({ error }: MutationReturn) => error, 71 | }, 72 | conversation: { 73 | type: PetType, 74 | resolve: ({ conversation }: MutationReturn) => conversation, 75 | }, 76 | }, 77 | }); 78 | -------------------------------------------------------------------------------- /packages/server/src/mutation/LoginEmailMutation.js: -------------------------------------------------------------------------------- 1 | import { GraphQLString, GraphQLNonNull } from 'graphql'; 2 | import { mutationWithClientMutationId } from 'graphql-relay'; 3 | 4 | import { User } from '../model'; 5 | import { generateToken } from '../auth'; 6 | 7 | export default mutationWithClientMutationId({ 8 | name: 'LoginEmail', 9 | inputFields: { 10 | email: { 11 | type: new GraphQLNonNull(GraphQLString), 12 | }, 13 | password: { 14 | type: new GraphQLNonNull(GraphQLString), 15 | }, 16 | }, 17 | mutateAndGetPayload: async ({ email, password }) => { 18 | const user = await User.findOne({ email: email.toLowerCase() }); 19 | 20 | if (!user) { 21 | return { 22 | token: null, 23 | error: 'INVALID_EMAIL_PASSWORD', 24 | }; 25 | } 26 | 27 | const correctPassword = user.authenticate(password); 28 | 29 | if (!correctPassword) { 30 | return { 31 | token: null, 32 | error: 'INVALID_EMAIL_PASSWORD', 33 | }; 34 | } 35 | 36 | return { 37 | token: generateToken(user), 38 | error: null, 39 | }; 40 | }, 41 | outputFields: { 42 | token: { 43 | type: GraphQLString, 44 | resolve: ({ token }) => token, 45 | }, 46 | error: { 47 | type: GraphQLString, 48 | resolve: ({ error }) => error, 49 | }, 50 | }, 51 | }); 52 | -------------------------------------------------------------------------------- /packages/server/src/mutation/PetDeleteMutation.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLString, GraphQLNonNull, GraphQLBoolean } from 'graphql'; 4 | import { mutationWithClientMutationId } from 'graphql-relay'; 5 | import { Pet } from '../model'; 6 | import type { GraphQLContext } from '../TypeDefinition'; 7 | 8 | type MutationArgs = { 9 | id: string, 10 | }; 11 | 12 | type MutationReturn = { 13 | error: string | null, 14 | message: string, 15 | status: boolean, 16 | }; 17 | 18 | export default mutationWithClientMutationId({ 19 | name: 'PetDelete', 20 | inputFields: { 21 | id: { 22 | type: new GraphQLNonNull(GraphQLString), 23 | }, 24 | }, 25 | mutateAndGetPayload: async ({ id }: MutationArgs, { user }: GraphQLContext): Promise => { 26 | if (!user) { 27 | return { 28 | error: 'Unauthenticated', 29 | message: 'Oops me parece que você não esta logado! Por Favor Refaça o Login', 30 | status: false, 31 | }; 32 | } 33 | 34 | const pet = Pet.findOne({ 35 | _id: id, 36 | }); 37 | 38 | await pet.update({ 39 | active: false, 40 | }); 41 | 42 | return { 43 | error: null, 44 | message: 'Seu pet foi removido com sucesso!!', 45 | status: true, 46 | }; 47 | }, 48 | outputFields: { 49 | status: { 50 | type: GraphQLBoolean, 51 | resolve: ({ status }: MutationReturn) => status, 52 | }, 53 | message: { 54 | type: GraphQLString, 55 | resolve: ({ message }: MutationReturn) => message, 56 | }, 57 | error: { 58 | type: GraphQLString, 59 | resolve: ({ error }: MutationReturn) => error, 60 | }, 61 | }, 62 | }); 63 | -------------------------------------------------------------------------------- /packages/server/src/mutation/RegisterEmailMutation.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLString, GraphQLNonNull } from 'graphql'; 4 | import { mutationWithClientMutationId } from 'graphql-relay'; 5 | import { User } from '../model'; 6 | import { generateToken } from '../auth'; 7 | 8 | export default mutationWithClientMutationId({ 9 | name: 'RegisterEmail', 10 | inputFields: { 11 | name: { 12 | type: new GraphQLNonNull(GraphQLString), 13 | }, 14 | email: { 15 | type: new GraphQLNonNull(GraphQLString), 16 | }, 17 | password: { 18 | type: new GraphQLNonNull(GraphQLString), 19 | }, 20 | }, 21 | mutateAndGetPayload: async ({ name, email, password }) => { 22 | let user = await User.findOne({ email: email.toLowerCase() }); 23 | 24 | if (user) { 25 | return { 26 | token: null, 27 | error: 'EMAIL_ALREADY_IN_USE', 28 | }; 29 | } 30 | 31 | user = new User({ 32 | name, 33 | email, 34 | password, 35 | }); 36 | await user.save(); 37 | 38 | return { 39 | token: generateToken(user), 40 | error: null, 41 | }; 42 | }, 43 | outputFields: { 44 | token: { 45 | type: GraphQLString, 46 | resolve: ({ token }) => token, 47 | }, 48 | error: { 49 | type: GraphQLString, 50 | resolve: ({ error }) => error, 51 | }, 52 | }, 53 | }); 54 | -------------------------------------------------------------------------------- /packages/server/src/mutation/StartConversationMutation.js: -------------------------------------------------------------------------------- 1 | import { GraphQLString, GraphQLNonNull, GraphQLBoolean } from 'graphql'; 2 | import { mutationWithClientMutationId } from 'graphql-relay'; 3 | 4 | import { Conversation, User } from '../model'; 5 | import ConversationType from '../type/ConversationType'; 6 | 7 | export default mutationWithClientMutationId({ 8 | name: 'StartConversation', 9 | inputFields: { 10 | email: { 11 | type: new GraphQLNonNull(GraphQLString), 12 | }, 13 | }, 14 | mutateAndGetPayload: async ({ email }, { user }) => { 15 | const conversation = await Conversation.findOne({ email: email.toLowerCase() }); 16 | const otherUser = await User.findOne({ email: email.toLowerCase() }); 17 | 18 | if (conversation) { 19 | return { 20 | error: 'Conversation already exists', 21 | id: conversation._id, 22 | }; 23 | } 24 | 25 | const newConversation = new Conversation({ 26 | owner: user, 27 | otherUser, 28 | }); 29 | await newConversation.save(); 30 | 31 | const { _id } = newConversation; 32 | 33 | return { 34 | error: null, 35 | message: 'Your conversation started', 36 | status: true, 37 | conversation: await Conversation.findOne({ _id }), 38 | }; 39 | }, 40 | outputFields: { 41 | status: { 42 | type: GraphQLBoolean, 43 | resolve: ({ status }) => status, 44 | }, 45 | message: { 46 | type: GraphQLString, 47 | resolve: ({ message }) => message, 48 | }, 49 | error: { 50 | type: GraphQLString, 51 | resolve: ({ error }) => error, 52 | }, 53 | conversation: { 54 | type: ConversationType, 55 | resolve: ({ conversation }) => conversation, 56 | }, 57 | }, 58 | }); 59 | -------------------------------------------------------------------------------- /packages/server/src/mutation/__tests__/ChangePasswordMutation.spec.js: -------------------------------------------------------------------------------- 1 | import { graphql } from 'graphql'; 2 | import { schema } from '../../schema'; 3 | import { User } from '../../model'; 4 | import { getContext, setupTest } from '../../../test/helper'; 5 | 6 | beforeEach(async () => await setupTest()); 7 | 8 | it('should not change password of non authorized user', async () => { 9 | // language=GraphQL 10 | const query = ` 11 | mutation M { 12 | ChangePassword(input: { 13 | clientMutationId: "abc" 14 | oldPassword: "old" 15 | password: "new" 16 | }) { 17 | clientMutationId 18 | error 19 | } 20 | } 21 | `; 22 | 23 | const rootValue = {}; 24 | const context = getContext(); 25 | 26 | const result = await graphql(schema, query, rootValue, context); 27 | const { errors } = result; 28 | 29 | expect(errors.length).toBe(1); 30 | expect(errors[0].message).toBe('invalid user'); 31 | }); 32 | 33 | it('should not change password if oldPassword is invalid', async () => { 34 | const user = new User({ 35 | name: 'user', 36 | email: 'awesome@example.com', 37 | password: 'awesome', 38 | }); 39 | await user.save(); 40 | 41 | // language=GraphQL 42 | const query = ` 43 | mutation M { 44 | ChangePassword(input: { 45 | clientMutationId: "abc" 46 | oldPassword: "old" 47 | password: "new" 48 | }) { 49 | clientMutationId 50 | error 51 | } 52 | } 53 | `; 54 | 55 | const rootValue = {}; 56 | const context = getContext({ user }); 57 | 58 | const result = await graphql(schema, query, rootValue, context); 59 | const { ChangePassword } = result.data; 60 | 61 | expect(ChangePassword.error).toBe('INVALID_PASSWORD'); 62 | }); 63 | 64 | it('should change password if oldPassword is correct', async () => { 65 | const password = 'awesome'; 66 | 67 | const user = new User({ 68 | name: 'user', 69 | email: 'awesome@example.com', 70 | password, 71 | }); 72 | await user.save(); 73 | 74 | // language=GraphQL 75 | const query = ` 76 | mutation M { 77 | ChangePassword(input: { 78 | clientMutationId: "abc" 79 | oldPassword: "${password}" 80 | password: "new" 81 | }) { 82 | clientMutationId 83 | error 84 | } 85 | } 86 | `; 87 | 88 | const rootValue = {}; 89 | const context = getContext({ user }); 90 | 91 | const result = await graphql(schema, query, rootValue, context); 92 | const { ChangePassword } = result.data; 93 | 94 | expect(ChangePassword.error).toBe(null); 95 | }); 96 | -------------------------------------------------------------------------------- /packages/server/src/mutation/__tests__/LoginEmailMutation.spec.js: -------------------------------------------------------------------------------- 1 | import { graphql } from 'graphql'; 2 | import { schema } from '../../schema'; 3 | import { User } from '../../model'; 4 | import { generateToken } from '../../auth'; 5 | import { getContext, setupTest } from '../../../test/helper'; 6 | 7 | beforeEach(async () => await setupTest()); 8 | 9 | it('should not login if email is not in the database', async () => { 10 | // language=GraphQL 11 | const query = ` 12 | mutation M { 13 | LoginEmail(input: { 14 | clientMutationId: "abc" 15 | email: "awesome@example.com" 16 | password: "awesome" 17 | }) { 18 | clientMutationId 19 | token 20 | error 21 | } 22 | } 23 | `; 24 | 25 | const rootValue = {}; 26 | const context = getContext(); 27 | 28 | const result = await graphql(schema, query, rootValue, context); 29 | const { LoginEmail } = result.data; 30 | 31 | expect(LoginEmail.token).toBe(null); 32 | expect(LoginEmail.error).toBe('INVALID_EMAIL_PASSWORD'); 33 | }); 34 | 35 | it('should not login with wrong email', async () => { 36 | const user = new User({ 37 | name: 'user', 38 | email: 'awesome@example.com', 39 | password: 'awesome', 40 | }); 41 | await user.save(); 42 | 43 | // language=GraphQL 44 | const query = ` 45 | mutation M { 46 | LoginEmail(input: { 47 | clientMutationId: "abc" 48 | email: "awesome@example.com" 49 | password: "notawesome" 50 | }) { 51 | clientMutationId 52 | token 53 | error 54 | } 55 | } 56 | `; 57 | 58 | const rootValue = {}; 59 | const context = getContext(); 60 | 61 | const result = await graphql(schema, query, rootValue, context); 62 | const { LoginEmail } = result.data; 63 | 64 | expect(LoginEmail.token).toBe(null); 65 | expect(LoginEmail.error).toBe('INVALID_EMAIL_PASSWORD'); 66 | }); 67 | 68 | it('should generate token when email and password is correct', async () => { 69 | const email = 'awesome@example.com'; 70 | const password = 'awesome'; 71 | 72 | const user = new User({ 73 | name: 'user', 74 | email, 75 | password, 76 | }); 77 | await user.save(); 78 | 79 | // language=GraphQL 80 | const query = ` 81 | mutation M { 82 | LoginEmail(input: { 83 | clientMutationId: "abc" 84 | email: "${email}" 85 | password: "${password}" 86 | }) { 87 | clientMutationId 88 | token 89 | error 90 | } 91 | } 92 | `; 93 | 94 | const rootValue = {}; 95 | const context = getContext(); 96 | 97 | const result = await graphql(schema, query, rootValue, context); 98 | const { LoginEmail } = result.data; 99 | 100 | expect(LoginEmail.token).toBe(generateToken(user)); 101 | expect(LoginEmail.error).toBe(null); 102 | }); 103 | -------------------------------------------------------------------------------- /packages/server/src/mutation/__tests__/RegisterEmailMutation.spec.js: -------------------------------------------------------------------------------- 1 | import { graphql } from 'graphql'; 2 | import { schema } from '../../schema'; 3 | import { User } from '../../model'; 4 | import { generateToken } from '../../auth'; 5 | import { getContext, setupTest } from '../../../test/helper'; 6 | 7 | beforeEach(async () => await setupTest()); 8 | 9 | it('should not register with the an existing email', async () => { 10 | const name = 'awesome'; 11 | const email = 'awesome@example.com'; 12 | 13 | const user = new User({ 14 | name, 15 | email, 16 | password: '123', 17 | }); 18 | await user.save(); 19 | 20 | // language=GraphQL 21 | const query = ` 22 | mutation M { 23 | RegisterEmail(input: { 24 | clientMutationId: "abc" 25 | name: "Awesome" 26 | email: "${email}" 27 | password: "awesome" 28 | }) { 29 | clientMutationId 30 | token 31 | error 32 | } 33 | } 34 | `; 35 | 36 | const rootValue = {}; 37 | const context = getContext(); 38 | 39 | const result = await graphql(schema, query, rootValue, context); 40 | const { RegisterEmail } = result.data; 41 | 42 | expect(RegisterEmail.token).toBe(null); 43 | expect(RegisterEmail.error).toBe('EMAIL_ALREADY_IN_USE'); 44 | }); 45 | 46 | it('should create a new user with parameters are valid', async () => { 47 | const email = 'awesome@example.com'; 48 | 49 | // language=GraphQL 50 | const query = ` 51 | mutation M { 52 | RegisterEmail(input: { 53 | clientMutationId: "abc" 54 | name: "Awesome" 55 | email: "${email}" 56 | password: "awesome" 57 | }) { 58 | clientMutationId 59 | token 60 | error 61 | } 62 | } 63 | `; 64 | 65 | const rootValue = {}; 66 | const context = getContext(); 67 | 68 | const result = await graphql(schema, query, rootValue, context); 69 | const { RegisterEmail } = result.data; 70 | 71 | const user = await User.findOne({ 72 | email, 73 | }); 74 | 75 | expect(user).not.toBe(null); 76 | expect(RegisterEmail.token).toBe(generateToken(user)); 77 | expect(RegisterEmail.error).toBe(null); 78 | }); 79 | -------------------------------------------------------------------------------- /packages/server/src/schema.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLSchema } from 'graphql'; 4 | 5 | import QueryType from './type/QueryType'; 6 | import MutationType from './type/MutationType'; 7 | 8 | export const schema = new GraphQLSchema({ 9 | query: QueryType, 10 | mutation: MutationType, 11 | }); 12 | -------------------------------------------------------------------------------- /packages/server/src/type/ConversationType.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLObjectType, GraphQLString, GraphQLBoolean, GraphQLList } from 'graphql'; 4 | import { globalIdField } from 'graphql-relay'; 5 | import { NodeInterface } from '../interface/NodeInterface'; 6 | import UserType from './UserType'; 7 | import MessageType from './MessageType'; 8 | import { UserLoader } from '../loader'; 9 | import { MessageLoader } from '../loader'; 10 | import type { UserType as UserFlowType } from '../loader/UserLoader'; 11 | 12 | export type ConversationType = { 13 | id: string, 14 | _id: string, 15 | messages: Array, 16 | owner: UserFlowType, 17 | otherUser: UserFlowType, 18 | lastMessage: string, 19 | }; 20 | 21 | export default new GraphQLObjectType({ 22 | name: 'Conversation', 23 | description: 'Conversation data', 24 | fields: () => ({ 25 | id: globalIdField('Conversation'), 26 | _id: { 27 | type: GraphQLString, 28 | resolve: (conversation: ConversationType) => conversation._id, 29 | }, 30 | owner: { 31 | type: UserType, 32 | resolve: ({ owner }: ConversationType, args, context) => UserLoader.load(context, owner), 33 | }, 34 | otherUser: { 35 | type: UserType, 36 | resolve: ({ otherUser }: ConversationType, args, context) => UserLoader.load(context, otherUser), 37 | }, 38 | lastMessage: { 39 | type: GraphQLString, 40 | resolve: (conversation: ConversationType) => conversation.lastMessage, 41 | }, 42 | updatedAt: { 43 | type: GraphQLString, 44 | resolve: (conversation: ConversationType) => conversation.updatedAt, 45 | }, 46 | messages: { 47 | type: MessageType, 48 | resolve: ({ owner }: ConversationType, args, context) => MessageLoader.load(context, owner), 49 | }, 50 | }), 51 | interfaces: () => [NodeInterface], 52 | }); 53 | -------------------------------------------------------------------------------- /packages/server/src/type/MessageType.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLObjectType, GraphQLString, GraphQLBoolean, GraphQLList } from 'graphql'; 4 | import { globalIdField } from 'graphql-relay'; 5 | import { NodeInterface } from '../interface/NodeInterface'; 6 | import UserType from './UserType'; 7 | import { UserLoader } from '../loader'; 8 | import { MessageLoader } from '../loader'; 9 | import type { UserType as UserFlowType } from '../loader/UserLoader'; 10 | 11 | export type messageType = { 12 | id: string, 13 | _id: string, 14 | owner: UserFlowType, 15 | text: string, 16 | }; 17 | 18 | export default new GraphQLObjectType({ 19 | name: 'Message', 20 | description: 'message data', 21 | fields: () => ({ 22 | id: globalIdField('Message'), 23 | _id: { 24 | type: GraphQLString, 25 | resolve: (message: messageType) => message._id, 26 | }, 27 | owner: { 28 | type: UserType, 29 | resolve: ({ owner }: messageType, args, context) => UserLoader.load(context, owner), 30 | }, 31 | text: { 32 | type: GraphQLString, 33 | resolve: (message: messageType) => message.text, 34 | }, 35 | }), 36 | interfaces: () => [NodeInterface], 37 | }); 38 | -------------------------------------------------------------------------------- /packages/server/src/type/MutationType.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLObjectType } from 'graphql'; 4 | 5 | import LoginEmail from '../mutation/LoginEmailMutation'; 6 | import RegisterEmail from '../mutation/RegisterEmailMutation'; 7 | import ChangePassword from '../mutation/ChangePasswordMutation'; 8 | import PetAdd from '../mutation/PetAddMutation'; 9 | import StartConversation from '../mutation/StartConversationMutation'; 10 | import PetDelete from '../mutation/PetDeleteMutation'; 11 | 12 | export default new GraphQLObjectType({ 13 | name: 'Mutation', 14 | fields: () => ({ 15 | // auth 16 | LoginEmail, 17 | RegisterEmail, 18 | ChangePassword, 19 | 20 | // conversation 21 | StartConversation, 22 | 23 | // pet 24 | PetAdd, 25 | PetDelete, 26 | }), 27 | }); 28 | -------------------------------------------------------------------------------- /packages/server/src/type/PetType.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLObjectType, GraphQLString, GraphQLBoolean, GraphQLList } from 'graphql'; 4 | import { globalIdField } from 'graphql-relay'; 5 | import { NodeInterface } from '../interface/NodeInterface'; 6 | import UserType from './UserType'; 7 | import { UserLoader } from '../loader'; 8 | import type { UserType as UserFlowType } from '../loader/UserLoader'; 9 | 10 | export type PetType = { 11 | id: string, 12 | _id: string, 13 | image: string, 14 | name: string, 15 | gender: string, 16 | castrated: boolean, 17 | alergic: Array, 18 | owner: UserFlowType, 19 | doctor: string, 20 | race: string, 21 | type: string, 22 | active: Boolean, 23 | port: string, 24 | birthDate: string, 25 | color: string, 26 | }; 27 | 28 | export default new GraphQLObjectType({ 29 | name: 'Pet', 30 | description: 'Pet data', 31 | fields: () => ({ 32 | id: globalIdField('Pet'), 33 | _id: { 34 | type: GraphQLString, 35 | resolve: (pet: PetType) => pet._id, 36 | }, 37 | image: { 38 | type: GraphQLString, 39 | resolve: (pet: PetType) => pet.image, 40 | }, 41 | owner: { 42 | type: UserType, 43 | resolve: ({ owner }: PetType, args, context) => UserLoader.load(context, owner), 44 | }, 45 | name: { 46 | type: GraphQLString, 47 | resolve: (pet: PetType) => pet.name, 48 | }, 49 | gender: { 50 | type: GraphQLString, 51 | resolve: (pet: PetType) => pet.gender, 52 | }, 53 | port: { 54 | type: GraphQLString, 55 | resolve: (pet: PetType) => pet.port, 56 | }, 57 | birthDate: { 58 | type: GraphQLString, 59 | resolve: (pet: PetType) => pet.birthDate, 60 | }, 61 | color: { 62 | type: GraphQLString, 63 | resolve: (pet: PetType) => pet.color, 64 | }, 65 | castrated: { 66 | type: GraphQLBoolean, 67 | resolve: (pet: PetType) => pet.castrated, 68 | }, 69 | alergic: { 70 | type: new GraphQLList(GraphQLString), 71 | resolve: (pet: PetType) => pet.alergic, 72 | }, 73 | race: { 74 | type: GraphQLString, 75 | resolve: (pet: PetType) => pet.race, 76 | }, 77 | type: { 78 | type: GraphQLString, 79 | resolve: (pet: PetType) => pet.type, 80 | }, 81 | }), 82 | interfaces: () => [NodeInterface], 83 | }); 84 | -------------------------------------------------------------------------------- /packages/server/src/type/UserType.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import { GraphQLObjectType, GraphQLString, GraphQLBoolean } from 'graphql'; 4 | import { globalIdField } from 'graphql-relay'; 5 | import { NodeInterface } from '../interface/NodeInterface'; 6 | 7 | export type UserType = { 8 | id: string, 9 | _id: string, 10 | name: string, 11 | password: string, 12 | email: string, 13 | active: boolean, 14 | }; 15 | 16 | export default new GraphQLObjectType({ 17 | name: 'User', 18 | description: 'User data', 19 | fields: () => ({ 20 | id: globalIdField('User'), 21 | _id: { 22 | type: GraphQLString, 23 | resolve: user => user._id, 24 | }, 25 | name: { 26 | type: GraphQLString, 27 | resolve: user => user.name, 28 | }, 29 | email: { 30 | type: GraphQLString, 31 | resolve: user => user.email, 32 | }, 33 | active: { 34 | type: GraphQLBoolean, 35 | resolve: user => user.active, 36 | }, 37 | }), 38 | interfaces: () => [NodeInterface], 39 | }); 40 | -------------------------------------------------------------------------------- /packages/server/src/type/__tests__/UserType.spec.js: -------------------------------------------------------------------------------- 1 | import { graphql } from 'graphql'; 2 | import { schema } from '../../schema'; 3 | import { User } from '../../model'; 4 | import { getContext, setupTest } from '../../../test/helper'; 5 | 6 | beforeEach(async () => await setupTest()); 7 | 8 | it('should not show email of other users', async () => { 9 | const user = new User({ 10 | name: 'user', 11 | email: 'user@example.com', 12 | password: '123', 13 | }); 14 | await user.save(); 15 | 16 | const user1 = new User({ 17 | name: 'awesome', 18 | email: 'awesome@example.com', 19 | password: '123', 20 | }); 21 | await user1.save(); 22 | 23 | // language=GraphQL 24 | const query = ` 25 | query Q { 26 | users(first: 2) { 27 | edges { 28 | node { 29 | _id 30 | name 31 | email 32 | active 33 | } 34 | } 35 | } 36 | } 37 | `; 38 | 39 | const rootValue = {}; 40 | const context = getContext({ user }); 41 | 42 | const result = await graphql(schema, query, rootValue, context); 43 | const { edges } = result.data.users; 44 | 45 | expect(edges[0].node.name).toBe(user1.name); 46 | expect(edges[0].node.email).toBe(null); 47 | 48 | expect(edges[1].node.name).toBe(user.name); 49 | expect(edges[1].node.email).toBe(user.email); 50 | }); 51 | -------------------------------------------------------------------------------- /packages/server/test/helper.js: -------------------------------------------------------------------------------- 1 | 2 | import mongoose from 'mongoose'; 3 | import * as loaders from '../src/loader'; 4 | 5 | const { ObjectId } = mongoose.Types; 6 | 7 | process.env.NODE_ENV = 'test'; 8 | 9 | const MONGO_URL = process.env.MONGO_URL || 'mongodb://localhost/test'; 10 | 11 | const config = { 12 | db: { 13 | test: MONGO_URL, 14 | }, 15 | connection: null, 16 | }; 17 | 18 | function connect() { 19 | return new Promise((resolve, reject) => { 20 | if (config.connection) { 21 | return resolve(); 22 | } 23 | 24 | mongoose.Promise = Promise; 25 | 26 | const options = { 27 | auto_reconnect: true, 28 | reconnectTries: Number.MAX_VALUE, 29 | reconnectInterval: 1000, 30 | }; 31 | 32 | mongoose.connect(MONGO_URL, options); 33 | 34 | config.connection = mongoose.connection; 35 | 36 | config.connection.once('open', resolve).on('error', e => { 37 | if (e.message.code === 'ETIMEDOUT') { 38 | console.log(e); 39 | 40 | mongoose.connect(MONGO_URL, options); 41 | } 42 | 43 | console.log(e); 44 | reject(e); 45 | }); 46 | }); 47 | } 48 | 49 | function clearDatabase() { 50 | return new Promise(resolve => { 51 | let cont = 0; 52 | let max = Object.keys(mongoose.connection.collections).length; 53 | for (const i in mongoose.connection.collections) { 54 | mongoose.connection.collections[i].remove(function() { 55 | cont++; 56 | if (cont >= max) { 57 | resolve(); 58 | } 59 | }); 60 | } 61 | }); 62 | } 63 | 64 | export function getContext(context: Object) { 65 | const dataloaders = Object.keys(loaders).reduce( 66 | (dataloaders, loaderKey) => ({ 67 | ...dataloaders, 68 | [loaderKey]: loaders[loaderKey].getLoader(), 69 | }), 70 | {}, 71 | ); 72 | 73 | return { 74 | ...context, 75 | req: {}, 76 | dataloaders, 77 | }; 78 | } 79 | 80 | export async function setupTest() { 81 | await connect(); 82 | await clearDatabase(); 83 | } 84 | -------------------------------------------------------------------------------- /packages/server/test/mongooseConnection.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose'; 2 | 3 | const mongoUri = 'mongodb://localhost/test'; 4 | 5 | // mongoose.set('debug', true); 6 | 7 | mongoose.Promise = Promise; 8 | mongoose.connect(mongoUri, { 9 | auto_reconnect: true, 10 | reconnectTries: Number.MAX_VALUE, 11 | reconnectInterval: 1000, 12 | }); 13 | 14 | export const connection = mongoose.connection; 15 | 16 | connection.on('error', e => { 17 | if (e.message.code === 'ETIMEDOUT') { 18 | console.log(e); 19 | mongoose.connect(mongoUri, opts); 20 | } 21 | console.log(e); 22 | }); 23 | 24 | connection.once('open', () => { 25 | console.log(`MongoDB successfully connected to ${mongoUri}`); 26 | }); 27 | -------------------------------------------------------------------------------- /packages/web/.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 | -------------------------------------------------------------------------------- /packages/web/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 | -------------------------------------------------------------------------------- /packages/web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/jest": "23.3.12", 7 | "@types/node": "10.12.18", 8 | "@types/react": "16.7.18", 9 | "@types/react-dom": "16.0.11", 10 | "react": "^16.7.0", 11 | "react-dom": "^16.7.0", 12 | "react-scripts": "2.1.3", 13 | "typescript": "3.2.2" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "now-build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject" 21 | }, 22 | "eslintConfig": { 23 | "extends": "react-app" 24 | }, 25 | "browserslist": [ 26 | ">0.2%", 27 | "not dead", 28 | "not ie <= 11", 29 | "not op_mini all" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /packages/web/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FotonTech/foton-chat/a145122ac094e2e689b7a3283cc6916bc684572c/packages/web/public/favicon.ico -------------------------------------------------------------------------------- /packages/web/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 15 | 16 | 25 | React App 26 | 27 | 28 | 29 |
30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /packages/web/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 | -------------------------------------------------------------------------------- /packages/web/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | animation: App-logo-spin infinite 20s linear; 7 | height: 40vmin; 8 | } 9 | 10 | .App-header { 11 | background-color: #282c34; 12 | min-height: 100vh; 13 | display: flex; 14 | flex-direction: column; 15 | align-items: center; 16 | justify-content: center; 17 | font-size: calc(10px + 2vmin); 18 | color: white; 19 | } 20 | 21 | .App-link { 22 | color: #61dafb; 23 | } 24 | 25 | @keyframes App-logo-spin { 26 | from { 27 | transform: rotate(0deg); 28 | } 29 | to { 30 | transform: rotate(360deg); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/web/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 | -------------------------------------------------------------------------------- /packages/web/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import logo from './logo.svg'; 3 | import './App.css'; 4 | 5 | class App extends Component { 6 | render() { 7 | return ( 8 |
9 |
10 | logo 11 |

12 | Edit src/App.tsx and save to reload. 13 |

14 | 20 | Learn React 21 | 22 |
23 |
24 | ); 25 | } 26 | } 27 | 28 | export default App; 29 | -------------------------------------------------------------------------------- /packages/web/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /packages/web/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: http://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /packages/web/src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/web/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/web/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 | --------------------------------------------------------------------------------