import React from "react"; import ReactDOM from "react-dom"; import ApolloClient from "apollo-client"; import { ApolloProvider } from "@apollo/react-hooks"; import { ApolloLink, fromPromise, Observable } from "apollo-link"; import { onError } from "apollo-link-error"; // import "./index.css"; import App from "./App"; import * as serviceWorker from "./serviceWorker"; import { createUploadLink } from "apollo-upload-client"; import { setContext } from "apollo-link-context"; import { InMemoryCache } from "apollo-cache-inmemory"; import "./assets/main.css"; // import { signOut } from "./components/Auth"; import { getToken, getRefreshToken, getNewToken } from "./constants/token"; const API_URL = process.env.REACT_APP_API_URL; const httpLink = createUploadLink({ uri: API_URL ? API_URL : "/graphql", credentials: "omit", }); const authLink = setContext((_, { headers }) => { // get the authentication token from local storage if it exists const token = localStorage.getItem("token"); console.log("Token in auth link: ", token); return { headers: { ...headers, authorization: token ? `JWT ${token}` : "", }, }; }); let isRefreshing = false; let pendingRequests = []; const resolvePendingRequests = () => { pendingRequests.map((callback) => callback()); pendingRequests = []; }; // const getAndStoreToken = () => new Promise const errorLink = onError( ({ graphQLErrors, networkError, operation, forward, location, ...other }) => { console.log("On error"); console.log(graphQLErrors, networkError, other); // TODO --- On error message invalid token clear local storage if (graphQLErrors && graphQLErrors.filter((e) => e).length > 0) { console.log("Errors: ", graphQLErrors); graphQLErrors.map(({ message, status }) => { console.log("Message: ", message); console.log("Status: ", status); console.log("Location: ", location); if (message.includes("You do not have permission")) { const token = getToken(); const refreshToken = getRefreshToken(); console.log("Token, refresh", token, refreshToken); if (token && refreshToken) { console.log("In if condition"); // error code is set to UNAUTHENTICATED // when AuthenticationError thrown in resolver let forward$; if (!isRefreshing) { isRefreshing = true; forward$ = fromPromise( getNewToken(client) .then(({ data: { refreshToken } }) => { console.log("Promise data: ", refreshToken); // localStorage.setItem("token", refreshToken.token); // localStorage.setItem( // "refreshToken", // refreshToken.refreshToken // ); resolvePendingRequests(); return refreshToken.token; }) .catch((error) => { // Handle token refresh errors e.g clear stored tokens, redirect to login, ... console.log("Error after setting token: ", error); pendingRequests = []; return; }) .finally(() => { console.log("Finally"); isRefreshing = false; }) ).filter((value) => { console.log("In Filter: ", value); return Boolean(value); }); } else { // Will only emit once the Promise is resolved forward$ = fromPromise( new Promise((resolve) => { pendingRequests.push(() => resolve()); }) ); } return forward$.flatMap(() => { console.log("Forwarding!"); return forward(operation); }); } // else { // // If there's no token, then sign out user // console.log("There's no token, sign out the user", signOut); // signOut(); // } } }); } if (networkError) { console.log("Network error: ", networkError); } } ); const links = [errorLink, authLink, httpLink]; const link = ApolloLink.from(links); export const client = new ApolloClient({ link, cache: new InMemoryCache(), fetchOptions: { mode: "no-cors", }, }); ReactDOM.render( , document.getElementById("root") ); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA serviceWorker.unregister();