import ApolloClient, { DefaultOptions } from 'apollo-client'; import { InMemoryCache } from 'apollo-cache-inmemory'; import { split } from 'apollo-link'; import { HttpLink } from 'apollo-link-http'; import { WebSocketLink } from 'apollo-link-ws'; import { getMainDefinition, variablesInOperation } from 'apollo-utilities'; import gql from 'graphql-tag'; import { ProfileChanges } from '../store/actions/profile'; export class UnauthorizedError extends Error { constructor(...args: any[]) { super(...args) Object.setPrototypeOf(this, UnauthorizedError.prototype); } } let client: DaddyClient export function getClient(graphQLEndpoint: string, subscriptionEndpoint: string): DaddyClient { if (!client) { client = new DaddyClient(graphQLEndpoint, subscriptionEndpoint); } return client; } export class DaddyClient { gql: ApolloClient constructor(graphQLEndpoint: string, subscriptionEndpoint: string) { const wsLink = new WebSocketLink({ uri: subscriptionEndpoint, options: { reconnect: true } }); const httpLink = new HttpLink({ uri: graphQLEndpoint, fetchOptions: { mode: 'cors', credentials: 'include', } }); const link = split( ({ query }) => { const definition = getMainDefinition(query); return ( definition.kind === 'OperationDefinition' && definition.operation === 'subscription' ); }, wsLink, httpLink, ); const defaultOptions: DefaultOptions = { watchQuery: { fetchPolicy: 'no-cache', errorPolicy: 'ignore', }, query: { fetchPolicy: 'no-cache', errorPolicy: 'all', }, }; this.gql = new ApolloClient({ link: link, cache: new InMemoryCache(), defaultOptions, }); } fetchProfile() { return this.gql.query({ query: gql` query { userProfile { id, name, email, createdAt, connectedAt } }` }) .then(this.assertAuthorization) } fetchWorkgroups() { return this.gql.query({ query: gql` query { workgroups { id, name, createdAt, closedAt, members { id } } }` }) .then(this.assertAuthorization) } updateProfile(changes: ProfileChanges) { return this.gql.mutate({ variables: { changes, }, mutation: gql` mutation updateProfile($changes: ProfileChanges!) { updateProfile(changes: $changes) { name, email, createdAt, connectedAt } }`, }) .then(this.assertAuthorization) } assertAuthorization({ status, data }: any) { if (status === 401) return Promise.reject(new UnauthorizedError()); return data; } }