202 lines
5.4 KiB
JavaScript
202 lines
5.4 KiB
JavaScript
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 query’s 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;
|