├── .babelrc
├── .eslintignore
├── .eslintrc
├── .gitignore
├── LICENSE
├── README.md
├── build
└── babelRelayPlugin.js
├── data
├── data.js
├── database.js
├── schema.js
└── schema.json
├── js
├── app.js
├── components
│ ├── ChatApp.js
│ ├── MessageComposer.js
│ ├── MessageListItem.js
│ ├── MessageSection.js
│ ├── ThreadListItem.js
│ └── ThreadSection.js
├── mutations
│ ├── AddMessageMutation.js
│ └── MarkThreadAsReadMutation.js
└── routes
│ ├── chatApp.js
│ ├── index.js
│ └── messageSection.js
├── package.json
├── public
├── app.css
├── index.html
└── learn.json
├── scripts
└── updateSchema.js
├── server.js
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "stage": 0,
3 | "loose": "all"
4 | }
5 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/node_modules
2 | **/webpack.config.js
3 | server.js
4 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | ---
2 | parser: babel-eslint
3 |
4 | plugins:
5 | - react
6 |
7 | env:
8 | node: true
9 | es6: true
10 |
11 | globals:
12 | document: false
13 | window: false
14 |
15 | arrowFunctions: true
16 | blockBindings: true
17 | classes: true
18 | defaultParams: true
19 | destructuring: true
20 | forOf: true
21 | generators: true
22 | modules: true
23 | objectLiteralComputedProperties: true
24 | objectLiteralShorthandMethods: true
25 | objectLiteralShorthandProperties: true
26 | spread: true
27 | templateStrings: true
28 |
29 | rules:
30 | # ERRORS
31 | brace-style: [2, 1tbs, allowSingleLine: true]
32 | camelcase: [2, properties: always]
33 | comma-style: [2, last]
34 | curly: [2, all]
35 | eol-last: 2
36 | eqeqeq: 2
37 | guard-for-in: 2
38 | handle-callback-err: [2, error]
39 | indent: [2, 2, SwitchCase: 1]
40 | key-spacing: [2, {beforeColon: false, afterColon: true}]
41 | max-len: [2, 80, 4, ignorePattern: "^(\\s*var\\s.+=\\s*require\\s*\\(|import )"]
42 | new-parens: 2
43 | no-alert: 2
44 | no-array-constructor: 2
45 | no-caller: 2
46 | no-catch-shadow: 2
47 | no-cond-assign: 2
48 | no-constant-condition: 2
49 | no-delete-var: 2
50 | no-div-regex: 2
51 | no-dupe-args: 2
52 | no-dupe-keys: 2
53 | no-duplicate-case: 2
54 | no-empty-character-class: 2
55 | no-empty-label: 2
56 | no-empty: 2
57 | no-eval: 2
58 | no-ex-assign: 2
59 | no-extend-native: 2
60 | no-extra-bind: 2
61 | no-extra-boolean-cast: 2
62 | no-extra-semi: 2
63 | no-fallthrough: 2
64 | no-floating-decimal: 2
65 | no-func-assign: 2
66 | no-implied-eval: 2
67 | no-inner-declarations: [2, functions]
68 | no-invalid-regexp: 2
69 | no-irregular-whitespace: 2
70 | no-iterator: 2
71 | no-label-var: 2
72 | no-lonely-if: 2
73 | no-mixed-requires: [2, true]
74 | no-mixed-spaces-and-tabs: 2
75 | no-multi-spaces: 2
76 | no-multi-str: 2
77 | no-negated-in-lhs: 2
78 | no-new-object: 2
79 | no-new-require: 2
80 | no-new-wrappers: 2
81 | no-new: 2
82 | no-obj-calls: 2
83 | no-octal-escape: 2
84 | no-octal: 2
85 | no-param-reassign: 2
86 | no-path-concat: 2
87 | no-proto: 2
88 | no-redeclare: 2
89 | no-regex-spaces: 2
90 | no-return-assign: 2
91 | no-script-url: 2
92 | no-sequences: 2
93 | no-shadow-restricted-names: 2
94 | no-shadow: 2
95 | no-spaced-func: 2
96 | no-sparse-arrays: 2
97 | no-sync: 2
98 | no-throw-literal: 2
99 | no-trailing-spaces: 2
100 | no-undef-init: 2
101 | no-undef: 2
102 | no-unreachable: 2
103 | no-unused-expressions: 2
104 | no-unused-vars: [2, {vars: all, args: after-used}]
105 | no-void: 2
106 | no-with: 2
107 | one-var: [2, never]
108 | operator-assignment: [2, always]
109 | quote-props: [2, as-needed]
110 | quotes: [2, single]
111 | radix: 2
112 | semi-spacing: [2, {before: false, after: true}]
113 | semi: [2, always]
114 | space-after-keywords: [2, always]
115 | space-before-blocks: [2, always]
116 | space-before-function-paren: [2, {anonymous: always, named: never}]
117 | space-infix-ops: [2, int32Hint: false]
118 | space-return-throw-case: 2
119 | space-unary-ops: [2, {words: true, nonwords: false}]
120 | spaced-comment: [2, always]
121 | use-isnan: 2
122 | valid-typeof: 2
123 | wrap-iife: 2
124 | yoda: [2, never, exceptRange: true]
125 |
126 | # WARNINGS
127 |
128 | # DISABLED
129 | block-scoped-var: 0
130 | comma-dangle: 0
131 | complexity: 0
132 | consistent-return: 0
133 | consistent-this: 0
134 | default-case: 0
135 | dot-notation: 0
136 | func-names: 0
137 | func-style: 0
138 | max-nested-callbacks: 0
139 | new-cap: 0
140 | newline-after-var: 0
141 | no-console: 0
142 | no-control-regex: 0
143 | no-debugger: 0
144 | no-eq-null: 0
145 | no-inline-comments: 0
146 | no-labels: 0
147 | no-lone-blocks: 0
148 | no-loop-func: 0
149 | no-multiple-empty-lines: 0
150 | no-native-reassign: 0
151 | no-nested-ternary: 0
152 | no-new-func: 0
153 | no-process-env: 0
154 | no-process-exit: 0
155 | no-reserved-keys: 0
156 | no-restricted-modules: 0
157 | no-self-compare: 0
158 | no-ternary: 0
159 | no-undefined: 0
160 | no-underscore-dangle: 0
161 | no-use-before-define: 0
162 | no-var: 0
163 | no-warning-comments: 0
164 | padded-blocks: 0
165 | sort-vars: 0
166 | space-in-brackets: 0
167 | space-in-parens: 0
168 | strict: 0
169 | valid-jsdoc: 0
170 | vars-on-top: 0
171 | wrap-regex: 0
172 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | *.log
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 CHEN HUNG TU
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Relay Chat
2 |
3 | **I no longer maintain this project. Since it is a demonstration, you can still fork and play with it**
4 |
5 | ## Installation
6 |
7 | ```
8 | npm install --global babel
9 | npm install
10 | ```
11 |
12 | ## Running
13 |
14 | Start a local server:
15 |
16 | ```
17 | npm start
18 | ```
19 |
20 | ## Developing
21 |
22 | Any changes you make to files in the `js/` directory will cause the server to
23 | automatically rebuild the app and refresh your browser.
24 |
25 | If at any time you make changes to `data/schema.js`, stop the server,
26 | regenerate `data/schema.json`, and restart the server:
27 |
28 | ```
29 | npm run update-schema
30 | npm start
31 | ```
32 |
33 | ## Feature Highlight:
34 |
35 | 1. use with [relay-nested-routes](https://github.com/devknoll/relay-nested-routes) and [react-router](https://github.com/rackt/react-router) to let multiple routes work and route params as query params
36 |
37 | 2. using route params as global state variable (ex: currentThreadID), not ideal for now, but it shows a different possibility
38 |
39 | 3. and a more complicated model structure as `user-> threads-> messages`
40 | 4. [pagination for messages](https://github.com/transedward/relay-chat/tree/add-pagination)
41 |
42 |
43 | ## Advice
44 |
45 | If you don't know much about GraphQL and Relay, I suggest you:
46 |
47 | 1. [To know GraphQL first](https://github.com/facebook/graphql/blob/master/README.md)
48 | (at least things before introspection part)
49 | 2. [Know how Relay connect to GraphQL](http://facebook.github.io/relay/docs/graphql-relay-specification.html#content)
50 | (and the series below)
51 | 3. [Last, learn Relay](http://facebook.github.io/relay/docs/guides-containers.html#content)
52 | (and the series below)
53 |
54 | I tried these 3 steps in reverse, and I went step by step again.
55 |
--------------------------------------------------------------------------------
/build/babelRelayPlugin.js:
--------------------------------------------------------------------------------
1 | var getBabelRelayPlugin = require('babel-relay-plugin');
2 | var schema = require('../data/schema.json');
3 |
4 | module.exports = getBabelRelayPlugin(schema.data);
5 |
--------------------------------------------------------------------------------
/data/data.js:
--------------------------------------------------------------------------------
1 | export class Thread extends Object {}
2 | export class Message extends Object {}
3 | export class User extends Object {}
4 |
5 | // Mock authenticated ID
6 | export const VIEWER_ID = 'me';
7 |
8 | // Mock user data
9 | var viewer = new User();
10 | viewer.id = VIEWER_ID;
11 | export var usersById = {
12 | [VIEWER_ID]: viewer
13 | };
14 |
15 | export var threadsById = {};
16 | export var threadIdsByUser = {
17 | [VIEWER_ID]: []
18 | };
19 |
20 | export var messagesById = {};
21 | export var messageIdsByThread = {};
22 |
23 | // Mock raw message data then we can transform
24 | var messages = [
25 | {
26 | id: 'm_1',
27 | threadID: 't_1',
28 | threadName: 'Jing and Me',
29 | authorName: 'me',
30 | text: 'Hey Jing, want to give a Flux talk at ForwardJS?',
31 | timestamp: Date.now() - 99999
32 | },
33 | {
34 | id: 'm_2',
35 | threadID: 't_1',
36 | threadName: 'Jing and me',
37 | authorName: 'me',
38 | text: 'Seems like a pretty cool conference.',
39 | timestamp: Date.now() - 89999
40 | },
41 | {
42 | id: 'm_3',
43 | threadID: 't_1',
44 | threadName: 'Jing and me',
45 | authorName: 'Jing',
46 | text: 'Sounds good. Will they be serving dessert?',
47 | timestamp: Date.now() - 79999
48 | },
49 | {
50 | id: 'm_4',
51 | threadID: 't_2',
52 | threadName: 'Dave and me',
53 | authorName: 'me',
54 | text: 'Hey Dave, want to get a beer after the conference?',
55 | timestamp: Date.now() - 69999
56 | },
57 | {
58 | id: 'm_5',
59 | threadID: 't_2',
60 | threadName: 'Dave and me',
61 | authorName: 'Dave',
62 | text: 'Totally! Meet you at the hotel bar.',
63 | timestamp: Date.now() - 59999
64 | },
65 | {
66 | id: 'm_6',
67 | threadID: 't_3',
68 | threadName: 'Brian and me',
69 | authorName: 'me',
70 | text: 'Hey Brian, are you going to be talking about functional stuff?',
71 | timestamp: Date.now() - 49999
72 | },
73 | {
74 | id: 'm_7',
75 | threadID: 't_3',
76 | threadName: 'Brian and me',
77 | authorName: 'Brian',
78 | text: 'At ForwardJS? Yeah, of course. See you there!',
79 | timestamp: Date.now() - 39999
80 | }
81 | ];
82 | // inject raw messages into database
83 | // 這裡我們將 flux-chat 轉成符合 user -> threads -> messages 這樣的結構
84 | // -> : has many
85 | messages.map(mes => {
86 | let {threadID, threadName, timestamp} = mes;
87 | // if thread not exists
88 | if (!threadsById[threadID]) {
89 | let thread = new Thread();
90 | thread.id = threadID;
91 | thread.name = threadName;
92 | thread.isRead = false;
93 | thread.lastUpdated = timestamp;
94 | threadIdsByUser[VIEWER_ID].push(thread.id);
95 | threadsById[thread.id] = thread;
96 | }
97 | // if message are newer than lastUpdated, show update
98 | // 如果在同一個 thread 裡後面的訊息比較前面新, 更新 lastUpdated
99 | // 只有在這裡需要, 如果是透過 client 新增訊息, 就直接更新 lastUpdated
100 | if (timestamp > threadsById[threadID].lastUpdated) {
101 | threadsById[threadID].lastUpdated = timestamp;
102 | }
103 | let message = new Message();
104 | let {id, authorName, text} = mes;
105 | message.id = id;
106 | message.authorName = authorName;
107 | message.text = text;
108 | message.timestamp = timestamp;
109 | messagesById[message.id] = message;
110 | // if threadID is not defined in messageIdsByThread
111 | if (!messageIdsByThread[threadID]) {
112 | messageIdsByThread[threadID] = [];
113 | }
114 | messageIdsByThread[threadID].push(message.id);
115 | });
116 |
--------------------------------------------------------------------------------
/data/database.js:
--------------------------------------------------------------------------------
1 | import {Message, VIEWER_ID, usersById, threadsById, threadIdsByUser,
2 | messagesById, messageIdsByThread} from './data';
3 |
4 | export function addMessage(text, currentThreadID) {
5 | var timestamp = Date.now();
6 | var message = new Message();
7 | message.id = 'm_' + timestamp;
8 | message.authorName = 'me'; // hard coded for the example
9 | message.text = text;
10 | message.timestamp = timestamp;
11 |
12 | threadsById[currentThreadID].isRead = true;
13 | threadsById[currentThreadID].lastUpdated = timestamp;
14 |
15 | messagesById[message.id] = message;
16 | messageIdsByThread[currentThreadID].push(message.id);
17 |
18 | return {
19 | messageID: message.id,
20 | threadID: currentThreadID
21 | };
22 | }
23 |
24 | export function markThreadAsRead(id) {
25 | var thread = getThread(id);
26 | thread.isRead = true;
27 | }
28 |
29 | export function getThread(id) {
30 | return threadsById[id];
31 | }
32 |
33 | export function getThreads() {
34 | let orderedThreads = threadIdsByUser[VIEWER_ID].map(id => getThread(id));
35 | // let newer thread get lower index
36 | orderedThreads.sort((x, y) => {
37 | return x.lastUpdated > y.lastUpdated ?
38 | -1 : x.lastUpdated < y.lastUpdated ? 1 : 0;
39 | });
40 | return orderedThreads;
41 | }
42 |
43 | export function getMessage(id) {
44 | return messagesById[id];
45 | }
46 |
47 | export function getMessagesByThreadId(threadID) {
48 | let orderedMessages = messageIdsByThread[threadID].map(id => getMessage(id));
49 | // let newer message get higher index
50 | orderedMessages.sort((x, y) => {
51 | return x.timestamp < y.timestamp ? -1 : x.timestamp > y.timestamp ? 1 : 0;
52 | });
53 | return orderedMessages;
54 | }
55 |
56 | export function getUser(id) {
57 | return usersById[id];
58 | }
59 |
60 | export function getViewer() {
61 | return getUser(VIEWER_ID);
62 | }
63 |
--------------------------------------------------------------------------------
/data/schema.js:
--------------------------------------------------------------------------------
1 | import {
2 | GraphQLBoolean,
3 | GraphQLID,
4 | GraphQLInt,
5 | GraphQLNonNull,
6 | GraphQLObjectType,
7 | GraphQLSchema,
8 | GraphQLString,
9 | } from 'graphql';
10 |
11 | import {
12 | connectionArgs,
13 | connectionDefinitions,
14 | connectionFromArray,
15 | cursorForObjectInConnection,
16 | fromGlobalId,
17 | globalIdField,
18 | mutationWithClientMutationId,
19 | nodeDefinitions,
20 | } from 'graphql-relay';
21 |
22 | import {
23 | User,
24 | Thread,
25 | Message,
26 | } from './data.js';
27 |
28 | import {
29 | addMessage,
30 | getMessage,
31 | getMessagesByThreadId,
32 | getThread,
33 | getThreads,
34 | markThreadAsRead,
35 | getUser,
36 | getViewer,
37 | } from './database';
38 |
39 | var {nodeInterface, nodeField} = nodeDefinitions(
40 | (globalId) => {
41 | var {type, id} = fromGlobalId(globalId);
42 | if (type === 'Message') {
43 | return getMessage(id);
44 | } else if (type === 'Thread') {
45 | return getThread(id);
46 | } else if (type === 'User') {
47 | return getUser(id);
48 | }
49 | return null;
50 | },
51 | (obj) => {
52 | if (obj instanceof Message) {
53 | return GraphQLMessage;
54 | } else if (obj instanceof Thread) {
55 | return GraphQLThread;
56 | } else if (obj instanceof User) {
57 | return GraphQLUser;
58 | }
59 | return null;
60 | }
61 | );
62 |
63 | var GraphQLMessage = new GraphQLObjectType({
64 | name: 'Message',
65 | fields: {
66 | id: globalIdField('Message'),
67 | authorName: {
68 | type: GraphQLString,
69 | resolve: (obj) => obj.authorName
70 | },
71 | text: {
72 | type: GraphQLString,
73 | resolve: (obj) => obj.text
74 | },
75 | timestamp: {
76 | type: GraphQLInt,
77 | resolve: (obj) => obj.timestamp
78 | }
79 | },
80 | interfaces: [nodeInterface]
81 | });
82 |
83 | var {
84 | connectionType: MessageConnection,
85 | edgeType: GraphQLMessageEdge,
86 | } = connectionDefinitions({
87 | name: 'Message',
88 | nodeType: GraphQLMessage,
89 | });
90 |
91 | var GraphQLThread = new GraphQLObjectType({
92 | name: 'Thread',
93 | fields: {
94 | id: globalIdField('Thread'),
95 | name: {
96 | type: GraphQLString,
97 | resolve: (obj) => obj.name
98 | },
99 | isRead: {
100 | type: GraphQLBoolean,
101 | resolve: (obj) => obj.isRead
102 | },
103 | messages: {
104 | type: MessageConnection,
105 | args: connectionArgs,
106 | resolve: (thread, args) => {
107 | return connectionFromArray(getMessagesByThreadId(thread.id), args);
108 | }
109 | },
110 | lastUpdated: {
111 | type: GraphQLInt,
112 | resolve: (obj) => obj.lastUpdated
113 | }
114 | },
115 | interfaces: [nodeInterface]
116 | });
117 |
118 | var { connectionType: ThreadConnection } = connectionDefinitions({
119 | name: 'Thread',
120 | nodeType: GraphQLThread,
121 | connectionFields: () => ({
122 | unreadCount: {
123 | type: GraphQLInt,
124 | resolve: (conn) => conn.edges.filter(edge => !edge.node.isRead).length
125 | }
126 | })
127 | });
128 |
129 | var GraphQLUser = new GraphQLObjectType({
130 | name: 'User',
131 | fields: {
132 | id: globalIdField('User'),
133 | threads: {
134 | type: ThreadConnection,
135 | args: connectionArgs,
136 | resolve: (obj, args) => connectionFromArray(getThreads(), args),
137 | }
138 | },
139 | interfaces: [nodeInterface]
140 | });
141 |
142 | var Root = new GraphQLObjectType({
143 | name: 'Root',
144 | fields: {
145 | viewer: {
146 | type: GraphQLUser,
147 | resolve: () => getViewer()
148 | },
149 | node: nodeField
150 | },
151 | });
152 |
153 | var GraphQLAddMessageMutation = mutationWithClientMutationId({
154 | name: 'AddMessage',
155 | inputFields: {
156 | text: { type: new GraphQLNonNull(GraphQLString) },
157 | id: { type: new GraphQLNonNull(GraphQLID) },
158 | },
159 | outputFields: {
160 | messageEdge: {
161 | type: GraphQLMessageEdge,
162 | resolve: ({ messageID, threadID }) => {
163 | var message = getMessage(messageID);
164 | return {
165 | cursor: cursorForObjectInConnection(getMessagesByThreadId(
166 | threadID), message),
167 | node: message,
168 | };
169 | }
170 | },
171 | thread: {
172 | type: GraphQLThread,
173 | resolve: ({threadID}) => getThread(threadID)
174 | },
175 | viewer: {
176 | type: GraphQLUser,
177 | resolve: () => getViewer(),
178 | },
179 | },
180 | mutateAndGetPayload: ({text, id}) => {
181 | // important, else it would be encoded client id,
182 | // then database don't know how to handle
183 | var localThreadId = fromGlobalId(id).id;
184 | var {messageID, threadID} = addMessage(text, localThreadId);
185 | return {messageID, threadID};
186 | }
187 | });
188 |
189 | var GraphQLMarkThreadAsReadMutation = mutationWithClientMutationId({
190 | name: 'MarkThreadAsRead',
191 | inputFields: {
192 | id: { type: new GraphQLNonNull(GraphQLID) },
193 | },
194 | outputFields: {
195 | thread: {
196 | type: GraphQLThread,
197 | resolve: ({localThreadId}) => getThread(localThreadId),
198 | },
199 | viewer: {
200 | type: GraphQLUser,
201 | resolve: () => getViewer(),
202 | },
203 | },
204 | mutateAndGetPayload: ({id}) => {
205 | var localThreadId = fromGlobalId(id).id;
206 | markThreadAsRead(localThreadId);
207 | return {localThreadId};
208 | },
209 | });
210 |
211 | var Mutation = new GraphQLObjectType({
212 | name: 'Mutation',
213 | fields: {
214 | addMessage: GraphQLAddMessageMutation,
215 | markThreadAsRead: GraphQLMarkThreadAsReadMutation
216 | },
217 | });
218 |
219 | export var Schema = new GraphQLSchema({
220 | query: Root,
221 | mutation: Mutation
222 | });
223 |
--------------------------------------------------------------------------------
/data/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "data": {
3 | "__schema": {
4 | "queryType": {
5 | "name": "Root"
6 | },
7 | "mutationType": {
8 | "name": "Mutation"
9 | },
10 | "types": [
11 | {
12 | "kind": "OBJECT",
13 | "name": "Root",
14 | "description": null,
15 | "fields": [
16 | {
17 | "name": "viewer",
18 | "description": null,
19 | "args": [],
20 | "type": {
21 | "kind": "OBJECT",
22 | "name": "User",
23 | "ofType": null
24 | },
25 | "isDeprecated": false,
26 | "deprecationReason": null
27 | },
28 | {
29 | "name": "node",
30 | "description": "Fetches an object given its ID",
31 | "args": [
32 | {
33 | "name": "id",
34 | "description": "The ID of an object",
35 | "type": {
36 | "kind": "NON_NULL",
37 | "name": null,
38 | "ofType": {
39 | "kind": "SCALAR",
40 | "name": "ID",
41 | "ofType": null
42 | }
43 | },
44 | "defaultValue": null
45 | }
46 | ],
47 | "type": {
48 | "kind": "INTERFACE",
49 | "name": "Node",
50 | "ofType": null
51 | },
52 | "isDeprecated": false,
53 | "deprecationReason": null
54 | }
55 | ],
56 | "inputFields": null,
57 | "interfaces": [],
58 | "enumValues": null,
59 | "possibleTypes": null
60 | },
61 | {
62 | "kind": "OBJECT",
63 | "name": "User",
64 | "description": null,
65 | "fields": [
66 | {
67 | "name": "id",
68 | "description": "The ID of an object",
69 | "args": [],
70 | "type": {
71 | "kind": "NON_NULL",
72 | "name": null,
73 | "ofType": {
74 | "kind": "SCALAR",
75 | "name": "ID",
76 | "ofType": null
77 | }
78 | },
79 | "isDeprecated": false,
80 | "deprecationReason": null
81 | },
82 | {
83 | "name": "threads",
84 | "description": null,
85 | "args": [
86 | {
87 | "name": "before",
88 | "description": null,
89 | "type": {
90 | "kind": "SCALAR",
91 | "name": "String",
92 | "ofType": null
93 | },
94 | "defaultValue": null
95 | },
96 | {
97 | "name": "after",
98 | "description": null,
99 | "type": {
100 | "kind": "SCALAR",
101 | "name": "String",
102 | "ofType": null
103 | },
104 | "defaultValue": null
105 | },
106 | {
107 | "name": "first",
108 | "description": null,
109 | "type": {
110 | "kind": "SCALAR",
111 | "name": "Int",
112 | "ofType": null
113 | },
114 | "defaultValue": null
115 | },
116 | {
117 | "name": "last",
118 | "description": null,
119 | "type": {
120 | "kind": "SCALAR",
121 | "name": "Int",
122 | "ofType": null
123 | },
124 | "defaultValue": null
125 | }
126 | ],
127 | "type": {
128 | "kind": "OBJECT",
129 | "name": "ThreadConnection",
130 | "ofType": null
131 | },
132 | "isDeprecated": false,
133 | "deprecationReason": null
134 | }
135 | ],
136 | "inputFields": null,
137 | "interfaces": [
138 | {
139 | "kind": "INTERFACE",
140 | "name": "Node",
141 | "ofType": null
142 | }
143 | ],
144 | "enumValues": null,
145 | "possibleTypes": null
146 | },
147 | {
148 | "kind": "INTERFACE",
149 | "name": "Node",
150 | "description": "An object with an ID",
151 | "fields": [
152 | {
153 | "name": "id",
154 | "description": "The id of the object.",
155 | "args": [],
156 | "type": {
157 | "kind": "NON_NULL",
158 | "name": null,
159 | "ofType": {
160 | "kind": "SCALAR",
161 | "name": "ID",
162 | "ofType": null
163 | }
164 | },
165 | "isDeprecated": false,
166 | "deprecationReason": null
167 | }
168 | ],
169 | "inputFields": null,
170 | "interfaces": null,
171 | "enumValues": null,
172 | "possibleTypes": [
173 | {
174 | "kind": "OBJECT",
175 | "name": "Message",
176 | "ofType": null
177 | },
178 | {
179 | "kind": "OBJECT",
180 | "name": "Thread",
181 | "ofType": null
182 | },
183 | {
184 | "kind": "OBJECT",
185 | "name": "User",
186 | "ofType": null
187 | }
188 | ]
189 | },
190 | {
191 | "kind": "OBJECT",
192 | "name": "Message",
193 | "description": null,
194 | "fields": [
195 | {
196 | "name": "id",
197 | "description": "The ID of an object",
198 | "args": [],
199 | "type": {
200 | "kind": "NON_NULL",
201 | "name": null,
202 | "ofType": {
203 | "kind": "SCALAR",
204 | "name": "ID",
205 | "ofType": null
206 | }
207 | },
208 | "isDeprecated": false,
209 | "deprecationReason": null
210 | },
211 | {
212 | "name": "authorName",
213 | "description": null,
214 | "args": [],
215 | "type": {
216 | "kind": "SCALAR",
217 | "name": "String",
218 | "ofType": null
219 | },
220 | "isDeprecated": false,
221 | "deprecationReason": null
222 | },
223 | {
224 | "name": "text",
225 | "description": null,
226 | "args": [],
227 | "type": {
228 | "kind": "SCALAR",
229 | "name": "String",
230 | "ofType": null
231 | },
232 | "isDeprecated": false,
233 | "deprecationReason": null
234 | },
235 | {
236 | "name": "timestamp",
237 | "description": null,
238 | "args": [],
239 | "type": {
240 | "kind": "SCALAR",
241 | "name": "Int",
242 | "ofType": null
243 | },
244 | "isDeprecated": false,
245 | "deprecationReason": null
246 | }
247 | ],
248 | "inputFields": null,
249 | "interfaces": [
250 | {
251 | "kind": "INTERFACE",
252 | "name": "Node",
253 | "ofType": null
254 | }
255 | ],
256 | "enumValues": null,
257 | "possibleTypes": null
258 | },
259 | {
260 | "kind": "SCALAR",
261 | "name": "ID",
262 | "description": null,
263 | "fields": null,
264 | "inputFields": null,
265 | "interfaces": null,
266 | "enumValues": null,
267 | "possibleTypes": null
268 | },
269 | {
270 | "kind": "SCALAR",
271 | "name": "String",
272 | "description": null,
273 | "fields": null,
274 | "inputFields": null,
275 | "interfaces": null,
276 | "enumValues": null,
277 | "possibleTypes": null
278 | },
279 | {
280 | "kind": "SCALAR",
281 | "name": "Int",
282 | "description": null,
283 | "fields": null,
284 | "inputFields": null,
285 | "interfaces": null,
286 | "enumValues": null,
287 | "possibleTypes": null
288 | },
289 | {
290 | "kind": "OBJECT",
291 | "name": "Thread",
292 | "description": null,
293 | "fields": [
294 | {
295 | "name": "id",
296 | "description": "The ID of an object",
297 | "args": [],
298 | "type": {
299 | "kind": "NON_NULL",
300 | "name": null,
301 | "ofType": {
302 | "kind": "SCALAR",
303 | "name": "ID",
304 | "ofType": null
305 | }
306 | },
307 | "isDeprecated": false,
308 | "deprecationReason": null
309 | },
310 | {
311 | "name": "name",
312 | "description": null,
313 | "args": [],
314 | "type": {
315 | "kind": "SCALAR",
316 | "name": "String",
317 | "ofType": null
318 | },
319 | "isDeprecated": false,
320 | "deprecationReason": null
321 | },
322 | {
323 | "name": "isRead",
324 | "description": null,
325 | "args": [],
326 | "type": {
327 | "kind": "SCALAR",
328 | "name": "Boolean",
329 | "ofType": null
330 | },
331 | "isDeprecated": false,
332 | "deprecationReason": null
333 | },
334 | {
335 | "name": "messages",
336 | "description": null,
337 | "args": [
338 | {
339 | "name": "before",
340 | "description": null,
341 | "type": {
342 | "kind": "SCALAR",
343 | "name": "String",
344 | "ofType": null
345 | },
346 | "defaultValue": null
347 | },
348 | {
349 | "name": "after",
350 | "description": null,
351 | "type": {
352 | "kind": "SCALAR",
353 | "name": "String",
354 | "ofType": null
355 | },
356 | "defaultValue": null
357 | },
358 | {
359 | "name": "first",
360 | "description": null,
361 | "type": {
362 | "kind": "SCALAR",
363 | "name": "Int",
364 | "ofType": null
365 | },
366 | "defaultValue": null
367 | },
368 | {
369 | "name": "last",
370 | "description": null,
371 | "type": {
372 | "kind": "SCALAR",
373 | "name": "Int",
374 | "ofType": null
375 | },
376 | "defaultValue": null
377 | }
378 | ],
379 | "type": {
380 | "kind": "OBJECT",
381 | "name": "MessageConnection",
382 | "ofType": null
383 | },
384 | "isDeprecated": false,
385 | "deprecationReason": null
386 | },
387 | {
388 | "name": "lastUpdated",
389 | "description": null,
390 | "args": [],
391 | "type": {
392 | "kind": "SCALAR",
393 | "name": "Int",
394 | "ofType": null
395 | },
396 | "isDeprecated": false,
397 | "deprecationReason": null
398 | }
399 | ],
400 | "inputFields": null,
401 | "interfaces": [
402 | {
403 | "kind": "INTERFACE",
404 | "name": "Node",
405 | "ofType": null
406 | }
407 | ],
408 | "enumValues": null,
409 | "possibleTypes": null
410 | },
411 | {
412 | "kind": "SCALAR",
413 | "name": "Boolean",
414 | "description": null,
415 | "fields": null,
416 | "inputFields": null,
417 | "interfaces": null,
418 | "enumValues": null,
419 | "possibleTypes": null
420 | },
421 | {
422 | "kind": "OBJECT",
423 | "name": "MessageConnection",
424 | "description": "A connection to a list of items.",
425 | "fields": [
426 | {
427 | "name": "pageInfo",
428 | "description": "Information to aid in pagination.",
429 | "args": [],
430 | "type": {
431 | "kind": "NON_NULL",
432 | "name": null,
433 | "ofType": {
434 | "kind": "OBJECT",
435 | "name": "PageInfo",
436 | "ofType": null
437 | }
438 | },
439 | "isDeprecated": false,
440 | "deprecationReason": null
441 | },
442 | {
443 | "name": "edges",
444 | "description": "Information to aid in pagination.",
445 | "args": [],
446 | "type": {
447 | "kind": "LIST",
448 | "name": null,
449 | "ofType": {
450 | "kind": "OBJECT",
451 | "name": "MessageEdge",
452 | "ofType": null
453 | }
454 | },
455 | "isDeprecated": false,
456 | "deprecationReason": null
457 | }
458 | ],
459 | "inputFields": null,
460 | "interfaces": [],
461 | "enumValues": null,
462 | "possibleTypes": null
463 | },
464 | {
465 | "kind": "OBJECT",
466 | "name": "PageInfo",
467 | "description": "Information about pagination in a connection.",
468 | "fields": [
469 | {
470 | "name": "hasNextPage",
471 | "description": "When paginating forwards, are there more items?",
472 | "args": [],
473 | "type": {
474 | "kind": "NON_NULL",
475 | "name": null,
476 | "ofType": {
477 | "kind": "SCALAR",
478 | "name": "Boolean",
479 | "ofType": null
480 | }
481 | },
482 | "isDeprecated": false,
483 | "deprecationReason": null
484 | },
485 | {
486 | "name": "hasPreviousPage",
487 | "description": "When paginating backwards, are there more items?",
488 | "args": [],
489 | "type": {
490 | "kind": "NON_NULL",
491 | "name": null,
492 | "ofType": {
493 | "kind": "SCALAR",
494 | "name": "Boolean",
495 | "ofType": null
496 | }
497 | },
498 | "isDeprecated": false,
499 | "deprecationReason": null
500 | },
501 | {
502 | "name": "startCursor",
503 | "description": "When paginating backwards, the cursor to continue.",
504 | "args": [],
505 | "type": {
506 | "kind": "SCALAR",
507 | "name": "String",
508 | "ofType": null
509 | },
510 | "isDeprecated": false,
511 | "deprecationReason": null
512 | },
513 | {
514 | "name": "endCursor",
515 | "description": "When paginating forwards, the cursor to continue.",
516 | "args": [],
517 | "type": {
518 | "kind": "SCALAR",
519 | "name": "String",
520 | "ofType": null
521 | },
522 | "isDeprecated": false,
523 | "deprecationReason": null
524 | }
525 | ],
526 | "inputFields": null,
527 | "interfaces": [],
528 | "enumValues": null,
529 | "possibleTypes": null
530 | },
531 | {
532 | "kind": "OBJECT",
533 | "name": "MessageEdge",
534 | "description": "An edge in a connection.",
535 | "fields": [
536 | {
537 | "name": "node",
538 | "description": "The item at the end of the edge",
539 | "args": [],
540 | "type": {
541 | "kind": "OBJECT",
542 | "name": "Message",
543 | "ofType": null
544 | },
545 | "isDeprecated": false,
546 | "deprecationReason": null
547 | },
548 | {
549 | "name": "cursor",
550 | "description": "A cursor for use in pagination",
551 | "args": [],
552 | "type": {
553 | "kind": "NON_NULL",
554 | "name": null,
555 | "ofType": {
556 | "kind": "SCALAR",
557 | "name": "String",
558 | "ofType": null
559 | }
560 | },
561 | "isDeprecated": false,
562 | "deprecationReason": null
563 | }
564 | ],
565 | "inputFields": null,
566 | "interfaces": [],
567 | "enumValues": null,
568 | "possibleTypes": null
569 | },
570 | {
571 | "kind": "OBJECT",
572 | "name": "ThreadConnection",
573 | "description": "A connection to a list of items.",
574 | "fields": [
575 | {
576 | "name": "pageInfo",
577 | "description": "Information to aid in pagination.",
578 | "args": [],
579 | "type": {
580 | "kind": "NON_NULL",
581 | "name": null,
582 | "ofType": {
583 | "kind": "OBJECT",
584 | "name": "PageInfo",
585 | "ofType": null
586 | }
587 | },
588 | "isDeprecated": false,
589 | "deprecationReason": null
590 | },
591 | {
592 | "name": "edges",
593 | "description": "Information to aid in pagination.",
594 | "args": [],
595 | "type": {
596 | "kind": "LIST",
597 | "name": null,
598 | "ofType": {
599 | "kind": "OBJECT",
600 | "name": "ThreadEdge",
601 | "ofType": null
602 | }
603 | },
604 | "isDeprecated": false,
605 | "deprecationReason": null
606 | },
607 | {
608 | "name": "unreadCount",
609 | "description": null,
610 | "args": [],
611 | "type": {
612 | "kind": "SCALAR",
613 | "name": "Int",
614 | "ofType": null
615 | },
616 | "isDeprecated": false,
617 | "deprecationReason": null
618 | }
619 | ],
620 | "inputFields": null,
621 | "interfaces": [],
622 | "enumValues": null,
623 | "possibleTypes": null
624 | },
625 | {
626 | "kind": "OBJECT",
627 | "name": "ThreadEdge",
628 | "description": "An edge in a connection.",
629 | "fields": [
630 | {
631 | "name": "node",
632 | "description": "The item at the end of the edge",
633 | "args": [],
634 | "type": {
635 | "kind": "OBJECT",
636 | "name": "Thread",
637 | "ofType": null
638 | },
639 | "isDeprecated": false,
640 | "deprecationReason": null
641 | },
642 | {
643 | "name": "cursor",
644 | "description": "A cursor for use in pagination",
645 | "args": [],
646 | "type": {
647 | "kind": "NON_NULL",
648 | "name": null,
649 | "ofType": {
650 | "kind": "SCALAR",
651 | "name": "String",
652 | "ofType": null
653 | }
654 | },
655 | "isDeprecated": false,
656 | "deprecationReason": null
657 | }
658 | ],
659 | "inputFields": null,
660 | "interfaces": [],
661 | "enumValues": null,
662 | "possibleTypes": null
663 | },
664 | {
665 | "kind": "OBJECT",
666 | "name": "Mutation",
667 | "description": null,
668 | "fields": [
669 | {
670 | "name": "addMessage",
671 | "description": null,
672 | "args": [
673 | {
674 | "name": "input",
675 | "description": null,
676 | "type": {
677 | "kind": "NON_NULL",
678 | "name": null,
679 | "ofType": {
680 | "kind": "INPUT_OBJECT",
681 | "name": "AddMessageInput",
682 | "ofType": null
683 | }
684 | },
685 | "defaultValue": null
686 | }
687 | ],
688 | "type": {
689 | "kind": "OBJECT",
690 | "name": "AddMessagePayload",
691 | "ofType": null
692 | },
693 | "isDeprecated": false,
694 | "deprecationReason": null
695 | },
696 | {
697 | "name": "markThreadAsRead",
698 | "description": null,
699 | "args": [
700 | {
701 | "name": "input",
702 | "description": null,
703 | "type": {
704 | "kind": "NON_NULL",
705 | "name": null,
706 | "ofType": {
707 | "kind": "INPUT_OBJECT",
708 | "name": "MarkThreadAsReadInput",
709 | "ofType": null
710 | }
711 | },
712 | "defaultValue": null
713 | }
714 | ],
715 | "type": {
716 | "kind": "OBJECT",
717 | "name": "MarkThreadAsReadPayload",
718 | "ofType": null
719 | },
720 | "isDeprecated": false,
721 | "deprecationReason": null
722 | }
723 | ],
724 | "inputFields": null,
725 | "interfaces": [],
726 | "enumValues": null,
727 | "possibleTypes": null
728 | },
729 | {
730 | "kind": "INPUT_OBJECT",
731 | "name": "AddMessageInput",
732 | "description": null,
733 | "fields": null,
734 | "inputFields": [
735 | {
736 | "name": "text",
737 | "description": null,
738 | "type": {
739 | "kind": "NON_NULL",
740 | "name": null,
741 | "ofType": {
742 | "kind": "SCALAR",
743 | "name": "String",
744 | "ofType": null
745 | }
746 | },
747 | "defaultValue": null
748 | },
749 | {
750 | "name": "id",
751 | "description": null,
752 | "type": {
753 | "kind": "NON_NULL",
754 | "name": null,
755 | "ofType": {
756 | "kind": "SCALAR",
757 | "name": "ID",
758 | "ofType": null
759 | }
760 | },
761 | "defaultValue": null
762 | },
763 | {
764 | "name": "clientMutationId",
765 | "description": null,
766 | "type": {
767 | "kind": "NON_NULL",
768 | "name": null,
769 | "ofType": {
770 | "kind": "SCALAR",
771 | "name": "String",
772 | "ofType": null
773 | }
774 | },
775 | "defaultValue": null
776 | }
777 | ],
778 | "interfaces": null,
779 | "enumValues": null,
780 | "possibleTypes": null
781 | },
782 | {
783 | "kind": "OBJECT",
784 | "name": "AddMessagePayload",
785 | "description": null,
786 | "fields": [
787 | {
788 | "name": "messageEdge",
789 | "description": null,
790 | "args": [],
791 | "type": {
792 | "kind": "OBJECT",
793 | "name": "MessageEdge",
794 | "ofType": null
795 | },
796 | "isDeprecated": false,
797 | "deprecationReason": null
798 | },
799 | {
800 | "name": "thread",
801 | "description": null,
802 | "args": [],
803 | "type": {
804 | "kind": "OBJECT",
805 | "name": "Thread",
806 | "ofType": null
807 | },
808 | "isDeprecated": false,
809 | "deprecationReason": null
810 | },
811 | {
812 | "name": "viewer",
813 | "description": null,
814 | "args": [],
815 | "type": {
816 | "kind": "OBJECT",
817 | "name": "User",
818 | "ofType": null
819 | },
820 | "isDeprecated": false,
821 | "deprecationReason": null
822 | },
823 | {
824 | "name": "clientMutationId",
825 | "description": null,
826 | "args": [],
827 | "type": {
828 | "kind": "NON_NULL",
829 | "name": null,
830 | "ofType": {
831 | "kind": "SCALAR",
832 | "name": "String",
833 | "ofType": null
834 | }
835 | },
836 | "isDeprecated": false,
837 | "deprecationReason": null
838 | }
839 | ],
840 | "inputFields": null,
841 | "interfaces": [],
842 | "enumValues": null,
843 | "possibleTypes": null
844 | },
845 | {
846 | "kind": "INPUT_OBJECT",
847 | "name": "MarkThreadAsReadInput",
848 | "description": null,
849 | "fields": null,
850 | "inputFields": [
851 | {
852 | "name": "id",
853 | "description": null,
854 | "type": {
855 | "kind": "NON_NULL",
856 | "name": null,
857 | "ofType": {
858 | "kind": "SCALAR",
859 | "name": "ID",
860 | "ofType": null
861 | }
862 | },
863 | "defaultValue": null
864 | },
865 | {
866 | "name": "clientMutationId",
867 | "description": null,
868 | "type": {
869 | "kind": "NON_NULL",
870 | "name": null,
871 | "ofType": {
872 | "kind": "SCALAR",
873 | "name": "String",
874 | "ofType": null
875 | }
876 | },
877 | "defaultValue": null
878 | }
879 | ],
880 | "interfaces": null,
881 | "enumValues": null,
882 | "possibleTypes": null
883 | },
884 | {
885 | "kind": "OBJECT",
886 | "name": "MarkThreadAsReadPayload",
887 | "description": null,
888 | "fields": [
889 | {
890 | "name": "thread",
891 | "description": null,
892 | "args": [],
893 | "type": {
894 | "kind": "OBJECT",
895 | "name": "Thread",
896 | "ofType": null
897 | },
898 | "isDeprecated": false,
899 | "deprecationReason": null
900 | },
901 | {
902 | "name": "viewer",
903 | "description": null,
904 | "args": [],
905 | "type": {
906 | "kind": "OBJECT",
907 | "name": "User",
908 | "ofType": null
909 | },
910 | "isDeprecated": false,
911 | "deprecationReason": null
912 | },
913 | {
914 | "name": "clientMutationId",
915 | "description": null,
916 | "args": [],
917 | "type": {
918 | "kind": "NON_NULL",
919 | "name": null,
920 | "ofType": {
921 | "kind": "SCALAR",
922 | "name": "String",
923 | "ofType": null
924 | }
925 | },
926 | "isDeprecated": false,
927 | "deprecationReason": null
928 | }
929 | ],
930 | "inputFields": null,
931 | "interfaces": [],
932 | "enumValues": null,
933 | "possibleTypes": null
934 | },
935 | {
936 | "kind": "OBJECT",
937 | "name": "__Schema",
938 | "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query and mutation operations.",
939 | "fields": [
940 | {
941 | "name": "types",
942 | "description": "A list of all types supported by this server.",
943 | "args": [],
944 | "type": {
945 | "kind": "NON_NULL",
946 | "name": null,
947 | "ofType": {
948 | "kind": "LIST",
949 | "name": null,
950 | "ofType": {
951 | "kind": "NON_NULL",
952 | "name": null,
953 | "ofType": {
954 | "kind": "OBJECT",
955 | "name": "__Type"
956 | }
957 | }
958 | }
959 | },
960 | "isDeprecated": false,
961 | "deprecationReason": null
962 | },
963 | {
964 | "name": "queryType",
965 | "description": "The type that query operations will be rooted at.",
966 | "args": [],
967 | "type": {
968 | "kind": "NON_NULL",
969 | "name": null,
970 | "ofType": {
971 | "kind": "OBJECT",
972 | "name": "__Type",
973 | "ofType": null
974 | }
975 | },
976 | "isDeprecated": false,
977 | "deprecationReason": null
978 | },
979 | {
980 | "name": "mutationType",
981 | "description": "If this server supports mutation, the type that mutation operations will be rooted at.",
982 | "args": [],
983 | "type": {
984 | "kind": "OBJECT",
985 | "name": "__Type",
986 | "ofType": null
987 | },
988 | "isDeprecated": false,
989 | "deprecationReason": null
990 | },
991 | {
992 | "name": "directives",
993 | "description": "A list of all directives supported by this server.",
994 | "args": [],
995 | "type": {
996 | "kind": "NON_NULL",
997 | "name": null,
998 | "ofType": {
999 | "kind": "LIST",
1000 | "name": null,
1001 | "ofType": {
1002 | "kind": "NON_NULL",
1003 | "name": null,
1004 | "ofType": {
1005 | "kind": "OBJECT",
1006 | "name": "__Directive"
1007 | }
1008 | }
1009 | }
1010 | },
1011 | "isDeprecated": false,
1012 | "deprecationReason": null
1013 | }
1014 | ],
1015 | "inputFields": null,
1016 | "interfaces": [],
1017 | "enumValues": null,
1018 | "possibleTypes": null
1019 | },
1020 | {
1021 | "kind": "OBJECT",
1022 | "name": "__Type",
1023 | "description": null,
1024 | "fields": [
1025 | {
1026 | "name": "kind",
1027 | "description": null,
1028 | "args": [],
1029 | "type": {
1030 | "kind": "NON_NULL",
1031 | "name": null,
1032 | "ofType": {
1033 | "kind": "ENUM",
1034 | "name": "__TypeKind",
1035 | "ofType": null
1036 | }
1037 | },
1038 | "isDeprecated": false,
1039 | "deprecationReason": null
1040 | },
1041 | {
1042 | "name": "name",
1043 | "description": null,
1044 | "args": [],
1045 | "type": {
1046 | "kind": "SCALAR",
1047 | "name": "String",
1048 | "ofType": null
1049 | },
1050 | "isDeprecated": false,
1051 | "deprecationReason": null
1052 | },
1053 | {
1054 | "name": "description",
1055 | "description": null,
1056 | "args": [],
1057 | "type": {
1058 | "kind": "SCALAR",
1059 | "name": "String",
1060 | "ofType": null
1061 | },
1062 | "isDeprecated": false,
1063 | "deprecationReason": null
1064 | },
1065 | {
1066 | "name": "fields",
1067 | "description": null,
1068 | "args": [
1069 | {
1070 | "name": "includeDeprecated",
1071 | "description": null,
1072 | "type": {
1073 | "kind": "SCALAR",
1074 | "name": "Boolean",
1075 | "ofType": null
1076 | },
1077 | "defaultValue": "false"
1078 | }
1079 | ],
1080 | "type": {
1081 | "kind": "LIST",
1082 | "name": null,
1083 | "ofType": {
1084 | "kind": "NON_NULL",
1085 | "name": null,
1086 | "ofType": {
1087 | "kind": "OBJECT",
1088 | "name": "__Field",
1089 | "ofType": null
1090 | }
1091 | }
1092 | },
1093 | "isDeprecated": false,
1094 | "deprecationReason": null
1095 | },
1096 | {
1097 | "name": "interfaces",
1098 | "description": null,
1099 | "args": [],
1100 | "type": {
1101 | "kind": "LIST",
1102 | "name": null,
1103 | "ofType": {
1104 | "kind": "NON_NULL",
1105 | "name": null,
1106 | "ofType": {
1107 | "kind": "OBJECT",
1108 | "name": "__Type",
1109 | "ofType": null
1110 | }
1111 | }
1112 | },
1113 | "isDeprecated": false,
1114 | "deprecationReason": null
1115 | },
1116 | {
1117 | "name": "possibleTypes",
1118 | "description": null,
1119 | "args": [],
1120 | "type": {
1121 | "kind": "LIST",
1122 | "name": null,
1123 | "ofType": {
1124 | "kind": "NON_NULL",
1125 | "name": null,
1126 | "ofType": {
1127 | "kind": "OBJECT",
1128 | "name": "__Type",
1129 | "ofType": null
1130 | }
1131 | }
1132 | },
1133 | "isDeprecated": false,
1134 | "deprecationReason": null
1135 | },
1136 | {
1137 | "name": "enumValues",
1138 | "description": null,
1139 | "args": [
1140 | {
1141 | "name": "includeDeprecated",
1142 | "description": null,
1143 | "type": {
1144 | "kind": "SCALAR",
1145 | "name": "Boolean",
1146 | "ofType": null
1147 | },
1148 | "defaultValue": "false"
1149 | }
1150 | ],
1151 | "type": {
1152 | "kind": "LIST",
1153 | "name": null,
1154 | "ofType": {
1155 | "kind": "NON_NULL",
1156 | "name": null,
1157 | "ofType": {
1158 | "kind": "OBJECT",
1159 | "name": "__EnumValue",
1160 | "ofType": null
1161 | }
1162 | }
1163 | },
1164 | "isDeprecated": false,
1165 | "deprecationReason": null
1166 | },
1167 | {
1168 | "name": "inputFields",
1169 | "description": null,
1170 | "args": [],
1171 | "type": {
1172 | "kind": "LIST",
1173 | "name": null,
1174 | "ofType": {
1175 | "kind": "NON_NULL",
1176 | "name": null,
1177 | "ofType": {
1178 | "kind": "OBJECT",
1179 | "name": "__InputValue",
1180 | "ofType": null
1181 | }
1182 | }
1183 | },
1184 | "isDeprecated": false,
1185 | "deprecationReason": null
1186 | },
1187 | {
1188 | "name": "ofType",
1189 | "description": null,
1190 | "args": [],
1191 | "type": {
1192 | "kind": "OBJECT",
1193 | "name": "__Type",
1194 | "ofType": null
1195 | },
1196 | "isDeprecated": false,
1197 | "deprecationReason": null
1198 | }
1199 | ],
1200 | "inputFields": null,
1201 | "interfaces": [],
1202 | "enumValues": null,
1203 | "possibleTypes": null
1204 | },
1205 | {
1206 | "kind": "ENUM",
1207 | "name": "__TypeKind",
1208 | "description": "An enum describing what kind of type a given __Type is",
1209 | "fields": null,
1210 | "inputFields": null,
1211 | "interfaces": null,
1212 | "enumValues": [
1213 | {
1214 | "name": "SCALAR",
1215 | "description": "Indicates this type is a scalar.",
1216 | "isDeprecated": false,
1217 | "deprecationReason": null
1218 | },
1219 | {
1220 | "name": "OBJECT",
1221 | "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.",
1222 | "isDeprecated": false,
1223 | "deprecationReason": null
1224 | },
1225 | {
1226 | "name": "INTERFACE",
1227 | "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.",
1228 | "isDeprecated": false,
1229 | "deprecationReason": null
1230 | },
1231 | {
1232 | "name": "UNION",
1233 | "description": "Indicates this type is a union. `possibleTypes` is a valid field.",
1234 | "isDeprecated": false,
1235 | "deprecationReason": null
1236 | },
1237 | {
1238 | "name": "ENUM",
1239 | "description": "Indicates this type is an enum. `enumValues` is a valid field.",
1240 | "isDeprecated": false,
1241 | "deprecationReason": null
1242 | },
1243 | {
1244 | "name": "INPUT_OBJECT",
1245 | "description": "Indicates this type is an input object. `inputFields` is a valid field.",
1246 | "isDeprecated": false,
1247 | "deprecationReason": null
1248 | },
1249 | {
1250 | "name": "LIST",
1251 | "description": "Indicates this type is a list. `ofType` is a valid field.",
1252 | "isDeprecated": false,
1253 | "deprecationReason": null
1254 | },
1255 | {
1256 | "name": "NON_NULL",
1257 | "description": "Indicates this type is a non-null. `ofType` is a valid field.",
1258 | "isDeprecated": false,
1259 | "deprecationReason": null
1260 | }
1261 | ],
1262 | "possibleTypes": null
1263 | },
1264 | {
1265 | "kind": "OBJECT",
1266 | "name": "__Field",
1267 | "description": null,
1268 | "fields": [
1269 | {
1270 | "name": "name",
1271 | "description": null,
1272 | "args": [],
1273 | "type": {
1274 | "kind": "NON_NULL",
1275 | "name": null,
1276 | "ofType": {
1277 | "kind": "SCALAR",
1278 | "name": "String",
1279 | "ofType": null
1280 | }
1281 | },
1282 | "isDeprecated": false,
1283 | "deprecationReason": null
1284 | },
1285 | {
1286 | "name": "description",
1287 | "description": null,
1288 | "args": [],
1289 | "type": {
1290 | "kind": "SCALAR",
1291 | "name": "String",
1292 | "ofType": null
1293 | },
1294 | "isDeprecated": false,
1295 | "deprecationReason": null
1296 | },
1297 | {
1298 | "name": "args",
1299 | "description": null,
1300 | "args": [],
1301 | "type": {
1302 | "kind": "NON_NULL",
1303 | "name": null,
1304 | "ofType": {
1305 | "kind": "LIST",
1306 | "name": null,
1307 | "ofType": {
1308 | "kind": "NON_NULL",
1309 | "name": null,
1310 | "ofType": {
1311 | "kind": "OBJECT",
1312 | "name": "__InputValue"
1313 | }
1314 | }
1315 | }
1316 | },
1317 | "isDeprecated": false,
1318 | "deprecationReason": null
1319 | },
1320 | {
1321 | "name": "type",
1322 | "description": null,
1323 | "args": [],
1324 | "type": {
1325 | "kind": "NON_NULL",
1326 | "name": null,
1327 | "ofType": {
1328 | "kind": "OBJECT",
1329 | "name": "__Type",
1330 | "ofType": null
1331 | }
1332 | },
1333 | "isDeprecated": false,
1334 | "deprecationReason": null
1335 | },
1336 | {
1337 | "name": "isDeprecated",
1338 | "description": null,
1339 | "args": [],
1340 | "type": {
1341 | "kind": "NON_NULL",
1342 | "name": null,
1343 | "ofType": {
1344 | "kind": "SCALAR",
1345 | "name": "Boolean",
1346 | "ofType": null
1347 | }
1348 | },
1349 | "isDeprecated": false,
1350 | "deprecationReason": null
1351 | },
1352 | {
1353 | "name": "deprecationReason",
1354 | "description": null,
1355 | "args": [],
1356 | "type": {
1357 | "kind": "SCALAR",
1358 | "name": "String",
1359 | "ofType": null
1360 | },
1361 | "isDeprecated": false,
1362 | "deprecationReason": null
1363 | }
1364 | ],
1365 | "inputFields": null,
1366 | "interfaces": [],
1367 | "enumValues": null,
1368 | "possibleTypes": null
1369 | },
1370 | {
1371 | "kind": "OBJECT",
1372 | "name": "__InputValue",
1373 | "description": null,
1374 | "fields": [
1375 | {
1376 | "name": "name",
1377 | "description": null,
1378 | "args": [],
1379 | "type": {
1380 | "kind": "NON_NULL",
1381 | "name": null,
1382 | "ofType": {
1383 | "kind": "SCALAR",
1384 | "name": "String",
1385 | "ofType": null
1386 | }
1387 | },
1388 | "isDeprecated": false,
1389 | "deprecationReason": null
1390 | },
1391 | {
1392 | "name": "description",
1393 | "description": null,
1394 | "args": [],
1395 | "type": {
1396 | "kind": "SCALAR",
1397 | "name": "String",
1398 | "ofType": null
1399 | },
1400 | "isDeprecated": false,
1401 | "deprecationReason": null
1402 | },
1403 | {
1404 | "name": "type",
1405 | "description": null,
1406 | "args": [],
1407 | "type": {
1408 | "kind": "NON_NULL",
1409 | "name": null,
1410 | "ofType": {
1411 | "kind": "OBJECT",
1412 | "name": "__Type",
1413 | "ofType": null
1414 | }
1415 | },
1416 | "isDeprecated": false,
1417 | "deprecationReason": null
1418 | },
1419 | {
1420 | "name": "defaultValue",
1421 | "description": null,
1422 | "args": [],
1423 | "type": {
1424 | "kind": "SCALAR",
1425 | "name": "String",
1426 | "ofType": null
1427 | },
1428 | "isDeprecated": false,
1429 | "deprecationReason": null
1430 | }
1431 | ],
1432 | "inputFields": null,
1433 | "interfaces": [],
1434 | "enumValues": null,
1435 | "possibleTypes": null
1436 | },
1437 | {
1438 | "kind": "OBJECT",
1439 | "name": "__EnumValue",
1440 | "description": null,
1441 | "fields": [
1442 | {
1443 | "name": "name",
1444 | "description": null,
1445 | "args": [],
1446 | "type": {
1447 | "kind": "NON_NULL",
1448 | "name": null,
1449 | "ofType": {
1450 | "kind": "SCALAR",
1451 | "name": "String",
1452 | "ofType": null
1453 | }
1454 | },
1455 | "isDeprecated": false,
1456 | "deprecationReason": null
1457 | },
1458 | {
1459 | "name": "description",
1460 | "description": null,
1461 | "args": [],
1462 | "type": {
1463 | "kind": "SCALAR",
1464 | "name": "String",
1465 | "ofType": null
1466 | },
1467 | "isDeprecated": false,
1468 | "deprecationReason": null
1469 | },
1470 | {
1471 | "name": "isDeprecated",
1472 | "description": null,
1473 | "args": [],
1474 | "type": {
1475 | "kind": "NON_NULL",
1476 | "name": null,
1477 | "ofType": {
1478 | "kind": "SCALAR",
1479 | "name": "Boolean",
1480 | "ofType": null
1481 | }
1482 | },
1483 | "isDeprecated": false,
1484 | "deprecationReason": null
1485 | },
1486 | {
1487 | "name": "deprecationReason",
1488 | "description": null,
1489 | "args": [],
1490 | "type": {
1491 | "kind": "SCALAR",
1492 | "name": "String",
1493 | "ofType": null
1494 | },
1495 | "isDeprecated": false,
1496 | "deprecationReason": null
1497 | }
1498 | ],
1499 | "inputFields": null,
1500 | "interfaces": [],
1501 | "enumValues": null,
1502 | "possibleTypes": null
1503 | },
1504 | {
1505 | "kind": "OBJECT",
1506 | "name": "__Directive",
1507 | "description": null,
1508 | "fields": [
1509 | {
1510 | "name": "name",
1511 | "description": null,
1512 | "args": [],
1513 | "type": {
1514 | "kind": "NON_NULL",
1515 | "name": null,
1516 | "ofType": {
1517 | "kind": "SCALAR",
1518 | "name": "String",
1519 | "ofType": null
1520 | }
1521 | },
1522 | "isDeprecated": false,
1523 | "deprecationReason": null
1524 | },
1525 | {
1526 | "name": "description",
1527 | "description": null,
1528 | "args": [],
1529 | "type": {
1530 | "kind": "SCALAR",
1531 | "name": "String",
1532 | "ofType": null
1533 | },
1534 | "isDeprecated": false,
1535 | "deprecationReason": null
1536 | },
1537 | {
1538 | "name": "args",
1539 | "description": null,
1540 | "args": [],
1541 | "type": {
1542 | "kind": "NON_NULL",
1543 | "name": null,
1544 | "ofType": {
1545 | "kind": "LIST",
1546 | "name": null,
1547 | "ofType": {
1548 | "kind": "NON_NULL",
1549 | "name": null,
1550 | "ofType": {
1551 | "kind": "OBJECT",
1552 | "name": "__InputValue"
1553 | }
1554 | }
1555 | }
1556 | },
1557 | "isDeprecated": false,
1558 | "deprecationReason": null
1559 | },
1560 | {
1561 | "name": "onOperation",
1562 | "description": null,
1563 | "args": [],
1564 | "type": {
1565 | "kind": "NON_NULL",
1566 | "name": null,
1567 | "ofType": {
1568 | "kind": "SCALAR",
1569 | "name": "Boolean",
1570 | "ofType": null
1571 | }
1572 | },
1573 | "isDeprecated": false,
1574 | "deprecationReason": null
1575 | },
1576 | {
1577 | "name": "onFragment",
1578 | "description": null,
1579 | "args": [],
1580 | "type": {
1581 | "kind": "NON_NULL",
1582 | "name": null,
1583 | "ofType": {
1584 | "kind": "SCALAR",
1585 | "name": "Boolean",
1586 | "ofType": null
1587 | }
1588 | },
1589 | "isDeprecated": false,
1590 | "deprecationReason": null
1591 | },
1592 | {
1593 | "name": "onField",
1594 | "description": null,
1595 | "args": [],
1596 | "type": {
1597 | "kind": "NON_NULL",
1598 | "name": null,
1599 | "ofType": {
1600 | "kind": "SCALAR",
1601 | "name": "Boolean",
1602 | "ofType": null
1603 | }
1604 | },
1605 | "isDeprecated": false,
1606 | "deprecationReason": null
1607 | }
1608 | ],
1609 | "inputFields": null,
1610 | "interfaces": [],
1611 | "enumValues": null,
1612 | "possibleTypes": null
1613 | }
1614 | ],
1615 | "directives": [
1616 | {
1617 | "name": "include",
1618 | "description": "Directs the executor to include this field or fragment only when the `if` argument is true.",
1619 | "args": [
1620 | {
1621 | "name": "if",
1622 | "description": "Included when true.",
1623 | "type": {
1624 | "kind": "NON_NULL",
1625 | "name": null,
1626 | "ofType": {
1627 | "kind": "SCALAR",
1628 | "name": "Boolean",
1629 | "ofType": null
1630 | }
1631 | },
1632 | "defaultValue": null
1633 | }
1634 | ],
1635 | "onOperation": false,
1636 | "onFragment": true,
1637 | "onField": true
1638 | },
1639 | {
1640 | "name": "skip",
1641 | "description": "Directs the executor to skip this field or fragment when the `if` argument is true.",
1642 | "args": [
1643 | {
1644 | "name": "if",
1645 | "description": "Skipped when true.",
1646 | "type": {
1647 | "kind": "NON_NULL",
1648 | "name": null,
1649 | "ofType": {
1650 | "kind": "SCALAR",
1651 | "name": "Boolean",
1652 | "ofType": null
1653 | }
1654 | },
1655 | "defaultValue": null
1656 | }
1657 | ],
1658 | "onOperation": false,
1659 | "onFragment": true,
1660 | "onField": true
1661 | }
1662 | ]
1663 | }
1664 | }
1665 | }
--------------------------------------------------------------------------------
/js/app.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Router} from 'react-router';
4 | import createBrowserHistory from 'history/lib/createBrowserHistory';
5 | import Routes from './routes';
6 | import ReactRouterRelay from 'react-router-relay';
7 |
8 | ReactDOM.render(
9 |