import {ApolloClient, ApolloLink, InMemoryCache, split} from "@apollo/client"; import {setContext} from "@apollo/client/link/context"; import {HttpLink} from "@apollo/client/link/http"; //"apollo-link-http"; import {RetryLink} from "@apollo/client/link/retry"; import {WebSocketLink} from "@apollo/client/link/ws"; import {getMainDefinition, offsetLimitPagination,} from "@apollo/client/utilities"; //import { split } from "apollo-link"; import apolloLogger from "apollo-link-logger"; //import axios from "axios"; import {auth} from "../firebase/firebase.utils"; import errorLink from "../graphql/apollo-error-handling"; import {SentryLink} from "apollo-link-sentry"; //import { store } from "../redux/store"; const httpLink = new HttpLink({ uri: import.meta.env.VITE_APP_GRAPHQL_ENDPOINT, }); const wsLink = new WebSocketLink({ uri: import.meta.env.VITE_APP_GRAPHQL_ENDPOINT_WS, options: { lazy: true, reconnect: true, connectionParams: async () => { const token = auth.currentUser && (await auth.currentUser.getIdToken()); if (token) { return { headers: { authorization: token ? `Bearer ${token}` : "", }, }; } }, }, }); const roundTripLink = new ApolloLink((operation, forward) => { // Called before operation is sent to server operation.setContext({start: new Date()}); return forward(operation).map((data) => { // Called after server responds const time = new Date() - operation.getContext().start; // console.log( // `Operation ${operation.operationName} took ${time} to complete` // ); TrackExecutionTime(operation.operationName, time); return data; }); }); const TrackExecutionTime = async (operationName, time) => { // if (process.env.NODE_ENV === "development") return; // const rdxStore = store.getState(); // try { // axios.post("/ioevent", { // operationName, // time, // dbevent: true, // user: // rdxStore.user && // rdxStore.user.currentUser && // rdxStore.user.currentUser.email, // imexshopid: // rdxStore.user && // rdxStore.user.bodyshop && // rdxStore.user.bodyshop.imexshopid, // }); // } catch (error) { // console.log("IOEvent Error", error); // } }; const subscriptionMiddleware = { applyMiddleware: async (options, next) => { options.authToken = auth.currentUser && (await auth.currentUser.getIdToken()); next(); }, }; wsLink.subscriptionClient.use([subscriptionMiddleware]); const link = split( // split based on operation type ({query}) => { const definition = getMainDefinition(query); // console.log( // "##Intercepted GQL Transaction : " + // definition.operation + // "|" + // definition.name.value + // "##", // query // ); return ( definition.kind === "OperationDefinition" && definition.operation === "subscription" ); }, wsLink, httpLink ); const authLink = setContext((_, {headers}) => { return ( auth.currentUser && auth.currentUser .getIdToken() .then((token) => { if (token) { return { headers: { ...headers, authorization: token ? `Bearer ${token}` : "", }, }; } else { console.error( "Authentication error. Unable to add authorization token because it was empty." ); return {headers}; } }) .catch((error) => { console.error( "Authentication error. Unable to add authorization token.", error.message ); return {headers}; }) ); }); const retryLink = new RetryLink({ delay: { initial: 500, max: 5, jitter: true, }, attempts: { max: 5, retryIf: (error, _operation) => !!error, }, }); const middlewares = []; if (import.meta.env.DEV) { middlewares.push(apolloLogger); } middlewares.push( new SentryLink().concat( roundTripLink.concat( retryLink.concat(errorLink.concat(authLink.concat(link))) ) ) ); const cache = new InMemoryCache({ typePolicies: { Query: { fields: { conversations: offsetLimitPagination(), }, }, }, }); const client = new ApolloClient({ link: ApolloLink.from(middlewares), cache, connectToDevTools: import.meta.env.DEV, defaultOptions: { watchQuery: { fetchPolicy: "network-only", nextFetchPolicy: "network-only", errorPolicy: "ignore", }, query: { fetchPolicy: "network-only", errorPolicy: "all", }, mutate: { errorPolicy: "all", }, }, }); export default client;