{"version":3,"file":"http-fetch.mjs","sources":["../../src/graphql-client/http-fetch.ts"],"sourcesContent":["import {CLIENT, RETRIABLE_STATUS_CODES, RETRY_WAIT_TIME} from './constants';\nimport {CustomFetchApi, GraphQLClient, Logger} from './types';\nimport {formatErrorMessage, getErrorMessage} from './utilities';\n\nconst REDACTED_HEADER_VALUE = '****';\n\n// These headers carry reusable credentials and must not reach the logger.\n// Keep in sync with SENSITIVE_LOG_HEADERS in @shopify/shopify-api.\nconst SENSITIVE_HEADERS = new Set([\n  'authorization',\n  'cookie',\n  'set-cookie',\n  'shopify-storefront-private-token',\n  'x-shopify-access-token',\n  'x-shopify-storefront-access-token',\n]);\n\ninterface GenerateHttpFetchOptions {\n  clientLogger: Logger;\n  customFetchApi?: CustomFetchApi;\n  client?: string;\n  defaultRetryWaitTime?: number;\n  retriableCodes?: number[];\n}\n\nexport function generateHttpFetch({\n  clientLogger,\n  customFetchApi = fetch,\n  client = CLIENT,\n  defaultRetryWaitTime = RETRY_WAIT_TIME,\n  retriableCodes = RETRIABLE_STATUS_CODES,\n}: GenerateHttpFetchOptions) {\n  const httpFetch = async (\n    requestParams: Parameters<CustomFetchApi>,\n    count: number,\n    maxRetries: number,\n  ): ReturnType<GraphQLClient['fetch']> => {\n    const nextCount = count + 1;\n    const maxTries = maxRetries + 1;\n    const loggedRequestParams = redactRequestParams(requestParams);\n    let response: Response | undefined;\n\n    try {\n      response = await customFetchApi(...requestParams);\n\n      clientLogger({\n        type: 'HTTP-Response',\n        content: {\n          requestParams: loggedRequestParams,\n          response,\n        },\n      });\n\n      if (\n        !response.ok &&\n        retriableCodes.includes(response.status) &&\n        nextCount <= maxTries\n      ) {\n        throw new Error();\n      }\n\n      const deprecationNotice =\n        response?.headers.get('X-Shopify-API-Deprecated-Reason') || '';\n      if (deprecationNotice) {\n        clientLogger({\n          type: 'HTTP-Response-GraphQL-Deprecation-Notice',\n          content: {\n            requestParams: loggedRequestParams,\n            deprecationNotice,\n          },\n        });\n      }\n\n      return response;\n    } catch (error) {\n      if (nextCount <= maxTries) {\n        const retryAfter = response?.headers.get('Retry-After');\n        await sleep(\n          retryAfter ? parseInt(retryAfter, 10) : defaultRetryWaitTime,\n        );\n\n        clientLogger({\n          type: 'HTTP-Retry',\n          content: {\n            requestParams: loggedRequestParams,\n            lastResponse: response,\n            retryAttempt: count,\n            maxRetries,\n          },\n        });\n\n        return httpFetch(requestParams, nextCount, maxRetries);\n      }\n\n      throw new Error(\n        formatErrorMessage(\n          `${\n            maxRetries > 0\n              ? `Attempted maximum number of ${maxRetries} network retries. Last message - `\n              : ''\n          }${getErrorMessage(error)}`,\n          client,\n        ),\n      );\n    }\n  };\n\n  return httpFetch;\n}\n\nfunction redactRequestParams(\n  requestParams: Parameters<CustomFetchApi>,\n): Parameters<CustomFetchApi> {\n  const [url, init] = requestParams;\n  if (!init?.headers) {\n    return requestParams;\n  }\n\n  return [url, {...init, headers: redactHeaders(init.headers)}];\n}\n\nfunction redactHeaders(headers: HeadersInit): HeadersInit {\n  const redactValue = (name: string, value: string) =>\n    SENSITIVE_HEADERS.has(name.toLowerCase()) ? REDACTED_HEADER_VALUE : value;\n\n  if (Array.isArray(headers)) {\n    return headers.map(([name, value]) => [name, redactValue(name, value)]);\n  }\n\n  // Duck-typed so Headers from polyfills or other realms are handled too\n  if (typeof (headers as Headers).forEach === 'function') {\n    const redacted: Record<string, string> = {};\n    (headers as Headers).forEach((value, name) => {\n      redacted[name] = redactValue(name, value);\n    });\n    return typeof Headers === 'undefined' ? redacted : new Headers(redacted);\n  }\n\n  return Object.fromEntries(\n    Object.entries(headers).map(([name, value]) => [\n      name,\n      redactValue(name, value),\n    ]),\n  );\n}\n\nasync function sleep(waitTime: number): Promise<void> {\n  return new Promise((resolve) => setTimeout(resolve, waitTime));\n}\n"],"names":[],"mappings":"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"}