2021-12-13 00:20:48 +08:00
|
|
|
import { createClient, defaultExchanges, dedupExchange, cacheExchange, fetchExchange, errorExchange, subscriptionExchange } from 'urql';
|
2021-04-18 18:54:07 +08:00
|
|
|
import { makeOperation } from '@urql/core';
|
2021-11-08 01:01:12 +08:00
|
|
|
import { devtoolsExchange } from '@urql/devtools'
|
2021-07-03 22:41:46 +08:00
|
|
|
import { authExchange } from '@urql/exchange-auth';
|
2021-04-18 18:54:07 +08:00
|
|
|
|
2022-02-06 03:36:45 +08:00
|
|
|
import { GQL_BASE_URL, WS_BASE_URL } from './conf'
|
2021-12-13 00:20:48 +08:00
|
|
|
|
|
|
|
import { createClient as createWSClient } from 'graphql-ws';
|
|
|
|
import { SubscriptionClient } from 'subscriptions-transport-ws'
|
2022-03-06 02:06:07 +08:00
|
|
|
import { authFromStorage, authLogout } from './auth';
|
2021-12-13 00:20:48 +08:00
|
|
|
|
2022-02-06 03:36:45 +08:00
|
|
|
const subscriptionClient = new SubscriptionClient( WS_BASE_URL, { reconnect: true });
|
2021-12-13 00:20:48 +08:00
|
|
|
|
|
|
|
const wsClient = createWSClient({
|
2022-02-06 03:36:45 +08:00
|
|
|
url: WS_BASE_URL,
|
2021-12-13 00:20:48 +08:00
|
|
|
});
|
2021-02-27 19:24:39 +08:00
|
|
|
|
2021-09-05 17:10:59 +08:00
|
|
|
// 1. get auth data
|
2021-11-08 01:01:12 +08:00
|
|
|
const getAuth = async ({ authState }) => {
|
|
|
|
|
2021-04-18 18:54:07 +08:00
|
|
|
if (!authState) {
|
2022-03-06 02:06:07 +08:00
|
|
|
const token = authFromStorage()?.token;
|
2021-04-18 18:54:07 +08:00
|
|
|
if (token) {
|
|
|
|
return { token };
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2021-11-08 01:01:12 +08:00
|
|
|
if(authState.token) {
|
|
|
|
return { token: authState.token };
|
|
|
|
}
|
|
|
|
|
2022-03-06 02:06:07 +08:00
|
|
|
authLogout();
|
2021-04-18 18:54:07 +08:00
|
|
|
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
|
2021-09-05 17:10:59 +08:00
|
|
|
// 2. add auth to all requests
|
2021-11-08 01:01:12 +08:00
|
|
|
const addAuthToOperation = ({ authState, operation }) => {
|
2021-04-18 18:54:07 +08:00
|
|
|
if (!authState || !authState.token) {
|
|
|
|
return operation;
|
|
|
|
}
|
|
|
|
|
|
|
|
const fetchOptions =
|
|
|
|
typeof operation.context.fetchOptions === 'function'
|
|
|
|
? operation.context.fetchOptions()
|
|
|
|
: operation.context.fetchOptions || {};
|
|
|
|
|
2021-07-03 22:41:46 +08:00
|
|
|
return makeOperation(operation?.kind, operation, {
|
2021-04-18 18:54:07 +08:00
|
|
|
...operation.context,
|
|
|
|
fetchOptions: {
|
|
|
|
...fetchOptions,
|
|
|
|
headers: {
|
|
|
|
...fetchOptions.headers,
|
2021-11-08 01:01:12 +08:00
|
|
|
Authorization: `Bearer ${authState.token}`,
|
2021-04-18 18:54:07 +08:00
|
|
|
},
|
2021-11-08 01:01:12 +08:00
|
|
|
credentials: 'include',
|
2021-04-18 18:54:07 +08:00
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const didAuthError = (error: any ) => {
|
2021-11-08 01:01:12 +08:00
|
|
|
if(!error.graphQLErrors|| error.graphQLErrors.length ===0){
|
|
|
|
return error.message == "[Network] Failed to fetch"
|
|
|
|
}
|
2021-04-18 18:54:07 +08:00
|
|
|
return error.graphQLErrors.some((e: any) => e.extensions?.code === 'FORBIDDEN');
|
|
|
|
};
|
|
|
|
|
|
|
|
const willAuthError = (authState: any) => {
|
|
|
|
if (!authState || "/* JWT is expired */") return true;
|
|
|
|
return false;
|
2021-07-03 22:41:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// https://github.com/FormidableLabs/urql/tree/main/exchanges/auth#quick-start-guide
|
|
|
|
export const urqlClient = createClient({
|
2022-02-06 03:36:45 +08:00
|
|
|
url: GQL_BASE_URL,
|
2021-11-08 01:01:12 +08:00
|
|
|
...(('process.env.DEV') && { exchanges: [devtoolsExchange, ...defaultExchanges] }),
|
|
|
|
exchanges: [
|
|
|
|
dedupExchange,
|
|
|
|
cacheExchange,
|
|
|
|
errorExchange({
|
|
|
|
onError: error => {
|
|
|
|
let isAuthError = false;
|
|
|
|
if(!error.graphQLErrors || error.graphQLErrors.length ===0){
|
|
|
|
isAuthError = error.message === "[Network] Failed to fetch";
|
|
|
|
}else{
|
|
|
|
isAuthError = error.graphQLErrors.some(e => e.extensions?.code === 'FORBIDDEN');
|
|
|
|
}
|
|
|
|
if (isAuthError) {
|
2022-03-06 02:06:07 +08:00
|
|
|
console.log("isAuthError")
|
|
|
|
authLogout();
|
2021-11-08 01:01:12 +08:00
|
|
|
}
|
2021-09-05 17:10:59 +08:00
|
|
|
},
|
2021-11-08 01:01:12 +08:00
|
|
|
}),
|
|
|
|
authExchange({
|
|
|
|
addAuthToOperation,
|
|
|
|
willAuthError,
|
|
|
|
didAuthError,
|
|
|
|
getAuth,
|
|
|
|
}),
|
2021-12-13 00:20:48 +08:00
|
|
|
fetchExchange,
|
|
|
|
subscriptionExchange({
|
|
|
|
// forwardSubscription: (operation) => ({
|
|
|
|
// subscribe: (sink: any) => ({
|
|
|
|
// unsubscribe: wsClient.subscribe(operation, sink),
|
|
|
|
// }),
|
|
|
|
// }),
|
|
|
|
forwardSubscription: operation => subscriptionClient.request(operation) as any
|
|
|
|
}),
|
2021-11-08 01:01:12 +08:00
|
|
|
],
|
2021-11-12 05:30:10 +08:00
|
|
|
fetchOptions: () => {
|
2022-03-06 02:06:07 +08:00
|
|
|
const token = authFromStorage()?.token;
|
2021-11-12 05:30:10 +08:00
|
|
|
return {
|
|
|
|
headers: {
|
|
|
|
'Access-Control-Allow-Origin': '*',
|
|
|
|
'Access-Control-Allow-Methods': 'GET, POST, PATCH, PUT, DELETE, OPTIONS',
|
|
|
|
'Access-Control-Allow-Headers': 'Origin, Content-Type, X-Auth-Token',
|
|
|
|
...(token && {
|
|
|
|
'x-felicity-user-id': "felicity-user",
|
|
|
|
'x-felicity-role': "felicity-administrator",
|
|
|
|
'Authorization': `Bearer ${token}`
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
};
|
2021-12-13 00:20:48 +08:00
|
|
|
},
|
2021-09-05 17:10:59 +08:00
|
|
|
});
|