import { ApolloLink , Operation , NextLink , FetchResult , Observable , } from 'apollo-link' ; export class DedupLink extends ApolloLink { private inFlightRequestObservables : Map < string , Observable < FetchResult > > = new Map ( ) ; private subscribers : Map < string , any > = new Map ( ) ; public request ( operation , forward ) { if ( operation . getContext ( ) . forceFetch ) { return forward ( operation ) ; } const key = operation . toKey ( ) ; if ( ! this . inFlightRequestObservables . get ( key ) ) { const singleObserver = forward ( operation ) ; let subscription ; const sharedObserver = new Observable ( observer => { if ( ! this . subscribers . has ( key ) ) this . subscribers . set ( key , new Set ( ) ) ; this . subscribers . get ( key ) . add ( observer ) ; if ( ! subscription ) { subscription = singleObserver . subscribe ( { next : result => { const subscribers = this . subscribers . get ( key ) ; this . subscribers . delete ( key ) ; this . inFlightRequestObservables . delete ( key ) ; if ( subscribers ) { subscribers . forEach ( obs => obs . next ( result ) ) ; subscribers . forEach ( obs => obs . complete ( ) ) ; } } , error : error => { const subscribers = this . subscribers . get ( key ) ; this . subscribers . delete ( key ) ; this . inFlightRequestObservables . delete ( key ) ; if ( subscribers ) { subscribers . forEach ( obs => obs . error ( error ) ) ; } } , } ) ; } return ( ) => { if ( this . subscribers . has ( key ) ) { this . subscribers . get ( key ) . delete ( observer ) ; if ( this . subscribers . get ( key ) . size === 0 ) { this . inFlightRequestObservables . delete ( key ) ; if ( subscription ) subscription . unsubscribe ( ) ; } } } ; } ) ; this . inFlightRequestObservables . set ( key , sharedObserver ) ; } return this . inFlightRequestObservables . get ( key ) ; } }