Files
bodyshop/client/src/utils/GraphQLClient.js
2025-03-07 10:58:01 -05:00

202 lines
5.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 } from "@apollo/client/utilities";
//import { split } from "apollo-link";
import apolloLogger from "apollo-link-logger";
//import axios from "axios";
import { SentryLink } from "apollo-link-sentry";
import { auth } from "../firebase/firebase.utils";
import errorLink from "../graphql/apollo-error-handling";
//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: {
// Note: This is required because we switch from a read to an unread state with a toggle,
notifications: {
merge(existing = [], incoming = [], { readField }) {
// Create a map to deduplicate by __ref
const merged = new Map();
// Add existing items to retain cached data
existing.forEach((item) => {
const ref = readField("__ref", item);
if (ref) {
merged.set(ref, item);
}
});
// Add incoming items, overwriting duplicates
incoming.forEach((item) => {
const ref = readField("__ref", item);
if (ref) {
merged.set(ref, item);
}
});
// Return incoming to respect the current querys filter (e.g., unread-only or all)
return incoming;
}
}
}
}
}
});
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;