{"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import { mergeHeaders, normalizeHeaders } from '@md-oss/common/http';\nimport {\n\ttype CreateHTTPErrorOptions,\n\tHTTPError,\n} from '@md-oss/common/http/errors';\nimport { statusCodes } from '@md-oss/common/http/status-codes';\nimport type {\n\tHeadersInit,\n\tHTTPErrorResponse,\n\tHTTPResponse,\n} from '@md-oss/common/http/types';\nimport { RuntimeUtils } from '@md-oss/common/utils';\nimport { parseJson } from '@md-oss/serdes';\nimport {\n\tappendQuery,\n\tbuildUrl,\n\tparseErrorResponse,\n\tresolvePathParams,\n\tresolveRequestHeaders,\n\ttoBody,\n} from './resolvers';\nimport {\n\tDEFAULT_TIMEOUT_MS,\n\tdefaultRetryOptions,\n\tevaluateRetry,\n} from './retry';\nimport type {\n\tDefaultHeadersResolver,\n\tHTTPClientRequestOptions,\n\tHttpClientConfig,\n\tHttpRequestRetryOptions,\n} from './types';\n\nexport type {\n\tHeadersInit,\n\tHTTPErrorResponse,\n\tHTTPResponse,\n\tHTTPSuccessResponse,\n\tStatusCode,\n\tStatusCodeText,\n} from '@md-oss/common/http';\nexport {\n\tcreateHTTPError,\n\tcreateHTTPErrorResponse,\n\tHTTPError,\n\tisHTTPError,\n\tisHTTPErrorResponse,\n\tisStatusCodeText,\n\tmergeHeaders,\n\tnormalizeHeaders,\n\tparseError,\n\tparseHeaders,\n\tresolveStatusCode,\n\tresolveStatusText,\n\tstatusCodes,\n\tstripProxyAndWebsocketHeaders,\n} from '@md-oss/common/http';\nexport {\n\ttype JsonPrimitive,\n\ttype JsonValueLike,\n\ttype SerializedJson,\n\tserializeJson,\n} from '@md-oss/serdes';\nexport * from './resolvers';\nexport * from './retry';\nexport type * from './types';\n\nexport type HTTPClientResponse<\n\tT,\n\tR extends HTTPResponse<T>,\n> = R extends HTTPErrorResponse\n\t? HTTPErrorResponse & {\n\t\t\t/** The original Response object from the Fetch API (cloned). May be null if the error was due to a network failure. */\n\t\t\traw: Response | null;\n\t\t}\n\t: R & {\n\t\t\t/** The original Response object from the Fetch API (cloned). */\n\t\t\traw: Response;\n\t\t};\n\nconst createRequestError = <T>(\n\tbody: CreateHTTPErrorOptions,\n\tresponse: Response | null\n): HTTPClientResponse<T, HTTPErrorResponse> => {\n\treturn {\n\t\t...new HTTPError({\n\t\t\t...body,\n\t\t}).toJSON(),\n\t\traw: response,\n\t};\n};\n\nexport class HttpClient {\n\treadonly baseUrl: string;\n\treadonly serviceName: string;\n\treadonly defaultHeaders?: HeadersInit | DefaultHeadersResolver;\n\treadonly defaultRetryOptions?: HttpRequestRetryOptions;\n\n\tprivate readonly staticDefaultHeaders: Headers;\n\tprivate readonly defaultHeadersResolver?: DefaultHeadersResolver;\n\n\tconstructor(config: HttpClientConfig) {\n\t\tthis.baseUrl = buildUrl(config.baseUrl, null);\n\t\tthis.serviceName = config.serviceName;\n\t\tthis.defaultHeaders = config.defaultHeaders;\n\t\tthis.defaultRetryOptions = config.retryOptions;\n\n\t\tif (typeof config.defaultHeaders === 'function') {\n\t\t\tthis.defaultHeadersResolver = config.defaultHeaders;\n\t\t\tthis.staticDefaultHeaders = new Headers();\n\t\t} else {\n\t\t\tthis.defaultHeadersResolver = undefined;\n\t\t\tthis.staticDefaultHeaders = mergeHeaders(config.defaultHeaders);\n\t\t}\n\t}\n\n\tprivate async getDefaultHeaders(accessToken?: string) {\n\t\tif (this.defaultHeadersResolver) {\n\t\t\treturn this.defaultHeadersResolver({ accessToken });\n\t\t}\n\n\t\treturn this.staticDefaultHeaders;\n\t}\n\n\tasync request<T = unknown>(\n\t\tinput: string,\n\t\toptions: HTTPClientRequestOptions\n\t): Promise<HTTPClientResponse<T, HTTPResponse<T>>> {\n\t\tconst {\n\t\t\ttimeoutMs = DEFAULT_TIMEOUT_MS,\n\t\t\tretryOptions: requestRetryOptions,\n\t\t\tparseAs = 'json',\n\t\t\taccessToken,\n\t\t\tserviceName,\n\t\t\theaders,\n\t\t\tbody,\n\t\t\tquery,\n\t\t\tpathParams,\n\t\t\t...init\n\t\t} = options;\n\n\t\tconst retryOptions = {\n\t\t\t...defaultRetryOptions,\n\t\t\t...this.defaultRetryOptions,\n\t\t\t...requestRetryOptions,\n\t\t};\n\t\tconst maxRetryAttempts = retryOptions.enabled\n\t\t\t? Math.max(0, retryOptions.maxAttempts)\n\t\t\t: 1;\n\n\t\tconst resolvedServiceName = serviceName ?? this.serviceName;\n\t\tconst resolvedPath = resolvePathParams(input, pathParams);\n\t\tconst url = appendQuery(buildUrl(this.baseUrl, resolvedPath), query);\n\t\tconst method = (init.method ?? 'GET').toUpperCase();\n\t\tconst defaultHeaders = await this.getDefaultHeaders(accessToken);\n\t\tconst mergedHeaders = resolveRequestHeaders(\n\t\t\tmergeHeaders(defaultHeaders, headers),\n\t\t\tbody,\n\t\t\tparseAs\n\t\t);\n\n\t\tfor (let attempt = 0; attempt < maxRetryAttempts; attempt++) {\n\t\t\tconst controller = new AbortController();\n\t\t\tconst timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n\t\t\ttry {\n\t\t\t\tconst response = await fetch(url, {\n\t\t\t\t\t...init,\n\t\t\t\t\theaders: mergedHeaders,\n\t\t\t\t\tbody: toBody(body),\n\t\t\t\t\tsignal: controller.signal,\n\t\t\t\t});\n\t\t\t\tclearTimeout(timeout);\n\n\t\t\t\tconst responseClone = response.clone();\n\t\t\t\tconst responseFields = {\n\t\t\t\t\tstatusCode: response.status,\n\t\t\t\t\tstatusText: response.statusText,\n\t\t\t\t\theaders: normalizeHeaders(response.headers),\n\t\t\t\t\traw: responseClone,\n\t\t\t\t};\n\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tconst retryDecision = await evaluateRetry({\n\t\t\t\t\t\tresponse,\n\t\t\t\t\t\tattempt,\n\t\t\t\t\t\tmethod,\n\t\t\t\t\t\tinput,\n\t\t\t\t\t\tserviceName: resolvedServiceName,\n\t\t\t\t\t\trequest: options,\n\t\t\t\t\t\t...retryOptions,\n\t\t\t\t\t\tmaxAttempts: maxRetryAttempts,\n\t\t\t\t\t});\n\n\t\t\t\t\tif (retryDecision.retry) {\n\t\t\t\t\t\tawait RuntimeUtils.sleep(retryDecision.delayMs);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst errorBody = await parseErrorResponse(\n\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t`${resolvedServiceName} request failed (${response.status})`\n\t\t\t\t\t);\n\n\t\t\t\t\treturn createRequestError(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t...errorBody,\n\t\t\t\t\t\t\t...responseFields,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tresponse\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (parseAs === 'text') {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tdata: (await response.text()) as T,\n\t\t\t\t\t\t...responseFields,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tconst text = await response.text();\n\t\t\t\tif (!text) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tdata: undefined as T,\n\t\t\t\t\t\t...responseFields,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tdata: parseJson<T>(text),\n\t\t\t\t\t\t...responseFields,\n\t\t\t\t\t};\n\t\t\t\t} catch {\n\t\t\t\t\treturn createRequestError(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcode: 'INVALID_RESPONSE',\n\t\t\t\t\t\t\tmessage: `${resolvedServiceName} returned invalid JSON`,\n\t\t\t\t\t\t\t...responseFields,\n\t\t\t\t\t\t\tdetails: { responseText: text },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tresponse\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tclearTimeout(timeout);\n\n\t\t\t\tconst retryDecision = await evaluateRetry({\n\t\t\t\t\terror,\n\t\t\t\t\tattempt,\n\t\t\t\t\tmethod,\n\t\t\t\t\tinput,\n\t\t\t\t\tserviceName: resolvedServiceName,\n\t\t\t\t\trequest: options,\n\t\t\t\t\t...retryOptions,\n\t\t\t\t\tmaxAttempts: maxRetryAttempts,\n\t\t\t\t});\n\n\t\t\t\tif (retryDecision.retry) {\n\t\t\t\t\tawait RuntimeUtils.sleep(retryDecision.delayMs);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\treturn createRequestError(\n\t\t\t\t\t{\n\t\t\t\t\t\tcode: 'NETWORK_ERROR',\n\t\t\t\t\t\tmessage: `${resolvedServiceName} request failed due to a network error`,\n\t\t\t\t\t\tstatusCode: 0,\n\t\t\t\t\t\tstatusText: 'Network Error',\n\t\t\t\t\t\tdetails: {\n\t\t\t\t\t\t\toriginalError:\n\t\t\t\t\t\t\t\terror instanceof Error ? error.message : String(error),\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tnull\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn createRequestError(\n\t\t\t{\n\t\t\t\tcode: 'RETRIES_EXCEEDED',\n\t\t\t\tmessage: `${resolvedServiceName} request failed after retries`,\n\t\t\t\tstatusCode: statusCodes.SERVICE_UNAVAILABLE,\n\t\t\t\tstatusText: 'Service Unavailable',\n\t\t\t\tdetails: null,\n\t\t\t},\n\t\t\tnull\n\t\t);\n\t}\n}\n\nexport const createHttpClient = (config: HttpClientConfig) => {\n\treturn new HttpClient(config);\n};\n"],"names":["createRequestError","__name","body","response","HTTPError","HttpClient","config","buildUrl","mergeHeaders","accessToken","input","options","timeoutMs","DEFAULT_TIMEOUT_MS","requestRetryOptions","parseAs","serviceName","headers","query","pathParams","init","retryOptions","defaultRetryOptions","maxRetryAttempts","resolvedServiceName","resolvedPath","resolvePathParams","url","appendQuery","method","defaultHeaders","mergedHeaders","resolveRequestHeaders","attempt","controller","timeout","toBody","responseClone","responseFields","normalizeHeaders","retryDecision","evaluateRetry","RuntimeUtils","errorBody","parseErrorResponse","text","parseJson","error","statusCodes","createHttpClient"],"mappings":"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"}