import { ITelemetryLogger } from "@fluidframework/common-definitions" ; import { assert , delay } from "@fluidframework/common-utils" ; import { canRetryOnError , getRetryDelayFromError , NonRetryableError } from "@fluidframework/driver-utils" ; import { PerformanceEvent } from "@fluidframework/telemetry-utils" ; import { DriverErrorType } from "@fluidframework/driver-definitions" ; import { IOdspUrlParts , OdspResourceTokenFetchOptions , IdentityType , TokenFetcher , tokenFromResponse , } from "@fluidframework/odsp-driver-definitions" ; import { getUrlAndHeadersWithAuth } from "./getUrlAndHeadersWithAuth" ; import { fetchHelper , getWithRetryForTokenRefresh } from "./odspUtils" ; const fileLinkCache = new Map < string , Promise < string > > ( ) ; param getToken param siteUrl param driveId param itemId param identityType param logger returns export async function getFileLink ( getToken , odspUrlParts , identityType , logger ) { const cacheKey = `${ odspUrlParts . siteUrl }_${ odspUrlParts . driveId }_${ odspUrlParts . itemId }` ; const maybeFileLinkCacheEntry = fileLinkCache . get ( cacheKey ) ; if ( maybeFileLinkCacheEntry !== undefined ) { return maybeFileLinkCacheEntry ; } const valueGenerator = async function ( ) { let result ; let success = false ; let retryAfterMs = 1000 ; do { try { result = await getFileLinkCore ( getToken , odspUrlParts , identityType , logger ) ; success = true ; } catch ( err ) { if ( ! canRetryOnError ( err ) ) { fileLinkCache . delete ( cacheKey ) ; throw err ; } retryAfterMs = getRetryDelayFromError ( err ) ?? Math . min ( retryAfterMs * 2 , 8000 ) ; await delay ( retryAfterMs ) ; } } while ( ! success ) ; assert ( result !== undefined , 0x292 ) ; return result ; } ; const fileLink = valueGenerator ( ) ; fileLinkCache . set ( cacheKey , fileLink ) ; return fileLink ; } async function getFileLinkCore ( getToken , odspUrlParts , identityType , logger ) { const fileItem = await getFileItemLite ( getToken , odspUrlParts , logger ) ; if ( identityType === "Consumer" ) { return fileItem . webUrl ; } return PerformanceEvent . timedExecAsync ( logger , { eventName : "odspFileLink" , requestName : "getSharingInformation" } , async ( event ) => { let attempts = 0 ; let additionalProps ; const fileLink = await getWithRetryForTokenRefresh ( async ( options ) => { attempts ++ ; const token = await getToken ( { ... options , ... odspUrlParts } ) ; const { url , headers } = getUrlAndHeadersWithAuth ( `${ odspUrlParts . siteUrl }/_api/web/GetFileByUrl(@a1)/ListItemAllFields/GetSharingInformation?@a1=${ encodeURIComponent ( `'${ fileItem . webDavUrl }'` ) }` , tokenFromResponse ( token ) ) ; const requestInit = { method : "POST" , headers : { "Content-Type" : "application/json;odata=verbose" , "Accept" : "application/json;odata=verbose" , ... headers } } ; const response = await fetchHelper ( url , requestInit ) ; additionalProps = response . commonSpoHeaders ; const sharingInfo = await response . content . json ( ) ; const directUrl = sharingInfo ?. d ?. directUrl ; if ( typeof directUrl !== "string" ) { throw new NonRetryableError ( "getFileLinkCoreMalformedResponse" , "Malformed GetSharingInformation response" , DriverErrorType . incorrectServerResponse ) ; } return directUrl ; } ) ; event . end ( { ... additionalProps , attempts } ) ; return fileLink ; } ) ; } /**
 * This represents a lite version of file item containing only the webUrl and webDavUrl properties
 */ interface FileItemLite { webUrl : string ; webDavUrl : string ; } const isFileItemLite = ( maybeFileItemLite ) : maybeFileItemLite is FileItemLite => { if ( typeof maybeFileItemLite . webUrl !== "string" || typeof maybeFileItemLite . webDavUrl !== "string" ) { return false ; } return true ; } ; async function getFileItemLite ( getToken , odspUrlParts , logger ) { return PerformanceEvent . timedExecAsync ( logger , { eventName : "odspFileLink" , requestName : "getFileItemLite" } , async ( event ) => { let attempts = 0 ; let additionalProps ; const fileItem = await getWithRetryForTokenRefresh ( async ( options ) => { attempts ++ ; const { siteUrl , driveId , itemId } = odspUrlParts ; const token = await getToken ( { ... options , siteUrl , driveId , itemId } ) ; const { url , headers } = getUrlAndHeadersWithAuth ( `${ siteUrl }/_api/v2.0/drives/${ driveId }/items/${ itemId }?select=webUrl,webDavUrl` , tokenFromResponse ( token ) ) ; const requestInit = { method : "GET" , headers } ; const response = await fetchHelper ( url , requestInit ) ; additionalProps = response . commonSpoHeaders ; const responseJson = await response . content . json ( ) ; if ( ! isFileItemLite ( responseJson ) ) { throw new NonRetryableError ( "getFileItemLiteMalformedResponse" , "Malformed getFileItemLite response" , DriverErrorType . incorrectServerResponse ) ; } return responseJson ; } ) ; event . end ( { ... additionalProps , attempts } ) ; return fileItem ; } ) ; }