import { retryExchange } from '@urql/exchange-retry'; import { CONFIG } from 'config'; import { getTokenFromStore } from 'lib/auth'; import { initUrqlClient, NextComponentType, withUrqlClient, WithUrqlProps, } from 'next-urql'; import React, { createElement } from 'react'; import { cacheExchange, Client, CombinedError, createClient, // debugExchange, dedupExchange, fetchExchange, ssrExchange, } from 'urql'; const errorHasResponseTimeout = (err: CombinedError): boolean => err.graphQLErrors.length > 0 && !!err.graphQLErrors.find((e) => e.message === 'ResponseTimeout'); const retryExchangeFunc = retryExchange({ maxNumberAttempts: 5, initialDelayMs: 1000, randomDelay: true, retryIf: (error) => { console.debug('GraphQL Retry', { error }); // eslint-disable-line no-console return !!(errorHasResponseTimeout(error) || error.networkError); }, }); export const client = createClient({ url: CONFIG.graphqlURL, suspense: false, exchanges: [dedupExchange, cacheExchange, retryExchangeFunc, fetchExchange], }); export const getSsrClient = (): [Client, ReturnType] => { const ssrCache = ssrExchange({ isClient: false }); const ssrClient = initUrqlClient( { url: CONFIG.graphqlURL, exchanges: [ // debugExchange, dedupExchange, cacheExchange, ssrCache, retryExchangeFunc, fetchExchange, ], }, false, ); if (!ssrClient) throw new Error('wtf'); return [ssrClient, ssrCache]; }; // We do this to enable ssr cache on pages that are not directly wrapped in 'withUrqlClient' (but on _app) // https://github.com/FormidableLabs/urql/issues/1481 const customWithUrqlClient = ( WithUrql: NextComponentType, ): React.FC => ({ pageProps, urqlState, ...props }) => createElement(WithUrql, { urqlState: pageProps.urqlState || urqlState, pageProps, ...props, }); export const wrapUrqlClient = (AppOrPage: React.FC) => customWithUrqlClient( withUrqlClient( (_ssrExchange, ctx) => ({ url: CONFIG.graphqlURL, fetchOptions: () => { const token = ctx ? ctx?.req?.headers?.authorization : getTokenFromStore(); return { headers: { Authorization: token ? `Bearer ${token}` : '', }, }; }, }), { neverSuspend: true, ssr: false, }, )(AppOrPage), );