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

100% Statements 28/28
100% Branches 14/14
100% Functions 6/6
100% Lines 28/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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100                                      28x 15x 15x     15x 1x     14x       13x 3x 3x     3x 1x     2x       10x 9x     9x 1x     8x 8x           6x 6x 6x       6x             1x   1x             16x 16x           8x       8x            
import { logger } from '../../../shared/logger'
import { PatcherRequest } from '../types'
import { resolveRequestInitMethod, setHeaderForRequestInit, setIncludeCredentialsForRequestInit } from './requestInit'
 
/**
 * Resolves fetch parameters into a standardized PatcherRequest object.
 *
 * Supports three types of fetch calls:
 * - fetch(url, requestInit) - URL as string
 * - fetch(urlObject, requestInit) - URL as URL object
 * - fetch(request) - Request object
 *
 * @param params - The parameters passed to the fetch function by the app.
 * @returns A `PatcherRequest` and the parameters to pass to the actual fetch invocation, or undefined if patching is unsupported.
 */
export function resolvePatcherRequest(
  params: Parameters<typeof fetch>
): [PatcherRequest, Parameters<typeof fetch>] | undefined {
  // fetch("https://example.com", {...})
  if (typeof params[0] === 'string') {
    const url = params[0]
    const requestInit = params[1]
 
    // no-cors mode requests disallow custom headers: https://developer.mozilla.org/en-US/docs/Web/API/RequestInit#mode
    if (requestInit?.mode === 'no-cors') {
      return undefined
    }
 
    return resolveRequestInitPatcherRequest(url, requestInit)
  }
 
  // fetch(new URL("https://example.com", window.location.href), {...})
  if (params[0] instanceof URL) {
    const url = params[0]
    const requestInit = params[1]
 
    // no-cors mode requests disallow custom headers: https://developer.mozilla.org/en-US/docs/Web/API/RequestInit#mode
    if (requestInit?.mode === 'no-cors') {
      return undefined
    }
 
    return resolveRequestInitPatcherRequest(url, requestInit)
  }
 
  // fetch({url: "https://example.com", method: "POST"})
  if (params[0] instanceof Request) {
    const request = params[0]
 
    // no-cors mode requests disallow custom headers: https://developer.mozilla.org/en-US/docs/Web/API/RequestInit#mode
    if (request.mode === 'no-cors') {
      return undefined
    }
 
    const updatedParams: [Request] = [request]
    return [
      {
        url: request.url.toString(),
        method: request.method,
 
        setIncludeCredentials() {
          const appIncludedCredentials = updatedParams[0].credentials === 'include'
          updatedParams[0] = new Request(request, { credentials: 'include' })
          return appIncludedCredentials
        },
 
        setHeader(name, value) {
          updatedParams[0].headers.set(name, value)
        },
      },
      updatedParams,
    ]
  }
 
  logger.warn('Unsupported fetch request', params)
 
  return undefined
}
 
function resolveRequestInitPatcherRequest(
  url: string | URL,
  requestInit?: RequestInit
): [PatcherRequest, Parameters<typeof fetch>] {
  const updatedParams: [string | URL, RequestInit] = [url, requestInit ? { ...requestInit } : {}]
  return [
    {
      url: url.toString(),
      method: resolveRequestInitMethod(updatedParams[1]),
 
      setIncludeCredentials() {
        return setIncludeCredentialsForRequestInit(updatedParams[1])
      },
 
      setHeader(name, value) {
        setHeaderForRequestInit(name, value, updatedParams[1])
      },
    },
    updatedParams,
  ]
}