1 |
|
2 | export * from 'apollo-client';
|
3 | export * from 'apollo-link';
|
4 | export * from 'apollo-cache-inmemory';
|
5 |
|
6 | import { Operation, ApolloLink, Observable } from 'apollo-link';
|
7 | import { HttpLink } from 'apollo-link-http';
|
8 | import { onError, ErrorLink } from 'apollo-link-error';
|
9 | import { ApolloCache } from 'apollo-cache';
|
10 | import { InMemoryCache, CacheResolverMap } from 'apollo-cache-inmemory';
|
11 | import gql from 'graphql-tag';
|
12 | import ApolloClient, {
|
13 | Resolvers,
|
14 | LocalStateFragmentMatcher,
|
15 | } from 'apollo-client';
|
16 | import { DocumentNode } from 'graphql';
|
17 | import { invariant } from 'ts-invariant';
|
18 |
|
19 | export { gql, HttpLink };
|
20 |
|
21 | type ClientStateConfig = {
|
22 | cache?: ApolloCache<any>;
|
23 | defaults?: Record<string, any>;
|
24 | resolvers?: Resolvers | Resolvers[];
|
25 | typeDefs?: string | string[] | DocumentNode | DocumentNode[];
|
26 | fragmentMatcher?: LocalStateFragmentMatcher;
|
27 | };
|
28 |
|
29 | export interface PresetConfig {
|
30 | request?: (operation: Operation) => Promise<void>;
|
31 | uri?: string;
|
32 | credentials?: string;
|
33 | headers?: any;
|
34 | fetch?: GlobalFetch['fetch'];
|
35 | fetchOptions?: HttpLink.Options;
|
36 | clientState?: ClientStateConfig;
|
37 | onError?: ErrorLink.ErrorHandler;
|
38 | cacheRedirects?: CacheResolverMap;
|
39 | cache?: ApolloCache<any>;
|
40 | name?: string;
|
41 | version?: string;
|
42 | resolvers?: Resolvers | Resolvers[];
|
43 | typeDefs?: string | string[] | DocumentNode | DocumentNode[];
|
44 | fragmentMatcher?: LocalStateFragmentMatcher;
|
45 | }
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 | const PRESET_CONFIG_KEYS = [
|
58 | 'request',
|
59 | 'uri',
|
60 | 'credentials',
|
61 | 'headers',
|
62 | 'fetch',
|
63 | 'fetchOptions',
|
64 | 'clientState',
|
65 | 'onError',
|
66 | 'cacheRedirects',
|
67 | 'cache',
|
68 | 'name',
|
69 | 'version',
|
70 | 'resolvers',
|
71 | 'typeDefs',
|
72 | 'fragmentMatcher',
|
73 | ];
|
74 |
|
75 | export default class DefaultClient<TCache> extends ApolloClient<TCache> {
|
76 | constructor(config: PresetConfig = {}) {
|
77 | if (config) {
|
78 | const diff = Object.keys(config).filter(
|
79 | key => PRESET_CONFIG_KEYS.indexOf(key) === -1,
|
80 | );
|
81 |
|
82 | if (diff.length > 0) {
|
83 | invariant.warn(
|
84 | 'ApolloBoost was initialized with unsupported options: ' +
|
85 | `${diff.join(' ')}`,
|
86 | );
|
87 | }
|
88 | }
|
89 |
|
90 | const {
|
91 | request,
|
92 | uri,
|
93 | credentials,
|
94 | headers,
|
95 | fetch,
|
96 | fetchOptions,
|
97 | clientState,
|
98 | cacheRedirects,
|
99 | onError: errorCallback,
|
100 | name,
|
101 | version,
|
102 | resolvers,
|
103 | typeDefs,
|
104 | fragmentMatcher,
|
105 | } = config;
|
106 |
|
107 | let { cache } = config;
|
108 |
|
109 | invariant(
|
110 | !cache || !cacheRedirects,
|
111 | 'Incompatible cache configuration. If providing `cache` then ' +
|
112 | 'configure the provided instance with `cacheRedirects` instead.',
|
113 | );
|
114 |
|
115 | if (!cache) {
|
116 | cache = cacheRedirects
|
117 | ? new InMemoryCache({ cacheRedirects })
|
118 | : new InMemoryCache();
|
119 | }
|
120 |
|
121 | const errorLink = errorCallback
|
122 | ? onError(errorCallback)
|
123 | : onError(({ graphQLErrors, networkError }) => {
|
124 | if (graphQLErrors) {
|
125 | graphQLErrors.map(({ message, locations, path }) =>
|
126 |
|
127 | invariant.warn(
|
128 | `[GraphQL error]: Message: ${message}, Location: ` +
|
129 | `${locations}, Path: ${path}`,
|
130 | ),
|
131 | );
|
132 | }
|
133 | if (networkError) {
|
134 |
|
135 | invariant.warn(`[Network error]: ${networkError}`);
|
136 | }
|
137 | });
|
138 |
|
139 | const requestHandler = request
|
140 | ? new ApolloLink(
|
141 | (operation, forward) =>
|
142 | new Observable(observer => {
|
143 | let handle: any;
|
144 | Promise.resolve(operation)
|
145 | .then(oper => request(oper))
|
146 | .then(() => {
|
147 | handle = forward(operation).subscribe({
|
148 | next: observer.next.bind(observer),
|
149 | error: observer.error.bind(observer),
|
150 | complete: observer.complete.bind(observer),
|
151 | });
|
152 | })
|
153 | .catch(observer.error.bind(observer));
|
154 |
|
155 | return () => {
|
156 | if (handle) {
|
157 | handle.unsubscribe();
|
158 | }
|
159 | };
|
160 | }),
|
161 | )
|
162 | : false;
|
163 |
|
164 | const httpLink = new HttpLink({
|
165 | uri: uri || '/graphql',
|
166 | fetch,
|
167 | fetchOptions: fetchOptions || {},
|
168 | credentials: credentials || 'same-origin',
|
169 | headers: headers || {},
|
170 | });
|
171 |
|
172 | const link = ApolloLink.from([errorLink, requestHandler, httpLink].filter(
|
173 | x => !!x,
|
174 | ) as ApolloLink[]);
|
175 |
|
176 | let activeResolvers = resolvers;
|
177 | let activeTypeDefs = typeDefs;
|
178 | let activeFragmentMatcher = fragmentMatcher;
|
179 | if (clientState) {
|
180 | if (clientState.defaults) {
|
181 | cache.writeData({
|
182 | data: clientState.defaults,
|
183 | });
|
184 | }
|
185 | activeResolvers = clientState.resolvers;
|
186 | activeTypeDefs = clientState.typeDefs;
|
187 | activeFragmentMatcher = clientState.fragmentMatcher;
|
188 | }
|
189 |
|
190 |
|
191 | super({
|
192 | cache,
|
193 | link,
|
194 | name,
|
195 | version,
|
196 | resolvers: activeResolvers,
|
197 | typeDefs: activeTypeDefs,
|
198 | fragmentMatcher: activeFragmentMatcher,
|
199 | } as any);
|
200 | }
|
201 | }
|