import { ApolloClient, createHttpLink, from, InMemoryCache, Observable, } from '@apollo/client'; import { setContext } from '@apollo/client/link/context'; import { onError } from '@apollo/client/link/error'; import { RestLink } from 'apollo-link-rest'; import { CommentThreadTarget } from './generated/graphql'; import { getTokensFromRefreshToken } from './modules/auth/services/AuthService'; const apiLink = createHttpLink({ uri: `${process.env.REACT_APP_API_URL}`, }); const withAuthHeadersLink = setContext((_, { headers }) => { const token = localStorage.getItem('accessToken'); return { headers: { ...headers, authorization: token ? `Bearer ${token}` : '', }, }; }); const errorLink = onError(({ graphQLErrors, operation, forward }) => { if (graphQLErrors) { for (const err of graphQLErrors) { switch (err.extensions.code) { case 'UNAUTHENTICATED': return new Observable((observer) => { (async () => { try { await getTokensFromRefreshToken(); const oldHeaders = operation.getContext().headers; operation.setContext({ headers: { ...oldHeaders, authorization: `Bearer ${localStorage.getItem( 'accessToken', )}`, }, }); const subscriber = { next: observer.next.bind(observer), error: observer.error.bind(observer), complete: observer.complete.bind(observer), }; forward(operation).subscribe(subscriber); } catch (error) { observer.error(error); } })(); }); } } } }); export const apiClient = new ApolloClient({ link: from([errorLink, withAuthHeadersLink, apiLink]), cache: new InMemoryCache({ typePolicies: { CommentThread: { fields: { commentThreadTargets: { merge( existing: CommentThreadTarget[] = [], incoming: CommentThreadTarget[], ) { return [...incoming]; }, }, }, }, }, }), defaultOptions: { query: { fetchPolicy: 'cache-first', }, }, }); const authLink = new RestLink({ uri: `${process.env.REACT_APP_AUTH_URL}`, credentials: 'same-origin', }); export const authClient = new ApolloClient({ link: authLink, cache: new InMemoryCache(), });