@autofleet/rapido-http-client 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ Object.defineProperty(exports,`__esModule`,{value:!0});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));const c=require(`./utils-B1ZhSXeE.cjs`);let l=require(`undici`);l=s(l);let u=require(`@autofleet/outbreak`);const d=Symbol.for(`RapidoHttpClientErrorBrand`);let f;(function(e){e.UndiciError=l.errors.UndiciError,e.ConnectTimeoutError=l.errors.ConnectTimeoutError,e.HeadersTimeoutError=l.errors.HeadersTimeoutError,e.HeadersOverflowError=l.errors.HeadersOverflowError,e.BodyTimeoutError=l.errors.BodyTimeoutError,e.ResponseError=l.errors.ResponseError,e.InvalidArgumentError=l.errors.InvalidArgumentError,e.InvalidReturnValueError=l.errors.InvalidReturnValueError,e.RequestAbortedError=l.errors.RequestAbortedError,e.InformationalError=l.errors.InformationalError,e.RequestContentLengthMismatchError=l.errors.RequestContentLengthMismatchError,e.ResponseContentLengthMismatchError=l.errors.ResponseContentLengthMismatchError,e.ClientDestroyedError=l.errors.ClientDestroyedError,e.ClientClosedError=l.errors.ClientClosedError,e.SocketError=l.errors.SocketError,e.NotSupportedError=l.errors.NotSupportedError,e.BalancedPoolMissingUpstreamError=l.errors.BalancedPoolMissingUpstreamError,e.HTTPParserError=l.errors.HTTPParserError,e.ResponseExceededMaxSizeError=l.errors.ResponseExceededMaxSizeError,e.RequestRetryError=l.errors.RequestRetryError,e.SecureProxyConnectionError=l.errors.SecureProxyConnectionError,e.MaxOriginsReachedError=l.errors.MaxOriginsReachedError;function t(e){return typeof e==`object`&&!!e&&d in e}e.isRapidoHttpClientError=t;class n extends l.errors.ResponseError{constructor(e,t,n){super(`HTTP Error ${t.statusCode}`,t.statusCode,{headers:t.headers,body:e}),this.response=t,this.data=n,this.status=t.statusCode,Object.defineProperty(this,d,{value:!0,enumerable:!1,writable:!1})}static isRapidoHttpClientError(e){return t(e)}}e.RapidoHttpClientError=n})(f||={});const p=Symbol(`testAgentParam`),m=e=>function(t,n){let r=(0,u.getCurrentContext)().context;if(r){let e;e=Array.isArray(t.headers)?Object.fromEntries(t.headers):{...t.headers};for(let[t,n]of r)typeof n==`symbol`||n===void 0||(e[t]=n);t.headers=e}return e(t,n)},{cacheStores:h}=l.default,{cache:g,retry:_,decompress:v}=l.interceptors,y=[`GET`,`HEAD`,`OPTIONS`,`PUT`,`DELETE`,`TRACE`,`QUERY`];var b=class{#e;get(e,t){return this.#i(`GET`,e,void 0,t)}post(e,t,n){return this.#i(`POST`,e,t,n)}delete(e,t){return this.#i(`DELETE`,e,void 0,t)}head(e,t){return this.#i(`HEAD`,e,void 0,t)}put(e,t,n){return this.#i(`PUT`,e,t,n)}patch(e,t,n){return this.#i(`PATCH`,e,t,n)}options(e,t){return this.#i(`OPTIONS`,e,void 0,t)}query(e,t,n){return this.#i(`QUERY`,e,t,n)}constructor(e){this.#e=e.logger,this.settings=c.o(e.autoDecompress?c.i:c.r,e),this.#t();let t=globalThis.__RAPIDO_HTTP_CLIENT_MOCK_AGENT__;this.client=this.settings[p]??t??new l.Agent({connect:{timeout:this.settings.timeout},keepAliveTimeout:this.settings.keepAliveTimeout,keepAliveMaxTimeout:this.settings.keepAliveMaxTimeout,connections:this.settings.connections}),this.settings.cache&&(this.client=this.client.compose(g({store:new h.MemoryCacheStore({...this.settings.cache})}))),this.settings.retries&&(this.client=this.client.compose(_({methods:y,...this.settings.retries,retry:(e,t,n)=>{let{counter:r}=t.state,i=t.opts.retryOptions?.maxRetries??5;(this.settings.retries?.retry??c.n)(e,t,t=>{t||this.#e.warn(`Request retry attempt ${r}/${i}`,{err:e}),n(t)})}}))),this.settings.autoDecompress&&(this.client=this.client.compose(v({skipErrorResponses:!1}))),this.client=this.client.compose(m)}#t(){let e=c.c(this.settings),t=new URL(e);this.settings.baseURL=t.origin,this.settings.basePath=t.pathname===`/`?``:t.pathname}#n(e,t){if(!e&&!t)return{signal:void 0,timeoutSignal:void 0};if(e&&!t)return{signal:e,timeoutSignal:void 0};let n=AbortSignal.timeout(t);return!e&&t?{signal:n,timeoutSignal:n}:{signal:AbortSignal.any([e,n]),timeoutSignal:n}}#r(e,t){if(e!=null){if(c.a(e))return!t[`Content-Type`]&&!t[`content-type`]&&(t[`Content-Type`]=`application/x-www-form-urlencoded`),e;if(typeof e==`object`&&!Buffer.isBuffer(e)){let n=t[`Content-Type`]||t[`content-type`];if(n&&/application\/x-www-form-urlencoded/i.test(n)){let t=new URLSearchParams;for(let[n,r]of Object.entries(e))Array.isArray(r)?r.forEach(e=>t.append(n,String(e))):r!=null&&t.append(n,String(r));return t.toString()}return!t[`Content-Type`]&&!t[`content-type`]&&(t[`Content-Type`]=`application/json`),JSON.stringify(e)}else if(typeof e==`string`)return e;else if(Buffer.isBuffer(e))return e;return String(e)}}async#i(e,t,n,r={}){let i=c.o(this.settings,r);if(i.signal?.aborted)throw this.#e.error(`Request aborted before start: ${c.t(e,i.baseURL,t)}`),new f.RequestAbortedError(i.signal.reason?.message||`Request aborted`,{cause:i.signal.reason});let a={...i.headers},o=this.#r(n,a),{origin:s,path:l}=c.s(t,i.baseURL,i.basePath),u={method:e,baseURL:s,url:t};if(i.params)for(let[e,t]of Object.entries(i.params))Array.isArray(t)&&!e.endsWith(`[]`)&&(i.params[`${e}[]`]=t,delete i.params[e]);let{signal:d,timeoutSignal:p}=this.#n(i.signal,i.timeout);try{this.#e.info(`Start Request: ${c.t(e,s,l)}`);let t={path:l,origin:s,method:e,signal:d,headers:a,body:o,query:i.params},n=await this.client.request(t);if(n.statusCode>=400){let t=await this.#a(n,r.responseSchema);throw this.#e.error(`Finish Request with error ${c.t(e,s,l)}`,{status:n.statusCode,data:t}),new f.RapidoHttpClientError(o,n,t)}return this.#e.info(`Finish Request: ${c.t(e,s,l)}`),{data:n.statusCode===204?void 0:await this.#a(n,r.responseSchema),status:n.statusCode,statusText:``,headers:n.headers,config:u}}catch(t){if(p&&p.reason===t){this.#e.error(`Request timeout: ${c.t(e,s,l)}`);let t=new f.UndiciError(`Request timeout after ${i.timeout}ms`,{cause:p.reason});throw t.code=`UND_ERR_TIMEOUT`,t}throw d&&d.reason===t?(this.#e.error(`Request aborted: ${c.t(e,s,l)}`),new f.RequestAbortedError(d.reason.message,{cause:d.reason})):(this.#e.error(`Finish Request with error ${c.t(e,s,l)}`,{error:t}),t)}}async#a(e,t){let n=e.headers[`content-type`]||``,r=await e.body.text();if(!r)return;if(/text/i.test(n))return r;let i;try{i=JSON.parse(r)}catch{return r}return t?t.parse(i):i}async getAllPages(e,t={}){let n=[],r=null,i=null,a={...t,params:{...t.params,page:1}};for(a.params.page||=1;(a.params.page===1||i===r)&&i!==0;){let{data:t}=await this.get(e,a);i=t.length,a.params.page===1&&(r=t.length),a.params.page+=1,Array.prototype.push.apply(n,t)}return n}async getAllPagesFromQueryEndpoint(e,t={},n=100){let r=[],i=!0,a=1;for(;i&&(n===-1||a<n);){let{data:n}=await this.post(e,{...t,page:a}),{rows:o,count:s}=n;a+=1,Array.prototype.push.apply(r,o),i=r.length<s}return r}async close(){await this.client.close()}async[Symbol.asyncDispose](){await this.close()}},x=b;exports.RapidoHttpClient=b,exports.default=x,Object.defineProperty(exports,`errors`,{enumerable:!0,get:function(){return f}}),exports.t=s;
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["undiciErrors","response: Dispatcher.ResponseData","data: T","testAgentParam: unique symbol","outbreakInterceptor: Dispatcher.DispatcherComposeInterceptor","headers: Record<string, string | string[]>","Undici","interceptors","retriableMethods: Dispatcher.HttpMethod[]","#logger","#request","mergeConfig","defaultSettingsWithDecompress","defaultSettings","#createBaseUrl","Agent","defaultRetryMethod","resolveServiceUrl","isFormData","createRequestString","headers: Record<string, string>","#prepareRequestBody","parseUrlAndOrigin","#getSignal","requestOptions: Dispatcher.RequestOptions","#parseResponse","error","json: unknown","currentResult: T[]","resultsInFirstPage: number | null","lastResultsSize: number | null"],"sources":["../src/errors.ts","../src/testingHelper.ts","../src/outbreakInterceptor.ts","../src/index.ts"],"sourcesContent":["import { type Dispatcher, errors as undiciErrors } from 'undici';\n\nconst RapidoHttpClientErrorBrand = Symbol.for('RapidoHttpClientErrorBrand');\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace errors {\n export import UndiciError = undiciErrors.UndiciError;\n export import ConnectTimeoutError = undiciErrors.ConnectTimeoutError;\n export import HeadersTimeoutError = undiciErrors.HeadersTimeoutError;\n export import HeadersOverflowError = undiciErrors.HeadersOverflowError;\n export import BodyTimeoutError = undiciErrors.BodyTimeoutError;\n export import ResponseError = undiciErrors.ResponseError;\n export import InvalidArgumentError = undiciErrors.InvalidArgumentError;\n export import InvalidReturnValueError = undiciErrors.InvalidReturnValueError;\n export import RequestAbortedError = undiciErrors.RequestAbortedError;\n export import InformationalError = undiciErrors.InformationalError;\n export import RequestContentLengthMismatchError = undiciErrors.RequestContentLengthMismatchError;\n export import ResponseContentLengthMismatchError = undiciErrors.ResponseContentLengthMismatchError;\n export import ClientDestroyedError = undiciErrors.ClientDestroyedError;\n export import ClientClosedError = undiciErrors.ClientClosedError;\n export import SocketError = undiciErrors.SocketError;\n export import NotSupportedError = undiciErrors.NotSupportedError;\n export import BalancedPoolMissingUpstreamError = undiciErrors.BalancedPoolMissingUpstreamError;\n export import HTTPParserError = undiciErrors.HTTPParserError;\n export import ResponseExceededMaxSizeError = undiciErrors.ResponseExceededMaxSizeError;\n export import RequestRetryError = undiciErrors.RequestRetryError;\n export import SecureProxyConnectionError = undiciErrors.SecureProxyConnectionError;\n export import MaxOriginsReachedError = undiciErrors.MaxOriginsReachedError;\n\n export function isRapidoHttpClientError(value: unknown): value is RapidoHttpClientError<unknown> {\n return typeof value === 'object' && value !== null && RapidoHttpClientErrorBrand in value;\n }\n\n export class RapidoHttpClientError<T> extends undiciErrors.ResponseError {\n public readonly status: number;\n\n constructor(\n body: ConstructorParameters<typeof undiciErrors.ResponseError>[2]['body'],\n public readonly response: Dispatcher.ResponseData,\n public readonly data: T,\n ) {\n super(`HTTP Error ${response.statusCode}`, response.statusCode, { headers: response.headers, body });\n this.status = response.statusCode;\n\n Object.defineProperty(this, RapidoHttpClientErrorBrand, {\n value: true,\n enumerable: false,\n writable: false,\n });\n }\n\n public static isRapidoHttpClientError(value: unknown): value is RapidoHttpClientError<unknown> {\n return isRapidoHttpClientError(value);\n }\n }\n}\n","export const testAgentParam: unique symbol = Symbol('testAgentParam');\n","import type { Dispatcher } from 'undici';\nimport { getCurrentContext } from '@autofleet/outbreak';\n\nexport const outbreakInterceptor: Dispatcher.DispatcherComposeInterceptor = dispatch => function outbreakInterceptorInner(opts, handler) {\n const currentTraceContext = getCurrentContext().context;\n if (currentTraceContext) {\n // Convert headers to object format if they're in array format\n let headers: Record<string, string | string[]>;\n if (Array.isArray(opts.headers)) {\n /* c8 ignore next */\n headers = Object.fromEntries(opts.headers as unknown as [string, string | string[]][]);\n } else {\n headers = { ...opts.headers as Record<string, string | string[]> };\n }\n\n // Inject outbreak trace headers\n for (const [header, value] of currentTraceContext) {\n if (typeof value === 'symbol' || typeof value === 'undefined') {\n continue;\n }\n headers[header] = value as string;\n }\n opts.headers = headers;\n }\n return dispatch(opts, handler);\n};\n","import type { ZodType, output } from 'zod';\nimport type { LoggerInstanceManager } from '@autofleet/logger';\nimport type CacheHandler from 'undici/types/cache-interceptor';\nimport Undici, { Agent, type Dispatcher, interceptors } from 'undici';\nimport { errors } from './errors';\nimport { testAgentParam } from './testingHelper';\nimport { outbreakInterceptor } from './outbreakInterceptor';\nimport {\n createRequestString,\n defaultRetryMethod,\n defaultSettings,\n defaultSettingsWithDecompress,\n isFormData,\n mergeConfig,\n parseUrlAndOrigin,\n resolveServiceUrl,\n} from './utils';\n\nconst { cacheStores } = Undici;\nconst { cache, retry, decompress } = interceptors;\n\nexport interface RapidoHttpClientSettings {\n [testAgentParam]?: Dispatcher;\n serviceName?: string;\n serviceUrl?: string;\n logger: LoggerInstanceManager;\n timeout?: number;\n retries?: interceptors.RetryInterceptorOpts;\n headers?: Record<string, string> | string[][];\n keepAliveTimeout?: number;\n keepAliveMaxTimeout?: number;\n connections?: number;\n cache?: CacheHandler.MemoryCacheStoreOpts;\n autoDecompress?: boolean;\n}\n\nexport interface RequestConfig {\n params?: Record<string, any>;\n body?: any;\n timeout?: number;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n responseSchema?: ZodType;\n}\n\nexport interface RapidoHttpClientResponse<T = any> {\n data: T;\n status: number;\n statusText: string;\n headers: Record<string, string | string[]>;\n config: RequestConfig & { url: string; method: string; baseURL?: string; };\n}\n\nconst retriableMethods: Dispatcher.HttpMethod[] = ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE', 'QUERY'];\n\nexport class RapidoHttpClient {\n readonly #logger: LoggerInstanceManager;\n private readonly settings: RapidoHttpClientSettings & { baseURL?: string; basePath?: string; };\n public readonly client: Dispatcher.ComposedDispatcher;\n\n public get<T = unknown>(url: string, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public get<T extends ZodType>(url: string, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public get<T = unknown>(url: string, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('GET', url, undefined, config);\n }\n\n public post<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public post<T extends ZodType>(url: string, body: any, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public post<T = unknown>(url: string, body?: any, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('POST', url, body, config);\n }\n\n public delete<T = unknown>(url: string, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public delete<T extends ZodType>(url: string, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public delete<T = unknown>(url: string, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('DELETE', url, undefined, config);\n }\n\n public head<T = unknown>(url: string, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public head<T extends ZodType>(url: string, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public head<T = unknown>(url: string, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('HEAD', url, undefined, config);\n }\n\n public put<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public put<T extends ZodType>(url: string, body: any, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public put<T = unknown>(url: string, body?: any, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('PUT', url, body, config);\n }\n\n public patch<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public patch<T extends ZodType>(url: string, body: any, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public patch<T = unknown>(url: string, body?: any, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('PATCH', url, body, config);\n }\n\n public options<T = unknown>(url: string, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public options<T extends ZodType>(url: string, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public options<T = unknown>(url: string, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('OPTIONS', url, undefined, config);\n }\n\n public query<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public query<T extends ZodType>(url: string, body: any, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public query<T = unknown>(url: string, body?: any, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('QUERY', url, body, config);\n }\n\n constructor(settings: RapidoHttpClientSettings) {\n this.#logger = settings.logger;\n this.settings = mergeConfig<typeof defaultSettings, Partial<typeof settings>>(\n settings.autoDecompress ? defaultSettingsWithDecompress : defaultSettings,\n settings,\n ) as RapidoHttpClientSettings & { baseURL?: string; };\n this.#createBaseUrl();\n\n // In test mode, use the test dispatcher directly (MockAgent or MockPool) Otherwise, create an Agent which creates Client Pools\n // Check for global mock agent first (for testing), then test param, then create real Agent\n /* c8 ignore next */\n const globalMockAgent = (globalThis as any).__RAPIDO_HTTP_CLIENT_MOCK_AGENT__;\n /* c8 ignore next */\n this.client = this.settings[testAgentParam] ?? globalMockAgent ?? new Agent({\n connect: {\n timeout: this.settings.timeout,\n },\n keepAliveTimeout: this.settings.keepAliveTimeout,\n keepAliveMaxTimeout: this.settings.keepAliveMaxTimeout,\n connections: this.settings.connections,\n });\n\n if (this.settings.cache) {\n this.client = this.client.compose(cache({\n store: new cacheStores.MemoryCacheStore({\n ...this.settings.cache,\n }),\n }));\n }\n\n if (this.settings.retries) {\n this.client = this.client.compose(retry({\n methods: retriableMethods,\n ...this.settings.retries,\n retry: (err, context, callback) => {\n const { counter } = context.state;\n /* c8 ignore next */\n const maxRetries = context.opts.retryOptions?.maxRetries ?? 5;\n\n const retryToUse = this.settings.retries?.retry ?? defaultRetryMethod;\n const callbackWithLogging = (result?: Error | null) => {\n if (!result) {\n this.#logger.warn(`Request retry attempt ${counter}/${maxRetries}`, { err });\n }\n callback(result);\n };\n retryToUse(err, context, callbackWithLogging);\n },\n }));\n }\n\n if (this.settings.autoDecompress) {\n this.client = this.client.compose(decompress({ skipErrorResponses: false }));\n }\n\n this.client = this.client.compose(outbreakInterceptor);\n }\n\n #createBaseUrl(): void {\n const fullUrl = resolveServiceUrl(this.settings);\n const urlObj = new URL(fullUrl);\n this.settings.baseURL = urlObj.origin;\n this.settings.basePath = urlObj.pathname !== '/' ? urlObj.pathname : '';\n }\n\n #getSignal(currentSignal?: AbortSignal, timeout?: number): { signal?: AbortSignal; timeoutSignal?: AbortSignal; } {\n if (!currentSignal && !timeout) {\n return { signal: undefined, timeoutSignal: undefined };\n }\n\n if (currentSignal && !timeout) {\n return { signal: currentSignal, timeoutSignal: undefined };\n }\n\n const timeoutSignal = AbortSignal.timeout(timeout!);\n if (!currentSignal && timeout) {\n return { signal: timeoutSignal, timeoutSignal };\n }\n\n return { signal: AbortSignal.any([currentSignal!, timeoutSignal]), timeoutSignal };\n }\n\n #prepareRequestBody(body: any, headers: Record<string, string>): string | Buffer | FormData | undefined {\n if (body === undefined || body === null) {\n return undefined;\n }\n\n // Handle FormData instances automatically\n if (isFormData(body)) {\n if (!headers['Content-Type'] && !headers['content-type']) {\n headers['Content-Type'] = 'application/x-www-form-urlencoded';\n }\n return body;\n }\n\n if (typeof body === 'object' && !Buffer.isBuffer(body)) {\n // Check if Content-Type is set to application/x-www-form-urlencoded\n const contentType = headers['Content-Type'] || headers['content-type'];\n if (contentType && /application\\/x-www-form-urlencoded/i.test(contentType)) {\n // Encode as URL parameters\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(body)) {\n if (Array.isArray(value)) {\n value.forEach(v => params.append(key, String(v)));\n } else if (value !== undefined && value !== null) {\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n params.append(key, String(value));\n }\n }\n return params.toString();\n }\n // Default to JSON\n if (!headers['Content-Type'] && !headers['content-type']) {\n headers['Content-Type'] = 'application/json';\n }\n return JSON.stringify(body);\n } else if (typeof body === 'string') {\n return body;\n } else if (Buffer.isBuffer(body)) {\n return body;\n }\n return String(body);\n }\n\n async #request<T = any>(\n method: Dispatcher.HttpMethod,\n url: string,\n body?: any,\n config: RequestConfig = {},\n ): Promise<RapidoHttpClientResponse<T>> {\n const mergedConfig = mergeConfig(this.settings, config);\n\n if (mergedConfig.signal?.aborted) {\n this.#logger.error(`Request aborted before start: ${createRequestString(method, mergedConfig.baseURL, url)}`);\n throw new errors.RequestAbortedError(mergedConfig.signal.reason?.message || 'Request aborted', { cause: mergedConfig.signal.reason });\n }\n\n const headers: Record<string, string> = { ...mergedConfig.headers };\n const requestBody = this.#prepareRequestBody(body, headers);\n\n const { origin, path } = parseUrlAndOrigin(url, mergedConfig.baseURL!, mergedConfig.basePath);\n const requestInfo = { method, baseURL: origin, url };\n\n if (mergedConfig.params) {\n for (const [key, value] of Object.entries(mergedConfig.params)) {\n if (Array.isArray(value) && !key.endsWith('[]')) {\n mergedConfig.params[`${key}[]`] = value;\n delete mergedConfig.params[key];\n }\n }\n }\n\n const { signal, timeoutSignal } = this.#getSignal(mergedConfig.signal, mergedConfig.timeout);\n\n try {\n this.#logger.info(`Start Request: ${createRequestString(method, origin, path)}`);\n\n const requestOptions: Dispatcher.RequestOptions = {\n path,\n origin,\n method,\n signal,\n headers,\n body: requestBody,\n query: mergedConfig.params,\n };\n\n const response = await this.client.request(requestOptions);\n\n if (response.statusCode >= 400) {\n const data = await this.#parseResponse<T>(response, config.responseSchema);\n this.#logger.error(`Finish Request with error ${createRequestString(method, origin, path)}`, {\n status: response.statusCode,\n data,\n });\n\n throw new errors.RapidoHttpClientError<T>(requestBody, response, data);\n }\n\n this.#logger.info(`Finish Request: ${createRequestString(method, origin, path)}`);\n\n const data = response.statusCode !== 204 ? await this.#parseResponse<T>(response, config.responseSchema) : undefined as T;\n\n return {\n data,\n status: response.statusCode,\n statusText: '',\n headers: response.headers as Record<string, string | string[]>,\n config: requestInfo,\n };\n } catch (error) {\n if (timeoutSignal && timeoutSignal.reason === error) {\n // If the timeoutSignal aborted (config timeout), throw a timeout-specific error\n this.#logger.error(`Request timeout: ${createRequestString(method, origin, path)}`);\n const error = new errors.UndiciError(`Request timeout after ${mergedConfig.timeout}ms`, { cause: timeoutSignal.reason });\n error.code = 'UND_ERR_TIMEOUT';\n throw error;\n }\n if (signal && signal.reason === error) {\n // If the user's signal aborted, throw RequestAbortedError\n this.#logger.error(`Request aborted: ${createRequestString(method, origin, path)}`);\n throw new errors.RequestAbortedError(signal.reason.message, { cause: signal.reason });\n }\n\n this.#logger.error(`Finish Request with error ${createRequestString(method, origin, path)}`, { error });\n throw error;\n }\n }\n\n async #parseResponse<T>(response: Dispatcher.ResponseData, schema?: ZodType): Promise<T> {\n const contentType = (response.headers['content-type'] as string) || '';\n const bodyText = await response.body.text();\n\n if (!bodyText) {\n return undefined as T;\n }\n\n if (/text/i.test(contentType)) {\n return bodyText as T;\n }\n\n let json: unknown;\n try {\n json = JSON.parse(bodyText);\n } catch {\n return bodyText as T;\n }\n return (schema ? schema.parse(json) : json) as T;\n }\n\n /**\n * @param url The endpoint URL to send the request to.\n * @param options Additional options to include in the request payload.\n * @returns A promise that resolves to an array of all results.\n */\n async getAllPages<T>(url: string, options: RequestConfig = {}): Promise<T[]> {\n const currentResult: T[] = [];\n let resultsInFirstPage: number | null = null;\n let lastResultsSize: number | null = null;\n\n const localOptions = { ...options, params: { ...options.params, page: 1 } };\n // Make sure even if `options` had `params` we initialize `page` to 1.\n localOptions.params.page ||= 1;\n\n while ((localOptions.params.page === 1 || lastResultsSize === resultsInFirstPage) && lastResultsSize !== 0) {\n const { data } = await this.get<T[]>(url, localOptions as Omit<RequestConfig, 'responseSchema'>);\n lastResultsSize = data.length;\n if (localOptions.params.page === 1) {\n resultsInFirstPage = data.length;\n }\n\n localOptions.params.page += 1;\n Array.prototype.push.apply(currentResult, data);\n }\n\n return currentResult;\n }\n\n /**\n * Fetches all pages from a paginated API endpoint until all results are retrieved\n * or an optional page limit is reached.\n *\n * @param url The endpoint URL to send the request to.\n * @param options Additional options to include in the request payload.\n * @param pageLimit The maximum number of pages to fetch. Set to -1 for no limit.\n * @returns A promise that resolves to an array of all results.\n */\n async getAllPagesFromQueryEndpoint<T>(url: string, options: object = {}, pageLimit = 100): Promise<T[]> {\n const currentResult: T[] = [];\n\n let moreResultsToLoad = true;\n let page = 1;\n while (moreResultsToLoad && (pageLimit === -1 || page < pageLimit)) {\n const { data } = await this.post<{ rows: T[]; count: number; }>(url, {\n ...options,\n page,\n });\n const { rows, count } = data;\n page += 1;\n Array.prototype.push.apply(currentResult, rows);\n moreResultsToLoad = currentResult.length < count;\n }\n\n return currentResult;\n }\n\n async close(): Promise<void> {\n await this.client.close();\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.close();\n }\n}\n\nexport default RapidoHttpClient;\nexport { errors };\n"],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ import { ZodType, output } from "zod";
2
+ import { LoggerInstanceManager } from "@autofleet/logger";
3
+ import CacheHandler from "undici/types/cache-interceptor";
4
+ import { Dispatcher, errors as errors$1, interceptors } from "undici";
5
+
6
+ //#region src/errors.d.ts
7
+ declare namespace errors {
8
+ import UndiciError = undiciErrors.UndiciError;
9
+ import ConnectTimeoutError = undiciErrors.ConnectTimeoutError;
10
+ import HeadersTimeoutError = undiciErrors.HeadersTimeoutError;
11
+ import HeadersOverflowError = undiciErrors.HeadersOverflowError;
12
+ import BodyTimeoutError = undiciErrors.BodyTimeoutError;
13
+ import ResponseError = undiciErrors.ResponseError;
14
+ import InvalidArgumentError = undiciErrors.InvalidArgumentError;
15
+ import InvalidReturnValueError = undiciErrors.InvalidReturnValueError;
16
+ import RequestAbortedError = undiciErrors.RequestAbortedError;
17
+ import InformationalError = undiciErrors.InformationalError;
18
+ import RequestContentLengthMismatchError = undiciErrors.RequestContentLengthMismatchError;
19
+ import ResponseContentLengthMismatchError = undiciErrors.ResponseContentLengthMismatchError;
20
+ import ClientDestroyedError = undiciErrors.ClientDestroyedError;
21
+ import ClientClosedError = undiciErrors.ClientClosedError;
22
+ import SocketError = undiciErrors.SocketError;
23
+ import NotSupportedError = undiciErrors.NotSupportedError;
24
+ import BalancedPoolMissingUpstreamError = undiciErrors.BalancedPoolMissingUpstreamError;
25
+ import HTTPParserError = undiciErrors.HTTPParserError;
26
+ import ResponseExceededMaxSizeError = undiciErrors.ResponseExceededMaxSizeError;
27
+ import RequestRetryError = undiciErrors.RequestRetryError;
28
+ import SecureProxyConnectionError = undiciErrors.SecureProxyConnectionError;
29
+ import MaxOriginsReachedError = undiciErrors.MaxOriginsReachedError;
30
+ function isRapidoHttpClientError(value: unknown): value is RapidoHttpClientError<unknown>;
31
+ class RapidoHttpClientError<T> extends errors$1.ResponseError {
32
+ readonly response: Dispatcher.ResponseData;
33
+ readonly data: T;
34
+ readonly status: number;
35
+ constructor(body: ConstructorParameters<typeof errors$1.ResponseError>[2]["body"], response: Dispatcher.ResponseData, data: T);
36
+ static isRapidoHttpClientError(value: unknown): value is RapidoHttpClientError<unknown>;
37
+ }
38
+ }
39
+ //#endregion
40
+ //#region src/testingHelper.d.ts
41
+ declare const testAgentParam: unique symbol;
42
+ //#endregion
43
+ //#region src/index.d.ts
44
+ interface RapidoHttpClientSettings {
45
+ [testAgentParam]?: Dispatcher;
46
+ serviceName?: string;
47
+ serviceUrl?: string;
48
+ logger: LoggerInstanceManager;
49
+ timeout?: number;
50
+ retries?: interceptors.RetryInterceptorOpts;
51
+ headers?: Record<string, string> | string[][];
52
+ keepAliveTimeout?: number;
53
+ keepAliveMaxTimeout?: number;
54
+ connections?: number;
55
+ cache?: CacheHandler.MemoryCacheStoreOpts;
56
+ autoDecompress?: boolean;
57
+ }
58
+ interface RequestConfig {
59
+ params?: Record<string, any>;
60
+ body?: any;
61
+ timeout?: number;
62
+ headers?: Record<string, string>;
63
+ signal?: AbortSignal;
64
+ responseSchema?: ZodType;
65
+ }
66
+ interface RapidoHttpClientResponse<T = any> {
67
+ data: T;
68
+ status: number;
69
+ statusText: string;
70
+ headers: Record<string, string | string[]>;
71
+ config: RequestConfig & {
72
+ url: string;
73
+ method: string;
74
+ baseURL?: string;
75
+ };
76
+ }
77
+ declare class RapidoHttpClient {
78
+ #private;
79
+ private readonly settings;
80
+ readonly client: Dispatcher.ComposedDispatcher;
81
+ get<T = unknown>(url: string, config?: Omit<RequestConfig, "responseSchema"> & {
82
+ responseSchema?: never;
83
+ }): Promise<RapidoHttpClientResponse<T>>;
84
+ get<T extends ZodType>(url: string, config: RequestConfig & {
85
+ responseSchema: T;
86
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
87
+ post<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, "responseSchema"> & {
88
+ responseSchema?: never;
89
+ }): Promise<RapidoHttpClientResponse<T>>;
90
+ post<T extends ZodType>(url: string, body: any, config: RequestConfig & {
91
+ responseSchema: T;
92
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
93
+ delete<T = unknown>(url: string, config?: Omit<RequestConfig, "responseSchema"> & {
94
+ responseSchema?: never;
95
+ }): Promise<RapidoHttpClientResponse<T>>;
96
+ delete<T extends ZodType>(url: string, config: RequestConfig & {
97
+ responseSchema: T;
98
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
99
+ head<T = unknown>(url: string, config?: Omit<RequestConfig, "responseSchema"> & {
100
+ responseSchema?: never;
101
+ }): Promise<RapidoHttpClientResponse<T>>;
102
+ head<T extends ZodType>(url: string, config: RequestConfig & {
103
+ responseSchema: T;
104
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
105
+ put<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, "responseSchema"> & {
106
+ responseSchema?: never;
107
+ }): Promise<RapidoHttpClientResponse<T>>;
108
+ put<T extends ZodType>(url: string, body: any, config: RequestConfig & {
109
+ responseSchema: T;
110
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
111
+ patch<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, "responseSchema"> & {
112
+ responseSchema?: never;
113
+ }): Promise<RapidoHttpClientResponse<T>>;
114
+ patch<T extends ZodType>(url: string, body: any, config: RequestConfig & {
115
+ responseSchema: T;
116
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
117
+ options<T = unknown>(url: string, config?: Omit<RequestConfig, "responseSchema"> & {
118
+ responseSchema?: never;
119
+ }): Promise<RapidoHttpClientResponse<T>>;
120
+ options<T extends ZodType>(url: string, config: RequestConfig & {
121
+ responseSchema: T;
122
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
123
+ query<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, "responseSchema"> & {
124
+ responseSchema?: never;
125
+ }): Promise<RapidoHttpClientResponse<T>>;
126
+ query<T extends ZodType>(url: string, body: any, config: RequestConfig & {
127
+ responseSchema: T;
128
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
129
+ constructor(settings: RapidoHttpClientSettings);
130
+ /**
131
+ * @param url The endpoint URL to send the request to.
132
+ * @param options Additional options to include in the request payload.
133
+ * @returns A promise that resolves to an array of all results.
134
+ */
135
+ getAllPages<T>(url: string, options?: RequestConfig): Promise<T[]>;
136
+ /**
137
+ * Fetches all pages from a paginated API endpoint until all results are retrieved
138
+ * or an optional page limit is reached.
139
+ *
140
+ * @param url The endpoint URL to send the request to.
141
+ * @param options Additional options to include in the request payload.
142
+ * @param pageLimit The maximum number of pages to fetch. Set to -1 for no limit.
143
+ * @returns A promise that resolves to an array of all results.
144
+ */
145
+ getAllPagesFromQueryEndpoint<T>(url: string, options?: object, pageLimit?: number): Promise<T[]>;
146
+ close(): Promise<void>;
147
+ [Symbol.asyncDispose](): Promise<void>;
148
+ }
149
+ //#endregion
150
+ export { RapidoHttpClient, RapidoHttpClient as default, RapidoHttpClientResponse, RapidoHttpClientSettings, RequestConfig, errors };
151
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,151 @@
1
+ import { Dispatcher, errors as errors$1, interceptors } from "undici";
2
+ import { ZodType, output } from "zod";
3
+ import { LoggerInstanceManager } from "@autofleet/logger";
4
+ import CacheHandler from "undici/types/cache-interceptor";
5
+
6
+ //#region src/errors.d.ts
7
+ declare namespace errors {
8
+ import UndiciError = undiciErrors.UndiciError;
9
+ import ConnectTimeoutError = undiciErrors.ConnectTimeoutError;
10
+ import HeadersTimeoutError = undiciErrors.HeadersTimeoutError;
11
+ import HeadersOverflowError = undiciErrors.HeadersOverflowError;
12
+ import BodyTimeoutError = undiciErrors.BodyTimeoutError;
13
+ import ResponseError = undiciErrors.ResponseError;
14
+ import InvalidArgumentError = undiciErrors.InvalidArgumentError;
15
+ import InvalidReturnValueError = undiciErrors.InvalidReturnValueError;
16
+ import RequestAbortedError = undiciErrors.RequestAbortedError;
17
+ import InformationalError = undiciErrors.InformationalError;
18
+ import RequestContentLengthMismatchError = undiciErrors.RequestContentLengthMismatchError;
19
+ import ResponseContentLengthMismatchError = undiciErrors.ResponseContentLengthMismatchError;
20
+ import ClientDestroyedError = undiciErrors.ClientDestroyedError;
21
+ import ClientClosedError = undiciErrors.ClientClosedError;
22
+ import SocketError = undiciErrors.SocketError;
23
+ import NotSupportedError = undiciErrors.NotSupportedError;
24
+ import BalancedPoolMissingUpstreamError = undiciErrors.BalancedPoolMissingUpstreamError;
25
+ import HTTPParserError = undiciErrors.HTTPParserError;
26
+ import ResponseExceededMaxSizeError = undiciErrors.ResponseExceededMaxSizeError;
27
+ import RequestRetryError = undiciErrors.RequestRetryError;
28
+ import SecureProxyConnectionError = undiciErrors.SecureProxyConnectionError;
29
+ import MaxOriginsReachedError = undiciErrors.MaxOriginsReachedError;
30
+ function isRapidoHttpClientError(value: unknown): value is RapidoHttpClientError<unknown>;
31
+ class RapidoHttpClientError<T> extends errors$1.ResponseError {
32
+ readonly response: Dispatcher.ResponseData;
33
+ readonly data: T;
34
+ readonly status: number;
35
+ constructor(body: ConstructorParameters<typeof errors$1.ResponseError>[2]["body"], response: Dispatcher.ResponseData, data: T);
36
+ static isRapidoHttpClientError(value: unknown): value is RapidoHttpClientError<unknown>;
37
+ }
38
+ }
39
+ //#endregion
40
+ //#region src/testingHelper.d.ts
41
+ declare const testAgentParam: unique symbol;
42
+ //#endregion
43
+ //#region src/index.d.ts
44
+ interface RapidoHttpClientSettings {
45
+ [testAgentParam]?: Dispatcher;
46
+ serviceName?: string;
47
+ serviceUrl?: string;
48
+ logger: LoggerInstanceManager;
49
+ timeout?: number;
50
+ retries?: interceptors.RetryInterceptorOpts;
51
+ headers?: Record<string, string> | string[][];
52
+ keepAliveTimeout?: number;
53
+ keepAliveMaxTimeout?: number;
54
+ connections?: number;
55
+ cache?: CacheHandler.MemoryCacheStoreOpts;
56
+ autoDecompress?: boolean;
57
+ }
58
+ interface RequestConfig {
59
+ params?: Record<string, any>;
60
+ body?: any;
61
+ timeout?: number;
62
+ headers?: Record<string, string>;
63
+ signal?: AbortSignal;
64
+ responseSchema?: ZodType;
65
+ }
66
+ interface RapidoHttpClientResponse<T = any> {
67
+ data: T;
68
+ status: number;
69
+ statusText: string;
70
+ headers: Record<string, string | string[]>;
71
+ config: RequestConfig & {
72
+ url: string;
73
+ method: string;
74
+ baseURL?: string;
75
+ };
76
+ }
77
+ declare class RapidoHttpClient {
78
+ #private;
79
+ private readonly settings;
80
+ readonly client: Dispatcher.ComposedDispatcher;
81
+ get<T = unknown>(url: string, config?: Omit<RequestConfig, "responseSchema"> & {
82
+ responseSchema?: never;
83
+ }): Promise<RapidoHttpClientResponse<T>>;
84
+ get<T extends ZodType>(url: string, config: RequestConfig & {
85
+ responseSchema: T;
86
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
87
+ post<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, "responseSchema"> & {
88
+ responseSchema?: never;
89
+ }): Promise<RapidoHttpClientResponse<T>>;
90
+ post<T extends ZodType>(url: string, body: any, config: RequestConfig & {
91
+ responseSchema: T;
92
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
93
+ delete<T = unknown>(url: string, config?: Omit<RequestConfig, "responseSchema"> & {
94
+ responseSchema?: never;
95
+ }): Promise<RapidoHttpClientResponse<T>>;
96
+ delete<T extends ZodType>(url: string, config: RequestConfig & {
97
+ responseSchema: T;
98
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
99
+ head<T = unknown>(url: string, config?: Omit<RequestConfig, "responseSchema"> & {
100
+ responseSchema?: never;
101
+ }): Promise<RapidoHttpClientResponse<T>>;
102
+ head<T extends ZodType>(url: string, config: RequestConfig & {
103
+ responseSchema: T;
104
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
105
+ put<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, "responseSchema"> & {
106
+ responseSchema?: never;
107
+ }): Promise<RapidoHttpClientResponse<T>>;
108
+ put<T extends ZodType>(url: string, body: any, config: RequestConfig & {
109
+ responseSchema: T;
110
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
111
+ patch<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, "responseSchema"> & {
112
+ responseSchema?: never;
113
+ }): Promise<RapidoHttpClientResponse<T>>;
114
+ patch<T extends ZodType>(url: string, body: any, config: RequestConfig & {
115
+ responseSchema: T;
116
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
117
+ options<T = unknown>(url: string, config?: Omit<RequestConfig, "responseSchema"> & {
118
+ responseSchema?: never;
119
+ }): Promise<RapidoHttpClientResponse<T>>;
120
+ options<T extends ZodType>(url: string, config: RequestConfig & {
121
+ responseSchema: T;
122
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
123
+ query<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, "responseSchema"> & {
124
+ responseSchema?: never;
125
+ }): Promise<RapidoHttpClientResponse<T>>;
126
+ query<T extends ZodType>(url: string, body: any, config: RequestConfig & {
127
+ responseSchema: T;
128
+ }): Promise<RapidoHttpClientResponse<output<T>>>;
129
+ constructor(settings: RapidoHttpClientSettings);
130
+ /**
131
+ * @param url The endpoint URL to send the request to.
132
+ * @param options Additional options to include in the request payload.
133
+ * @returns A promise that resolves to an array of all results.
134
+ */
135
+ getAllPages<T>(url: string, options?: RequestConfig): Promise<T[]>;
136
+ /**
137
+ * Fetches all pages from a paginated API endpoint until all results are retrieved
138
+ * or an optional page limit is reached.
139
+ *
140
+ * @param url The endpoint URL to send the request to.
141
+ * @param options Additional options to include in the request payload.
142
+ * @param pageLimit The maximum number of pages to fetch. Set to -1 for no limit.
143
+ * @returns A promise that resolves to an array of all results.
144
+ */
145
+ getAllPagesFromQueryEndpoint<T>(url: string, options?: object, pageLimit?: number): Promise<T[]>;
146
+ close(): Promise<void>;
147
+ [Symbol.asyncDispose](): Promise<void>;
148
+ }
149
+ //#endregion
150
+ export { RapidoHttpClient, RapidoHttpClient as default, RapidoHttpClientResponse, RapidoHttpClientSettings, RequestConfig, errors };
151
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import{a as e,c as t,i as n,n as r,o as i,r as a,s as o,t as s}from"./utils-B2KjeMp7.js";import c,{Agent as l,errors as u,interceptors as d}from"undici";import{getCurrentContext as f}from"@autofleet/outbreak";const p=Symbol.for(`RapidoHttpClientErrorBrand`);let m;(function(e){e.UndiciError=u.UndiciError,e.ConnectTimeoutError=u.ConnectTimeoutError,e.HeadersTimeoutError=u.HeadersTimeoutError,e.HeadersOverflowError=u.HeadersOverflowError,e.BodyTimeoutError=u.BodyTimeoutError,e.ResponseError=u.ResponseError,e.InvalidArgumentError=u.InvalidArgumentError,e.InvalidReturnValueError=u.InvalidReturnValueError,e.RequestAbortedError=u.RequestAbortedError,e.InformationalError=u.InformationalError,e.RequestContentLengthMismatchError=u.RequestContentLengthMismatchError,e.ResponseContentLengthMismatchError=u.ResponseContentLengthMismatchError,e.ClientDestroyedError=u.ClientDestroyedError,e.ClientClosedError=u.ClientClosedError,e.SocketError=u.SocketError,e.NotSupportedError=u.NotSupportedError,e.BalancedPoolMissingUpstreamError=u.BalancedPoolMissingUpstreamError,e.HTTPParserError=u.HTTPParserError,e.ResponseExceededMaxSizeError=u.ResponseExceededMaxSizeError,e.RequestRetryError=u.RequestRetryError,e.SecureProxyConnectionError=u.SecureProxyConnectionError,e.MaxOriginsReachedError=u.MaxOriginsReachedError;function t(e){return typeof e==`object`&&!!e&&p in e}e.isRapidoHttpClientError=t;class n extends u.ResponseError{constructor(e,t,n){super(`HTTP Error ${t.statusCode}`,t.statusCode,{headers:t.headers,body:e}),this.response=t,this.data=n,this.status=t.statusCode,Object.defineProperty(this,p,{value:!0,enumerable:!1,writable:!1})}static isRapidoHttpClientError(e){return t(e)}}e.RapidoHttpClientError=n})(m||={});const h=Symbol(`testAgentParam`),g=e=>function(t,n){let r=f().context;if(r){let e;e=Array.isArray(t.headers)?Object.fromEntries(t.headers):{...t.headers};for(let[t,n]of r)typeof n==`symbol`||n===void 0||(e[t]=n);t.headers=e}return e(t,n)},{cacheStores:_}=c,{cache:v,retry:y,decompress:b}=d,x=[`GET`,`HEAD`,`OPTIONS`,`PUT`,`DELETE`,`TRACE`,`QUERY`];var S=class{#e;get(e,t){return this.#i(`GET`,e,void 0,t)}post(e,t,n){return this.#i(`POST`,e,t,n)}delete(e,t){return this.#i(`DELETE`,e,void 0,t)}head(e,t){return this.#i(`HEAD`,e,void 0,t)}put(e,t,n){return this.#i(`PUT`,e,t,n)}patch(e,t,n){return this.#i(`PATCH`,e,t,n)}options(e,t){return this.#i(`OPTIONS`,e,void 0,t)}query(e,t,n){return this.#i(`QUERY`,e,t,n)}constructor(e){this.#e=e.logger,this.settings=i(e.autoDecompress?n:a,e),this.#t();let t=globalThis.__RAPIDO_HTTP_CLIENT_MOCK_AGENT__;this.client=this.settings[h]??t??new l({connect:{timeout:this.settings.timeout},keepAliveTimeout:this.settings.keepAliveTimeout,keepAliveMaxTimeout:this.settings.keepAliveMaxTimeout,connections:this.settings.connections}),this.settings.cache&&(this.client=this.client.compose(v({store:new _.MemoryCacheStore({...this.settings.cache})}))),this.settings.retries&&(this.client=this.client.compose(y({methods:x,...this.settings.retries,retry:(e,t,n)=>{let{counter:i}=t.state,a=t.opts.retryOptions?.maxRetries??5;(this.settings.retries?.retry??r)(e,t,t=>{t||this.#e.warn(`Request retry attempt ${i}/${a}`,{err:e}),n(t)})}}))),this.settings.autoDecompress&&(this.client=this.client.compose(b({skipErrorResponses:!1}))),this.client=this.client.compose(g)}#t(){let e=t(this.settings),n=new URL(e);this.settings.baseURL=n.origin,this.settings.basePath=n.pathname===`/`?``:n.pathname}#n(e,t){if(!e&&!t)return{signal:void 0,timeoutSignal:void 0};if(e&&!t)return{signal:e,timeoutSignal:void 0};let n=AbortSignal.timeout(t);return!e&&t?{signal:n,timeoutSignal:n}:{signal:AbortSignal.any([e,n]),timeoutSignal:n}}#r(t,n){if(t!=null){if(e(t))return!n[`Content-Type`]&&!n[`content-type`]&&(n[`Content-Type`]=`application/x-www-form-urlencoded`),t;if(typeof t==`object`&&!Buffer.isBuffer(t)){let e=n[`Content-Type`]||n[`content-type`];if(e&&/application\/x-www-form-urlencoded/i.test(e)){let e=new URLSearchParams;for(let[n,r]of Object.entries(t))Array.isArray(r)?r.forEach(t=>e.append(n,String(t))):r!=null&&e.append(n,String(r));return e.toString()}return!n[`Content-Type`]&&!n[`content-type`]&&(n[`Content-Type`]=`application/json`),JSON.stringify(t)}else if(typeof t==`string`)return t;else if(Buffer.isBuffer(t))return t;return String(t)}}async#i(e,t,n,r={}){let a=i(this.settings,r);if(a.signal?.aborted)throw this.#e.error(`Request aborted before start: ${s(e,a.baseURL,t)}`),new m.RequestAbortedError(a.signal.reason?.message||`Request aborted`,{cause:a.signal.reason});let c={...a.headers},l=this.#r(n,c),{origin:u,path:d}=o(t,a.baseURL,a.basePath),f={method:e,baseURL:u,url:t};if(a.params)for(let[e,t]of Object.entries(a.params))Array.isArray(t)&&!e.endsWith(`[]`)&&(a.params[`${e}[]`]=t,delete a.params[e]);let{signal:p,timeoutSignal:h}=this.#n(a.signal,a.timeout);try{this.#e.info(`Start Request: ${s(e,u,d)}`);let t={path:d,origin:u,method:e,signal:p,headers:c,body:l,query:a.params},n=await this.client.request(t);if(n.statusCode>=400){let t=await this.#a(n,r.responseSchema);throw this.#e.error(`Finish Request with error ${s(e,u,d)}`,{status:n.statusCode,data:t}),new m.RapidoHttpClientError(l,n,t)}return this.#e.info(`Finish Request: ${s(e,u,d)}`),{data:n.statusCode===204?void 0:await this.#a(n,r.responseSchema),status:n.statusCode,statusText:``,headers:n.headers,config:f}}catch(t){if(h&&h.reason===t){this.#e.error(`Request timeout: ${s(e,u,d)}`);let t=new m.UndiciError(`Request timeout after ${a.timeout}ms`,{cause:h.reason});throw t.code=`UND_ERR_TIMEOUT`,t}throw p&&p.reason===t?(this.#e.error(`Request aborted: ${s(e,u,d)}`),new m.RequestAbortedError(p.reason.message,{cause:p.reason})):(this.#e.error(`Finish Request with error ${s(e,u,d)}`,{error:t}),t)}}async#a(e,t){let n=e.headers[`content-type`]||``,r=await e.body.text();if(!r)return;if(/text/i.test(n))return r;let i;try{i=JSON.parse(r)}catch{return r}return t?t.parse(i):i}async getAllPages(e,t={}){let n=[],r=null,i=null,a={...t,params:{...t.params,page:1}};for(a.params.page||=1;(a.params.page===1||i===r)&&i!==0;){let{data:t}=await this.get(e,a);i=t.length,a.params.page===1&&(r=t.length),a.params.page+=1,Array.prototype.push.apply(n,t)}return n}async getAllPagesFromQueryEndpoint(e,t={},n=100){let r=[],i=!0,a=1;for(;i&&(n===-1||a<n);){let{data:n}=await this.post(e,{...t,page:a}),{rows:o,count:s}=n;a+=1,Array.prototype.push.apply(r,o),i=r.length<s}return r}async close(){await this.client.close()}async[Symbol.asyncDispose](){await this.close()}},C=S;export{S as RapidoHttpClient,C as default,m as errors};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["undiciErrors","response: Dispatcher.ResponseData","data: T","testAgentParam: unique symbol","outbreakInterceptor: Dispatcher.DispatcherComposeInterceptor","headers: Record<string, string | string[]>","retriableMethods: Dispatcher.HttpMethod[]","#logger","#request","#createBaseUrl","headers: Record<string, string>","#prepareRequestBody","#getSignal","requestOptions: Dispatcher.RequestOptions","#parseResponse","error","json: unknown","currentResult: T[]","resultsInFirstPage: number | null","lastResultsSize: number | null"],"sources":["../src/errors.ts","../src/testingHelper.ts","../src/outbreakInterceptor.ts","../src/index.ts"],"sourcesContent":["import { type Dispatcher, errors as undiciErrors } from 'undici';\n\nconst RapidoHttpClientErrorBrand = Symbol.for('RapidoHttpClientErrorBrand');\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace errors {\n export import UndiciError = undiciErrors.UndiciError;\n export import ConnectTimeoutError = undiciErrors.ConnectTimeoutError;\n export import HeadersTimeoutError = undiciErrors.HeadersTimeoutError;\n export import HeadersOverflowError = undiciErrors.HeadersOverflowError;\n export import BodyTimeoutError = undiciErrors.BodyTimeoutError;\n export import ResponseError = undiciErrors.ResponseError;\n export import InvalidArgumentError = undiciErrors.InvalidArgumentError;\n export import InvalidReturnValueError = undiciErrors.InvalidReturnValueError;\n export import RequestAbortedError = undiciErrors.RequestAbortedError;\n export import InformationalError = undiciErrors.InformationalError;\n export import RequestContentLengthMismatchError = undiciErrors.RequestContentLengthMismatchError;\n export import ResponseContentLengthMismatchError = undiciErrors.ResponseContentLengthMismatchError;\n export import ClientDestroyedError = undiciErrors.ClientDestroyedError;\n export import ClientClosedError = undiciErrors.ClientClosedError;\n export import SocketError = undiciErrors.SocketError;\n export import NotSupportedError = undiciErrors.NotSupportedError;\n export import BalancedPoolMissingUpstreamError = undiciErrors.BalancedPoolMissingUpstreamError;\n export import HTTPParserError = undiciErrors.HTTPParserError;\n export import ResponseExceededMaxSizeError = undiciErrors.ResponseExceededMaxSizeError;\n export import RequestRetryError = undiciErrors.RequestRetryError;\n export import SecureProxyConnectionError = undiciErrors.SecureProxyConnectionError;\n export import MaxOriginsReachedError = undiciErrors.MaxOriginsReachedError;\n\n export function isRapidoHttpClientError(value: unknown): value is RapidoHttpClientError<unknown> {\n return typeof value === 'object' && value !== null && RapidoHttpClientErrorBrand in value;\n }\n\n export class RapidoHttpClientError<T> extends undiciErrors.ResponseError {\n public readonly status: number;\n\n constructor(\n body: ConstructorParameters<typeof undiciErrors.ResponseError>[2]['body'],\n public readonly response: Dispatcher.ResponseData,\n public readonly data: T,\n ) {\n super(`HTTP Error ${response.statusCode}`, response.statusCode, { headers: response.headers, body });\n this.status = response.statusCode;\n\n Object.defineProperty(this, RapidoHttpClientErrorBrand, {\n value: true,\n enumerable: false,\n writable: false,\n });\n }\n\n public static isRapidoHttpClientError(value: unknown): value is RapidoHttpClientError<unknown> {\n return isRapidoHttpClientError(value);\n }\n }\n}\n","export const testAgentParam: unique symbol = Symbol('testAgentParam');\n","import type { Dispatcher } from 'undici';\nimport { getCurrentContext } from '@autofleet/outbreak';\n\nexport const outbreakInterceptor: Dispatcher.DispatcherComposeInterceptor = dispatch => function outbreakInterceptorInner(opts, handler) {\n const currentTraceContext = getCurrentContext().context;\n if (currentTraceContext) {\n // Convert headers to object format if they're in array format\n let headers: Record<string, string | string[]>;\n if (Array.isArray(opts.headers)) {\n /* c8 ignore next */\n headers = Object.fromEntries(opts.headers as unknown as [string, string | string[]][]);\n } else {\n headers = { ...opts.headers as Record<string, string | string[]> };\n }\n\n // Inject outbreak trace headers\n for (const [header, value] of currentTraceContext) {\n if (typeof value === 'symbol' || typeof value === 'undefined') {\n continue;\n }\n headers[header] = value as string;\n }\n opts.headers = headers;\n }\n return dispatch(opts, handler);\n};\n","import type { ZodType, output } from 'zod';\nimport type { LoggerInstanceManager } from '@autofleet/logger';\nimport type CacheHandler from 'undici/types/cache-interceptor';\nimport Undici, { Agent, type Dispatcher, interceptors } from 'undici';\nimport { errors } from './errors';\nimport { testAgentParam } from './testingHelper';\nimport { outbreakInterceptor } from './outbreakInterceptor';\nimport {\n createRequestString,\n defaultRetryMethod,\n defaultSettings,\n defaultSettingsWithDecompress,\n isFormData,\n mergeConfig,\n parseUrlAndOrigin,\n resolveServiceUrl,\n} from './utils';\n\nconst { cacheStores } = Undici;\nconst { cache, retry, decompress } = interceptors;\n\nexport interface RapidoHttpClientSettings {\n [testAgentParam]?: Dispatcher;\n serviceName?: string;\n serviceUrl?: string;\n logger: LoggerInstanceManager;\n timeout?: number;\n retries?: interceptors.RetryInterceptorOpts;\n headers?: Record<string, string> | string[][];\n keepAliveTimeout?: number;\n keepAliveMaxTimeout?: number;\n connections?: number;\n cache?: CacheHandler.MemoryCacheStoreOpts;\n autoDecompress?: boolean;\n}\n\nexport interface RequestConfig {\n params?: Record<string, any>;\n body?: any;\n timeout?: number;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n responseSchema?: ZodType;\n}\n\nexport interface RapidoHttpClientResponse<T = any> {\n data: T;\n status: number;\n statusText: string;\n headers: Record<string, string | string[]>;\n config: RequestConfig & { url: string; method: string; baseURL?: string; };\n}\n\nconst retriableMethods: Dispatcher.HttpMethod[] = ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE', 'QUERY'];\n\nexport class RapidoHttpClient {\n readonly #logger: LoggerInstanceManager;\n private readonly settings: RapidoHttpClientSettings & { baseURL?: string; basePath?: string; };\n public readonly client: Dispatcher.ComposedDispatcher;\n\n public get<T = unknown>(url: string, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public get<T extends ZodType>(url: string, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public get<T = unknown>(url: string, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('GET', url, undefined, config);\n }\n\n public post<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public post<T extends ZodType>(url: string, body: any, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public post<T = unknown>(url: string, body?: any, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('POST', url, body, config);\n }\n\n public delete<T = unknown>(url: string, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public delete<T extends ZodType>(url: string, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public delete<T = unknown>(url: string, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('DELETE', url, undefined, config);\n }\n\n public head<T = unknown>(url: string, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public head<T extends ZodType>(url: string, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public head<T = unknown>(url: string, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('HEAD', url, undefined, config);\n }\n\n public put<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public put<T extends ZodType>(url: string, body: any, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public put<T = unknown>(url: string, body?: any, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('PUT', url, body, config);\n }\n\n public patch<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public patch<T extends ZodType>(url: string, body: any, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public patch<T = unknown>(url: string, body?: any, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('PATCH', url, body, config);\n }\n\n public options<T = unknown>(url: string, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public options<T extends ZodType>(url: string, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public options<T = unknown>(url: string, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('OPTIONS', url, undefined, config);\n }\n\n public query<T = unknown>(url: string, body?: any, config?: Omit<RequestConfig, 'responseSchema'> & { responseSchema?: never; }): Promise<RapidoHttpClientResponse<T>>;\n public query<T extends ZodType>(url: string, body: any, config: RequestConfig & { responseSchema: T; }): Promise<RapidoHttpClientResponse<output<T>>>;\n public query<T = unknown>(url: string, body?: any, config?: RequestConfig): Promise<RapidoHttpClientResponse<T>> {\n return this.#request<T>('QUERY', url, body, config);\n }\n\n constructor(settings: RapidoHttpClientSettings) {\n this.#logger = settings.logger;\n this.settings = mergeConfig<typeof defaultSettings, Partial<typeof settings>>(\n settings.autoDecompress ? defaultSettingsWithDecompress : defaultSettings,\n settings,\n ) as RapidoHttpClientSettings & { baseURL?: string; };\n this.#createBaseUrl();\n\n // In test mode, use the test dispatcher directly (MockAgent or MockPool) Otherwise, create an Agent which creates Client Pools\n // Check for global mock agent first (for testing), then test param, then create real Agent\n /* c8 ignore next */\n const globalMockAgent = (globalThis as any).__RAPIDO_HTTP_CLIENT_MOCK_AGENT__;\n /* c8 ignore next */\n this.client = this.settings[testAgentParam] ?? globalMockAgent ?? new Agent({\n connect: {\n timeout: this.settings.timeout,\n },\n keepAliveTimeout: this.settings.keepAliveTimeout,\n keepAliveMaxTimeout: this.settings.keepAliveMaxTimeout,\n connections: this.settings.connections,\n });\n\n if (this.settings.cache) {\n this.client = this.client.compose(cache({\n store: new cacheStores.MemoryCacheStore({\n ...this.settings.cache,\n }),\n }));\n }\n\n if (this.settings.retries) {\n this.client = this.client.compose(retry({\n methods: retriableMethods,\n ...this.settings.retries,\n retry: (err, context, callback) => {\n const { counter } = context.state;\n /* c8 ignore next */\n const maxRetries = context.opts.retryOptions?.maxRetries ?? 5;\n\n const retryToUse = this.settings.retries?.retry ?? defaultRetryMethod;\n const callbackWithLogging = (result?: Error | null) => {\n if (!result) {\n this.#logger.warn(`Request retry attempt ${counter}/${maxRetries}`, { err });\n }\n callback(result);\n };\n retryToUse(err, context, callbackWithLogging);\n },\n }));\n }\n\n if (this.settings.autoDecompress) {\n this.client = this.client.compose(decompress({ skipErrorResponses: false }));\n }\n\n this.client = this.client.compose(outbreakInterceptor);\n }\n\n #createBaseUrl(): void {\n const fullUrl = resolveServiceUrl(this.settings);\n const urlObj = new URL(fullUrl);\n this.settings.baseURL = urlObj.origin;\n this.settings.basePath = urlObj.pathname !== '/' ? urlObj.pathname : '';\n }\n\n #getSignal(currentSignal?: AbortSignal, timeout?: number): { signal?: AbortSignal; timeoutSignal?: AbortSignal; } {\n if (!currentSignal && !timeout) {\n return { signal: undefined, timeoutSignal: undefined };\n }\n\n if (currentSignal && !timeout) {\n return { signal: currentSignal, timeoutSignal: undefined };\n }\n\n const timeoutSignal = AbortSignal.timeout(timeout!);\n if (!currentSignal && timeout) {\n return { signal: timeoutSignal, timeoutSignal };\n }\n\n return { signal: AbortSignal.any([currentSignal!, timeoutSignal]), timeoutSignal };\n }\n\n #prepareRequestBody(body: any, headers: Record<string, string>): string | Buffer | FormData | undefined {\n if (body === undefined || body === null) {\n return undefined;\n }\n\n // Handle FormData instances automatically\n if (isFormData(body)) {\n if (!headers['Content-Type'] && !headers['content-type']) {\n headers['Content-Type'] = 'application/x-www-form-urlencoded';\n }\n return body;\n }\n\n if (typeof body === 'object' && !Buffer.isBuffer(body)) {\n // Check if Content-Type is set to application/x-www-form-urlencoded\n const contentType = headers['Content-Type'] || headers['content-type'];\n if (contentType && /application\\/x-www-form-urlencoded/i.test(contentType)) {\n // Encode as URL parameters\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(body)) {\n if (Array.isArray(value)) {\n value.forEach(v => params.append(key, String(v)));\n } else if (value !== undefined && value !== null) {\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n params.append(key, String(value));\n }\n }\n return params.toString();\n }\n // Default to JSON\n if (!headers['Content-Type'] && !headers['content-type']) {\n headers['Content-Type'] = 'application/json';\n }\n return JSON.stringify(body);\n } else if (typeof body === 'string') {\n return body;\n } else if (Buffer.isBuffer(body)) {\n return body;\n }\n return String(body);\n }\n\n async #request<T = any>(\n method: Dispatcher.HttpMethod,\n url: string,\n body?: any,\n config: RequestConfig = {},\n ): Promise<RapidoHttpClientResponse<T>> {\n const mergedConfig = mergeConfig(this.settings, config);\n\n if (mergedConfig.signal?.aborted) {\n this.#logger.error(`Request aborted before start: ${createRequestString(method, mergedConfig.baseURL, url)}`);\n throw new errors.RequestAbortedError(mergedConfig.signal.reason?.message || 'Request aborted', { cause: mergedConfig.signal.reason });\n }\n\n const headers: Record<string, string> = { ...mergedConfig.headers };\n const requestBody = this.#prepareRequestBody(body, headers);\n\n const { origin, path } = parseUrlAndOrigin(url, mergedConfig.baseURL!, mergedConfig.basePath);\n const requestInfo = { method, baseURL: origin, url };\n\n if (mergedConfig.params) {\n for (const [key, value] of Object.entries(mergedConfig.params)) {\n if (Array.isArray(value) && !key.endsWith('[]')) {\n mergedConfig.params[`${key}[]`] = value;\n delete mergedConfig.params[key];\n }\n }\n }\n\n const { signal, timeoutSignal } = this.#getSignal(mergedConfig.signal, mergedConfig.timeout);\n\n try {\n this.#logger.info(`Start Request: ${createRequestString(method, origin, path)}`);\n\n const requestOptions: Dispatcher.RequestOptions = {\n path,\n origin,\n method,\n signal,\n headers,\n body: requestBody,\n query: mergedConfig.params,\n };\n\n const response = await this.client.request(requestOptions);\n\n if (response.statusCode >= 400) {\n const data = await this.#parseResponse<T>(response, config.responseSchema);\n this.#logger.error(`Finish Request with error ${createRequestString(method, origin, path)}`, {\n status: response.statusCode,\n data,\n });\n\n throw new errors.RapidoHttpClientError<T>(requestBody, response, data);\n }\n\n this.#logger.info(`Finish Request: ${createRequestString(method, origin, path)}`);\n\n const data = response.statusCode !== 204 ? await this.#parseResponse<T>(response, config.responseSchema) : undefined as T;\n\n return {\n data,\n status: response.statusCode,\n statusText: '',\n headers: response.headers as Record<string, string | string[]>,\n config: requestInfo,\n };\n } catch (error) {\n if (timeoutSignal && timeoutSignal.reason === error) {\n // If the timeoutSignal aborted (config timeout), throw a timeout-specific error\n this.#logger.error(`Request timeout: ${createRequestString(method, origin, path)}`);\n const error = new errors.UndiciError(`Request timeout after ${mergedConfig.timeout}ms`, { cause: timeoutSignal.reason });\n error.code = 'UND_ERR_TIMEOUT';\n throw error;\n }\n if (signal && signal.reason === error) {\n // If the user's signal aborted, throw RequestAbortedError\n this.#logger.error(`Request aborted: ${createRequestString(method, origin, path)}`);\n throw new errors.RequestAbortedError(signal.reason.message, { cause: signal.reason });\n }\n\n this.#logger.error(`Finish Request with error ${createRequestString(method, origin, path)}`, { error });\n throw error;\n }\n }\n\n async #parseResponse<T>(response: Dispatcher.ResponseData, schema?: ZodType): Promise<T> {\n const contentType = (response.headers['content-type'] as string) || '';\n const bodyText = await response.body.text();\n\n if (!bodyText) {\n return undefined as T;\n }\n\n if (/text/i.test(contentType)) {\n return bodyText as T;\n }\n\n let json: unknown;\n try {\n json = JSON.parse(bodyText);\n } catch {\n return bodyText as T;\n }\n return (schema ? schema.parse(json) : json) as T;\n }\n\n /**\n * @param url The endpoint URL to send the request to.\n * @param options Additional options to include in the request payload.\n * @returns A promise that resolves to an array of all results.\n */\n async getAllPages<T>(url: string, options: RequestConfig = {}): Promise<T[]> {\n const currentResult: T[] = [];\n let resultsInFirstPage: number | null = null;\n let lastResultsSize: number | null = null;\n\n const localOptions = { ...options, params: { ...options.params, page: 1 } };\n // Make sure even if `options` had `params` we initialize `page` to 1.\n localOptions.params.page ||= 1;\n\n while ((localOptions.params.page === 1 || lastResultsSize === resultsInFirstPage) && lastResultsSize !== 0) {\n const { data } = await this.get<T[]>(url, localOptions as Omit<RequestConfig, 'responseSchema'>);\n lastResultsSize = data.length;\n if (localOptions.params.page === 1) {\n resultsInFirstPage = data.length;\n }\n\n localOptions.params.page += 1;\n Array.prototype.push.apply(currentResult, data);\n }\n\n return currentResult;\n }\n\n /**\n * Fetches all pages from a paginated API endpoint until all results are retrieved\n * or an optional page limit is reached.\n *\n * @param url The endpoint URL to send the request to.\n * @param options Additional options to include in the request payload.\n * @param pageLimit The maximum number of pages to fetch. Set to -1 for no limit.\n * @returns A promise that resolves to an array of all results.\n */\n async getAllPagesFromQueryEndpoint<T>(url: string, options: object = {}, pageLimit = 100): Promise<T[]> {\n const currentResult: T[] = [];\n\n let moreResultsToLoad = true;\n let page = 1;\n while (moreResultsToLoad && (pageLimit === -1 || page < pageLimit)) {\n const { data } = await this.post<{ rows: T[]; count: number; }>(url, {\n ...options,\n page,\n });\n const { rows, count } = data;\n page += 1;\n Array.prototype.push.apply(currentResult, rows);\n moreResultsToLoad = currentResult.length < count;\n }\n\n return currentResult;\n }\n\n async close(): Promise<void> {\n await this.client.close();\n }\n\n async [Symbol.asyncDispose](): Promise<void> {\n await this.close();\n }\n}\n\nexport default RapidoHttpClient;\nexport { errors };\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require(`./utils-B1ZhSXeE.cjs`),t=require(`./index.cjs`);let n=require(`undici`);function r({blockNonMockedNetwork:t,collectCallHistory:r}={}){let i=new n.MockAgent({enableCallHistory:r??!1});(t??!0)&&i.disableNetConnect(),globalThis.__RAPIDO_HTTP_CLIENT_MOCK_AGENT__=i;let a=new Map,o=new Map,s=e=>{let t=new URL(e),n=t.origin,r=t.pathname===`/`?``:t.pathname.replace(/\/$/,``);if(!a.has(n)){let e=i.get(n);a.set(n,e)}return r&&!o.has(n)&&o.set(n,r),{pool:a.get(n),basePath:o.get(n)||``}},c=(e,t)=>{if(typeof e==`string`)return{path:t+e};let n={...e};if(typeof n.path==`string`&&(n.path=t+n.path),n.body&&typeof n.body==`object`&&!(n.body instanceof RegExp)&&typeof n.body!=`function`){let e=n.headers,t=e?.[`Content-Type`]||e?.[`content-type`];if(t&&/application\/x-www-form-urlencoded/i.test(t)){let e=new URLSearchParams;for(let[t,r]of Object.entries(n.body))Array.isArray(r)?r.forEach(n=>e.append(t,String(n))):r!=null&&e.append(t,String(r));n.body=e.toString()}else n.body=JSON.stringify(n.body)}if(n.query)for(let[e,t]of Object.entries(n.query))Array.isArray(t)&&!e.endsWith(`[]`)&&(n.query[`${e}[]`]=t,delete n.query[e]);return n};return{intercept:t=>{let{pool:n,basePath:r}=s(typeof t==`string`?t:e.c(t));return{get:e=>n.intercept({...c(e,r),method:`GET`}),head:e=>n.intercept({...c(e,r),method:`HEAD`}),delete:e=>n.intercept({...c(e,r),method:`DELETE`}),options:e=>n.intercept({...c(e,r),method:`OPTIONS`}),put:e=>n.intercept({...c(e,r),method:`PUT`}),post:e=>n.intercept({...c(e,r),method:`POST`}),patch:e=>n.intercept({...c(e,r),method:`PATCH`}),query:e=>n.intercept({...c(e,r),method:`QUERY`})}},getPool:t=>s(typeof t==`string`?t:e.c(t)).pool,cleanup:async()=>{delete globalThis.__RAPIDO_HTTP_CLIENT_MOCK_AGENT__,a.clear(),o.clear(),await i.close(),i.clearCallHistory()},get calls(){return i.getCallHistory()?.calls()??[]},clearCallHistory:()=>i.clearCallHistory(),enableCallHistory:()=>{i.enableCallHistory()},disableCallHistory:()=>{i.disableCallHistory()},mockAgent:i}}exports.setupRapidoHttpClientMock=r;
2
+ //# sourceMappingURL=testing.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.cjs","names":["MockAgent","resolveServiceUrl"],"sources":["../src/testing.ts"],"sourcesContent":["import { MockAgent, type MockCallHistoryLog, type MockPool } from 'undici';\nimport { resolveServiceUrl } from './utils';\nimport type { MockInterceptor } from 'undici/types/mock-interceptor';\n\ninterface SetupRapidoHttpClientMockOptions {\n /** Whether to block any real network requests that are not mocked. @default true */\n blockNonMockedNetwork?: boolean;\n /** Collect call history for inspection/assertion. @default false */\n collectCallHistory?: boolean;\n}\n\ninterface InterceptOptions {\n /** Path to intercept on. */\n path: string | RegExp | ((path: string) => boolean);\n /** Body to intercept on. Plain objects will be JSON.stringify'd automatically. */\n body?: string | Record<string, any> | RegExp | ((body: string) => boolean);\n /** Headers to intercept on. */\n headers?: Record<string, string | RegExp | ((body: string) => boolean)> | ((headers: Record<string, string>) => boolean);\n /** Query params to intercept on */\n query?: Record<string, any>;\n}\n\nexport interface RapidoHttpClientMocker {\n /**\n * Set up intercepts for a specific origin with a chainable API.\n *\n * Returns an object with HTTP method helpers that create MockInterceptors.\n * Each method accepts either a path string or an InterceptOptions object for advanced matching.\n * The returned MockInterceptor supports `.reply()`, `.replyWithError()`, `.times()`, and `.persist()`.\n *\n * @param target - Either a URL string, or an object with serviceName or serviceUrl\n *\n * @example\n * ```typescript\n * // Simple path matching\n * mock.intercept('https://api.example.com')\n * .get('/users')\n * .reply(200, { users: [] }, { headers: { 'content-type': 'application/json' } });\n *\n * // Advanced matching with body, headers, query params\n * mock.intercept('https://api.example.com')\n * .post({ path: '/users', body: JSON.stringify({ name: 'John' }) })\n * .reply(201, { id: 1, name: 'John' }, { headers: { 'content-type': 'application/json' } });\n *\n * // Using serviceName (reads from env)\n * mock.intercept({ serviceName: 'USER' })\n * .get({ path: '/profile', query: { id: '123' } })\n * .reply(200, { id: 123, name: 'Alice' }, { headers: { 'content-type': 'application/json' } });\n *\n * // Chain with times() or persist()\n * mock.intercept({ serviceUrl: 'https://api.example.com' })\n * .get('/data')\n * .reply(200, { data: [] }, { headers: { 'content-type': 'application/json' } })\n * .times(3); // Only mock 3 times\n *\n * // Mock errors\n * mock.intercept('https://api.example.com')\n * .get('/error')\n * .replyWithError(new Error('Network failure'))\n * .persist(); // Always throw this error\n * ```\n */\n intercept: (target: string | { serviceName: string; } | { serviceUrl: string; }) => {\n get: (options: string | InterceptOptions) => MockInterceptor;\n head: (options: string | InterceptOptions) => MockInterceptor;\n delete: (options: string | InterceptOptions) => MockInterceptor;\n options: (options: string | InterceptOptions) => MockInterceptor;\n put: (options: string | InterceptOptions) => MockInterceptor;\n post: (options: string | InterceptOptions) => MockInterceptor;\n patch: (options: string | InterceptOptions) => MockInterceptor;\n query: (options: string | InterceptOptions) => MockInterceptor;\n };\n /**\n * Get the mock pool for a specific origin for advanced usage.\n * This gives you direct access to the undici MockPool for full control.\n *\n * @param target - Either a URL string, or an object with serviceName or serviceUrl\n */\n getPool: (target: string | { serviceName: string; } | { serviceUrl: string; }) => MockPool;\n /**\n * Clean up the global mock.\n * Should be called in afterEach or after tests complete.\n */\n cleanup: () => Promise<void>;\n /**\n * Access the underlying mock agent for advanced usage\n */\n mockAgent: MockAgent<MockAgent.Options>;\n /** Call history log of all intercepted requests. */\n calls: MockCallHistoryLog[];\n /** Clear the call history log. */\n clearCallHistory: () => void;\n /** Enable call history collection. */\n enableCallHistory: () => void;\n /** Disable call history collection. */\n disableCallHistory: () => void;\n}\n\n/**\n * Global mock setup for RapidoHttpClient.\n *\n * This provides a nock-like global mocking experience where you can set up\n * mock responses before creating RapidoHttpClient instances. The mock is automatically\n * used by any RapidoHttpClient instance created after setupGlobalMock() is called.\n *\n * @example\n * ```typescript\n * import { setupRapidoHttpClientMock } from '@autofleet/rapido-http-client/testing';\n * import { RapidoHttpClient } from '@autofleet/rapido-http-client';\n *\n * // In your test setup (e.g., beforeEach)\n * const mock = setupRapidoHttpClientMock();\n *\n * // Set up mocks for specific origins\n * const apiMock = mock.intercept('https://api.example.com');\n * apiMock.get('/users').reply(200, { users: [] });\n * apiMock.post('/users', { name: 'John' }).reply(201, { id: 1, name: 'John' });\n *\n * // Or use the pool directly for more control\n * mock.getPool('https://api.example.com')\n * .intercept({ path: '/data', method: 'GET' })\n * .reply(200, { data: 'test' }, { headers: { 'content-type': 'application/json' } });\n *\n * // Create RapidoHttpClient instances normally - mocks are automatically used!\n * const client = new RapidoHttpClient({\n * serviceUrl: 'https://api.example.com',\n * logger: mockLogger,\n * });\n *\n * // Use the client - it will use the mocked responses\n * const response = await client.get('/users');\n *\n * // Clean up in afterEach\n * await mock.cleanup();\n * ```\n */\nexport function setupRapidoHttpClientMock({ blockNonMockedNetwork, collectCallHistory }: SetupRapidoHttpClientMockOptions = {}): RapidoHttpClientMocker {\n const mockAgent = new MockAgent({ enableCallHistory: collectCallHistory ?? false });\n if (blockNonMockedNetwork ?? true) {\n mockAgent.disableNetConnect();\n }\n\n // Store the mock agent globally for RapidoHttpClient to use\n (globalThis as any).__RAPIDO_HTTP_CLIENT_MOCK_AGENT__ = mockAgent;\n\n const mockPools = new Map<string, MockPool>();\n const basePaths = new Map<string, string>(); // Track base paths for each origin\n\n const getOrCreatePool = (urlOrOrigin: string): { pool: MockPool; basePath: string; } => {\n // MockAgent requires just the origin, not the full URL with path\n // Extract origin and pathname if a full URL is provided\n const url = new URL(urlOrOrigin);\n const origin = url.origin;\n // Remove trailing slash from base path to avoid double slashes\n const basePath = url.pathname === '/' ? '' : url.pathname.replace(/\\/$/, '');\n\n if (!mockPools.has(origin)) {\n const pool = mockAgent.get<MockPool>(origin);\n mockPools.set(origin, pool);\n }\n\n // Store or retrieve the base path for this origin\n if (basePath && !basePaths.has(origin)) {\n basePaths.set(origin, basePath);\n }\n\n return { pool: mockPools.get(origin)!, basePath: basePaths.get(origin) || '' };\n };\n\n const normalizeOptions = (options: string | InterceptOptions, basePath: string): MockInterceptor.Options => {\n if (typeof options === 'string') {\n return { path: basePath + options };\n }\n const normalized = { ...options };\n\n // Prepend base path to the path option\n if (typeof normalized.path === 'string') {\n normalized.path = basePath + normalized.path;\n }\n\n // Auto-encode object bodies based on Content-Type\n if (normalized.body && typeof normalized.body === 'object' && !(normalized.body instanceof RegExp) && typeof normalized.body !== 'function') {\n // Check if Content-Type is application/x-www-form-urlencoded\n const headers = normalized.headers as Record<string, string> | undefined;\n const contentType = headers?.['Content-Type'] || headers?.['content-type'];\n\n if (contentType && /application\\/x-www-form-urlencoded/i.test(contentType)) {\n // URL-encode the body (same logic as RapidoHttpClient's #prepareRequestBody)\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(normalized.body)) {\n if (Array.isArray(value)) {\n value.forEach(v => params.append(key, String(v)));\n } else if (value !== undefined && value !== null) {\n params.append(key, String(value));\n }\n }\n normalized.body = params.toString();\n } else {\n // Default to JSON\n normalized.body = JSON.stringify(normalized.body);\n }\n }\n // Auto-append [] to array query params\n if (normalized.query) {\n for (const [key, value] of Object.entries(normalized.query)) {\n if (Array.isArray(value) && !key.endsWith('[]')) {\n normalized.query[`${key}[]`] = value;\n delete normalized.query[key];\n }\n }\n }\n return normalized as MockInterceptor.Options;\n };\n\n return {\n intercept: (target: string | { serviceName: string; } | { serviceUrl: string; }) => {\n const origin = typeof target === 'string' ? target : resolveServiceUrl(target);\n const { pool, basePath } = getOrCreatePool(origin);\n\n return {\n get: (options: string | InterceptOptions) => pool.intercept({ ...normalizeOptions(options, basePath), method: 'GET' }),\n head: (options: string | InterceptOptions) => pool.intercept({ ...normalizeOptions(options, basePath), method: 'HEAD' }),\n delete: (options: string | InterceptOptions) => pool.intercept({ ...normalizeOptions(options, basePath), method: 'DELETE' }),\n options: (options: string | InterceptOptions) => pool.intercept({ ...normalizeOptions(options, basePath), method: 'OPTIONS' }),\n put: (options: string | InterceptOptions) => pool.intercept({ ...normalizeOptions(options, basePath), method: 'PUT' }),\n post: (options: string | InterceptOptions) => pool.intercept({ ...normalizeOptions(options, basePath), method: 'POST' }),\n patch: (options: string | InterceptOptions) => pool.intercept({ ...normalizeOptions(options, basePath), method: 'PATCH' }),\n query: (options: string | InterceptOptions) => pool.intercept({ ...normalizeOptions(options, basePath), method: 'QUERY' }),\n };\n },\n\n getPool: (target: string | { serviceName: string; } | { serviceUrl: string; }): MockPool => {\n const origin = typeof target === 'string' ? target : resolveServiceUrl(target);\n return getOrCreatePool(origin).pool;\n },\n cleanup: async (): Promise<void> => {\n delete (globalThis as any).__RAPIDO_HTTP_CLIENT_MOCK_AGENT__;\n mockPools.clear();\n basePaths.clear();\n await mockAgent.close();\n mockAgent.clearCallHistory();\n },\n\n get calls(): MockCallHistoryLog[] {\n return mockAgent.getCallHistory()?.calls() ?? [];\n },\n\n clearCallHistory: (): void => mockAgent.clearCallHistory(),\n\n enableCallHistory: (): void => {\n mockAgent.enableCallHistory();\n },\n\n disableCallHistory: (): void => {\n mockAgent.disableCallHistory();\n },\n\n mockAgent,\n };\n}\n"],"mappings":"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"}