├── .buildkite ├── browserTests ├── nodeTests └── pipeline.yml ├── .cuprc.js ├── .eslintrc.js ├── .flowconfig ├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── .npmrc ├── Dockerfile ├── LICENSE ├── README.md ├── docker-compose.yml ├── docs └── migrations │ └── 00159.md ├── flow-typed ├── globals.js ├── npm │ ├── apollo-client_v2.x.x.js │ ├── flow-bin_v0.x.x.js │ ├── prettier_v1.x.x.js │ ├── react-apollo_v2.x.x.js │ └── redux_v4.x.x.js └── tape-cup_v4.x.x.js ├── package.json ├── renovate.json ├── src ├── __tests__ │ ├── client.browser.js │ ├── exports.js │ ├── integration.node.js │ └── server.node.js ├── apollo-client │ ├── __tests__ │ │ ├── exports.js │ │ ├── index.js │ │ └── local-state.js │ └── index.js ├── client.js ├── flow │ └── flow-fixture.js ├── index.js ├── plugin.js ├── server.js └── tokens.js └── yarn.lock /.buildkite/browserTests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | export DISPLAY=:99.0 3 | /etc/init.d/xvfb start 4 | 5 | ./node_modules/.bin/unitest --browser=dist-tests/browser.js 6 | -------------------------------------------------------------------------------- /.buildkite/nodeTests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ./node_modules/.bin/unitest --node=dist-tests/node.js 3 | -------------------------------------------------------------------------------- /.buildkite/pipeline.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - name: ':docker: :package:' 3 | plugins: 4 | 'docker-compose#v1.5.2': 5 | build: fusion-plugin-apollo 6 | image-repository: 027047743804.dkr.ecr.us-east-2.amazonaws.com/uber 7 | agents: 8 | queue: builders 9 | - name: ':docker: :package: node8' 10 | plugins: 11 | 'docker-compose#v1.5.2': 12 | build: fusion-plugin-apollo-node-last 13 | image-repository: 027047743804.dkr.ecr.us-east-2.amazonaws.com/uber 14 | agents: 15 | queue: builders 16 | - wait 17 | - name: ':flowtype:' 18 | command: yarn flow 19 | plugins: 20 | 'docker-compose#v1.5.2': 21 | run: fusion-plugin-apollo 22 | agents: 23 | queue: workers 24 | - name: ':flowtype: node8' 25 | command: yarn flow 26 | plugins: 27 | 'docker-compose#v1.5.2': 28 | run: fusion-plugin-apollo-node-last 29 | agents: 30 | queue: workers 31 | - name: ':eslint:' 32 | command: yarn lint 33 | plugins: 34 | 'docker-compose#v1.5.2': 35 | run: fusion-plugin-apollo 36 | agents: 37 | queue: workers 38 | - name: ':eslint: node8' 39 | command: yarn lint 40 | plugins: 41 | 'docker-compose#v1.5.2': 42 | run: fusion-plugin-apollo-node-last 43 | agents: 44 | queue: workers 45 | - name: ':chrome: :white_check_mark:' 46 | command: .buildkite/browserTests 47 | plugins: 48 | 'docker-compose#v1.5.2': 49 | run: fusion-plugin-apollo 50 | agents: 51 | queue: workers 52 | - name: ':chrome: :white_check_mark: node8' 53 | command: .buildkite/browserTests 54 | plugins: 55 | 'docker-compose#v1.5.2': 56 | run: fusion-plugin-apollo-node-last 57 | agents: 58 | queue: workers 59 | - name: ':node: :white_check_mark:' 60 | command: .buildkite/nodeTests 61 | plugins: 62 | 'docker-compose#v1.5.2': 63 | run: fusion-plugin-apollo 64 | agents: 65 | queue: workers 66 | - name: ':node: :white_check_mark: node8' 67 | command: .buildkite/nodeTests 68 | plugins: 69 | 'docker-compose#v1.5.2': 70 | run: fusion-plugin-apollo-node-last 71 | agents: 72 | queue: workers 73 | -------------------------------------------------------------------------------- /.cuprc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | babel: { 3 | presets: [ 4 | require.resolve('@babel/preset-react') 5 | ], 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [require.resolve('eslint-config-fusion')], 3 | }; 4 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | .*/node_modules/.*[^(package)]\.json$ 3 | /dist/.* 4 | 5 | [include] 6 | ./src/ 7 | 8 | [libs] 9 | ./node_modules/fusion-core/flow-typed 10 | 11 | [lints] 12 | 13 | [options] 14 | 15 | [strict] 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | ### Type of issue 13 | 14 | 15 | 16 | ### Description 17 | 18 | 19 | 20 | ### Current behavior 21 | 22 | 23 | 24 | ### Expected behavior 25 | 26 | 27 | 28 | ### Steps to reproduce 29 | 30 | 1. 31 | 2. 32 | 3. 33 | 34 | ### Your environment 35 | 36 | * fusion-plugin-apollo version: 37 | 38 | * Node.js version (`node --version`): 39 | 40 | * npm version (`npm --version`): 41 | 42 | * Operating System: -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | dist-tests/ 4 | coverage/ 5 | .nyc_output/ 6 | 7 | .vscode 8 | .DS_Store 9 | npm-debug.log 10 | yarn-error.log 11 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.yarnpkg.com 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BASE_IMAGE=uber/web-base-image:2.0.0 2 | FROM $BASE_IMAGE 3 | 4 | WORKDIR /fusion-plugin-apollo 5 | 6 | COPY . . 7 | 8 | RUN yarn 9 | 10 | RUN yarn --ignore-scripts run build-test 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Uber Technologies, Inc. 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 | # fusion-plugin-apollo 2 | 3 | [![Build status](https://badge.buildkite.com/2ac76cfb209dae257969b7464a2c90834ed82705cfd5bfcc52.svg?branch=master)](https://buildkite.com/uberopensource/fusion-plugin-apollo) 4 | 5 | Fusion.js plugin for universal rendering with React and Apollo 6 | 7 | This package provides universal rendering for Fusion.js applications leveraging GraphQL. 8 | 9 | The plugin will perform graphql queries on the server, thereby rendering your applications initial HTML view on the server before sending it to the client. Additionally this plugin will also provide initial state hydration on the client side. 10 | 11 | --- 12 | 13 | # Table of contents 14 | 15 | - [Installation](#installation) 16 | - [Usage](#usage) 17 | - [API](#api) 18 | - [Registration API](#registration-api) 19 | - [`ApolloContextToken`](#apollocontexttoken) 20 | - [`ApolloClientToken`](#apolloclienttoken) 21 | - [`GraphQLSchemaToken`](#graphqlschematoken) 22 | - [`GraphQLEndpointToken`](#graphqlendpointtoken) 23 | - [`GetApolloClientCacheToken`](#GetApolloClientCacheToken) 24 | - [`ApolloClientCredentialsToken`](#apolloclientcredentialstoken) 25 | - [`GetApolloClientLinksToken`](#getapolloclientlinkstoken) 26 | - [`ApolloClientResolversToken`](#apolloclientresolverstoken) 27 | - [`ApolloBodyParserConfigToken`](#apollobodyparserconfigtoken) 28 | = [GQL Macro]($gql) 29 | 30 | --- 31 | 32 | ### Installation 33 | 34 | ```sh 35 | yarn add fusion-plugin-apollo 36 | ``` 37 | 38 | --- 39 | 40 | ### Usage 41 | 42 | ```js 43 | // ./src/main.js 44 | import React from 'react'; 45 | import App from 'fusion-react'; 46 | import {RenderToken} from 'fusion-core'; 47 | 48 | import { 49 | ApolloRenderEnhancer, 50 | ApolloClientPlugin, 51 | ApolloClientToken, 52 | GraphQLSchemaToken, 53 | } from 'fusion-plugin-apollo'; 54 | 55 | export default function() { 56 | const app = new App(); 57 | app.enhance(RenderToken, ApolloRenderEnhancer); 58 | app.register(ApolloClientToken, ApolloClientPlugin); 59 | if (__NODE__) { 60 | app.register(GraphQLSchemaToken, YourGraphQLSchema); 61 | } 62 | return app; 63 | } 64 | ``` 65 | 66 | ### Usage with external server 67 | 68 | When schema file is not provided, the plugin will not run graphQL server locally. The endpoint of the external graphQL server can be then provided using `GraphQLEndpointToken`. 69 | 70 | ```js 71 | // ./src/main.js 72 | import React from 'react'; 73 | import App from 'fusion-react'; 74 | import {RenderToken} from 'fusion-core'; 75 | 76 | import { 77 | ApolloRenderEnhancer, 78 | ApolloClientPlugin, 79 | ApolloClientToken, 80 | GraphQLSchemaToken, 81 | } from 'fusion-plugin-apollo'; 82 | 83 | export default function() { 84 | const app = new App(); 85 | app.enhance(RenderToken, ApolloRenderEnhancer); 86 | app.register(ApolloClientToken, ApolloClientPlugin); 87 | app.register(GraphQLEndpointToken, 'http://website.com/graphql'); 88 | return app; 89 | } 90 | ``` 91 | 92 | ### Loading GraphQL Queries/Schemas 93 | 94 | fusion-plugin-apollo ships with a compiler plugin that lets you load graphql queries and schemas with the `gql` macro. 95 | This macro takes a relative path argument and returns the query/schema as a string. 96 | 97 | NOTE: Because this is a build time feature, the path argument must be a string literal. Dynamic paths are not supported. 98 | 99 | ```js 100 | import {gql} from 'fusion-plugin-apollo'; 101 | const query = gql('./some-query.graphql'); 102 | const schema = gql('./some-schema.graphql'); 103 | ``` 104 | 105 | --- 106 | 107 | ### API 108 | 109 | #### Registration API 110 | 111 | ##### ApolloClientToken 112 | 113 | ```js 114 | import {ApolloClientToken} from 'fusion-plugin-apollo'; 115 | ``` 116 | 117 | A plugin, which provides an instance of [Apollo Client](https://www.apollographql.com/docs/react/api/apollo-client.html), to be registered and used as within the Apollo Provider. You can use [fusion-apollo-universal-client](https://github.com/fusionjs/fusion-apollo-universal-client) as a barebones Apollo Client token. 118 | 119 | ```flow 120 | type ApolloClient = (ctx: Context, initialState: TInitialState) => ApolloClientType; 121 | ``` 122 | 123 | ##### ApolloContextToken 124 | 125 | ```js 126 | import {ApolloContextToken} from 'fusion-plugin-apollo'; 127 | ``` 128 | 129 | Optional - A function which returns the apollo context. Defaults to the fusion context. See the [Apollo Client context documentation](https://www.apollographql.com/docs/apollo-server/v2/essentials/data.html#context) for more details. 130 | 131 | ```js 132 | type ApolloContext = (ctx: Context => T) | T; 133 | ``` 134 | 135 | ##### GraphQLSchemaToken 136 | 137 | ```js 138 | import {GraphQLSchemaToken} from 'fusion-plugin-apollo'; 139 | ``` 140 | 141 | Your graphql schema is registered on the `GraphQLSchemaToken` token. This is the result of `makeExecutableSchema` or `makeRemoteExecutableSchema` from the `graphql-tools` library. 142 | 143 | ##### GraphQLEndpointToken 144 | 145 | ```js 146 | import {GraphQLEndpointToken} from 'fusion-plugin-apollo'; 147 | ``` 148 | 149 | Optional - the endpoint for serving the graphql API. Defaults to `'/graphql'`. This can also be an endpoint of an external graphQL server (hosted outside fusion app). 150 | 151 | ```js 152 | type GraphQLEndpoint = string; 153 | ``` 154 | 155 | ##### `GetApolloClientCacheToken` 156 | 157 | ```js 158 | import {GetApolloClientCacheToken} from 'fusion-apollo-universal-client'; 159 | ``` 160 | 161 | Optional - A function that returns an Apollo [cache implementation](https://www.apollographql.com/docs/react/advanced/caching.html). 162 | 163 | ```js 164 | type GetApolloClientCache = (ctx: Context) => ApolloCache 165 | ``` 166 | 167 | ###### Default value 168 | 169 | The default cache implementation uses [InMemoryCache](https://github.com/apollographql/apollo-client/tree/master/packages/apollo-cache-inmemory). 170 | 171 | ##### `ApolloClientCredentialsToken` 172 | 173 | ```js 174 | import {ApolloClientCredentialsToken} from 'fusion-apollo-universal-client'; 175 | ``` 176 | 177 | Optional - A configuration value that provides the value of credentials value passed directly into the [fetch implementation](https://github.com/github/fetch). 178 | The default value is `same-origin`. 179 | 180 | ```js 181 | type ApolloClientCredentials = 'omit' | 'include' | 'same-origin' 182 | ``` 183 | 184 | ##### `GetApolloClientLinksToken` 185 | 186 | ```js 187 | import {GetApolloClientLinksToken} from 'fusion-apollo-universal-client'; 188 | ``` 189 | 190 | Optional - A configuration value that provides a array of [ApolloLinks](https://www.apollographql.com/docs/link/composition.html). The default links are provided as an argument to the provided function. 191 | 192 | ```js 193 | type GetApolloClientLinks = (Array) => Array 194 | ``` 195 | 196 | ##### `ApolloClientResolversToken` 197 | 198 | ```js 199 | import { ApolloClientResolversToken } from "fusion-apollo-universal-client"; 200 | ``` 201 | 202 | Optional - Provides the resolvers for [local state management](https://www.apollographql.com/docs/react/essentials/local-state.html). 203 | 204 | ##### `ApolloBodyParserConfigToken` 205 | 206 | ```js 207 | import { ApolloBodyParserConfigToken } from "fusion-apollo-universal-client"; 208 | // Example for increasing the json limit 209 | app.register(ApolloBodyParserConfigToken, { 210 | jsonLimit: '5mb', 211 | }); 212 | ``` 213 | 214 | Optional - Provides body parser config to koa-bodyparser for apollo-server. See https://github.com/koajs/bodyparser 215 | 216 | 217 | #### gql 218 | 219 | ```js 220 | import {gql} from 'fusion-plugin-apollo'; 221 | ``` 222 | 223 | A macro for loading graphql queries and schemas. Takes a relative path string and returns the contents of the graphql schema/query as a string. 224 | 225 | ```js 226 | type gql = (path: string): DocumentNode 227 | ``` 228 | 229 | - `path: string` - Relative path to the graphql schema/query file. NOTE: This must be a string literal, dynamic paths are not supported. 230 | 231 | --- 232 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | fusion-plugin-apollo: 4 | build: . 5 | volumes: 6 | - '.:/fusion-plugin-apollo' 7 | - /fusion-plugin-apollo/node_modules/ 8 | - /fusion-plugin-apollo/dist/ 9 | - /fusion-plugin-apollo/dist-tests/ 10 | fusion-plugin-apollo-node-last: 11 | extends: fusion-plugin-apollo 12 | build: 13 | context: . 14 | args: 15 | BASE_IMAGE: 'uber/web-base-image:1.0.9' 16 | -------------------------------------------------------------------------------- /docs/migrations/00159.md: -------------------------------------------------------------------------------- 1 | ## v2.0.0 2 | 3 | The 2.0.0 release also marks a refactor from `fusion-apollo` as an app wrapper into `fusion-plugin-apollo` which is implemented as an enhancer to be 4 | registered on the `RenderToken`. We also consolidated the code from `fusion-apollo-universal-server` and `fusion-apollo-universal-client` into this module. 5 | The migration looks like this: 6 | 7 | ```diff 8 | +import {RenderToken} from 'fusion-core'; 9 | +import App from 'fusion-react'; 10 | -import App from 'fusion-apollo'; 11 | -import ApolloServer from 'fusion-plugin-apollo-server'; 12 | -import ApolloClient from 'fusion-apollo-universal-client'; 13 | +import { 14 | + ApolloRenderEnhancer, 15 | + ApolloClientPlugin, 16 | +}from 'fusion-plugin-apollo'; 17 | 18 | export default async function main() { 19 | const app = new App(); 20 | + app.enhance(RenderToken, ApolloRenderEnhancer); 21 | - app.register(ApolloServer); // apollo-server 2.0 now integrated by default 22 | - app.middleware(require('koa-bodyparser')()); // Body parsing for /graphql route is included by default now with apollo-server 2 23 | } 24 | ``` -------------------------------------------------------------------------------- /flow-typed/globals.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | declare var __NODE__: boolean; 4 | declare var __BROWSER__: boolean; 5 | -------------------------------------------------------------------------------- /flow-typed/npm/apollo-client_v2.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 6834361f8e8bf3189282ec9320206060 2 | // flow-typed version: e3b214ebb0/apollo-client_v2.x.x/flow_>=v0.57.x 3 | 4 | declare module "apollo-client" { 5 | /** 6 | * Types From graphql 7 | * graphql types are maintained in the graphql-js repo 8 | */ 9 | declare type DocumentNode = any; 10 | declare type ExecutionResult = { 11 | data?: T, 12 | extensions?: { [string]: any }, 13 | errors?: any[] 14 | }; 15 | declare type GraphQLError = any; 16 | /** End From graphql */ 17 | 18 | declare type OperationVariables = { [key: string]: any }; 19 | 20 | declare export function print(ast: any): string; 21 | 22 | declare export class ObservableQuery extends Observable< 23 | ApolloQueryResult 24 | > { 25 | options: WatchQueryOptions; 26 | queryId: string; 27 | variables: { [key: string]: any }; 28 | isCurrentlyPolling: boolean; 29 | shouldSubscribe: boolean; 30 | isTornDown: boolean; 31 | scheduler: QueryScheduler; 32 | queryManager: QueryManager; 33 | observers: Observer>[]; 34 | subscriptionHandles: SubscriptionLINK[]; 35 | lastResult: ApolloQueryResult; 36 | lastError: ApolloError; 37 | lastVariables: { [key: string]: any }; 38 | 39 | constructor(data: { 40 | scheduler: QueryScheduler, 41 | options: WatchQueryOptions, 42 | shouldSubscribe?: boolean 43 | }): this; 44 | 45 | result(): Promise>; 46 | currentResult(): ApolloCurrentResult; 47 | getLastResult(): ApolloQueryResult; 48 | getLastError(): ApolloError; 49 | resetLastResults(): void; 50 | refetch(variables?: any): Promise>; 51 | fetchMore( 52 | fetchMoreOptions: FetchMoreQueryOptions & FetchMoreOptions 53 | ): Promise>; 54 | subscribeToMore(options: SubscribeToMoreOptions): () => void; 55 | setOptions( 56 | opts: ModifiableWatchQueryOptions 57 | ): Promise>; 58 | setVariables( 59 | variables: any, 60 | tryFetch?: boolean, 61 | fetchResults?: boolean 62 | ): Promise>; 63 | updateQuery( 64 | mapFn: (previousQueryResult: any, options: UpdateQueryOptions) => any 65 | ): void; 66 | stopPolling(): void; 67 | startPolling(pollInterval: number): void; 68 | } 69 | 70 | declare class QueryManager { 71 | scheduler: QueryScheduler; 72 | link: ApolloLink; 73 | mutationStore: MutationStore; 74 | queryStore: QueryStore; 75 | dataStore: DataStore; 76 | 77 | constructor({ 78 | link: ApolloLink, 79 | queryDeduplication?: boolean, 80 | store: DataStore, 81 | onBroadcast?: () => void, 82 | ssrMode?: boolean 83 | }): this; 84 | 85 | mutate(options: MutationOptions<>): Promise>; 86 | fetchQuery( 87 | queryId: string, 88 | options: WatchQueryOptions, 89 | fetchType?: FetchType, 90 | fetchMoreForQueryId?: string 91 | ): Promise>; 92 | queryListenerForObserver( 93 | queryId: string, 94 | options: WatchQueryOptions, 95 | observer: Observer> 96 | ): QueryListener; 97 | watchQuery( 98 | options: WatchQueryOptions, 99 | shouldSubscribe?: boolean 100 | ): ObservableQuery; 101 | query(options: WatchQueryOptions): Promise>; 102 | generateQueryId(): string; 103 | stopQueryInStore(queryId: string): void; 104 | addQueryListener(queryId: string, listener: QueryListener): void; 105 | updateQueryWatch( 106 | queryId: string, 107 | document: DocumentNode, 108 | options: WatchQueryOptions 109 | ): void; 110 | addFetchQueryPromise( 111 | requestId: number, 112 | promise: Promise>, 113 | resolve: (result: ApolloQueryResult) => void, 114 | reject: (error: Error) => void 115 | ): void; 116 | removeFetchQueryPromise(requestId: number): void; 117 | addObservableQuery( 118 | queryId: string, 119 | observableQuery: ObservableQuery 120 | ): void; 121 | removeObservableQuery(queryId: string): void; 122 | clearStore(): Promise; 123 | resetStore(): Promise[]>; 124 | } 125 | 126 | declare class QueryStore { 127 | getStore(): { [queryId: string]: QueryStoreValue }; 128 | get(queryId: string): QueryStoreValue; 129 | initQuery(query: { 130 | queryId: string, 131 | document: DocumentNode, 132 | storePreviousVariables: boolean, 133 | variables: Object, 134 | isPoll: boolean, 135 | isRefetch: boolean, 136 | metadata: any, 137 | fetchMoreForQueryId: string | void 138 | }): void; 139 | markQueryResult( 140 | queryId: string, 141 | result: ExecutionResult<>, 142 | fetchMoreForQueryId: string | void 143 | ): void; 144 | markQueryError( 145 | queryId: string, 146 | error: Error, 147 | fetchMoreForQueryId: string | void 148 | ): void; 149 | markQueryResultClient(queryId: string, complete: boolean): void; 150 | stopQuery(queryId: string): void; 151 | reset(observableQueryIds: string[]): void; 152 | } 153 | 154 | declare class QueryScheduler { 155 | inFlightQueries: { [queryId: string]: WatchQueryOptions }; 156 | registeredQueries: { [queryId: string]: WatchQueryOptions }; 157 | intervalQueries: { [interval: number]: string[] }; 158 | queryManager: QueryManager; 159 | constructor({ 160 | queryManager: QueryManager, 161 | ssrMode?: boolean 162 | }): this; 163 | checkInFlight(queryId: string): ?boolean; 164 | fetchQuery( 165 | queryId: string, 166 | options: WatchQueryOptions, 167 | fetchType: FetchType 168 | ): Promise>; 169 | startPollingQuery( 170 | options: WatchQueryOptions, 171 | queryId: string, 172 | listener?: QueryListener 173 | ): string; 174 | stopPollingQuery(queryId: string): void; 175 | fetchQueriesOnInterval(interval: number): void; 176 | addQueryOnInterval( 177 | queryId: string, 178 | queryOptions: WatchQueryOptions 179 | ): void; 180 | registerPollingQuery( 181 | queryOptions: WatchQueryOptions 182 | ): ObservableQuery; 183 | markMutationError(mutationId: string, error: Error): void; 184 | reset(): void; 185 | } 186 | 187 | declare class DataStore { 188 | constructor(initialCache: ApolloCache): this; 189 | getCache(): ApolloCache; 190 | markQueryResult( 191 | result: ExecutionResult<>, 192 | document: DocumentNode, 193 | variables: any, 194 | fetchMoreForQueryId: string | void, 195 | ignoreErrors?: boolean 196 | ): void; 197 | markSubscriptionResult( 198 | result: ExecutionResult<>, 199 | document: DocumentNode, 200 | variables: any 201 | ): void; 202 | markMutationInit(mutation: { 203 | mutationId: string, 204 | document: DocumentNode, 205 | variables: any, 206 | updateQueries: { [queryId: string]: QueryWithUpdater }, 207 | update: ((proxy: DataProxy, mutationResult: Object) => void) | void, 208 | optimisticResponse: Object | Function | void 209 | }): void; 210 | markMutationResult(mutation: { 211 | mutationId: string, 212 | result: ExecutionResult<>, 213 | document: DocumentNode, 214 | variables: any, 215 | updateQueries: { [queryId: string]: QueryWithUpdater }, 216 | update: ((proxy: DataProxy, mutationResult: Object) => void) | void 217 | }): void; 218 | markMutationComplete({ 219 | mutationId: string, 220 | optimisticResponse?: any 221 | }): void; 222 | markUpdateQueryResult( 223 | document: DocumentNode, 224 | variables: any, 225 | newResult: any 226 | ): void; 227 | reset(): Promise; 228 | } 229 | 230 | declare type QueryWithUpdater = { 231 | updater: MutationQueryReducer, 232 | query: QueryStoreValue 233 | }; 234 | 235 | declare interface MutationStoreValue { 236 | mutationString: string; 237 | variables: Object; 238 | loading: boolean; 239 | error: Error | null; 240 | } 241 | 242 | declare class MutationStore { 243 | getStore(): { [mutationId: string]: MutationStoreValue }; 244 | get(mutationId: string): MutationStoreValue; 245 | initMutation( 246 | mutationId: string, 247 | mutationString: string, 248 | variables: Object | void 249 | ): void; 250 | } 251 | 252 | declare export interface FetchMoreOptions { 253 | updateQuery: ( 254 | previousQueryResult: TData, 255 | options: { 256 | fetchMoreResult?: TData, 257 | variables: TVariables 258 | } 259 | ) => TData; 260 | } 261 | 262 | declare export interface UpdateQueryOptions { 263 | variables?: Object; 264 | } 265 | 266 | declare export type ApolloCurrentResult = { 267 | data: T | {}, 268 | errors?: Array, 269 | loading: boolean, 270 | networkStatus: NetworkStatus, 271 | error?: ApolloError, 272 | partial?: boolean 273 | }; 274 | 275 | declare interface ModifiableWatchQueryOptions { 276 | variables?: { [key: string]: any }; 277 | pollInterval?: number; 278 | fetchPolicy?: FetchPolicy; 279 | errorPolicy?: ErrorPolicy; 280 | fetchResults?: boolean; 281 | notifyOnNetworkStatusChange?: boolean; 282 | } 283 | 284 | declare export interface WatchQueryOptions 285 | extends ModifiableWatchQueryOptions { 286 | query: DocumentNode; 287 | metadata?: any; 288 | context?: any; 289 | } 290 | 291 | declare type RefetchQueryDescription = Array; 292 | 293 | declare interface MutationBaseOptions { 294 | optimisticResponse?: Object | Function; 295 | updateQueries?: MutationQueryReducersMap; 296 | optimisticResponse?: Object; 297 | refetchQueries?: 298 | | ((result: ExecutionResult<>) => RefetchQueryDescription) 299 | | RefetchQueryDescription; 300 | update?: MutationUpdaterFn; 301 | errorPolicy?: ErrorPolicy; 302 | variables?: any; 303 | } 304 | 305 | declare export type MutationOperation = (options: MutationBaseOptions) => Promise> 306 | 307 | declare export interface MutationOptions 308 | extends MutationBaseOptions { 309 | mutation: DocumentNode; 310 | context?: any; 311 | fetchPolicy?: FetchPolicy; 312 | } 313 | 314 | declare export interface SubscriptionOptions { 315 | query: DocumentNode; 316 | variables?: { [key: string]: any }; 317 | } 318 | 319 | declare export type FetchPolicy = 320 | | "cache-first" 321 | | "cache-and-network" 322 | | "network-only" 323 | | "cache-only" 324 | | "no-cache" 325 | | "standby"; 326 | 327 | declare export type ErrorPolicy = "none" | "ignore" | "all"; 328 | 329 | declare export interface FetchMoreQueryOptions { 330 | variables: $Shape; 331 | } 332 | 333 | declare export type SubscribeToMoreOptions< 334 | TData, 335 | TSubscriptionData, 336 | TSubscriptionVariables = void 337 | > = { 338 | document?: DocumentNode, 339 | variables?: TSubscriptionVariables, 340 | updateQuery?: ( 341 | previousResult: TData, 342 | result: { 343 | subscriptionData: { data?: TSubscriptionData }, 344 | variables: TSubscriptionVariables 345 | } 346 | ) => TData, 347 | onError?: (error: Error) => void 348 | }; 349 | 350 | declare export type MutationUpdaterFn = ( 351 | proxy: DataProxy, 352 | mutationResult: FetchResult 353 | ) => void; 354 | 355 | declare export type NetworkStatus = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8; 356 | 357 | declare export type QueryListener = ( 358 | queryStoreValue: QueryStoreValue, 359 | newData?: any 360 | ) => void; 361 | 362 | declare export type QueryStoreValue = { 363 | document: DocumentNode, 364 | variables: Object, 365 | previousVariables: Object | null, 366 | networkStatus: NetworkStatus, 367 | networkError: Error | null, 368 | graphQLErrors: GraphQLError[], 369 | metadata: any 370 | }; 371 | 372 | declare export type PureQueryOptions = { 373 | query: DocumentNode, 374 | variables?: { [key: string]: any } 375 | }; 376 | 377 | declare export type ApolloQueryResult = { 378 | data: T, 379 | errors?: Array, 380 | loading: boolean, 381 | networkStatus: NetworkStatus, 382 | stale: boolean 383 | }; 384 | 385 | declare export type FetchType = 1 | 2 | 3; 386 | 387 | declare export type MutationQueryReducer = ( 388 | previousResult: { [key: string]: any }, 389 | options: { 390 | mutationResult: FetchResult, 391 | queryName: string | void, 392 | queryVariables: { [key: string]: any } 393 | } 394 | ) => { [key: string]: any }; 395 | 396 | declare export type MutationQueryReducersMap = { 397 | [queryName: string]: MutationQueryReducer 398 | }; 399 | 400 | declare export class ApolloError extends Error { 401 | message: string; 402 | graphQLErrors: Array; 403 | networkError: Error | null; 404 | extraInfo: any; 405 | constructor(info: ErrorConstructor): this; 406 | } 407 | 408 | declare interface ErrorConstructor { 409 | graphQLErrors?: Array; 410 | networkError?: Error | null; 411 | errorMessage?: string; 412 | extraInfo?: any; 413 | } 414 | 415 | declare interface DefaultOptions { 416 | +watchQuery?: ModifiableWatchQueryOptions; 417 | +query?: ModifiableWatchQueryOptions; 418 | +mutate?: MutationBaseOptions<>; 419 | } 420 | 421 | declare export type ApolloClientOptions = { 422 | link: ApolloLink, 423 | cache: ApolloCache, 424 | ssrMode?: boolean, 425 | ssrForceFetchDelay?: number, 426 | connectToDevTools?: boolean, 427 | queryDeduplication?: boolean, 428 | defaultOptions?: DefaultOptions 429 | }; 430 | 431 | declare export class ApolloClient { 432 | link: ApolloLink; 433 | store: DataStore; 434 | cache: ApolloCache; 435 | queryManager: QueryManager; 436 | disableNetworkFetches: boolean; 437 | version: string; 438 | queryDeduplication: boolean; 439 | defaultOptions: DefaultOptions; 440 | devToolsHookCb: Function; 441 | proxy: ApolloCache | void; 442 | ssrMode: boolean; 443 | resetStoreCallbacks: Array<() => Promise>; 444 | 445 | constructor(options: ApolloClientOptions): this; 446 | watchQuery(options: WatchQueryOptions): ObservableQuery; 447 | query(options: WatchQueryOptions): Promise>; 448 | mutate(options: MutationOptions): Promise>; 449 | subscribe(options: SubscriptionOptions): Observable; 450 | readQuery(options: DataProxyReadQueryOptions): T | null; 451 | readFragment(options: DataProxyReadFragmentOptions): T | null; 452 | writeQuery(options: DataProxyWriteQueryOptions): void; 453 | writeFragment(options: DataProxyWriteFragmentOptions): void; 454 | writeData(options: DataProxyWriteDataOptions): void; 455 | __actionHookForDevTools(cb: () => any): void; 456 | __requestRaw(payload: GraphQLRequest): Observable>; 457 | initQueryManager(): void; 458 | resetStore(): Promise> | null>; 459 | onResetStore(cb: () => Promise): () => void; 460 | reFetchObservableQueries( 461 | includeStandby?: boolean 462 | ): Promise[]> | Promise; 463 | extract(optimistic?: boolean): TCacheShape; 464 | restore(serializedState: TCacheShape): ApolloCache; 465 | } 466 | 467 | declare export default typeof ApolloClient; 468 | 469 | /* apollo-link types */ 470 | declare export class ApolloLink { 471 | constructor(request?: RequestHandler): this; 472 | 473 | static empty(): ApolloLink; 474 | static from(links: Array): ApolloLink; 475 | static split( 476 | test: (op: Operation) => boolean, 477 | left: ApolloLink | RequestHandler, 478 | right: ApolloLink | RequestHandler 479 | ): ApolloLink; 480 | static execute( 481 | link: ApolloLink, 482 | operation: GraphQLRequest 483 | ): Observable>; 484 | 485 | split( 486 | test: (op: Operation) => boolean, 487 | left: ApolloLink | RequestHandler, 488 | right: ApolloLink | RequestHandler 489 | ): ApolloLink; 490 | 491 | concat(next: ApolloLink | RequestHandler): ApolloLink; 492 | 493 | request( 494 | operation: Operation, 495 | forward?: NextLink 496 | ): Observable> | null; 497 | } 498 | 499 | declare interface GraphQLRequest { 500 | query: DocumentNode; 501 | variables?: { [key: string]: any }; 502 | operationName?: string; 503 | context?: { [key: string]: any }; 504 | extensions?: { [key: string]: any }; 505 | } 506 | 507 | declare interface Operation { 508 | query: DocumentNode; 509 | variables: { [key: string]: any }; 510 | operationName: string; 511 | extensions: { [key: string]: any }; 512 | setContext: (context: { [key: string]: any }) => { [key: string]: any }; 513 | getContext: () => { [key: string]: any }; 514 | toKey: () => string; 515 | } 516 | 517 | declare type FetchResult< 518 | C = { [key: string]: any }, 519 | E = { [key: string]: any } 520 | > = ExecutionResult & { extension?: E, context?: C }; 521 | 522 | declare type NextLink = (operation: Operation) => Observable>; 523 | 524 | declare type RequestHandler = ( 525 | operation: Operation, 526 | forward?: NextLink 527 | ) => Observable> | null; 528 | 529 | declare class Observable { 530 | subscribe( 531 | observerOrNext: ((value: T) => void) | ZenObservableObserver, 532 | error?: (error: any) => void, 533 | complete?: () => void 534 | ): ZenObservableSubscription; 535 | 536 | forEach(fn: (value: T) => void): Promise; 537 | 538 | map(fn: (value: T) => R): Observable; 539 | 540 | filter(fn: (value: T) => boolean): Observable; 541 | 542 | reduce( 543 | fn: (previousValue: R | T, currentValue: T) => R | T, 544 | initialValue?: R | T 545 | ): Observable; 546 | 547 | flatMap(fn: (value: T) => ZenObservableObservableLike): Observable; 548 | 549 | from( 550 | observable: Observable | ZenObservableObservableLike | Array 551 | ): Observable; 552 | 553 | of(...args: Array): Observable; 554 | } 555 | 556 | declare interface Observer { 557 | start?: (subscription: SubscriptionLINK) => any; 558 | next?: (value: T) => void; 559 | error?: (errorValue: any) => void; 560 | complete?: () => void; 561 | } 562 | 563 | declare interface SubscriptionLINK { 564 | closed: boolean; 565 | unsubscribe(): void; 566 | } 567 | 568 | declare interface ZenObservableSubscriptionObserver { 569 | closed: boolean; 570 | next(value: T): void; 571 | error(errorValue: any): void; 572 | complete(): void; 573 | } 574 | 575 | declare interface ZenObservableSubscription { 576 | closed: boolean; 577 | unsubscribe(): void; 578 | } 579 | 580 | declare interface ZenObservableObserver { 581 | start?: (subscription: ZenObservableSubscription) => any; 582 | next?: (value: T) => void; 583 | error?: (errorValue: any) => void; 584 | complete?: () => void; 585 | } 586 | 587 | declare type ZenObservableSubscriber = ( 588 | observer: ZenObservableSubscriptionObserver 589 | ) => void | (() => void) | SubscriptionLINK; 590 | 591 | declare interface ZenObservableObservableLike { 592 | subscribe?: ZenObservableSubscriber; 593 | } 594 | /* apollo-link types */ 595 | 596 | /* apollo-cache types */ 597 | declare export class ApolloCache { 598 | read(query: CacheReadOptions): T | null; 599 | write(write: CacheWriteOptions): void; 600 | diff(query: CacheDiffOptions): CacheDiffResult; 601 | watch(watch: CacheWatchOptions): () => void; 602 | evict(query: CacheEvictOptions): CacheEvictionResult; 603 | reset(): Promise; 604 | 605 | restore(serializedState: TSerialized): ApolloCache; 606 | extract(optimistic?: boolean): TSerialized; 607 | 608 | removeOptimistic(id: string): void; 609 | 610 | performTransaction(transaction: Transaction): void; 611 | recordOptimisticTransaction( 612 | transaction: Transaction, 613 | id: string 614 | ): void; 615 | 616 | transformDocument(document: DocumentNode): DocumentNode; 617 | transformForLink(document: DocumentNode): DocumentNode; 618 | 619 | readQuery( 620 | options: DataProxyReadQueryOptions, 621 | optimistic?: boolean 622 | ): QueryType | null; 623 | readFragment( 624 | options: DataProxyReadFragmentOptions, 625 | optimistic?: boolean 626 | ): FragmentType | null; 627 | writeQuery(options: CacheWriteQueryOptions): void; 628 | writeFragment(options: CacheWriteFragmentOptions): void; 629 | writeData(options: CacheWriteDataOptions): void; 630 | } 631 | 632 | declare type Transaction = (c: ApolloCache) => void; 633 | 634 | declare type CacheWatchCallback = (newData: any) => void; 635 | 636 | declare interface CacheEvictionResult { 637 | success: boolean; 638 | } 639 | 640 | declare interface CacheReadOptions extends DataProxyReadQueryOptions { 641 | rootId?: string; 642 | previousResult?: any; 643 | optimistic: boolean; 644 | } 645 | 646 | declare interface CacheWriteOptions extends DataProxyReadQueryOptions { 647 | dataId: string; 648 | result: any; 649 | } 650 | 651 | declare interface CacheDiffOptions extends CacheReadOptions { 652 | returnPartialData?: boolean; 653 | } 654 | 655 | declare interface CacheWatchOptions extends CacheReadOptions { 656 | callback: CacheWatchCallback; 657 | } 658 | 659 | declare interface CacheEvictOptions extends DataProxyReadQueryOptions { 660 | rootId?: string; 661 | } 662 | 663 | declare type CacheDiffResult = DataProxyDiffResult; 664 | declare type CacheWriteQueryOptions = DataProxyWriteQueryOptions; 665 | declare type CacheWriteFragmentOptions = DataProxyWriteFragmentOptions; 666 | declare type CacheWriteDataOptions = DataProxyWriteDataOptions; 667 | declare type CacheReadFragmentOptions = DataProxyReadFragmentOptions; 668 | 669 | declare interface DataProxyReadQueryOptions { 670 | query: DocumentNode; 671 | variables?: any; 672 | } 673 | 674 | declare interface DataProxyReadFragmentOptions { 675 | id: string; 676 | fragment: DocumentNode; 677 | fragmentName?: string; 678 | variables?: any; 679 | } 680 | 681 | declare interface DataProxyWriteQueryOptions { 682 | data: any; 683 | query: DocumentNode; 684 | variables?: any; 685 | } 686 | 687 | declare interface DataProxyWriteFragmentOptions { 688 | data: any; 689 | id: string; 690 | fragment: DocumentNode; 691 | fragmentName?: string; 692 | variables?: any; 693 | } 694 | 695 | declare interface DataProxyWriteDataOptions { 696 | data: any; 697 | id?: string; 698 | } 699 | 700 | declare type DataProxyDiffResult = { 701 | result?: T, 702 | complete?: boolean 703 | }; 704 | 705 | declare interface DataProxy { 706 | readQuery( 707 | options: DataProxyReadQueryOptions, 708 | optimistic?: boolean 709 | ): QueryType | null; 710 | readFragment( 711 | options: DataProxyReadFragmentOptions, 712 | optimistic?: boolean 713 | ): FragmentType | null; 714 | writeQuery(options: DataProxyWriteQueryOptions): void; 715 | writeFragment(options: DataProxyWriteFragmentOptions): void; 716 | writeData(options: DataProxyWriteDataOptions): void; 717 | } 718 | /* End apollo-cache types */ 719 | } 720 | -------------------------------------------------------------------------------- /flow-typed/npm/flow-bin_v0.x.x.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fusionjs/fusion-plugin-apollo/97fd3f3e3e7a1c00ae9c6c8737d7eff9b19ab70a/flow-typed/npm/flow-bin_v0.x.x.js -------------------------------------------------------------------------------- /flow-typed/npm/prettier_v1.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 066c92e9ccb5f0711df8d73cbca837d6 2 | // flow-typed version: 9e32affdbd/prettier_v1.x.x/flow_>=v0.56.x 3 | 4 | declare module "prettier" { 5 | declare export type AST = Object; 6 | declare export type Doc = Object; 7 | declare export type FastPath = Object; 8 | 9 | declare export type PrettierParserName = 10 | | "babylon" 11 | | "flow" 12 | | "typescript" 13 | | "postcss" 14 | | "css" 15 | | "less" 16 | | "scss" 17 | | "json" 18 | | "graphql" 19 | | "markdown" 20 | | "vue"; 21 | 22 | declare export type PrettierParser = { 23 | [name: PrettierParserName]: (text: string, options?: Object) => AST 24 | }; 25 | 26 | declare export type CustomParser = ( 27 | text: string, 28 | parsers: PrettierParser, 29 | options: Options 30 | ) => AST; 31 | 32 | declare export type Options = {| 33 | printWidth?: number, 34 | tabWidth?: number, 35 | useTabs?: boolean, 36 | semi?: boolean, 37 | singleQuote?: boolean, 38 | trailingComma?: "none" | "es5" | "all", 39 | bracketSpacing?: boolean, 40 | jsxBracketSameLine?: boolean, 41 | arrowParens?: "avoid" | "always", 42 | rangeStart?: number, 43 | rangeEnd?: number, 44 | parser?: PrettierParserName | CustomParser, 45 | filepath?: string, 46 | requirePragma?: boolean, 47 | insertPragma?: boolean, 48 | proseWrap?: "always" | "never" | "preserve", 49 | plugins?: Array 50 | |}; 51 | 52 | declare export type Plugin = { 53 | languages: SupportLanguage, 54 | parsers: { [parserName: string]: Parser }, 55 | printers: { [astFormat: string]: Printer } 56 | }; 57 | 58 | declare export type Parser = { 59 | parse: ( 60 | text: string, 61 | parsers: { [parserName: string]: Parser }, 62 | options: Object 63 | ) => AST, 64 | astFormat: string 65 | }; 66 | 67 | declare export type Printer = { 68 | print: ( 69 | path: FastPath, 70 | options: Object, 71 | print: (path: FastPath) => Doc 72 | ) => Doc, 73 | embed: ( 74 | path: FastPath, 75 | print: (path: FastPath) => Doc, 76 | textToDoc: (text: string, options: Object) => Doc, 77 | options: Object 78 | ) => ?Doc 79 | }; 80 | 81 | declare export type CursorOptions = {| 82 | cursorOffset: number, 83 | printWidth?: $PropertyType, 84 | tabWidth?: $PropertyType, 85 | useTabs?: $PropertyType, 86 | semi?: $PropertyType, 87 | singleQuote?: $PropertyType, 88 | trailingComma?: $PropertyType, 89 | bracketSpacing?: $PropertyType, 90 | jsxBracketSameLine?: $PropertyType, 91 | arrowParens?: $PropertyType, 92 | parser?: $PropertyType, 93 | filepath?: $PropertyType, 94 | requirePragma?: $PropertyType, 95 | insertPragma?: $PropertyType, 96 | proseWrap?: $PropertyType, 97 | plugins?: $PropertyType 98 | |}; 99 | 100 | declare export type CursorResult = {| 101 | formatted: string, 102 | cursorOffset: number 103 | |}; 104 | 105 | declare export type ResolveConfigOptions = {| 106 | useCache?: boolean, 107 | config?: string, 108 | editorconfig?: boolean 109 | |}; 110 | 111 | declare export type SupportLanguage = { 112 | name: string, 113 | since: string, 114 | parsers: Array, 115 | group?: string, 116 | tmScope: string, 117 | aceMode: string, 118 | codemirrorMode: string, 119 | codemirrorMimeType: string, 120 | aliases?: Array, 121 | extensions: Array, 122 | filenames?: Array, 123 | linguistLanguageId: number, 124 | vscodeLanguageIds: Array 125 | }; 126 | 127 | declare export type SupportOption = {| 128 | since: string, 129 | type: "int" | "boolean" | "choice" | "path", 130 | deprecated?: string, 131 | redirect?: SupportOptionRedirect, 132 | description: string, 133 | oppositeDescription?: string, 134 | default: SupportOptionValue, 135 | range?: SupportOptionRange, 136 | choices?: SupportOptionChoice 137 | |}; 138 | 139 | declare export type SupportOptionRedirect = {| 140 | options: string, 141 | value: SupportOptionValue 142 | |}; 143 | 144 | declare export type SupportOptionRange = {| 145 | start: number, 146 | end: number, 147 | step: number 148 | |}; 149 | 150 | declare export type SupportOptionChoice = {| 151 | value: boolean | string, 152 | description?: string, 153 | since?: string, 154 | deprecated?: string, 155 | redirect?: SupportOptionValue 156 | |}; 157 | 158 | declare export type SupportOptionValue = number | boolean | string; 159 | 160 | declare export type SupportInfo = {| 161 | languages: Array, 162 | options: Array 163 | |}; 164 | 165 | declare export type Prettier = {| 166 | format: (source: string, options?: Options) => string, 167 | check: (source: string, options?: Options) => boolean, 168 | formatWithCursor: (source: string, options: CursorOptions) => CursorResult, 169 | resolveConfig: { 170 | (filePath: string, options?: ResolveConfigOptions): Promise, 171 | sync(filePath: string, options?: ResolveConfigOptions): ?Options 172 | }, 173 | clearConfigCache: () => void, 174 | getSupportInfo: (version?: string) => SupportInfo 175 | |}; 176 | 177 | declare export default Prettier; 178 | } 179 | -------------------------------------------------------------------------------- /flow-typed/npm/react-apollo_v2.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 8d4451a176bcfc890fe040aa6b6b07b5 2 | // flow-typed version: 45acb9a3f7/react-apollo_v2.x.x/flow_>=v0.58.x 3 | 4 | declare module "react-apollo" { 5 | import type { ComponentType, Element, Node } from "react"; 6 | 7 | declare type MakeOptional = (V) => ?V; 8 | /** 9 | * Copied types from Apollo Client libdef 10 | * Please update apollo-client libdef as well if updating these types 11 | */ 12 | declare class ObservableQuery extends Observable> { 13 | options: WatchQueryOptions; 14 | queryId: string; 15 | variables: { [key: string]: any }; 16 | isCurrentlyPolling: boolean; 17 | shouldSubscribe: boolean; 18 | isTornDown: boolean; 19 | scheduler: QueryScheduler; 20 | queryManager: QueryManager; 21 | observers: Observer>[]; 22 | subscriptionHandles: SubscriptionLINK[]; 23 | lastResult: ApolloQueryResult; 24 | lastError: ApolloError; 25 | lastVariables: { [key: string]: any }; 26 | 27 | constructor(data: { 28 | scheduler: QueryScheduler, 29 | options: WatchQueryOptions, 30 | shouldSubscribe?: boolean 31 | }): this; 32 | 33 | result(): Promise>; 34 | currentResult(): ApolloCurrentResult; 35 | getLastResult(): ApolloQueryResult; 36 | getLastError(): ApolloError; 37 | resetLastResults(): void; 38 | refetch(variables?: any): Promise>; 39 | fetchMore( 40 | fetchMoreOptions: FetchMoreQueryOptions & FetchMoreOptions 41 | ): Promise>; 42 | subscribeToMore(options: SubscribeToMoreOptions): () => void; 43 | setOptions( 44 | opts: ModifiableWatchQueryOptions 45 | ): Promise>; 46 | setVariables( 47 | variables: any, 48 | tryFetch?: boolean, 49 | fetchResults?: boolean 50 | ): Promise>; 51 | updateQuery( 52 | mapFn: (previousQueryResult: any, options: UpdateQueryOptions) => mixed 53 | ): void; 54 | stopPolling(): void; 55 | startPolling(pollInterval: number): void; 56 | } 57 | 58 | declare class QueryManager { 59 | scheduler: QueryScheduler; 60 | link: ApolloLink; 61 | mutationStore: MutationStore; 62 | queryStore: QueryStore; 63 | dataStore: DataStore; 64 | 65 | constructor({ 66 | link: ApolloLink, 67 | queryDeduplication?: boolean, 68 | store: DataStore, 69 | onBroadcast?: () => mixed, 70 | ssrMode?: boolean 71 | }): this; 72 | 73 | mutate(options: MutationOptions<>): Promise>; 74 | fetchQuery( 75 | queryId: string, 76 | options: WatchQueryOptions, 77 | fetchType?: FetchType, 78 | fetchMoreForQueryId?: string 79 | ): Promise>; 80 | queryListenerForObserver( 81 | queryId: string, 82 | options: WatchQueryOptions, 83 | observer: Observer> 84 | ): QueryListener; 85 | watchQuery( 86 | options: WatchQueryOptions, 87 | shouldSubscribe?: boolean 88 | ): ObservableQuery; 89 | query(options: WatchQueryOptions): Promise>; 90 | generateQueryId(): string; 91 | stopQueryInStore(queryId: string): void; 92 | addQueryListener(queryId: string, listener: QueryListener): void; 93 | updateQueryWatch( 94 | queryId: string, 95 | document: DocumentNode, 96 | options: WatchQueryOptions 97 | ): void; 98 | addFetchQueryPromise( 99 | requestId: number, 100 | promise: Promise>, 101 | resolve: (result: ApolloQueryResult) => void, 102 | reject: (error: Error) => void 103 | ): void; 104 | removeFetchQueryPromise(requestId: number): void; 105 | addObservableQuery( 106 | queryId: string, 107 | observableQuery: ObservableQuery 108 | ): void; 109 | removeObservableQuery(queryId: string): void; 110 | clearStore(): Promise; 111 | resetStore(): Promise[]>; 112 | } 113 | 114 | declare class QueryStore { 115 | getStore(): { [queryId: string]: QueryStoreValue }; 116 | get(queryId: string): QueryStoreValue; 117 | initQuery(query: { 118 | queryId: string, 119 | document: DocumentNode, 120 | storePreviousVariables: boolean, 121 | variables: Object, 122 | isPoll: boolean, 123 | isRefetch: boolean, 124 | metadata: any, 125 | fetchMoreForQueryId: string | void 126 | }): void; 127 | markQueryResult( 128 | queryId: string, 129 | result: ExecutionResult<>, 130 | fetchMoreForQueryId: string | void 131 | ): void; 132 | markQueryError( 133 | queryId: string, 134 | error: Error, 135 | fetchMoreForQueryId: string | void 136 | ): void; 137 | markQueryResultClient(queryId: string, complete: boolean): void; 138 | stopQuery(queryId: string): void; 139 | reset(observableQueryIds: string[]): void; 140 | } 141 | 142 | declare class QueryScheduler { 143 | inFlightQueries: { [queryId: string]: WatchQueryOptions }; 144 | registeredQueries: { [queryId: string]: WatchQueryOptions }; 145 | intervalQueries: { [interval: number]: string[] }; 146 | queryManager: QueryManager; 147 | constructor({ 148 | queryManager: QueryManager, 149 | ssrMode?: boolean 150 | }): this; 151 | checkInFlight(queryId: string): ?boolean; 152 | fetchQuery( 153 | queryId: string, 154 | options: WatchQueryOptions, 155 | fetchType: FetchType 156 | ): Promise>; 157 | startPollingQuery( 158 | options: WatchQueryOptions, 159 | queryId: string, 160 | listener?: QueryListener 161 | ): string; 162 | stopPollingQuery(queryId: string): void; 163 | fetchQueriesOnInterval(interval: number): void; 164 | addQueryOnInterval( 165 | queryId: string, 166 | queryOptions: WatchQueryOptions 167 | ): void; 168 | registerPollingQuery( 169 | queryOptions: WatchQueryOptions 170 | ): ObservableQuery; 171 | markMutationError(mutationId: string, error: Error): void; 172 | reset(): void; 173 | } 174 | 175 | declare class DataStore { 176 | constructor(initialCache: ApolloCache): this; 177 | getCache(): ApolloCache; 178 | markQueryResult( 179 | result: ExecutionResult<>, 180 | document: DocumentNode, 181 | variables: any, 182 | fetchMoreForQueryId: string | void, 183 | ignoreErrors?: boolean 184 | ): void; 185 | markSubscriptionResult( 186 | result: ExecutionResult<>, 187 | document: DocumentNode, 188 | variables: any 189 | ): void; 190 | markMutationInit(mutation: { 191 | mutationId: string, 192 | document: DocumentNode, 193 | variables: any, 194 | updateQueries: { [queryId: string]: QueryWithUpdater }, 195 | update: ((proxy: DataProxy, mutationResult: Object) => mixed) | void, 196 | optimisticResponse: Object | Function | void 197 | }): void; 198 | markMutationResult(mutation: { 199 | mutationId: string, 200 | result: ExecutionResult<>, 201 | document: DocumentNode, 202 | variables: any, 203 | updateQueries: { [queryId: string]: QueryWithUpdater }, 204 | update: ((proxy: DataProxy, mutationResult: Object) => mixed) | void 205 | }): void; 206 | markMutationComplete({ 207 | mutationId: string, 208 | optimisticResponse?: any 209 | }): void; 210 | markUpdateQueryResult( 211 | document: DocumentNode, 212 | variables: any, 213 | newResult: any 214 | ): void; 215 | reset(): Promise; 216 | } 217 | 218 | declare type QueryWithUpdater = { 219 | updater: MutationQueryReducer, 220 | query: QueryStoreValue 221 | }; 222 | 223 | declare interface MutationStoreValue { 224 | mutationString: string; 225 | variables: Object; 226 | loading: boolean; 227 | error: Error | null; 228 | } 229 | 230 | declare class MutationStore { 231 | getStore(): { [mutationId: string]: MutationStoreValue }; 232 | get(mutationId: string): MutationStoreValue; 233 | initMutation( 234 | mutationId: string, 235 | mutationString: string, 236 | variables: Object | void 237 | ): void; 238 | } 239 | 240 | declare export interface FetchMoreOptions { 241 | updateQuery: ( 242 | previousQueryResult: TData, 243 | options: { 244 | fetchMoreResult?: TData, 245 | variables: TVariables 246 | } 247 | ) => TData; 248 | } 249 | 250 | declare export interface UpdateQueryOptions { 251 | variables?: Object; 252 | } 253 | 254 | declare export type ApolloCurrentResult = { 255 | data: T | {}, 256 | errors?: Array, 257 | loading: boolean, 258 | networkStatus: NetworkStatus, 259 | error?: ApolloError, 260 | partial?: boolean 261 | }; 262 | 263 | declare interface ModifiableWatchQueryOptions { 264 | variables?: { [key: string]: any }; 265 | pollInterval?: number; 266 | fetchPolicy?: FetchPolicy; 267 | errorPolicy?: ErrorPolicy; 268 | fetchResults?: boolean; 269 | notifyOnNetworkStatusChange?: boolean; 270 | } 271 | 272 | declare export interface WatchQueryOptions 273 | extends ModifiableWatchQueryOptions { 274 | query: DocumentNode; 275 | metadata?: any; 276 | context?: any; 277 | } 278 | 279 | declare export type RefetchQueryDescription = $ReadOnlyArray< 280 | string | PureQueryOptions 281 | >; 282 | 283 | declare interface MutationBaseOptions { 284 | optimisticResponse?: Object | Function; 285 | updateQueries?: MutationQueryReducersMap; 286 | optimisticResponse?: Object; 287 | refetchQueries?: 288 | | ((result: ExecutionResult<>) => RefetchQueryDescription) 289 | | RefetchQueryDescription; 290 | update?: MutationUpdaterFn; 291 | errorPolicy?: ErrorPolicy; 292 | variables?: any; 293 | } 294 | 295 | declare export interface MutationOptions 296 | extends MutationBaseOptions { 297 | mutation: DocumentNode; 298 | context?: any; 299 | fetchPolicy?: FetchPolicy; 300 | } 301 | 302 | declare export interface SubscriptionOptions { 303 | query: DocumentNode; 304 | variables?: { [key: string]: any }; 305 | } 306 | 307 | declare export type FetchPolicy = 308 | | "cache-first" 309 | | "cache-and-network" 310 | | "network-only" 311 | | "cache-only" 312 | | "no-cache" 313 | | "standby"; 314 | 315 | declare export type ErrorPolicy = "none" | "ignore" | "all"; 316 | 317 | declare export interface FetchMoreQueryOptions { 318 | variables: $Shape; 319 | } 320 | 321 | declare export type SubscribeToMoreOptions< 322 | TData, 323 | TSubscriptionData, 324 | TSubscriptionVariables = void 325 | > = { 326 | document?: DocumentNode, 327 | variables?: TSubscriptionVariables, 328 | updateQuery?: ( 329 | previousResult: TData, 330 | result: { 331 | subscriptionData: { data?: TSubscriptionData }, 332 | variables: TSubscriptionVariables 333 | } 334 | ) => TData, 335 | onError?: (error: Error) => mixed 336 | }; 337 | 338 | declare export type MutationUpdaterFn = ( 339 | proxy: DataProxy, 340 | mutationResult: FetchResult 341 | ) => mixed; 342 | 343 | declare export type NetworkStatus = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8; 344 | 345 | declare export type QueryListener = ( 346 | queryStoreValue: QueryStoreValue, 347 | newData?: any 348 | ) => mixed; 349 | 350 | declare export type QueryStoreValue = { 351 | document: DocumentNode, 352 | variables: Object, 353 | previousVariables: Object | null, 354 | networkStatus: NetworkStatus, 355 | networkError: Error | null, 356 | graphQLErrors: GraphQLError[], 357 | metadata: any 358 | }; 359 | 360 | declare export type PureQueryOptions = { 361 | query: DocumentNode, 362 | variables?: { [key: string]: any } 363 | }; 364 | 365 | declare export type ApolloQueryResult = { 366 | data: T, 367 | errors?: Array, 368 | loading: boolean, 369 | networkStatus: NetworkStatus, 370 | stale: boolean 371 | }; 372 | 373 | declare export type FetchType = 1 | 2 | 3; 374 | 375 | declare export type MutationQueryReducer = ( 376 | previousResult: { [key: string]: any }, 377 | options: { 378 | mutationResult: FetchResult, 379 | queryName: string | void, 380 | queryVariables: { [key: string]: any } 381 | } 382 | ) => { [key: string]: any }; 383 | 384 | declare export type MutationQueryReducersMap = { 385 | [queryName: string]: MutationQueryReducer 386 | }; 387 | 388 | declare export class ApolloError extends Error { 389 | message: string; 390 | graphQLErrors: Array; 391 | networkError: Error | null; 392 | extraInfo: any; 393 | constructor(info: ErrorConstructor): this; 394 | } 395 | 396 | declare interface ErrorConstructor { 397 | graphQLErrors?: Array; 398 | networkError?: Error | null; 399 | errorMessage?: string; 400 | extraInfo?: any; 401 | } 402 | 403 | declare interface DefaultOptions { 404 | +watchQuery?: ModifiableWatchQueryOptions; 405 | +query?: ModifiableWatchQueryOptions; 406 | +mutate?: MutationBaseOptions<>; 407 | } 408 | 409 | declare export type ApolloClientOptions = { 410 | link: ApolloLink, 411 | cache: ApolloCache, 412 | ssrMode?: boolean, 413 | ssrForceFetchDelay?: number, 414 | connectToDevTools?: boolean, 415 | queryDeduplication?: boolean, 416 | defaultOptions?: DefaultOptions 417 | }; 418 | 419 | declare export class ApolloClient { 420 | link: ApolloLink; 421 | store: DataStore; 422 | cache: ApolloCache; 423 | queryManager: QueryManager; 424 | disableNetworkFetches: boolean; 425 | version: string; 426 | queryDeduplication: boolean; 427 | defaultOptions: DefaultOptions; 428 | devToolsHookCb: Function; 429 | proxy: ApolloCache | void; 430 | ssrMode: boolean; 431 | resetStoreCallbacks: Array<() => Promise>; 432 | 433 | constructor(options: ApolloClientOptions): this; 434 | watchQuery(options: WatchQueryOptions): ObservableQuery; 435 | query(options: WatchQueryOptions): Promise>; 436 | mutate(options: MutationOptions): Promise>; 437 | subscribe(options: SubscriptionOptions): Observable; 438 | readQuery(options: DataProxyReadQueryOptions): T | null; 439 | readFragment(options: DataProxyReadFragmentOptions): T | null; 440 | writeQuery(options: DataProxyWriteQueryOptions): void; 441 | writeFragment(options: DataProxyWriteFragmentOptions): void; 442 | writeData(options: DataProxyWriteDataOptions): void; 443 | __actionHookForDevTools(cb: () => mixed): void; 444 | __requestRaw(payload: GraphQLRequest): Observable>; 445 | initQueryManager(): void; 446 | resetStore(): Promise> | null>; 447 | onResetStore(cb: () => Promise): () => void; 448 | reFetchObservableQueries( 449 | includeStandby?: boolean 450 | ): Promise[]> | Promise; 451 | extract(optimistic?: boolean): TCacheShape; 452 | restore(serializedState: TCacheShape): ApolloCache; 453 | } 454 | 455 | /* apollo-link types */ 456 | declare class ApolloLink { 457 | constructor(request?: RequestHandler): this; 458 | 459 | static empty(): ApolloLink; 460 | static from(links: Array): ApolloLink; 461 | static split( 462 | test: (op: Operation) => boolean, 463 | left: ApolloLink | RequestHandler, 464 | right: ApolloLink | RequestHandler 465 | ): ApolloLink; 466 | static execute( 467 | link: ApolloLink, 468 | operation: GraphQLRequest 469 | ): Observable>; 470 | 471 | split( 472 | test: (op: Operation) => boolean, 473 | left: ApolloLink | RequestHandler, 474 | right: ApolloLink | RequestHandler 475 | ): ApolloLink; 476 | 477 | concat(next: ApolloLink | RequestHandler): ApolloLink; 478 | 479 | request( 480 | operation: Operation, 481 | forward?: NextLink 482 | ): Observable> | null; 483 | } 484 | 485 | declare interface GraphQLRequest { 486 | query: DocumentNode; 487 | variables?: { [key: string]: any }; 488 | operationName?: string; 489 | context?: { [key: string]: any }; 490 | extensions?: { [key: string]: any }; 491 | } 492 | 493 | declare interface Operation { 494 | query: DocumentNode; 495 | variables: { [key: string]: any }; 496 | operationName: string; 497 | extensions: { [key: string]: any }; 498 | setContext: (context: { [key: string]: any }) => { [key: string]: any }; 499 | getContext: () => { [key: string]: any }; 500 | toKey: () => string; 501 | } 502 | 503 | declare export type FetchResult< 504 | C = { [key: string]: any }, 505 | E = { [key: string]: any } 506 | > = ExecutionResult & { extension?: E, context?: C }; 507 | 508 | declare type NextLink = (operation: Operation) => Observable>; 509 | 510 | declare type RequestHandler = ( 511 | operation: Operation, 512 | forward?: NextLink 513 | ) => Observable> | null; 514 | 515 | declare class Observable { 516 | subscribe( 517 | observerOrNext: ((value: T) => mixed) | ZenObservableObserver, 518 | error?: (error: any) => mixed, 519 | complete?: () => mixed 520 | ): ZenObservableSubscription; 521 | 522 | forEach(fn: (value: T) => mixed): Promise; 523 | 524 | map(fn: (value: T) => R): Observable; 525 | 526 | filter(fn: (value: T) => boolean): Observable; 527 | 528 | reduce( 529 | fn: (previousValue: R | T, currentValue: T) => R | T, 530 | initialValue?: R | T 531 | ): Observable; 532 | 533 | flatMap(fn: (value: T) => ZenObservableObservableLike): Observable; 534 | 535 | from( 536 | observable: Observable | ZenObservableObservableLike | Array 537 | ): Observable; 538 | 539 | of(...args: Array): Observable; 540 | } 541 | 542 | declare interface Observer { 543 | start?: (subscription: SubscriptionLINK) => any; 544 | next?: (value: T) => void; 545 | error?: (errorValue: any) => void; 546 | complete?: () => void; 547 | } 548 | 549 | declare interface SubscriptionLINK { 550 | closed: boolean; 551 | unsubscribe(): void; 552 | } 553 | 554 | declare interface ZenObservableSubscriptionObserver { 555 | closed: boolean; 556 | next(value: T): void; 557 | error(errorValue: any): void; 558 | complete(): void; 559 | } 560 | 561 | declare interface ZenObservableSubscription { 562 | closed: boolean; 563 | unsubscribe(): void; 564 | } 565 | 566 | declare interface ZenObservableObserver { 567 | start?: (subscription: ZenObservableSubscription) => mixed; 568 | next?: (value: T) => mixed; 569 | error?: (errorValue: any) => mixed; 570 | complete?: () => mixed; 571 | } 572 | 573 | declare type ZenObservableSubscriber = ( 574 | observer: ZenObservableSubscriptionObserver 575 | ) => mixed | (() => mixed) | SubscriptionLINK; 576 | 577 | declare interface ZenObservableObservableLike { 578 | subscribe?: ZenObservableSubscriber; 579 | } 580 | /* apollo-link types */ 581 | 582 | /* apollo-cache types */ 583 | declare class ApolloCache { 584 | read(query: CacheReadOptions): T | null; 585 | write(write: CacheWriteOptions): void; 586 | diff(query: CacheDiffOptions): CacheDiffResult; 587 | watch(watch: CacheWatchOptions): () => void; 588 | evict(query: CacheEvictOptions): CacheEvictionResult; 589 | reset(): Promise; 590 | 591 | restore(serializedState: TSerialized): ApolloCache; 592 | extract(optimistic?: boolean): TSerialized; 593 | 594 | removeOptimistic(id: string): void; 595 | 596 | performTransaction(transaction: Transaction): void; 597 | recordOptimisticTransaction( 598 | transaction: Transaction, 599 | id: string 600 | ): void; 601 | 602 | transformDocument(document: DocumentNode): DocumentNode; 603 | transformForLink(document: DocumentNode): DocumentNode; 604 | 605 | readQuery( 606 | options: DataProxyReadQueryOptions, 607 | optimistic?: boolean 608 | ): QueryType | null; 609 | readFragment( 610 | options: DataProxyReadFragmentOptions, 611 | optimistic?: boolean 612 | ): FragmentType | null; 613 | writeQuery(options: CacheWriteQueryOptions): void; 614 | writeFragment(options: CacheWriteFragmentOptions): void; 615 | writeData(options: CacheWriteDataOptions): void; 616 | } 617 | 618 | declare type Transaction = (c: ApolloCache) => mixed; 619 | 620 | declare type CacheWatchCallback = (newData: any) => mixed; 621 | 622 | declare interface CacheEvictionResult { 623 | success: boolean; 624 | } 625 | 626 | declare interface CacheReadOptions extends DataProxyReadQueryOptions { 627 | rootId?: string; 628 | previousResult?: any; 629 | optimistic: boolean; 630 | } 631 | 632 | declare interface CacheWriteOptions extends DataProxyReadQueryOptions { 633 | dataId: string; 634 | result: any; 635 | } 636 | 637 | declare interface CacheDiffOptions extends CacheReadOptions { 638 | returnPartialData?: boolean; 639 | } 640 | 641 | declare interface CacheWatchOptions extends CacheReadOptions { 642 | callback: CacheWatchCallback; 643 | } 644 | 645 | declare interface CacheEvictOptions extends DataProxyReadQueryOptions { 646 | rootId?: string; 647 | } 648 | 649 | declare type CacheDiffResult = DataProxyDiffResult; 650 | declare type CacheWriteQueryOptions = DataProxyWriteQueryOptions; 651 | declare type CacheWriteFragmentOptions = DataProxyWriteFragmentOptions; 652 | declare type CacheWriteDataOptions = DataProxyWriteDataOptions; 653 | declare type CacheReadFragmentOptions = DataProxyReadFragmentOptions; 654 | 655 | declare interface DataProxyReadQueryOptions { 656 | query: DocumentNode; 657 | variables?: any; 658 | } 659 | 660 | declare interface DataProxyReadFragmentOptions { 661 | id: string; 662 | fragment: DocumentNode; 663 | fragmentName?: string; 664 | variables?: any; 665 | } 666 | 667 | declare interface DataProxyWriteQueryOptions { 668 | data: any; 669 | query: DocumentNode; 670 | variables?: any; 671 | } 672 | 673 | declare interface DataProxyWriteFragmentOptions { 674 | data: any; 675 | id: string; 676 | fragment: DocumentNode; 677 | fragmentName?: string; 678 | variables?: any; 679 | } 680 | 681 | declare interface DataProxyWriteDataOptions { 682 | data: any; 683 | id?: string; 684 | } 685 | 686 | declare type DataProxyDiffResult = { 687 | result?: T, 688 | complete?: boolean 689 | }; 690 | 691 | declare export interface DataProxy { 692 | readQuery( 693 | options: DataProxyReadQueryOptions, 694 | optimistic?: boolean 695 | ): QueryType | null; 696 | readFragment( 697 | options: DataProxyReadFragmentOptions, 698 | optimistic?: boolean 699 | ): FragmentType | null; 700 | writeQuery(options: DataProxyWriteQueryOptions): void; 701 | writeFragment(options: DataProxyWriteFragmentOptions): void; 702 | writeData(options: DataProxyWriteDataOptions): void; 703 | } 704 | /* End apollo-cache types */ 705 | 706 | /** End from Apollo Client */ 707 | 708 | /** 709 | * Types From graphql 710 | * graphql types are maintained in the graphql-js repo 711 | */ 712 | declare type DocumentNode = any; 713 | declare type ExecutionResult = { 714 | data?: T, 715 | extensions?: { [string]: any }, 716 | errors?: any[] 717 | }; 718 | declare type GraphQLError = any; 719 | declare type VariableDefinitionNode = any; 720 | /** End From graphql */ 721 | 722 | declare export interface ApolloProviderProps { 723 | client: any; // ApolloClient; 724 | children: Node; 725 | } 726 | 727 | declare export interface ApolloConsumerProps { 728 | children: (client: ApolloClient) => Node; 729 | } 730 | 731 | declare export class ApolloConsumer extends React$Component< 732 | ApolloConsumerProps 733 | > {} 734 | 735 | declare export class ApolloProvider extends React$Component< 736 | ApolloProviderProps 737 | > { 738 | childContextTypes: { 739 | client: ApolloClient, 740 | operations: Map 741 | }; 742 | 743 | getChildContext(): { 744 | client: ApolloClient, 745 | operations: Map 746 | }; 747 | } 748 | 749 | declare export type MutationFunc = ( 750 | opts: MutationOpts 751 | ) => Promise>; 752 | 753 | declare export type GraphqlData = TResult & 754 | GraphqlQueryControls & { 755 | variables: TVariables, 756 | refetch: (variables?: TVariables) => Promise> 757 | }; 758 | 759 | declare export type ChildProps< 760 | TOwnProps, 761 | TResult, 762 | TVariables: Object = {} 763 | > = { 764 | data: GraphqlData, 765 | mutate: MutationFunc 766 | } & TOwnProps; 767 | 768 | // back compat 769 | declare export type DefaultChildProps = ChildProps; 770 | 771 | declare export type RefetchQueriesProviderFn = ( 772 | ...args: any[] 773 | ) => RefetchQueryDescription; 774 | 775 | declare export type MutationOpts = {| 776 | variables?: TVariables, 777 | optimisticResponse?: Object, 778 | refetchQueries?: RefetchQueryDescription | RefetchQueriesProviderFn, 779 | update?: MutationUpdaterFn<*>, 780 | errorPolicy?: ErrorPolicy 781 | |}; 782 | 783 | declare export type QueryOpts = {| 784 | ssr?: boolean, 785 | variables?: TVariables, 786 | fetchPolicy?: FetchPolicy, 787 | pollInterval?: number, 788 | skip?: boolean, 789 | errorPolicy?: ErrorPolicy, 790 | context?: { [key: string]: any } 791 | |}; 792 | 793 | declare export interface GraphqlQueryControls< 794 | TGraphQLVariables = OperationVariables 795 | > { 796 | error?: ApolloError | any; // Added optional `any` to satisfy Flow < 0.62 797 | networkStatus: NetworkStatus; 798 | loading: boolean; 799 | variables: TGraphQLVariables; 800 | fetchMore: ( 801 | fetchMoreOptions: FetchMoreQueryOptions & 802 | FetchMoreOptions 803 | ) => Promise>; 804 | refetch: (variables?: TGraphQLVariables) => Promise>; 805 | startPolling: (pollInterval: number) => void; 806 | stopPolling: () => void; 807 | subscribeToMore: (options: SubscribeToMoreOptions) => () => void; 808 | updateQuery: ( 809 | mapFn: (previousQueryResult: any, options: UpdateQueryOptions) => mixed 810 | ) => void; 811 | } 812 | 813 | declare export interface OptionProps { 814 | ownProps: TProps; 815 | data?: GraphqlData; 816 | mutate: MutationFunc; 817 | } 818 | 819 | declare export type OptionDescription = 820 | | QueryOpts 821 | | MutationOpts 822 | | ((props: TProps) => QueryOpts | MutationOpts); 823 | 824 | declare export type NamedProps = P & { 825 | ownProps: R 826 | }; 827 | 828 | declare export interface OperationOption< 829 | TResult: {}, 830 | TProps: {}, 831 | TChildProps: {}, 832 | TVariables: {} 833 | > { 834 | +options?: OptionDescription; 835 | props?: ( 836 | props: OptionProps 837 | ) => TChildProps | ChildProps; 838 | +skip?: boolean | ((props: any) => boolean); 839 | name?: string; 840 | withRef?: boolean; 841 | shouldResubscribe?: (props: TProps, nextProps: TProps) => boolean; 842 | alias?: string; 843 | } 844 | 845 | declare export interface OperationComponent< 846 | TResult: Object = {}, 847 | TOwnProps: Object = {}, 848 | TVariables: Object = {}, 849 | TMergedProps: Object = ChildProps 850 | > { 851 | (component: ComponentType): ComponentType; 852 | } 853 | 854 | declare export function graphql( 855 | document: DocumentNode, 856 | operationOptions?: OperationOption 857 | ): OperationComponent; 858 | 859 | declare type WithApolloOptions = { 860 | withRef?: boolean 861 | }; 862 | 863 | declare export function withApollo( 864 | component: ComponentType<{ client: ApolloClient } & TProps>, 865 | operationOptions?: WithApolloOptions 866 | ): ComponentType; 867 | 868 | declare export interface IDocumentDefinition { 869 | type: DocumentType; 870 | name: string; 871 | variables: VariableDefinitionNode[]; 872 | } 873 | 874 | declare export function parser(document: DocumentNode): IDocumentDefinition; 875 | 876 | declare export interface Context { 877 | [key: string]: any; 878 | } 879 | 880 | declare export interface QueryResult { 881 | query: Promise>; 882 | element: Element<*>; 883 | context: Context; 884 | } 885 | 886 | declare export function walkTree( 887 | element: Node, 888 | context: Context, 889 | visitor: (element: Node, instance: any, context: Context) => boolean | void 890 | ): void; 891 | 892 | declare export function getDataFromTree( 893 | rootElement: Element<*>, 894 | rootContext?: any, 895 | fetchRoot?: boolean 896 | ): Promise; 897 | 898 | declare export function renderToStringWithData( 899 | component: Element<*> 900 | ): Promise; 901 | 902 | declare export function cleanupApolloState(apolloState: any): void; 903 | 904 | declare export type QueryRenderProps< 905 | TData = any, 906 | TVariables = OperationVariables 907 | > = { 908 | data: $ObjMap | void, 909 | loading: boolean, 910 | error?: ApolloError, 911 | variables: TVariables, 912 | networkStatus: NetworkStatus, 913 | refetch: (variables?: TVariables) => Promise>, 914 | fetchMore: (( 915 | options: FetchMoreOptions & 916 | FetchMoreQueryOptions 917 | ) => Promise>) & 918 | (( 919 | options: { query: DocumentNode } & FetchMoreQueryOptions & 920 | FetchMoreOptions 921 | ) => Promise>), 922 | load: () => void, 923 | startPolling: (interval: number) => void, 924 | stopPolling: () => void, 925 | subscribeToMore: ( 926 | options: SubscribeToMoreOptions 927 | ) => () => void, 928 | updateQuery: ( 929 | mapFn: ( 930 | previousResult: TData, 931 | options: { variables: TVariables } 932 | ) => TData 933 | ) => mixed, 934 | client: ApolloClient 935 | }; 936 | 937 | declare export type QueryRenderPropFunction = ( 938 | QueryRenderProps 939 | ) => Node; 940 | 941 | declare export class Query extends React$Component<{ 942 | query: DocumentNode, 943 | children: QueryRenderPropFunction, 944 | variables?: TVariables, 945 | pollInterval?: number, 946 | notifyOnNetworkStatusChange?: boolean, 947 | fetchPolicy?: FetchPolicy, 948 | errorPolicy?: ErrorPolicy, 949 | ssr?: boolean, 950 | displayName?: string, 951 | delay?: boolean, 952 | context?: { [string]: any } 953 | }> {} 954 | 955 | declare export type SubscriptionResult< 956 | TData, 957 | TVariables = OperationVariables 958 | > = { 959 | loading: boolean, 960 | data?: TData | {||} | void, 961 | error?: ApolloError 962 | }; 963 | 964 | declare export type SubscriptionRenderPropFunction = ( 965 | result: SubscriptionResult 966 | ) => Node; 967 | 968 | declare type SubscriptionProps = { 969 | subscription: DocumentNode, 970 | variables?: TVariables, 971 | shouldResubscribe?: 972 | | boolean 973 | | (( 974 | SubscriptionProps, 975 | SubscriptionProps 976 | ) => boolean), 977 | children: SubscriptionRenderPropFunction 978 | }; 979 | 980 | declare export class Subscription extends React$Component< 981 | SubscriptionProps 982 | > {} 983 | 984 | declare type OperationVariables = { [key: string]: any }; 985 | 986 | declare export type MutationFunction< 987 | TData = any, 988 | TVariables = OperationVariables 989 | > = (options?: { 990 | variables?: TVariables, 991 | optimisticResponse?: Object, 992 | refetchQueries?: RefetchQueryDescription | RefetchQueriesProviderFn, 993 | update?: MutationUpdaterFn 994 | }) => Promise>; 995 | 996 | declare export type MutationResult = { 997 | loading: boolean, 998 | error?: ApolloError, 999 | data?: TData, 1000 | called: boolean, 1001 | client: ApolloClient 1002 | }; 1003 | 1004 | declare export type MutationRenderPropFunction = ( 1005 | mutate: MutationFunction, 1006 | result: MutationResult 1007 | ) => Node; 1008 | 1009 | declare export class Mutation< 1010 | TData, 1011 | TVariables = void 1012 | > extends React$Component<{ 1013 | mutation: DocumentNode, 1014 | children: MutationRenderPropFunction, 1015 | variables?: TVariables, 1016 | update?: MutationUpdaterFn, 1017 | ignoreResults?: boolean, 1018 | optimisticResponse?: Object, 1019 | refetchQueries?: RefetchQueryDescription | RefetchQueriesProviderFn, 1020 | onCompleted?: (data: TData) => mixed, 1021 | onError?: (error: ApolloError) => mixed, 1022 | context?: { [string]: any } 1023 | }> {} 1024 | 1025 | declare export var compose: $Compose; 1026 | } 1027 | -------------------------------------------------------------------------------- /flow-typed/npm/redux_v4.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: df80bdd535bfed9cf3223e077f3b4543 2 | // flow-typed version: c4c8963c9c/redux_v4.x.x/flow_>=v0.55.x 3 | 4 | declare module 'redux' { 5 | 6 | /* 7 | 8 | S = State 9 | A = Action 10 | D = Dispatch 11 | 12 | */ 13 | 14 | declare export type DispatchAPI = (action: A) => A; 15 | declare export type Dispatch }> = DispatchAPI; 16 | 17 | declare export type MiddlewareAPI> = { 18 | dispatch: D; 19 | getState(): S; 20 | }; 21 | 22 | declare export type Store> = { 23 | // rewrite MiddlewareAPI members in order to get nicer error messages (intersections produce long messages) 24 | dispatch: D; 25 | getState(): S; 26 | subscribe(listener: () => void): () => void; 27 | replaceReducer(nextReducer: Reducer): void 28 | }; 29 | 30 | declare export type Reducer = (state: S | void, action: A) => S; 31 | 32 | declare export type CombinedReducer = (state: $Shape & {} | void, action: A) => S; 33 | 34 | declare export type Middleware> = 35 | (api: MiddlewareAPI) => 36 | (next: D) => D; 37 | 38 | declare export type StoreCreator> = { 39 | (reducer: Reducer, enhancer?: StoreEnhancer): Store; 40 | (reducer: Reducer, preloadedState: S, enhancer?: StoreEnhancer): Store; 41 | }; 42 | 43 | declare export type StoreEnhancer> = (next: StoreCreator) => StoreCreator; 44 | 45 | declare export function createStore(reducer: Reducer, enhancer?: StoreEnhancer): Store; 46 | declare export function createStore(reducer: Reducer, preloadedState?: S, enhancer?: StoreEnhancer): Store; 47 | 48 | declare export function applyMiddleware(...middlewares: Array>): StoreEnhancer; 49 | 50 | declare export type ActionCreator = (...args: Array) => A; 51 | declare export type ActionCreators = { [key: K]: ActionCreator }; 52 | 53 | declare export function bindActionCreators, D: DispatchAPI>(actionCreator: C, dispatch: D): C; 54 | declare export function bindActionCreators, D: DispatchAPI>(actionCreators: C, dispatch: D): C; 55 | 56 | declare export function combineReducers(reducers: O): CombinedReducer<$ObjMap(r: Reducer) => S>, A>; 57 | 58 | declare export var compose: $Compose; 59 | } 60 | -------------------------------------------------------------------------------- /flow-typed/tape-cup_v4.x.x.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 3 | declare type tape$TestOpts = { 4 | skip: boolean, 5 | timeout?: number, 6 | } | { 7 | skip?: boolean, 8 | timeout: number, 9 | }; 10 | 11 | declare type tape$TestCb = (t: tape$Context) => mixed; 12 | declare type tape$TestFn = (a: string | tape$TestOpts | tape$TestCb, b?: tape$TestOpts | tape$TestCb, c?: tape$TestCb) => void; 13 | 14 | declare interface tape$Context { 15 | fail(msg?: string): void, 16 | pass(msg?: string): void, 17 | 18 | error(err: mixed, msg?: string): void, 19 | ifError(err: mixed, msg?: string): void, 20 | ifErr(err: mixed, msg?: string): void, 21 | iferror(err: mixed, msg?: string): void, 22 | 23 | ok(value: mixed, msg?: string): void, 24 | true(value: mixed, msg?: string): void, 25 | assert(value: mixed, msg?: string): void, 26 | 27 | notOk(value: mixed, msg?: string): void, 28 | false(value: mixed, msg?: string): void, 29 | notok(value: mixed, msg?: string): void, 30 | 31 | // equal + aliases 32 | equal(actual: mixed, expected: mixed, msg?: string): void, 33 | equals(actual: mixed, expected: mixed, msg?: string): void, 34 | isEqual(actual: mixed, expected: mixed, msg?: string): void, 35 | is(actual: mixed, expected: mixed, msg?: string): void, 36 | strictEqual(actual: mixed, expected: mixed, msg?: string): void, 37 | strictEquals(actual: mixed, expected: mixed, msg?: string): void, 38 | 39 | // notEqual + aliases 40 | notEqual(actual: mixed, expected: mixed, msg?: string): void, 41 | notEquals(actual: mixed, expected: mixed, msg?: string): void, 42 | notStrictEqual(actual: mixed, expected: mixed, msg?: string): void, 43 | notStrictEquals(actual: mixed, expected: mixed, msg?: string): void, 44 | isNotEqual(actual: mixed, expected: mixed, msg?: string): void, 45 | isNot(actual: mixed, expected: mixed, msg?: string): void, 46 | not(actual: mixed, expected: mixed, msg?: string): void, 47 | doesNotEqual(actual: mixed, expected: mixed, msg?: string): void, 48 | isInequal(actual: mixed, expected: mixed, msg?: string): void, 49 | 50 | // deepEqual + aliases 51 | deepEqual(actual: mixed, expected: mixed, msg?: string): void, 52 | deepEquals(actual: mixed, expected: mixed, msg?: string): void, 53 | isEquivalent(actual: mixed, expected: mixed, msg?: string): void, 54 | same(actual: mixed, expected: mixed, msg?: string): void, 55 | 56 | // notDeepEqual 57 | notDeepEqual(actual: mixed, expected: mixed, msg?: string): void, 58 | notEquivalent(actual: mixed, expected: mixed, msg?: string): void, 59 | notDeeply(actual: mixed, expected: mixed, msg?: string): void, 60 | notSame(actual: mixed, expected: mixed, msg?: string): void, 61 | isNotDeepEqual(actual: mixed, expected: mixed, msg?: string): void, 62 | isNotDeeply(actual: mixed, expected: mixed, msg?: string): void, 63 | isNotEquivalent(actual: mixed, expected: mixed, msg?: string): void, 64 | isInequivalent(actual: mixed, expected: mixed, msg?: string): void, 65 | 66 | // deepLooseEqual 67 | deepLooseEqual(actual: mixed, expected: mixed, msg?: string): void, 68 | looseEqual(actual: mixed, expected: mixed, msg?: string): void, 69 | looseEquals(actual: mixed, expected: mixed, msg?: string): void, 70 | 71 | // notDeepLooseEqual 72 | notDeepLooseEqual(actual: mixed, expected: mixed, msg?: string): void, 73 | notLooseEqual(actual: mixed, expected: mixed, msg?: string): void, 74 | notLooseEquals(actual: mixed, expected: mixed, msg?: string): void, 75 | 76 | throws(fn: Function, expected?: RegExp | Function, msg?: string): void, 77 | doesNotThrow(fn: Function, expected?: RegExp | Function, msg?: string): void, 78 | 79 | timeoutAfter(ms: number): void, 80 | 81 | skip(msg?: string): void, 82 | plan(n: number): void, 83 | onFinish(fn: Function): void, 84 | end(): void, 85 | comment(msg: string): void, 86 | test: tape$TestFn, 87 | } 88 | 89 | declare module 'tape-cup' { 90 | declare type TestHarness = Tape; 91 | declare type StreamOpts = { 92 | objectMode?: boolean, 93 | }; 94 | 95 | declare type Tape = { 96 | (a: string | tape$TestOpts | tape$TestCb, b?: tape$TestCb | tape$TestOpts, c?: tape$TestCb, ...rest: Array): void, 97 | test: tape$TestFn, 98 | skip: (name: string, cb?: tape$TestCb) => void, 99 | createHarness: () => TestHarness, 100 | createStream: (opts?: StreamOpts) => stream$Readable, 101 | only: (a: string | tape$TestOpts | tape$TestCb, b?: tape$TestCb | tape$TestOpts, c?: tape$TestCb, ...rest: Array) => void, 102 | }; 103 | 104 | declare module.exports: Tape; 105 | } 106 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fusion-plugin-apollo", 3 | "description": "FusionJS entry point for React universal rendering /w Apollo", 4 | "version": "2.0.0-9", 5 | "license": "MIT", 6 | "repository": "fusionjs/fusion-plugin-apollo", 7 | "main": "./dist/index.js", 8 | "module": "./dist/index.es.js", 9 | "files": [ 10 | "dist", 11 | "src" 12 | ], 13 | "browser": { 14 | "./dist/index.js": "./dist/browser.es5.js", 15 | "./dist/index.es.js": "./dist/browser.es5.es.js" 16 | }, 17 | "es2015": { 18 | "./dist/browser.es5.es.js": "./dist/browser.es2015.es.js" 19 | }, 20 | "es2017": { 21 | "./dist/browser.es5.es.js": "./dist/browser.es2017.es.js", 22 | "./dist/browser.es2015.es.js": "./dist/browser.es2017.es.js" 23 | }, 24 | "dependencies": { 25 | "apollo-cache-inmemory": "^1.3.12", 26 | "apollo-client": "^2.4.7", 27 | "apollo-link": "^1.2.9", 28 | "apollo-link-http": "^1.5.12", 29 | "apollo-link-schema": "^1.1.4", 30 | "apollo-server-koa": "^2.4.8", 31 | "koa-compose": "^4.1.0" 32 | }, 33 | "devDependencies": { 34 | "@babel/preset-react": "^7.0.0", 35 | "babel-eslint": "^10.0.1", 36 | "create-universal-package": "^3.4.6", 37 | "eslint": "^5.9.0", 38 | "eslint-config-fusion": "^4.0.0", 39 | "eslint-plugin-cup": "^2.0.0", 40 | "eslint-plugin-flowtype": "^3.2.0", 41 | "eslint-plugin-import": "^2.14.0", 42 | "eslint-plugin-jest": "^22.1.0", 43 | "eslint-plugin-prettier": "^3.0.0", 44 | "eslint-plugin-react": "^7.11.1", 45 | "flow-bin": "^0.96.0", 46 | "fusion-core": "^1.10.4", 47 | "fusion-react": "^2.0.0", 48 | "fusion-test-utils": "^1.3.0", 49 | "fusion-tokens": "^1.1.1", 50 | "get-port": "^4.2.0", 51 | "graphql": "^14.1.1", 52 | "graphql-tag": "^2.10.0", 53 | "graphql-tools": "^4.0.3", 54 | "node-fetch": "^2.3.0", 55 | "nyc": "^13.3.0", 56 | "prettier": "^1.15.2", 57 | "react": "^16.6.3", 58 | "react-apollo": "^2.3.2", 59 | "react-dom": "^16.6.3", 60 | "redux": "^4.0.1", 61 | "tape-cup": "^4.7.1", 62 | "unfetch": "^4.1.0", 63 | "unitest": "^2.1.1" 64 | }, 65 | "peerDependencies": { 66 | "fusion-core": "^1.10.4", 67 | "fusion-react": "^2.0.0", 68 | "fusion-tokens": "^1.1.1", 69 | "react": "16.x", 70 | "react-apollo": "^2.0.4", 71 | "react-dom": "16.x" 72 | }, 73 | "scripts": { 74 | "clean": "rm -rf dist", 75 | "lint": "eslint src/", 76 | "transpile": "npm run clean && cup build", 77 | "build-test": "rm -rf dist-tests && cup build-tests", 78 | "just-test": "node_modules/.bin/unitest --browser=dist-tests/browser.js --node=dist-tests/node.js", 79 | "cover": "npm run build-test && npm run just-cover", 80 | "just-cover": "nyc --reporter=cobertura --reporter=text npm run just-test", 81 | "test": "npm run build-test && npm run just-test", 82 | "prepublish": "npm run transpile" 83 | }, 84 | "engines": { 85 | "node": ">= 8.9.0" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "uber" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /src/__tests__/client.browser.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | 9 | /* eslint-env browser */ 10 | 11 | import test from 'tape-cup'; 12 | import React from 'react'; 13 | import render from '../client'; 14 | 15 | test('renders', t => { 16 | const root = document.createElement('div'); 17 | root.id = 'root'; 18 | if (!document.body) { 19 | throw new Error('Could not find body'); 20 | } 21 | document.body.appendChild(root); 22 | render(React.createElement('span', null, 'hello')); 23 | const firstChild = root.firstChild; 24 | if (!firstChild) { 25 | throw new Error('Could not first child'); 26 | } 27 | t.equals(firstChild.nodeName, 'SPAN', 'has right tag'); 28 | t.equals(firstChild.textContent, 'hello', 'has right text'); 29 | 30 | if (!document.body) { 31 | throw new Error('Could not find body'); 32 | } 33 | document.body.removeChild(root); 34 | t.end(); 35 | }); 36 | -------------------------------------------------------------------------------- /src/__tests__/exports.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | import test from 'tape-cup'; 9 | import { 10 | ApolloRenderEnhancer, 11 | ApolloContextToken, 12 | GraphQLSchemaToken, 13 | gql, 14 | GraphQLEndpointToken, 15 | } from '../index.js'; 16 | 17 | test('fusion-tokens exports', t => { 18 | t.ok(ApolloContextToken, 'exports ApolloContextToken'); 19 | t.ok(GraphQLSchemaToken, 'exports GraphQLSchemaToken'); 20 | t.ok(GraphQLEndpointToken, 'exports GraphQLSchemaToken'); 21 | t.ok(ApolloRenderEnhancer, 'exports plugin'); 22 | t.equal(typeof gql, 'function', 'exports a gql function'); 23 | t.throws(gql, 'gql function throws an error if executed directly'); 24 | t.end(); 25 | }); 26 | -------------------------------------------------------------------------------- /src/__tests__/integration.node.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | import test from 'tape-cup'; 9 | import React from 'react'; 10 | import { 11 | ApolloRenderEnhancer, 12 | GraphQLSchemaToken, 13 | ApolloClientToken, 14 | ApolloBodyParserConfigToken, 15 | } from '../index'; 16 | import gql from 'graphql-tag'; 17 | import App from 'fusion-react/dist'; 18 | import {RenderToken} from 'fusion-core'; 19 | import {ApolloClient} from 'apollo-client'; 20 | import {InMemoryCache} from 'apollo-cache-inmemory'; 21 | import {HttpLink} from 'apollo-link-http'; 22 | import getPort from 'get-port'; 23 | import http from 'http'; 24 | import fetch from 'node-fetch'; 25 | import {makeExecutableSchema} from 'graphql-tools'; 26 | 27 | async function testApp(el, {typeDefs, resolvers}, enhanceApp) { 28 | const port = await getPort(); 29 | const endpoint = `http://localhost:${port}/graphql`; 30 | const app = new App(el); 31 | const schema = makeExecutableSchema({typeDefs, resolvers}); 32 | const client = new ApolloClient({ 33 | ssrMode: true, 34 | cache: new InMemoryCache().restore({}), 35 | link: new HttpLink({ 36 | endpoint, 37 | fetch: async (url, options) => { 38 | // required since the url here is only the path 39 | const result = await fetch(endpoint, options); 40 | return result; 41 | }, 42 | }), 43 | }); 44 | app.enhance(RenderToken, ApolloRenderEnhancer); 45 | app.register(GraphQLSchemaToken, schema); 46 | app.register(ApolloClientToken, ctx => { 47 | // $FlowFixMe 48 | return {}; // should hit server 49 | }); 50 | if (enhanceApp) { 51 | enhanceApp(app); 52 | } 53 | // $FlowFixMe 54 | const server = http.createServer(app.callback()); 55 | await new Promise((resolve, reject) => 56 | server.listen(port, err => { 57 | if (err) return reject(err); 58 | return resolve(); 59 | }) 60 | ); 61 | return {app, server, client}; 62 | } 63 | test('SSR with ', async t => { 64 | const query = gql` 65 | query Test { 66 | test 67 | } 68 | `; 69 | const el =
; 70 | const typeDefs = gql` 71 | type Query { 72 | test: String 73 | } 74 | `; 75 | const resolvers = { 76 | Query: { 77 | test(parent, args, ctx) { 78 | t.equal(ctx.path, '/graphql', 'context defaults correctly'); 79 | return 'test'; 80 | }, 81 | }, 82 | }; 83 | const {server, client} = await testApp(el, {typeDefs, resolvers}); 84 | const result = await client.query({query}); 85 | t.deepEqual(result, { 86 | data: {test: 'test'}, 87 | loading: false, 88 | networkStatus: 7, 89 | stale: false, 90 | }); 91 | server.close(); 92 | t.end(); 93 | }); 94 | 95 | test('/graphql endpoint with body parser config', async t => { 96 | const query = gql` 97 | query Test { 98 | test 99 | } 100 | `; 101 | const el =
; 102 | const typeDefs = gql` 103 | type Query { 104 | test: String 105 | } 106 | `; 107 | const resolvers = { 108 | Query: { 109 | test(parent, args, ctx) { 110 | t.equal(ctx.path, '/graphql', 'context defaults correctly'); 111 | return 'test'; 112 | }, 113 | }, 114 | }; 115 | let called = false; 116 | const {server, client} = await testApp(el, {typeDefs, resolvers}, app => { 117 | app.register(ApolloBodyParserConfigToken, { 118 | detectJSON: ctx => { 119 | called = true; 120 | return true; 121 | }, 122 | }); 123 | }); 124 | const result = await client.query({query}); 125 | t.ok(called, 'calls detectJSON function'); 126 | t.deepEqual(result, { 127 | data: {test: 'test'}, 128 | loading: false, 129 | networkStatus: 7, 130 | stale: false, 131 | }); 132 | server.close(); 133 | t.end(); 134 | }); 135 | -------------------------------------------------------------------------------- /src/__tests__/server.node.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | 9 | /* eslint-env browser */ 10 | 11 | import test from 'tape-cup'; 12 | import {getSimulator} from 'fusion-test-utils'; 13 | import React from 'react'; 14 | import { 15 | ApolloRenderEnhancer, 16 | GraphQLSchemaToken, 17 | ApolloClientToken, 18 | } from '../index'; 19 | import gql from 'graphql-tag'; 20 | import {makeExecutableSchema} from 'graphql-tools'; 21 | import {Query} from 'react-apollo'; 22 | import App from 'fusion-react'; 23 | import {RenderToken} from 'fusion-core'; 24 | import {ApolloClient} from 'apollo-client'; 25 | import {InMemoryCache} from 'apollo-cache-inmemory'; 26 | import {HttpLink} from 'apollo-link-http'; 27 | import {SchemaLink} from 'apollo-link-schema'; 28 | import fetch from 'node-fetch'; 29 | 30 | function testApp(el, {typeDefs, resolvers}) { 31 | const app = new App(el); 32 | const schema = makeExecutableSchema({typeDefs, resolvers}); 33 | app.enhance(RenderToken, ApolloRenderEnhancer); 34 | app.register(GraphQLSchemaToken, schema); 35 | app.register(ApolloClientToken, ctx => { 36 | return new ApolloClient({ 37 | ssrMode: true, 38 | cache: new InMemoryCache().restore({}), 39 | link: new SchemaLink({ 40 | schema, 41 | context: ctx, 42 | }), 43 | }); 44 | }); 45 | return app; 46 | } 47 | 48 | test('Server renders without schema', async t => { 49 | const el =
Hello World
; 50 | const app = new App(el); 51 | app.enhance(RenderToken, ApolloRenderEnhancer); 52 | app.register(ApolloClientToken, ctx => { 53 | return new ApolloClient({ 54 | ssrMode: true, 55 | cache: new InMemoryCache().restore({}), 56 | link: new HttpLink({ 57 | uri: 'http://localhost:4000', 58 | fetch, 59 | }), 60 | }); 61 | }); 62 | const simulator = getSimulator(app); 63 | const ctx = await simulator.render('/'); 64 | t.equal(ctx.rendered.includes('Hello World'), true, 'renders correctly'); 65 | t.end(); 66 | }); 67 | 68 | test('Server render simulate', async t => { 69 | const el =
Hello World
; 70 | const typeDefs = gql` 71 | type Query { 72 | test: String 73 | } 74 | `; 75 | const resolvers = { 76 | Query: { 77 | test(parent, args, ctx) { 78 | return 'test'; 79 | }, 80 | }, 81 | }; 82 | const app = testApp(el, {typeDefs, resolvers}); 83 | const simulator = getSimulator(app); 84 | const ctx = await simulator.render('/'); 85 | t.equal(ctx.rendered.includes('Hello World'), true, 'renders correctly'); 86 | t.end(); 87 | }); 88 | 89 | test('SSR with ', async t => { 90 | const query = gql` 91 | query Test { 92 | test 93 | } 94 | `; 95 | const el = ( 96 |
97 | 98 | {result => { 99 | if (result.loading) { 100 | return
Loading...
; 101 | } else if (result.data) { 102 | return
{result.data.test}
; 103 | } else { 104 | return
Failure
; 105 | } 106 | }} 107 |
108 |
109 | ); 110 | const typeDefs = gql` 111 | type Query { 112 | test: String 113 | } 114 | `; 115 | const resolvers = { 116 | Query: { 117 | test(parent, args, ctx) { 118 | t.equal(ctx.path, '/', 'context defaults correctly'); 119 | return 'test'; 120 | }, 121 | }, 122 | }; 123 | const app = testApp(el, {typeDefs, resolvers}); 124 | const simulator = getSimulator(app); 125 | const ctx = await simulator.render('/'); 126 | t.equal(ctx.rendered.includes('test'), true, 'renders correctly'); 127 | t.equal(ctx.rendered.includes('Loading'), false, 'does not render loading'); 128 | // $FlowFixMe 129 | t.ok(ctx.body.includes('ROOT_QUERY'), 'includes serialized data'); 130 | t.end(); 131 | }); 132 | 133 | test('SSR with and errors', async t => { 134 | const query = gql` 135 | query Test { 136 | test 137 | } 138 | `; 139 | const el = ( 140 |
141 | 142 | {result => { 143 | if (result.loading) { 144 | return
Loading...
; 145 | } else if (result.data) { 146 | return
{result.data.test}
; 147 | } else { 148 | return
Failure
; 149 | } 150 | }} 151 |
152 |
153 | ); 154 | const typeDefs = gql` 155 | type Query { 156 | test: String 157 | } 158 | `; 159 | const resolvers = { 160 | Query: { 161 | test() { 162 | throw new Error('FAIL'); 163 | }, 164 | }, 165 | }; 166 | const app = testApp(el, {typeDefs, resolvers}); 167 | const simulator = getSimulator(app); 168 | const ctx = await simulator.render('/'); 169 | t.equal(ctx.rendered.includes('test'), false, 'does not fetch data'); 170 | t.equal(ctx.rendered.includes('Loading'), true, 'Renders the loading'); 171 | t.end(); 172 | }); 173 | -------------------------------------------------------------------------------- /src/apollo-client/__tests__/exports.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | 9 | import test from 'tape-cup'; 10 | import { 11 | ApolloClientPlugin, 12 | GetApolloClientCacheToken, 13 | ApolloClientCredentialsToken, 14 | GetApolloClientLinksToken, 15 | ApolloClientDefaultOptionsToken, 16 | ApolloClientResolversToken, 17 | } from '../index.js'; 18 | 19 | test('exports', t => { 20 | t.ok(ApolloClientPlugin, 'exports ApolloClientPlugin'); 21 | t.ok(GetApolloClientCacheToken, 'exports GetApolloClientCacheToken'); 22 | t.ok(ApolloClientCredentialsToken, 'exports ApolloClientCredentialsToken'); 23 | t.ok(GetApolloClientLinksToken, 'exports ApolloClientAuthKeyToken'); 24 | t.ok(ApolloClientDefaultOptionsToken, 'exports ApolloClientAuthKeyToken'); 25 | t.ok(ApolloClientResolversToken, 'exports ApolloClientResolversToken'); 26 | t.end(); 27 | }); 28 | -------------------------------------------------------------------------------- /src/apollo-client/__tests__/index.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | 9 | import {InMemoryCache} from 'apollo-cache-inmemory'; 10 | import App, {createPlugin} from 'fusion-core'; 11 | import {getSimulator} from 'fusion-test-utils'; 12 | import {ApolloClientToken} from '../../tokens'; 13 | import {ApolloLink} from 'apollo-link'; 14 | import {FetchToken} from 'fusion-tokens'; 15 | import unfetch from 'unfetch'; 16 | import test from 'tape-cup'; 17 | 18 | import {ApolloClientPlugin, GetApolloClientLinksToken} from '../index.js'; 19 | 20 | test('ApolloUniveralClient', async t => { 21 | const app = new App('el', el => el); 22 | app.register(GetApolloClientLinksToken, links => [ 23 | new ApolloLink(), 24 | ...links, 25 | ]); 26 | app.register(ApolloClientToken, ApolloClientPlugin); 27 | app.register(FetchToken, unfetch); 28 | 29 | const clients = []; 30 | const testPlugin = createPlugin({ 31 | deps: { 32 | universalClient: ApolloClientToken, 33 | }, 34 | middleware({universalClient}) { 35 | return async (ctx, next) => { 36 | const client = universalClient(ctx, {}); 37 | clients.push(client); 38 | t.ok(client.link); 39 | t.ok(client.cache instanceof InMemoryCache); 40 | // memoizes the client on ctx correctly 41 | t.equal(client, universalClient(ctx, {})); 42 | return next(); 43 | }; 44 | }, 45 | }); 46 | app.register(testPlugin); 47 | 48 | const simulator = getSimulator(app); 49 | await simulator.render('/'); 50 | await simulator.render('/'); 51 | t.equal(clients.length, 2); 52 | t.notEqual(clients[0], clients[1]); 53 | t.notEqual(clients[0].cache, clients[1].cache); 54 | t.end(); 55 | }); 56 | -------------------------------------------------------------------------------- /src/apollo-client/__tests__/local-state.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | 9 | import {ApolloClientToken, GraphQLSchemaToken} from '../../tokens'; 10 | import App, {createPlugin} from 'fusion-core'; 11 | import {getSimulator} from 'fusion-test-utils'; 12 | import {FetchToken} from 'fusion-tokens'; 13 | import {buildSchema} from 'graphql'; 14 | import gql from 'graphql-tag'; 15 | import unfetch from 'unfetch'; 16 | import test from 'tape-cup'; 17 | 18 | import {ApolloClientResolversToken, ApolloClientPlugin} from '../index.js'; 19 | 20 | test('local state management', async t => { 21 | const app = new App('el', el => el); 22 | app.register(ApolloClientToken, ApolloClientPlugin); 23 | app.register( 24 | GraphQLSchemaToken, 25 | (buildSchema(` 26 | type Query { 27 | query: String! 28 | } 29 | 30 | type Mutation { 31 | mutate: String # returns nothing 32 | } 33 | `): any) 34 | ); 35 | app.register(FetchToken, unfetch); 36 | 37 | let mutationCalled = false; 38 | app.register(ApolloClientResolversToken, { 39 | Query: { 40 | query: () => 'foo', 41 | }, 42 | Mutation: { 43 | mutate: async () => { 44 | mutationCalled = true; 45 | }, 46 | }, 47 | }); 48 | 49 | const testPlugin = createPlugin({ 50 | deps: { 51 | universalClient: ApolloClientToken, 52 | }, 53 | middleware({universalClient}) { 54 | return async (ctx, next) => { 55 | const client = universalClient(ctx, {}); 56 | 57 | const {data} = await client.query({ 58 | query: gql` 59 | query { 60 | query @client 61 | } 62 | `, 63 | }); 64 | t.equal(data.query, 'foo'); 65 | 66 | t.equal(mutationCalled, false); 67 | await client.mutate({ 68 | mutation: gql` 69 | mutation { 70 | mutate @client 71 | } 72 | `, 73 | }); 74 | t.equal(mutationCalled, true); 75 | 76 | return next(); 77 | }; 78 | }, 79 | }); 80 | app.register(testPlugin); 81 | 82 | const simulator = getSimulator(app); 83 | await simulator.render('/'); 84 | t.end(); 85 | }); 86 | -------------------------------------------------------------------------------- /src/apollo-client/index.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | 9 | import {createPlugin, createToken} from 'fusion-core'; 10 | import {FetchToken} from 'fusion-tokens'; 11 | import { 12 | GraphQLSchemaToken, 13 | ApolloContextToken, 14 | GraphQLEndpointToken, 15 | } from '../tokens'; 16 | import {ApolloClient} from 'apollo-client'; 17 | import {HttpLink} from 'apollo-link-http'; 18 | import {from as apolloLinkFrom} from 'apollo-link'; 19 | import {SchemaLink} from 'apollo-link-schema'; 20 | import type {ApolloCache, ApolloClientOptions} from 'apollo-client'; 21 | 22 | import type {Context, FusionPlugin, Token} from 'fusion-core'; 23 | import {InMemoryCache} from 'apollo-cache-inmemory'; 24 | 25 | export const GetApolloClientCacheToken: Token< 26 | (ctx: Context) => ApolloCache 27 | > = createToken('GetApolloClientCacheToken'); 28 | 29 | export const ApolloClientCredentialsToken: Token = createToken( 30 | 'ApolloClientCredentialsToken' 31 | ); 32 | 33 | export const ApolloClientDefaultOptionsToken: Token< 34 | $PropertyType, 'defaultOptions'> 35 | > = createToken('ApolloClientDefaultOptionsToken'); 36 | 37 | type ApolloLinkType = {request: (operation: any, forward: any) => any}; 38 | 39 | export const GetApolloClientLinksToken: Token< 40 | (Array, ctx: Context) => Array 41 | > = createToken('GetApolloClientLinksToken'); 42 | 43 | export const ApolloClientResolversToken: Token< 44 | ResolverMapType | $ReadOnlyArray 45 | > = createToken('ApolloClientResolversToken'); 46 | 47 | type ResolverMapType = { 48 | +[key: string]: { 49 | +[field: string]: ( 50 | rootValue?: any, 51 | args?: any, 52 | context?: any, 53 | info?: any 54 | ) => any, 55 | }, 56 | }; 57 | 58 | type ApolloClientDepsType = { 59 | getCache: typeof GetApolloClientCacheToken.optional, 60 | endpoint: typeof GraphQLEndpointToken.optional, 61 | fetch: typeof FetchToken, 62 | includeCredentials: typeof ApolloClientCredentialsToken.optional, 63 | apolloContext: typeof ApolloContextToken.optional, 64 | getApolloLinks: typeof GetApolloClientLinksToken.optional, 65 | schema: typeof GraphQLSchemaToken.optional, 66 | resolvers: typeof ApolloClientResolversToken.optional, 67 | defaultOptions: typeof ApolloClientDefaultOptionsToken.optional, 68 | }; 69 | 70 | type InitApolloClientType = ( 71 | ctx: Context, 72 | initialState: mixed 73 | ) => ApolloClient; 74 | 75 | function Container() {} 76 | 77 | const ApolloClientPlugin: FusionPlugin< 78 | ApolloClientDepsType, 79 | InitApolloClientType 80 | > = createPlugin({ 81 | deps: { 82 | getCache: GetApolloClientCacheToken.optional, 83 | endpoint: GraphQLEndpointToken.optional, 84 | fetch: FetchToken, 85 | includeCredentials: ApolloClientCredentialsToken.optional, 86 | apolloContext: ApolloContextToken.optional, 87 | getApolloLinks: GetApolloClientLinksToken.optional, 88 | schema: GraphQLSchemaToken.optional, 89 | resolvers: ApolloClientResolversToken.optional, 90 | defaultOptions: ApolloClientDefaultOptionsToken.optional, 91 | }, 92 | provides({ 93 | getCache = ctx => new InMemoryCache(), 94 | endpoint = '/graphql', 95 | fetch, 96 | includeCredentials = 'same-origin', 97 | apolloContext = ctx => ctx, 98 | getApolloLinks, 99 | schema, 100 | resolvers, 101 | defaultOptions, 102 | }) { 103 | function getClient(ctx, initialState) { 104 | const cache = getCache(ctx); 105 | const connectionLink = 106 | schema && __NODE__ 107 | ? new SchemaLink({ 108 | schema, 109 | context: 110 | typeof apolloContext === 'function' 111 | ? apolloContext(ctx) 112 | : apolloContext, 113 | }) 114 | : new HttpLink({ 115 | uri: endpoint, 116 | credentials: includeCredentials, 117 | fetch, 118 | }); 119 | 120 | const links: Array = getApolloLinks 121 | ? getApolloLinks([connectionLink], ctx) 122 | : [connectionLink]; 123 | 124 | const client = new ApolloClient({ 125 | ssrMode: __NODE__, 126 | connectToDevTools: __BROWSER__ && __DEV__, 127 | link: apolloLinkFrom(links), 128 | cache: cache.restore(initialState), 129 | resolvers, 130 | defaultOptions, 131 | }); 132 | return client; 133 | } 134 | return (ctx: Context, initialState: mixed) => { 135 | if (ctx.memoized.has(Container)) { 136 | return ctx.memoized.get(Container); 137 | } 138 | const client = getClient(ctx, initialState); 139 | ctx.memoized.set(Container, client); 140 | return client; 141 | }; 142 | }, 143 | }); 144 | export {ApolloClientPlugin}; 145 | -------------------------------------------------------------------------------- /src/client.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | 9 | /* eslint-env browser */ 10 | import ReactDOM from 'react-dom'; 11 | 12 | import type {Element} from 'react'; 13 | 14 | export default (root: Element<*>) => { 15 | const domElement = document.getElementById('root'); 16 | 17 | if (!domElement) { 18 | throw new Error("Could not find 'root' element"); 19 | } 20 | 21 | ReactDOM.hydrate 22 | ? ReactDOM.hydrate(root, domElement) 23 | : ReactDOM.render(root, domElement); 24 | }; 25 | -------------------------------------------------------------------------------- /src/flow/flow-fixture.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | 9 | import App, {createPlugin} from 'fusion-core'; 10 | import {ApolloContextToken} from '../index.js'; 11 | 12 | const app = new App(); 13 | 14 | app.register(ApolloContextToken, ctx => ({ 15 | testcase: ctx.path, 16 | })); 17 | 18 | app.register(ApolloContextToken, () => ({ 19 | testcase: 'with no context', 20 | })); 21 | 22 | const plugin = createPlugin({ 23 | provides: () => { 24 | return () => {}; 25 | }, 26 | }); 27 | 28 | app.register(ApolloContextToken, plugin); 29 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | import type {DocumentNode} from 'graphql'; 9 | import ApolloRenderEnhancer from './plugin'; 10 | 11 | export * from './tokens.js'; 12 | export * from './apollo-client/index.js'; 13 | 14 | export {ApolloRenderEnhancer}; 15 | 16 | export function gql(path: string): DocumentNode { 17 | throw new Error('fusion-plugin-apollo/gql should be replaced at build time'); 18 | } 19 | -------------------------------------------------------------------------------- /src/plugin.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | 9 | /* eslint-env browser */ 10 | import React from 'react'; 11 | 12 | import {createPlugin, html, unescape} from 'fusion-core'; 13 | 14 | import {ApolloProvider} from 'react-apollo'; 15 | 16 | import type {Context, Render} from 'fusion-core'; 17 | 18 | import serverRender from './server'; 19 | import {LoggerToken} from 'fusion-tokens'; 20 | import {ApolloServer} from 'apollo-server-koa'; 21 | import compose from 'koa-compose'; 22 | import { 23 | ApolloContextToken, 24 | ApolloCacheContext, 25 | GraphQLSchemaToken, 26 | GraphQLEndpointToken, 27 | ApolloClientToken, 28 | ApolloBodyParserConfigToken, 29 | } from './tokens'; 30 | 31 | export type DepsType = { 32 | apolloContext: typeof ApolloContextToken.optional, 33 | logger: typeof LoggerToken.optional, 34 | schema: typeof GraphQLSchemaToken.optional, 35 | endpoint: typeof GraphQLEndpointToken.optional, 36 | getApolloClient: typeof ApolloClientToken, 37 | bodyParserConfig: typeof ApolloBodyParserConfigToken.optional, 38 | }; 39 | 40 | export type ProvidesType = (el: any, ctx: Context) => Promise; 41 | 42 | function getDeps(): DepsType { 43 | if (__NODE__) { 44 | return { 45 | apolloContext: ApolloContextToken.optional, 46 | logger: LoggerToken.optional, 47 | schema: GraphQLSchemaToken.optional, 48 | endpoint: GraphQLEndpointToken.optional, 49 | getApolloClient: ApolloClientToken, 50 | bodyParserConfig: ApolloBodyParserConfigToken.optional, 51 | }; 52 | } 53 | // $FlowFixMe 54 | return { 55 | getApolloClient: ApolloClientToken, 56 | }; 57 | } 58 | 59 | export default (renderFn: Render) => 60 | createPlugin({ 61 | deps: getDeps(), 62 | provides(deps) { 63 | if (__BROWSER__) { 64 | return renderFn; 65 | } 66 | return (el, ctx) => { 67 | return serverRender(el, deps.logger).then(() => { 68 | return renderFn(el, ctx); 69 | }); 70 | }; 71 | }, 72 | middleware({ 73 | schema, 74 | endpoint = '/graphql', 75 | getApolloClient, 76 | apolloContext = ctx => { 77 | return ctx; 78 | }, 79 | bodyParserConfig = {}, 80 | }) { 81 | const renderMiddleware = async (ctx, next) => { 82 | if (!ctx.element) { 83 | return next(); 84 | } 85 | let initialState = null; 86 | if (__BROWSER__) { 87 | // Deserialize initial state for the browser 88 | const apolloState = document.getElementById('__APOLLO_STATE__'); 89 | if (apolloState) { 90 | initialState = JSON.parse(unescape(apolloState.textContent)); 91 | } 92 | } 93 | // Create the client and apollo provider 94 | const client = getApolloClient(ctx, initialState); 95 | ctx.element = ( 96 | 97 | {ctx.element} 98 | 99 | ); 100 | 101 | await next(); 102 | 103 | if (__NODE__) { 104 | // Serialize state into html on server side render 105 | const initialState = client.cache && client.cache.extract(); 106 | const serialized = JSON.stringify(initialState); 107 | // eslint-disable-next-line prettier/prettier 108 | const script = html``; 109 | ctx.template.body.push(script); 110 | } 111 | }; 112 | if (__NODE__ && schema) { 113 | const server = new ApolloServer({ 114 | schema, 115 | // investigate other options 116 | context: ({ctx}) => { 117 | if (typeof apolloContext === 'function') { 118 | return apolloContext(ctx); 119 | } 120 | return apolloContext; 121 | }, 122 | }); 123 | let serverMiddleware = []; 124 | server.applyMiddleware({ 125 | // switch to server.getMiddleware once https://github.com/apollographql/apollo-server/pull/2435 lands 126 | app: { 127 | use: m => { 128 | serverMiddleware.push(m); 129 | }, 130 | }, 131 | // investigate other options 132 | path: endpoint, 133 | bodyParserConfig, 134 | }); 135 | return compose([...serverMiddleware, renderMiddleware]); 136 | } else { 137 | return renderMiddleware; 138 | } 139 | }, 140 | }); 141 | -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | 9 | /* eslint-env node */ 10 | import {getDataFromTree} from 'react-apollo'; 11 | import type {Logger} from 'fusion-tokens'; 12 | 13 | import type {Element} from 'react'; 14 | 15 | // Apollo currently does not have an effective error policy for server side rendering (see https://github.com/apollographql/react-apollo/issues/2680) 16 | // This render function first tries to use `renderToStringWithData`. If any query in this render function fails, we will catch the error, log it, and 17 | // fall back to a standard renderToString, which will set the `loading` props of all queries which failed to execute in the first pass to true. 18 | // This allows us to still render with data in the happy case, and defer to client side rendering if any queries fail. This also acts as a form 19 | // of retrying from the browser. 20 | export default (root: Element<*>, logger?: Logger) => { 21 | return getDataFromTree(root).catch(e => { 22 | logger && logger.error('SSR Failed with Error', e); 23 | }); 24 | }; 25 | -------------------------------------------------------------------------------- /src/tokens.js: -------------------------------------------------------------------------------- 1 | /** Copyright (c) 2018 Uber Technologies, Inc. 2 | * 3 | * This source code is licensed under the MIT license found in the 4 | * LICENSE file in the root directory of this source tree. 5 | * 6 | * @flow 7 | */ 8 | import React from 'react'; 9 | import {createToken, type Context, type Token} from 'fusion-core'; 10 | import type {ApolloClient} from 'apollo-client'; 11 | 12 | export type InitApolloClientType = ( 13 | ctx: Context, 14 | initialState: TInitialState 15 | ) => ApolloClient; 16 | 17 | // We should have better flow types for the schema 18 | export const GraphQLSchemaToken: Token = createToken('GraphQlSchemaToken'); 19 | 20 | export type ApolloContext = Context => T | T; 21 | 22 | export const ApolloContextToken: Token> = createToken( 23 | 'ApolloContextToken' 24 | ); 25 | 26 | export const ApolloCacheContext = React.createContext< 27 | $PropertyType, 'cache'> 28 | >(); 29 | 30 | export const GraphQLEndpointToken: Token = createToken( 31 | 'GraphQLEndpointToken' 32 | ); 33 | 34 | export const ApolloClientToken: Token< 35 | InitApolloClientType 36 | > = createToken('ApolloClientToken'); 37 | 38 | type BodyParserConfigType = { 39 | enableTypes?: Array, 40 | encoding?: string, 41 | formLimit?: string, 42 | jsonLimit?: string, 43 | textLimit?: string, 44 | strict?: boolean, 45 | detectJSON?: (ctx: Context) => boolean, 46 | extendTypes?: any, 47 | onerror?: (err: any, ctx: Context) => any, 48 | disableBodyParser?: (ctx: Context, next: () => Promise) => Promise, 49 | }; 50 | export const ApolloBodyParserConfigToken: Token = createToken( 51 | 'ApolloBodyParserConfigToken' 52 | ); 53 | --------------------------------------------------------------------------------