All files / scripts/instrumentor/patcher/fetch fetch.ts

89.28% Statements 25/28
90% Branches 9/10
100% Functions 2/2
89.28% Lines 25/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80                                                      29x           29x   29x 28x   28x 28x 28x   28x   28x 24x   24x 24x 23x 14x 14x       1x     28x   27x 27x 14x   14x 2x   12x             27x     29x    
import { PatcherContext } from '../context'
import { ProtectedApi } from '../../../../shared/types'
import { collectSignalsForProtectedUrl, injectSignalsIntoRequest } from '../signalsInjection'
import { resolvePatcherRequest } from './patcherRequest'
import { AGENT_DATA_HEADER } from '../../../../shared/const'
import { logger } from '../../../shared/logger'
 
/**
 * Parameters required for patching the fetch API.
 */
export type PatchFetchParams = {
  /** Array of protected APIs that should have signals attached to their requests */
  protectedApis: ProtectedApi[]
  /** Context object providing access to signals and other patcher functionality */
  ctx: PatcherContext
}
 
/**
 * Patches the global fetch API to automatically add Fingerprint signals to requests made to protected APIs.
 *
 * This function intercepts all fetch requests and checks if they target protected URLs. For protected
 * requests, it adds a signals' header before forwarding the request.
 *
 * @param ctx - Patcher context providing access to signals and other functionality
 *
 */
export function patchFetch(ctx: PatcherContext) {
  Iif (typeof window.fetch !== 'function') {
    logger.warn('window.fetch is not available.')
 
    return
  }
 
  const originalFetch = window.fetch
 
  window.fetch = async (...params) => {
    let signals: string | undefined = undefined
 
    let actualParams: Parameters<typeof fetch> = params
    try {
      logger.debug('Incoming fetch request', params)
 
      const result = resolvePatcherRequest(params)
 
      if (result) {
        const [request, updatedParams] = result
 
        logger.debug('Resolved fetch request and updated params:', request, updatedParams)
        signals = await collectSignalsForProtectedUrl({ request, ctx })
        if (signals) {
          injectSignalsIntoRequest(request, signals)
          actualParams = updatedParams
        }
      }
    } catch (error) {
      logger.error('Patched fetch error:', error)
    }
 
    const response = await originalFetch(...actualParams)
 
    try {
      if (signals) {
        const agentData = response.headers.get(AGENT_DATA_HEADER)
 
        if (agentData) {
          ctx.processAgentData(agentData)
        } else {
          logger.warn('Agent data not found in response')
        }
      }
    } catch (e) {
      logger.error('Error processing agent data:', e)
    }
 
    return response
  }
 
  logger.debug('Fetch patched successfully.')
}