import { commitLocalUpdate , Environment } from "react-relay" ; import { RecordProxy } from "relay-runtime" ; import { ManagedSubscriptionClient } from "../network" ; import { LOCAL_ID } from "../relay" ; import { PromisifiedStorage } from "../storage" ; import { Claims , computeExpiresIn , parseAccessTokenClaims } from "./helpers" ; /**
 * ACCESS_TOKEN_KEY is the key in storage where the accessToken is stored.
 */ const ACCESS_TOKEN_KEY = "v2:accessToken" ; export interface AuthState { /**
     * accessToken is the access token issued by the server.
     */ accessToken : string ; /**
     * claims are the parsed claims from the access token.
     */ claims : Claims ; } export type AccessTokenProvider = ( ) => string | undefined ; export function parseAccessToken ( accessToken ) { const claims = parseAccessTokenClaims ( accessToken ) ; if ( ! claims ) { return null ; } if ( claims . exp ) { const expiresIn = computeExpiresIn ( claims . exp ) ; if ( ! expiresIn ) { return null ; } } return { accessToken , claims } ; } export async function retrieveAccessToken ( localStorage ) { try { const accessToken = await localStorage . getItem ( ACCESS_TOKEN_KEY ) ; if ( ! accessToken ) { return ; } return parseAccessToken ( accessToken ) ; } catch ( err ) { console . error ( "could not get access token from storage" , err ) ; return ; } } export async function storeAccessTokenInLocalStorage ( localStorage , accessToken ) { const parsed = parseAccessToken ( accessToken ) ; if ( ! parsed ) { return null ; } try { await localStorage . setItem ( ACCESS_TOKEN_KEY , accessToken ) ; } catch ( err ) { console . error ( "could not set access token in storage" , err ) ; } return parsed ; } /**
 * Commits auth state to relay store.
 */ export function commitAuthState ( environment , auth ) { commitLocalUpdate ( environment , ( store ) => { const local = store . get ( LOCAL_ID ) ! ; setAuthStateInLocalRecord ( local , auth ) ; } ) ; } export function setAuthStateInLocalRecord ( local , auth ) { local . setValue ( auth ?. accessToken || null , "accessToken" ) ; local . setValue ( auth ?. claims . exp || null , "accessTokenExp" ) ; local . setValue ( auth ?. claims . jti || null , "accessTokenJTI" ) ; } export async function replaceAccessTokenOnTheFly ( environment , subscriptionClient , localStorage , accessToken , options = { } ) { const auth = options . ephemeral ? parseAccessToken ( accessToken ) : await storeAccessTokenInLocalStorage ( localStorage , accessToken ) ; if ( ! auth ) { return ; } subscriptionClient . pause ( ) ; commitAuthState ( environment , auth ) ; subscriptionClient . setAccessToken ( accessToken ) ; subscriptionClient . resume ( ) ; } export async function deleteAccessTokenFromLocalStorage ( localStorage ) { try { await localStorage . removeItem ( ACCESS_TOKEN_KEY ) ; } catch ( err ) { console . error ( "could not remove access token from storage" , err ) ; } return undefined ; }