import { ApolloLink , from , split } from "apollo-link" ; import { setContext } from "apollo-link-context" ; import * as URI from "urijs" ; import { ApolloCache } from "apollo-cache" ; import { InMemoryCache , NormalizedCacheObject } from "apollo-cache-inmemory" ; import ApolloClient from "apollo-client" ; import { createHttpLink } from "apollo-link-http" ; import { RetryLink } from "apollo-link-retry" ; import { WebSocketLink } from "apollo-link-ws" ; import { getMainDefinition } from "apollo-utilities" ; import * as fetch from "isomorphic-fetch" ; import * as ws from "isomorphic-ws" ; import { ConnectionParams } from "subscriptions-transport-ws" ; import { AccessToken , AuthenticationHelper } from "./AuthenticationHelper" ; import { User } from "./User" ; example export class GraphQLConfig { param user param realmPath param authErrorHandler param isQueryBasedSync returns public static async create ( user , realmPath , authErrorHandler ? , isQueryBasedSync ? ) { realmPath = realmPath . replace ( "/~/" , `/${ user . identity }/` ) ; if ( isQueryBasedSync ) { realmPath = `${ realmPath }/__partial/${ user . identity }/graphql-client` ; } const accessToken = await AuthenticationHelper . refreshAccessToken ( user , realmPath ) ; return new GraphQLConfig ( user , realmPath , accessToken , authErrorHandler ) ; } readonly example see https .
      public readonly httpEndpoint : string ; readonly example see https .
      public readonly webSocketEndpoint : string ; readonly example see https .
      public readonly connectionParams : ( ) => ConnectionParams ; readonly example see https * in the Apollo Client docs.
     *  see https .
      public readonly authLink : ApolloLink ; private readonly user : User ; private readonly authErrorHandler : ( error : any ) => boolean ; private readonly realmPath : string ; private token : string ; private constructor ( user , realmPath , accessToken , authErrorHandler ? ) { this . user = user ; this . authErrorHandler = authErrorHandler ; this . realmPath = realmPath ; this . token = accessToken . token ; if ( accessToken . expires ) { this . refreshToken ( accessToken . expires - Date . now ( ) - 10000 ) ; } const graphQLEndpoint = new URI ( user . server ) . segmentCoded ( [ "graphql" , realmPath ] ) ; this . httpEndpoint = graphQLEndpoint . toString ( ) ; let subscriptionScheme ; switch ( graphQLEndpoint . scheme ( ) ) { case "http" : subscriptionScheme = "ws" ; break ; case "https" : subscriptionScheme = "wss" ; break ; default : throw new Error ( `Unrecognized scheme for the server endpoint: ${ graphQLEndpoint . scheme ( ) }` ) ; } this . webSocketEndpoint = graphQLEndpoint . clone ( ) . scheme ( subscriptionScheme ) . toString ( ) ; this . connectionParams = ( ) => { if ( this . token ) { return { token : this . token , } ; } return { } ; } ; this . authLink = setContext ( ( _ , { headers } ) => { if ( this . token ) { return { headers : { ... headers , authorization : this . token , } , } ; } } ) ; } /**
     * Creates an Apollo client with InMemoryCache. The client will be configured with
     * an http link for query and mutation operations and a websocket link for subscriptions.
     */ public createApolloClient ( ) { return this . createApolloClientWithCache ( new InMemoryCache ( ) ) ; } param cache public createApolloClientWithCache < TCacheShape > ( cache ) { const httpLink = createHttpLink ( { uri : this . httpEndpoint , fetch , } ) ; const subscriptionLink = new WebSocketLink ( { uri : this . webSocketEndpoint , options : { connectionParams : this . connectionParams , reconnect : true , lazy : true , } , webSocketImpl : ws , } ) ; const retryLink = new RetryLink ( { delay : { initial : 100 , max : 5000 , } , attempts : { max : 3 , retryIf : async ( error ) => { if ( error && error . result && error . result . status === 401 ) { await this . refreshToken ( 0 , false ) ; } return true ; } , } , } ) ; const link = split ( ( { query } ) => { const { kind , operation } = getMainDefinition ( query ) ; return kind === "OperationDefinition" && operation === "subscription" ; } , subscriptionLink , from ( [ retryLink , this . authLink , httpLink ] ) ) ; return new ApolloClient ( { link , cache , } ) ; } param afterDelay param shouldRetry public async refreshToken ( afterDelay , shouldRetry = true ) { await this . delay ( afterDelay ) ; if ( ! this . user . token ) { return false ; } try { const result = await AuthenticationHelper . refreshAccessToken ( this . user , this . realmPath ) ; this . token = result . token ; this . refreshToken ( result . expires - Date . now ( ) - 10000 ) ; return true ; } catch ( e ) { if ( this . authErrorHandler ) { shouldRetry = ! this . authErrorHandler ( e ) && shouldRetry ; } if ( shouldRetry ) { return this . refreshToken ( 3000 ) ; } } return false ; } private delay ( ms ) { return new Promise ( ( resolve ) => { setTimeout ( resolve , ms ) ; } ) ; } }