import { ApolloLink , Observable , Operation , NextLink } from '@apollo/client/core' ; import { DefinitionNode } from 'graphql' ; import TimeoutError from './TimeoutError' ; const DEFAULT_TIMEOUT = 15000 ; /**
 * Aborts the request if the timeout expires before the response is received.
 */ export default class TimeoutLink extends ApolloLink { private timeout : number ; private statusCode ? : number ; constructor ( timeout , statusCode ? ) { super ( ) ; this . timeout = timeout || DEFAULT_TIMEOUT ; this . statusCode = statusCode ; } public request ( operation , forward ) { let controller ; const requestTimeout = operation . getContext ( ) . timeout || this . timeout ; if ( typeof AbortController !== 'undefined' ) { const context = operation . getContext ( ) ; let fetchOptions = context . fetchOptions || { } ; controller = fetchOptions . controller || new AbortController ( ) ; fetchOptions = { ... fetchOptions , controller , signal : controller . signal } ; operation . setContext ( { fetchOptions } ) ; } const chainObservable = forward ( operation ) ; const operationType = ( operation . query . definitions as any ) . find ( ( def ) => def . kind === 'OperationDefinition' ) . operation ; if ( requestTimeout <= 0 || operationType === 'subscription' ) { return chainObservable ; } const localObservable = new Observable ( observer => { let timer ; const subscription = chainObservable . subscribe ( result => { clearTimeout ( timer ) ; observer . next ( result ) ; observer . complete ( ) ; } , error => { clearTimeout ( timer ) ; observer . error ( error ) ; observer . complete ( ) ; } ) ; timer = setTimeout ( ( ) => { if ( controller ) { controller . abort ( ) ; const context = operation . getContext ( ) ; let fetchOptions = context . fetchOptions || { } ; if ( fetchOptions . controller === controller && fetchOptions . signal === controller . signal ) { fetchOptions = { ... fetchOptions , controller : null , signal : null } ; operation . setContext ( { fetchOptions } ) ; } } observer . error ( new TimeoutError ( 'Timeout exceeded' , requestTimeout , this . statusCode ) ) ; subscription . unsubscribe ( ) ; } , requestTimeout ) ; let ctxRef = operation . getContext ( ) . timeoutRef ; if ( ctxRef ) { ctxRef ( { unsubscribe : ( ) => { clearTimeout ( timer ) ; subscription . unsubscribe ( ) ; } } ) ; } return ( ) => { clearTimeout ( timer ) ; subscription . unsubscribe ( ) ; } ; } ) ; return localObservable ; } }