@autofleet/network 1.12.13 → 1.13.0
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/README.md +2 -1
- package/lib/index.cjs +1 -1
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +14 -1
- package/lib/index.d.ts +14 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ await client.post('/data', { payload });
|
|
|
30
30
|
- **Keep-alive connections** - Persistent HTTP/HTTPS connections with configurable socket timeout (default: 5s)
|
|
31
31
|
- **Request caching** - Cache responses with configurable TTL and invalidation
|
|
32
32
|
- **Automatic retries** - Exponential backoff retry logic with `axios-retry`
|
|
33
|
-
- **Logging** - Request/response logging via `@autofleet/logger`
|
|
33
|
+
- **Logging** - Request/response logging via `@autofleet/logger`. Failed requests are logged at `warn` for 4xx responses and `error` for 5xx responses or network failures (no status). Set `failuresLogLevel` (e.g. `'error'`, `'warn'`, `'debug'`) on the instance or per-request to override this default and force every failure to log at the given level.
|
|
34
34
|
- **Pagination helpers** - `getAllPages()` and `getAllPagesFromQueryEndpoint()` methods
|
|
35
35
|
|
|
36
36
|
## Configuration
|
|
@@ -46,6 +46,7 @@ await client.post('/data', { payload });
|
|
|
46
46
|
logger?: LoggerInstanceManager;
|
|
47
47
|
retries?: number; // Number of retry attempts
|
|
48
48
|
cache?: IAxiosCacheAdapterOptions; // Cache configuration
|
|
49
|
+
failuresLogLevel?: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'; // Override the level used for failed requests (default: 4xx→warn, 5xx→error)
|
|
49
50
|
}
|
|
50
51
|
```
|
|
51
52
|
|
package/lib/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
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));let c=require(`node:process`),l=require(`node:module`),u=require(`axios`);u=s(u);let d=require(`axios-retry`);d=s(d);let f=require(`@autofleet/logger`);f=s(f);let p=require(`deepmerge`);p=s(p);let m=require(`@autofleet/axios-cache-adapter`);m=s(m);let h=require(`agentkeepalive`);const{setup:g}=m.default,_=d.default,v=(0,l.createRequire)(require(`url`).pathToFileURL(__filename).href);let y;const b=(...e)=>(y??=v(`qs`).stringify,y(...e)),x=[`get`,`post`,`delete`,`head`,`put`,`patch`,`options`],S={arrayFormat:`brackets`},C={timeout:1e4,headers:{"X-AF-AUTH":`ANYONE`,"X-IAF-ORIGIN-SERVICE":c.env.AF_SERVICE_NAME||null},paramsSerializer:e=>b(e,S),"axios-retry":{shouldResetTimeout:!0},keepAlive:!0},w=e=>`[${(e.method||``).toUpperCase()}] ${e.baseURL??`unknown-base-url`}${e.url??`/unknown-url`}`,T=Number.parseInt(c.env.FREE_SOCKET_TIMEOUT||``,10)||5e3;var E=class{#e;constructor(e={}){this.#e=e.logger??(0,f.default)(),this.settings=(0,p.default)(C,e),this.settings.keepAlive?(this.settings.httpAgent=new h.HttpAgent({freeSocketTimeout:T}),this.settings.httpsAgent=new h.HttpsAgent({freeSocketTimeout:T}),delete this.settings.keepAlive):this.settings.keepAlive===!1&&process.env.NETWORK_ALLOW_KEEPALIVE_FALSE===`true`&&(this.settings.httpAgent=new h.HttpAgent({keepAlive:!1}),this.settings.httpsAgent=new h.HttpsAgent({keepAlive:!1}),delete this.settings.keepAlive),this.#r(),e.cache&&(this.settings.cache={maxAge:900*1e3,exclude:{query:!1},...e.cache}),this.axios=e.cache?g(this.settings):u.default.create(this.settings),this.#t(e),this.#i(),this.#n()}#t(e){_(this.axios,{retries:0,retryDelay:d.default.exponentialDelay,...e})}#n(){this.axios.interceptors.request.use(e=>(this.#e.info(`Start Request: ${w(e)}`),e)),this.axios.interceptors.response.use(e=>(this.#e.info(`Finish Request: ${w(e.config)}`),e),e=>{if(e.request?._currentRequest?.reusedSocket&&[`ECONNRESET`,`EPIPE`].includes(e.code))return this.#e.warn(`${e.code} issue, will retry`,{req:e.request._currentRequest._currentUrl}),this.axios.request(e.config);let t=e.config?.baseURL?e.config:e.request;throw this.#e
|
|
1
|
+
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));let c=require(`node:process`),l=require(`node:module`),u=require(`axios`);u=s(u);let d=require(`axios-retry`);d=s(d);let f=require(`@autofleet/logger`);f=s(f);let p=require(`deepmerge`);p=s(p);let m=require(`@autofleet/axios-cache-adapter`);m=s(m);let h=require(`agentkeepalive`);const{setup:g}=m.default,_=d.default,v=(0,l.createRequire)(require(`url`).pathToFileURL(__filename).href);let y;const b=(...e)=>(y??=v(`qs`).stringify,y(...e)),x=[`get`,`post`,`delete`,`head`,`put`,`patch`,`options`],S={arrayFormat:`brackets`},C={timeout:1e4,headers:{"X-AF-AUTH":`ANYONE`,"X-IAF-ORIGIN-SERVICE":c.env.AF_SERVICE_NAME||null},paramsSerializer:e=>b(e,S),"axios-retry":{shouldResetTimeout:!0},keepAlive:!0},w=e=>`[${(e.method||``).toUpperCase()}] ${e.baseURL??`unknown-base-url`}${e.url??`/unknown-url`}`,T=Number.parseInt(c.env.FREE_SOCKET_TIMEOUT||``,10)||5e3;var E=class{#e;constructor(e={}){this.#e=e.logger??(0,f.default)(),this.settings=(0,p.default)(C,e),this.settings.keepAlive?(this.settings.httpAgent=new h.HttpAgent({freeSocketTimeout:T}),this.settings.httpsAgent=new h.HttpsAgent({freeSocketTimeout:T}),delete this.settings.keepAlive):this.settings.keepAlive===!1&&process.env.NETWORK_ALLOW_KEEPALIVE_FALSE===`true`&&(this.settings.httpAgent=new h.HttpAgent({keepAlive:!1}),this.settings.httpsAgent=new h.HttpsAgent({keepAlive:!1}),delete this.settings.keepAlive),this.#r(),e.cache&&(this.settings.cache={maxAge:900*1e3,exclude:{query:!1},...e.cache}),this.axios=e.cache?g(this.settings):u.default.create(this.settings),this.#t(e),this.#i(),this.#n()}#t(e){_(this.axios,{retries:0,retryDelay:d.default.exponentialDelay,...e})}#n(){this.axios.interceptors.request.use(e=>(this.#e.info(`Start Request: ${w(e)}`),e)),this.axios.interceptors.response.use(e=>(this.#e.info(`Finish Request: ${w(e.config)}`),e),e=>{if(e.request?._currentRequest?.reusedSocket&&[`ECONNRESET`,`EPIPE`].includes(e.code))return this.#e.warn(`${e.code} issue, will retry`,{req:e.request._currentRequest._currentUrl}),this.axios.request(e.config);let t=e.config?.baseURL?e.config:e.request,n=e.response?.status??e.status,r=e.config?.failuresLogLevel??this.settings.failuresLogLevel??(!n||n>=500?`error`:`warn`);throw this.#e[r](`Finish Request with error ${t?w(t):``}`,{status:n,data:e.response?.data}),e})}#r(){if(!this.settings.serviceUrl&&!this.settings.serviceName)throw Error(`At least one of the settings Missing serviceUrl or serviceName`);let{settings:e}=this;e.serviceUrl?e.baseURL=e.serviceUrl:e.serviceName&&(e.baseURL=`http://${c.env[`${e.serviceName}_SERVICE_HOST`]}`)}#i(){x.forEach(e=>{this[e]=(...t)=>this.axios[e](...t)})}async getAllPages(e,t={}){let n=[],r=null,i=null,{params:{page:a=1,...o}={},...s}=t,c={params:{page:a||1,...o},...s};for(;(c.params.page===1||i===r)&&i!==0;){let{data:t}=await this.get(e,c);i=t.length,c.params.page===1&&(r=t.length),c.params.page+=1,Array.prototype.push.apply(n,t)}return n}async getAllPagesFromQueryEndpoint(e,t={},n=100,r){let i=[],a=!0,o=1;for(;a&&(n===-1||o<n);){let{data:n}=await this.post(e,{...t,page:o},r),{rows:s,count:c}=n;o+=1,Array.prototype.push.apply(i,s),a=i.length<c}return i}};module.exports=E;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/lib/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["axiosCacheAdapter","axiosRetry","qsStringify: typeof stringify | undefined","qsStringifyOptions: NonNullable<Parameters<typeof stringify>[1]>","defaultSettings: NetworkSettings","env","#logger","HttpAgent","HttpsAgent","#createBaseUrl","#addRetry","#buildClassHttpMethods","#addLogs","currentResult: T[]","resultsInFirstPage: number | null","lastResultsSize: number | null"],"sources":["../src/index.ts"],"sourcesContent":["import { env } from 'node:process';\nimport { createRequire } from 'node:module';\nimport axios, { type CreateAxiosDefaults, type AxiosRequestConfig, type AxiosInstance, type AxiosResponse, type AxiosRequestHeaders } from 'axios';\nimport axiosRetry, { type IAxiosRetryConfigExtended, type IAxiosRetryConfig, type IAxiosRetryReturn } from 'axios-retry';\nimport Logger, { type LoggerInstanceManager } from '@autofleet/logger';\nimport merge from 'deepmerge';\nimport axiosCacheAdapter from '@autofleet/axios-cache-adapter';\nimport { HttpAgent, HttpsAgent } from 'agentkeepalive';\nimport type { stringify } from 'qs';\nimport type { IAxiosCacheAdapterOptions } from '@autofleet/axios-cache-adapter';\n\ndeclare module 'axios' {\n interface AxiosRequestConfig {\n /** configure how the cached requests will be handled, where they will be stored, etc. */\n cache?: IAxiosCacheAdapterOptions;\n /** force cache invalidation */\n clearCacheEntry?: boolean;\n 'axios-retry'?: IAxiosRetryConfigExtended;\n }\n}\n\nconst { setup } = axiosCacheAdapter as { setup: (options: AxiosRequestConfig) => AxiosInstance; };\nconst correctlyTypedAxiosRetry = axiosRetry as unknown as (axiosInstance: AxiosInstance, axiosRetryConfig?: IAxiosRetryConfig) => IAxiosRetryReturn;\n\nconst safeRequire = createRequire(import.meta.url);\n\nlet qsStringify: typeof stringify | undefined;\nconst lazilyLoadQsStringify = (...args: Parameters<typeof stringify>) => {\n qsStringify ??= safeRequire('qs').stringify;\n return qsStringify!(...args);\n};\n\nconst HTTPMethods = [\n 'get',\n 'post',\n 'delete',\n 'head',\n 'put',\n 'patch',\n 'options',\n] as const;\n\nconst qsStringifyOptions: NonNullable<Parameters<typeof stringify>[1]> = { arrayFormat: 'brackets' };\n\n/**\n * Network client configuration settings\n */\ninterface NetworkSettings extends CreateAxiosDefaults, IAxiosRetryConfig {\n /** Service name for Kubernetes DNS resolution (e.g., 'EXAMPLE_MS' resolves to EXAMPLE_MS_SERVICE_HOST) */\n serviceName?: string;\n /** Direct service URL (alternative to serviceName) */\n serviceUrl?: string;\n /**\n * Enable HTTP keep-alive connections (default: true)\n * @since 1.9.0 - To disable keep-alive, set to false AND set env var NETWORK_ALLOW_KEEPALIVE_FALSE=true\n */\n keepAlive?: boolean;\n /** Logger instance for request/response logging */\n logger?: LoggerInstanceManager;\n /** Request timeout in milliseconds (default: 10000) */\n timeout?: number;\n}\n\nconst defaultSettings: NetworkSettings = {\n timeout: 10_000,\n headers: {\n 'X-AF-AUTH': 'ANYONE',\n 'X-IAF-ORIGIN-SERVICE': env.AF_SERVICE_NAME || null as unknown as string,\n },\n paramsSerializer: params => lazilyLoadQsStringify(params, qsStringifyOptions),\n 'axios-retry': {\n shouldResetTimeout: true,\n },\n keepAlive: true,\n};\n\nconst createRequestString = (request: AxiosRequestConfig): string => `[${(request.method || '').toUpperCase()}] ${request.baseURL ?? 'unknown-base-url'}${request.url ?? '/unknown-url'}`;\n\n/*\n The default free socket keepalive timeout, in milliseconds.\n Setting to 5000 (5 seconds) as default because out grace period is 10 seconds\n and we want to make sure we don't have any socket issues.\n See https://www.npmjs.com/package/agentkeepalive\n\n There is also autoscaling reason for that, if we don't timeout at some point,\n new pods that were auto scaled will not be used.\n*/\nconst FREE_SOCKET_TIMEOUT = Number.parseInt(env.FREE_SOCKET_TIMEOUT || '', 10) || 5_000;\n\n/**\n * HTTP client wrapper built on Axios with keep-alive connection pooling, caching, retry logic, and logging.\n *\n * @example\n * ```typescript\n * const client = new Network({\n * serviceName: 'EXAMPLE_MS',\n * timeout: 10000,\n * retries: 3\n * });\n *\n * const response = await client.get('/endpoint');\n * await client.post('/data', { payload });\n * ```\n */\nexport default class Network {\n readonly #logger: LoggerInstanceManager;\n private readonly settings: NetworkSettings;\n private readonly axios: AxiosInstance;\n\n public get!: AxiosInstance['get'];\n public post!: AxiosInstance['post'];\n public delete!: AxiosInstance['delete'];\n public head!: AxiosInstance['head'];\n public put!: AxiosInstance['put'];\n public patch!: AxiosInstance['patch'];\n public options!: AxiosInstance['options'];\n\n constructor(settings: NetworkSettings = {}) {\n this.#logger = settings.logger ?? Logger();\n this.settings = merge(defaultSettings, settings);\n\n // Configure keep-alive behavior\n if (this.settings.keepAlive) {\n // Enable keep-alive with custom free socket timeout\n this.settings.httpAgent = new HttpAgent({ freeSocketTimeout: FREE_SOCKET_TIMEOUT });\n this.settings.httpsAgent = new HttpsAgent({ freeSocketTimeout: FREE_SOCKET_TIMEOUT });\n delete this.settings.keepAlive;\n } else if (this.settings.keepAlive === false && process.env.NETWORK_ALLOW_KEEPALIVE_FALSE === 'true') {\n // [v1.9.0] Explicitly disable keep-alive\n // Node.js 20+ has keep-alive enabled by default, so we need to explicitly set keepAlive: false\n // This env var is required to prevent silent performance degradation in services that unknowingly relied on keep-alive\n this.settings.httpAgent = new HttpAgent({ keepAlive: false });\n this.settings.httpsAgent = new HttpsAgent({ keepAlive: false });\n delete this.settings.keepAlive;\n }\n\n this.#createBaseUrl();\n\n if (settings.cache) {\n this.settings.cache = {\n maxAge: 15 * 60 * 1000,\n // Store responses from requests with query parameters in cache\n exclude: { query: false },\n ...settings.cache,\n };\n }\n\n this.axios = settings.cache ? setup(this.settings as NetworkSettings & { headers: AxiosRequestHeaders; }) : axios.create(this.settings);\n this.#addRetry(settings);\n this.#buildClassHttpMethods();\n this.#addLogs();\n }\n\n #addRetry(settings: NetworkSettings): void {\n correctlyTypedAxiosRetry(this.axios, {\n retries: 0,\n retryDelay: axiosRetry.exponentialDelay,\n ...settings,\n });\n }\n\n #addLogs(): void {\n this.axios.interceptors.request.use((request) => {\n this.#logger.info(`Start Request: ${createRequestString(request)}`);\n return request;\n });\n\n this.axios.interceptors.response.use((response) => {\n this.#logger.info(`Finish Request: ${createRequestString(response.config)}`);\n return response;\n }, (error) => {\n if (error.request?._currentRequest?.reusedSocket && ['ECONNRESET', 'EPIPE'].includes(error.code)) {\n // See https://www.npmjs.com/package/agentkeepalive\n // Support req.reusedSocket\n // https://code-examples.net/en/q/28a8069\n this.#logger.warn(`${error.code} issue, will retry`, {\n req: error.request._currentRequest._currentUrl,\n // method: error.request._currentRequest._options.method,\n });\n return this.axios.request(error.config);\n }\n const request = error.config?.baseURL ? error.config : error.request;\n this.#logger.error(`Finish Request with error ${request ? createRequestString(request) : ''}`, {\n status: error.status,\n data: error.response?.data,\n });\n throw error;\n });\n }\n\n #createBaseUrl(): void {\n if (!this.settings.serviceUrl && !this.settings.serviceName) {\n throw new Error('At least one of the settings Missing serviceUrl or serviceName');\n }\n\n const { settings } = this;\n if (settings.serviceUrl) {\n settings.baseURL = settings.serviceUrl;\n } else if (settings.serviceName) {\n const envServiceHostName = `${settings.serviceName}_SERVICE_HOST`;\n settings.baseURL = `http://${env[envServiceHostName]}`;\n }\n }\n\n /**\n * Build class methods that wrap axios methods\n */\n #buildClassHttpMethods(): void {\n HTTPMethods.forEach((method) => {\n this[method] = <T = any, R = AxiosResponse<T>>(\n ...args: Parameters<AxiosInstance[typeof method]>\n ): Promise<R> => this.axios[method](...args as [url: string, leaveUsAlone?: AxiosRequestConfig<unknown>]);\n });\n }\n\n /**\n * Fetches all pages from a paginated API endpoint using page-based pagination.\n * Continues fetching until the response size differs from the first page or returns empty.\n *\n * @param url The endpoint URL to send the request to.\n * @param options Additional Axios request options to include (e.g., headers, params).\n * @returns A promise that resolves to an array of all results from all pages.\n *\n * @example\n * ```typescript\n * const allUsers = await client.getAllPages<User>('/users', {\n * params: { status: 'active' }\n * });\n * ```\n */\n public async getAllPages<T>(url: string, options: object = {}): Promise<T[]> {\n const currentResult: T[] = [];\n let resultsInFirstPage: number | null = null;\n let lastResultsSize: number | null = null;\n const { params: { page = 1, ...restParams } = {}, ...rest } = options as any;\n // Ensure `page` is always the first property in params and initialized to 1, even if `options` already had `params`.\n const localOptions = { params: { page: page || 1, ...restParams }, ...rest };\n while ((localOptions.params.page === 1 || lastResultsSize === resultsInFirstPage) && lastResultsSize !== 0) {\n const { data } = await this.get<T[]>(url, localOptions);\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 that uses POST requests with `{ rows, count }` response format.\n * Continues fetching until all results are retrieved or the optional page limit is reached.\n *\n * @param url The endpoint URL to send POST requests to.\n * @param options Additional options to include in the request payload (merged with page number).\n * @param pageLimit The maximum number of pages to fetch (default: 100). Set to -1 for no limit.\n * @param config Optional Axios request configuration (e.g., headers).\n * @returns A promise that resolves to an array of all results from all pages.\n *\n * @example\n * ```typescript\n * const allOrders = await client.getAllPagesFromQueryEndpoint<Order>('/orders/query', {\n * filters: { status: 'pending' }\n * }, 50);\n * ```\n */\n public async getAllPagesFromQueryEndpoint<T>(url: string, options: object = {}, pageLimit = 100, config?: AxiosRequestConfig<unknown>): 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 }, config);\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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["axiosCacheAdapter","axiosRetry","qsStringify: typeof stringify | undefined","qsStringifyOptions: NonNullable<Parameters<typeof stringify>[1]>","defaultSettings: NetworkSettings","env","#logger","HttpAgent","HttpsAgent","#createBaseUrl","#addRetry","#buildClassHttpMethods","#addLogs","currentResult: T[]","resultsInFirstPage: number | null","lastResultsSize: number | null"],"sources":["../src/index.ts"],"sourcesContent":["import { env } from 'node:process';\nimport { createRequire } from 'node:module';\nimport axios, { type CreateAxiosDefaults, type AxiosRequestConfig, type AxiosInstance, type AxiosResponse, type AxiosRequestHeaders } from 'axios';\nimport axiosRetry, { type IAxiosRetryConfigExtended, type IAxiosRetryConfig, type IAxiosRetryReturn } from 'axios-retry';\nimport Logger, { type LoggerInstanceManager, type LogLevel } from '@autofleet/logger';\nimport merge from 'deepmerge';\nimport axiosCacheAdapter from '@autofleet/axios-cache-adapter';\nimport { HttpAgent, HttpsAgent } from 'agentkeepalive';\nimport type { stringify } from 'qs';\nimport type { IAxiosCacheAdapterOptions } from '@autofleet/axios-cache-adapter';\n\ndeclare module 'axios' {\n interface AxiosRequestConfig {\n /** configure how the cached requests will be handled, where they will be stored, etc. */\n cache?: IAxiosCacheAdapterOptions;\n /** force cache invalidation */\n clearCacheEntry?: boolean;\n 'axios-retry'?: IAxiosRetryConfigExtended;\n /**\n * Override the log level used when this request fails. When set, replaces the default\n * 4xx → warn / 5xx → error split — *all* failures (including 5xx and network errors)\n * will be logged at this level. Leave undefined to use the status-based default.\n */\n failuresLogLevel?: `${LogLevel}`;\n }\n}\n\nconst { setup } = axiosCacheAdapter as { setup: (options: AxiosRequestConfig) => AxiosInstance; };\nconst correctlyTypedAxiosRetry = axiosRetry as unknown as (axiosInstance: AxiosInstance, axiosRetryConfig?: IAxiosRetryConfig) => IAxiosRetryReturn;\n\nconst safeRequire = createRequire(import.meta.url);\n\nlet qsStringify: typeof stringify | undefined;\nconst lazilyLoadQsStringify = (...args: Parameters<typeof stringify>) => {\n qsStringify ??= safeRequire('qs').stringify;\n return qsStringify!(...args);\n};\n\nconst HTTPMethods = [\n 'get',\n 'post',\n 'delete',\n 'head',\n 'put',\n 'patch',\n 'options',\n] as const;\n\nconst qsStringifyOptions: NonNullable<Parameters<typeof stringify>[1]> = { arrayFormat: 'brackets' };\n\n/**\n * Network client configuration settings\n */\ninterface NetworkSettings extends CreateAxiosDefaults, IAxiosRetryConfig {\n /** Service name for Kubernetes DNS resolution (e.g., 'EXAMPLE_MS' resolves to EXAMPLE_MS_SERVICE_HOST) */\n serviceName?: string;\n /** Direct service URL (alternative to serviceName) */\n serviceUrl?: string;\n /**\n * Enable HTTP keep-alive connections (default: true)\n * @since 1.9.0 - To disable keep-alive, set to false AND set env var NETWORK_ALLOW_KEEPALIVE_FALSE=true\n */\n keepAlive?: boolean;\n /** Logger instance for request/response logging */\n logger?: LoggerInstanceManager;\n /** Request timeout in milliseconds (default: 10000) */\n timeout?: number;\n /**\n * Override the log level used when a request fails. When set, replaces the default\n * 4xx → warn / 5xx → error split — *all* failures (including 5xx and network errors)\n * will be logged at this level. Can also be overridden per-request via the same key\n * on AxiosRequestConfig (per-request wins over instance).\n */\n failuresLogLevel?: `${LogLevel}`;\n}\n\nconst defaultSettings: NetworkSettings = {\n timeout: 10_000,\n headers: {\n 'X-AF-AUTH': 'ANYONE',\n 'X-IAF-ORIGIN-SERVICE': env.AF_SERVICE_NAME || null as unknown as string,\n },\n paramsSerializer: params => lazilyLoadQsStringify(params, qsStringifyOptions),\n 'axios-retry': {\n shouldResetTimeout: true,\n },\n keepAlive: true,\n};\n\nconst createRequestString = (request: AxiosRequestConfig): string => `[${(request.method || '').toUpperCase()}] ${request.baseURL ?? 'unknown-base-url'}${request.url ?? '/unknown-url'}`;\n\n/*\n The default free socket keepalive timeout, in milliseconds.\n Setting to 5000 (5 seconds) as default because out grace period is 10 seconds\n and we want to make sure we don't have any socket issues.\n See https://www.npmjs.com/package/agentkeepalive\n\n There is also autoscaling reason for that, if we don't timeout at some point,\n new pods that were auto scaled will not be used.\n*/\nconst FREE_SOCKET_TIMEOUT = Number.parseInt(env.FREE_SOCKET_TIMEOUT || '', 10) || 5_000;\n\n/**\n * HTTP client wrapper built on Axios with keep-alive connection pooling, caching, retry logic, and logging.\n *\n * @example\n * ```typescript\n * const client = new Network({\n * serviceName: 'EXAMPLE_MS',\n * timeout: 10000,\n * retries: 3\n * });\n *\n * const response = await client.get('/endpoint');\n * await client.post('/data', { payload });\n * ```\n */\nexport default class Network {\n readonly #logger: LoggerInstanceManager;\n private readonly settings: NetworkSettings;\n private readonly axios: AxiosInstance;\n\n public get!: AxiosInstance['get'];\n public post!: AxiosInstance['post'];\n public delete!: AxiosInstance['delete'];\n public head!: AxiosInstance['head'];\n public put!: AxiosInstance['put'];\n public patch!: AxiosInstance['patch'];\n public options!: AxiosInstance['options'];\n\n constructor(settings: NetworkSettings = {}) {\n this.#logger = settings.logger ?? Logger();\n this.settings = merge(defaultSettings, settings);\n\n // Configure keep-alive behavior\n if (this.settings.keepAlive) {\n // Enable keep-alive with custom free socket timeout\n this.settings.httpAgent = new HttpAgent({ freeSocketTimeout: FREE_SOCKET_TIMEOUT });\n this.settings.httpsAgent = new HttpsAgent({ freeSocketTimeout: FREE_SOCKET_TIMEOUT });\n delete this.settings.keepAlive;\n } else if (this.settings.keepAlive === false && process.env.NETWORK_ALLOW_KEEPALIVE_FALSE === 'true') {\n // [v1.9.0] Explicitly disable keep-alive\n // Node.js 20+ has keep-alive enabled by default, so we need to explicitly set keepAlive: false\n // This env var is required to prevent silent performance degradation in services that unknowingly relied on keep-alive\n this.settings.httpAgent = new HttpAgent({ keepAlive: false });\n this.settings.httpsAgent = new HttpsAgent({ keepAlive: false });\n delete this.settings.keepAlive;\n }\n\n this.#createBaseUrl();\n\n if (settings.cache) {\n this.settings.cache = {\n maxAge: 15 * 60 * 1000,\n // Store responses from requests with query parameters in cache\n exclude: { query: false },\n ...settings.cache,\n };\n }\n\n this.axios = settings.cache ? setup(this.settings as NetworkSettings & { headers: AxiosRequestHeaders; }) : axios.create(this.settings);\n this.#addRetry(settings);\n this.#buildClassHttpMethods();\n this.#addLogs();\n }\n\n #addRetry(settings: NetworkSettings): void {\n correctlyTypedAxiosRetry(this.axios, {\n retries: 0,\n retryDelay: axiosRetry.exponentialDelay,\n ...settings,\n });\n }\n\n #addLogs(): void {\n this.axios.interceptors.request.use((request) => {\n this.#logger.info(`Start Request: ${createRequestString(request)}`);\n return request;\n });\n\n this.axios.interceptors.response.use((response) => {\n this.#logger.info(`Finish Request: ${createRequestString(response.config)}`);\n return response;\n }, (error) => {\n if (error.request?._currentRequest?.reusedSocket && ['ECONNRESET', 'EPIPE'].includes(error.code)) {\n // See https://www.npmjs.com/package/agentkeepalive\n // Support req.reusedSocket\n // https://code-examples.net/en/q/28a8069\n this.#logger.warn(`${error.code} issue, will retry`, {\n req: error.request._currentRequest._currentUrl,\n // method: error.request._currentRequest._options.method,\n });\n return this.axios.request(error.config);\n }\n const request = error.config?.baseURL ? error.config : error.request;\n const status = error.response?.status ?? error.status;\n const overrideLevel: `${LogLevel}` | undefined = error.config?.failuresLogLevel ?? this.settings.failuresLogLevel;\n const defaultLevel: `${LogLevel}` = !status || status >= 500 ? 'error' : 'warn';\n const level = overrideLevel ?? defaultLevel;\n this.#logger[level](`Finish Request with error ${request ? createRequestString(request) : ''}`, {\n status,\n data: error.response?.data,\n });\n throw error;\n });\n }\n\n #createBaseUrl(): void {\n if (!this.settings.serviceUrl && !this.settings.serviceName) {\n throw new Error('At least one of the settings Missing serviceUrl or serviceName');\n }\n\n const { settings } = this;\n if (settings.serviceUrl) {\n settings.baseURL = settings.serviceUrl;\n } else if (settings.serviceName) {\n const envServiceHostName = `${settings.serviceName}_SERVICE_HOST`;\n settings.baseURL = `http://${env[envServiceHostName]}`;\n }\n }\n\n /**\n * Build class methods that wrap axios methods\n */\n #buildClassHttpMethods(): void {\n HTTPMethods.forEach((method) => {\n this[method] = <T = any, R = AxiosResponse<T>>(\n ...args: Parameters<AxiosInstance[typeof method]>\n ): Promise<R> => this.axios[method](...args as [url: string, leaveUsAlone?: AxiosRequestConfig<unknown>]);\n });\n }\n\n /**\n * Fetches all pages from a paginated API endpoint using page-based pagination.\n * Continues fetching until the response size differs from the first page or returns empty.\n *\n * @param url The endpoint URL to send the request to.\n * @param options Additional Axios request options to include (e.g., headers, params).\n * @returns A promise that resolves to an array of all results from all pages.\n *\n * @example\n * ```typescript\n * const allUsers = await client.getAllPages<User>('/users', {\n * params: { status: 'active' }\n * });\n * ```\n */\n public async getAllPages<T>(url: string, options: object = {}): Promise<T[]> {\n const currentResult: T[] = [];\n let resultsInFirstPage: number | null = null;\n let lastResultsSize: number | null = null;\n const { params: { page = 1, ...restParams } = {}, ...rest } = options as any;\n // Ensure `page` is always the first property in params and initialized to 1, even if `options` already had `params`.\n const localOptions = { params: { page: page || 1, ...restParams }, ...rest };\n while ((localOptions.params.page === 1 || lastResultsSize === resultsInFirstPage) && lastResultsSize !== 0) {\n const { data } = await this.get<T[]>(url, localOptions);\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 that uses POST requests with `{ rows, count }` response format.\n * Continues fetching until all results are retrieved or the optional page limit is reached.\n *\n * @param url The endpoint URL to send POST requests to.\n * @param options Additional options to include in the request payload (merged with page number).\n * @param pageLimit The maximum number of pages to fetch (default: 100). Set to -1 for no limit.\n * @param config Optional Axios request configuration (e.g., headers).\n * @returns A promise that resolves to an array of all results from all pages.\n *\n * @example\n * ```typescript\n * const allOrders = await client.getAllPagesFromQueryEndpoint<Order>('/orders/query', {\n * filters: { status: 'pending' }\n * }, 50);\n * ```\n */\n public async getAllPagesFromQueryEndpoint<T>(url: string, options: object = {}, pageLimit = 100, config?: AxiosRequestConfig<unknown>): 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 }, config);\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"],"mappings":"svBA2BA,KAAM,CAAE,SAAUA,EAAAA,QACZ,EAA2BC,EAAAA,QAE3B,GAAA,EAAA,EAAA,eAAA,QAAA,MAAA,CAAA,cAAA,WAAA,CAAA,KAA4C,CAElD,IAAIC,EACJ,MAAM,GAAyB,GAAG,KAChC,IAAgB,EAAY,KAAK,CAAC,UAC3B,EAAa,GAAG,EAAK,EAGxB,EAAc,CAClB,MACA,OACA,SACA,OACA,MACA,QACA,UACD,CAEKC,EAAmE,CAAE,YAAa,WAAY,CA4B9FC,EAAmC,CACvC,QAAS,IACT,QAAS,CACP,YAAa,SACb,uBAAwBC,EAAAA,IAAI,iBAAmB,KAChD,CACD,iBAAkB,GAAU,EAAsB,EAAQ,EAAmB,CAC7E,cAAe,CACb,mBAAoB,GACrB,CACD,UAAW,GACZ,CAEK,EAAuB,GAAwC,KAAK,EAAQ,QAAU,IAAI,aAAa,CAAC,IAAI,EAAQ,SAAW,qBAAqB,EAAQ,KAAO,iBAWnK,EAAsB,OAAO,SAASA,EAAAA,IAAI,qBAAuB,GAAI,GAAG,EAAI,IAiBlF,IAAqB,EAArB,KAA6B,CAC3B,GAYA,YAAY,EAA4B,EAAE,CAAE,CAC1C,MAAA,EAAe,EAAS,SAAA,EAAA,EAAA,UAAkB,CAC1C,KAAK,UAAA,EAAA,EAAA,SAAiB,EAAiB,EAAS,CAG5C,KAAK,SAAS,WAEhB,KAAK,SAAS,UAAY,IAAIE,EAAAA,UAAU,CAAE,kBAAmB,EAAqB,CAAC,CACnF,KAAK,SAAS,WAAa,IAAIC,EAAAA,WAAW,CAAE,kBAAmB,EAAqB,CAAC,CACrF,OAAO,KAAK,SAAS,WACZ,KAAK,SAAS,YAAc,IAAS,QAAQ,IAAI,gCAAkC,SAI5F,KAAK,SAAS,UAAY,IAAID,EAAAA,UAAU,CAAE,UAAW,GAAO,CAAC,CAC7D,KAAK,SAAS,WAAa,IAAIC,EAAAA,WAAW,CAAE,UAAW,GAAO,CAAC,CAC/D,OAAO,KAAK,SAAS,WAGvB,MAAA,GAAqB,CAEjB,EAAS,QACX,KAAK,SAAS,MAAQ,CACpB,OAAQ,IAAU,IAElB,QAAS,CAAE,MAAO,GAAO,CACzB,GAAG,EAAS,MACb,EAGH,KAAK,MAAQ,EAAS,MAAQ,EAAM,KAAK,SAAgE,CAAG,EAAA,QAAM,OAAO,KAAK,SAAS,CACvI,MAAA,EAAe,EAAS,CACxB,MAAA,GAA6B,CAC7B,MAAA,GAAe,CAGjB,GAAU,EAAiC,CACzC,EAAyB,KAAK,MAAO,CACnC,QAAS,EACT,WAAYP,EAAAA,QAAW,iBACvB,GAAG,EACJ,CAAC,CAGJ,IAAiB,CACf,KAAK,MAAM,aAAa,QAAQ,IAAK,IACnC,MAAA,EAAa,KAAK,kBAAkB,EAAoB,EAAQ,GAAG,CAC5D,GACP,CAEF,KAAK,MAAM,aAAa,SAAS,IAAK,IACpC,MAAA,EAAa,KAAK,mBAAmB,EAAoB,EAAS,OAAO,GAAG,CACrE,GACL,GAAU,CACZ,GAAI,EAAM,SAAS,iBAAiB,cAAgB,CAAC,aAAc,QAAQ,CAAC,SAAS,EAAM,KAAK,CAQ9F,OAJA,MAAA,EAAa,KAAK,GAAG,EAAM,KAAK,oBAAqB,CACnD,IAAK,EAAM,QAAQ,gBAAgB,YAEpC,CAAC,CACK,KAAK,MAAM,QAAQ,EAAM,OAAO,CAEzC,IAAM,EAAU,EAAM,QAAQ,QAAU,EAAM,OAAS,EAAM,QACvD,EAAS,EAAM,UAAU,QAAU,EAAM,OAGzC,EAF2C,EAAM,QAAQ,kBAAoB,KAAK,SAAS,mBAC7D,CAAC,GAAU,GAAU,IAAM,QAAU,QAMzE,MAJA,MAAA,EAAa,GAAO,6BAA6B,EAAU,EAAoB,EAAQ,CAAG,KAAM,CAC9F,SACA,KAAM,EAAM,UAAU,KACvB,CAAC,CACI,GACN,CAGJ,IAAuB,CACrB,GAAI,CAAC,KAAK,SAAS,YAAc,CAAC,KAAK,SAAS,YAC9C,MAAU,MAAM,iEAAiE,CAGnF,GAAM,CAAE,YAAa,KACjB,EAAS,WACX,EAAS,QAAU,EAAS,WACnB,EAAS,cAElB,EAAS,QAAU,UAAUI,EAAAA,IADF,GAAG,EAAS,YAAY,mBAQvD,IAA+B,CAC7B,EAAY,QAAS,GAAW,CAC9B,KAAK,IACH,GAAG,IACY,KAAK,MAAM,GAAQ,GAAG,EAAkE,EACzG,CAkBJ,MAAa,YAAe,EAAa,EAAkB,EAAE,CAAgB,CAC3E,IAAMQ,EAAqB,EAAE,CACzBC,EAAoC,KACpCC,EAAiC,KAC/B,CAAE,OAAQ,CAAE,OAAO,EAAG,GAAG,GAAe,EAAE,CAAE,GAAG,GAAS,EAExD,EAAe,CAAE,OAAQ,CAAE,KAAM,GAAQ,EAAG,GAAG,EAAY,CAAE,GAAG,EAAM,CAC5E,MAAQ,EAAa,OAAO,OAAS,GAAK,IAAoB,IAAuB,IAAoB,GAAG,CAC1G,GAAM,CAAE,QAAS,MAAM,KAAK,IAAS,EAAK,EAAa,CACvD,EAAkB,EAAK,OACnB,EAAa,OAAO,OAAS,IAC/B,EAAqB,EAAK,QAG5B,EAAa,OAAO,MAAQ,EAC5B,MAAM,UAAU,KAAK,MAAM,EAAe,EAAK,CAGjD,OAAO,EAoBT,MAAa,6BAAgC,EAAa,EAAkB,EAAE,CAAE,EAAY,IAAK,EAAoD,CACnJ,IAAMF,EAAqB,EAAE,CAEzB,EAAoB,GACpB,EAAO,EACX,KAAO,IAAsB,IAAc,IAAM,EAAO,IAAY,CAClE,GAAM,CAAE,QAAS,MAAM,KAAK,KAAoC,EAAK,CACnE,GAAG,EACH,OACD,CAAE,EAAO,CACJ,CAAE,OAAM,SAAU,EACxB,GAAQ,EACR,MAAM,UAAU,KAAK,MAAM,EAAe,EAAK,CAC/C,EAAoB,EAAc,OAAS,EAG7C,OAAO"}
|
package/lib/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AxiosInstance, AxiosRequestConfig, CreateAxiosDefaults } from "axios";
|
|
2
2
|
import { IAxiosRetryConfig, IAxiosRetryConfigExtended } from "axios-retry";
|
|
3
|
-
import { LoggerInstanceManager } from "@autofleet/logger";
|
|
3
|
+
import { LogLevel, LoggerInstanceManager } from "@autofleet/logger";
|
|
4
4
|
import { IAxiosCacheAdapterOptions } from "@autofleet/axios-cache-adapter";
|
|
5
5
|
|
|
6
6
|
//#region src/index.d.ts
|
|
@@ -11,6 +11,12 @@ declare module "axios" {
|
|
|
11
11
|
/** force cache invalidation */
|
|
12
12
|
clearCacheEntry?: boolean;
|
|
13
13
|
"axios-retry"?: IAxiosRetryConfigExtended;
|
|
14
|
+
/**
|
|
15
|
+
* Override the log level used when this request fails. When set, replaces the default
|
|
16
|
+
* 4xx → warn / 5xx → error split — *all* failures (including 5xx and network errors)
|
|
17
|
+
* will be logged at this level. Leave undefined to use the status-based default.
|
|
18
|
+
*/
|
|
19
|
+
failuresLogLevel?: `${LogLevel}`;
|
|
14
20
|
}
|
|
15
21
|
}
|
|
16
22
|
/**
|
|
@@ -30,6 +36,13 @@ interface NetworkSettings extends CreateAxiosDefaults, IAxiosRetryConfig {
|
|
|
30
36
|
logger?: LoggerInstanceManager;
|
|
31
37
|
/** Request timeout in milliseconds (default: 10000) */
|
|
32
38
|
timeout?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Override the log level used when a request fails. When set, replaces the default
|
|
41
|
+
* 4xx → warn / 5xx → error split — *all* failures (including 5xx and network errors)
|
|
42
|
+
* will be logged at this level. Can also be overridden per-request via the same key
|
|
43
|
+
* on AxiosRequestConfig (per-request wins over instance).
|
|
44
|
+
*/
|
|
45
|
+
failuresLogLevel?: `${LogLevel}`;
|
|
33
46
|
}
|
|
34
47
|
/**
|
|
35
48
|
* HTTP client wrapper built on Axios with keep-alive connection pooling, caching, retry logic, and logging.
|
package/lib/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AxiosInstance, AxiosRequestConfig, CreateAxiosDefaults } from "axios";
|
|
2
2
|
import { IAxiosRetryConfig, IAxiosRetryConfigExtended } from "axios-retry";
|
|
3
|
-
import { LoggerInstanceManager } from "@autofleet/logger";
|
|
3
|
+
import { LogLevel, LoggerInstanceManager } from "@autofleet/logger";
|
|
4
4
|
import { IAxiosCacheAdapterOptions } from "@autofleet/axios-cache-adapter";
|
|
5
5
|
|
|
6
6
|
//#region src/index.d.ts
|
|
@@ -11,6 +11,12 @@ declare module "axios" {
|
|
|
11
11
|
/** force cache invalidation */
|
|
12
12
|
clearCacheEntry?: boolean;
|
|
13
13
|
"axios-retry"?: IAxiosRetryConfigExtended;
|
|
14
|
+
/**
|
|
15
|
+
* Override the log level used when this request fails. When set, replaces the default
|
|
16
|
+
* 4xx → warn / 5xx → error split — *all* failures (including 5xx and network errors)
|
|
17
|
+
* will be logged at this level. Leave undefined to use the status-based default.
|
|
18
|
+
*/
|
|
19
|
+
failuresLogLevel?: `${LogLevel}`;
|
|
14
20
|
}
|
|
15
21
|
}
|
|
16
22
|
/**
|
|
@@ -30,6 +36,13 @@ interface NetworkSettings extends CreateAxiosDefaults, IAxiosRetryConfig {
|
|
|
30
36
|
logger?: LoggerInstanceManager;
|
|
31
37
|
/** Request timeout in milliseconds (default: 10000) */
|
|
32
38
|
timeout?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Override the log level used when a request fails. When set, replaces the default
|
|
41
|
+
* 4xx → warn / 5xx → error split — *all* failures (including 5xx and network errors)
|
|
42
|
+
* will be logged at this level. Can also be overridden per-request via the same key
|
|
43
|
+
* on AxiosRequestConfig (per-request wins over instance).
|
|
44
|
+
*/
|
|
45
|
+
failuresLogLevel?: `${LogLevel}`;
|
|
33
46
|
}
|
|
34
47
|
/**
|
|
35
48
|
* HTTP client wrapper built on Axios with keep-alive connection pooling, caching, retry logic, and logging.
|
package/lib/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createRequire as e}from"node:module";import{env as t}from"node:process";import n from"axios";import r from"axios-retry";import i from"@autofleet/logger";import a from"deepmerge";import o from"@autofleet/axios-cache-adapter";import{HttpAgent as s,HttpsAgent as c}from"agentkeepalive";const{setup:l}=o,u=r,d=e(import.meta.url);let f;const p=(...e)=>(f??=d(`qs`).stringify,f(...e)),m=[`get`,`post`,`delete`,`head`,`put`,`patch`,`options`],h={arrayFormat:`brackets`},g={timeout:1e4,headers:{"X-AF-AUTH":`ANYONE`,"X-IAF-ORIGIN-SERVICE":t.AF_SERVICE_NAME||null},paramsSerializer:e=>p(e,h),"axios-retry":{shouldResetTimeout:!0},keepAlive:!0},_=e=>`[${(e.method||``).toUpperCase()}] ${e.baseURL??`unknown-base-url`}${e.url??`/unknown-url`}`,v=Number.parseInt(t.FREE_SOCKET_TIMEOUT||``,10)||5e3;var y=class{#e;constructor(e={}){this.#e=e.logger??i(),this.settings=a(g,e),this.settings.keepAlive?(this.settings.httpAgent=new s({freeSocketTimeout:v}),this.settings.httpsAgent=new c({freeSocketTimeout:v}),delete this.settings.keepAlive):this.settings.keepAlive===!1&&process.env.NETWORK_ALLOW_KEEPALIVE_FALSE===`true`&&(this.settings.httpAgent=new s({keepAlive:!1}),this.settings.httpsAgent=new c({keepAlive:!1}),delete this.settings.keepAlive),this.#r(),e.cache&&(this.settings.cache={maxAge:900*1e3,exclude:{query:!1},...e.cache}),this.axios=e.cache?l(this.settings):n.create(this.settings),this.#t(e),this.#i(),this.#n()}#t(e){u(this.axios,{retries:0,retryDelay:r.exponentialDelay,...e})}#n(){this.axios.interceptors.request.use(e=>(this.#e.info(`Start Request: ${_(e)}`),e)),this.axios.interceptors.response.use(e=>(this.#e.info(`Finish Request: ${_(e.config)}`),e),e=>{if(e.request?._currentRequest?.reusedSocket&&[`ECONNRESET`,`EPIPE`].includes(e.code))return this.#e.warn(`${e.code} issue, will retry`,{req:e.request._currentRequest._currentUrl}),this.axios.request(e.config);let t=e.config?.baseURL?e.config:e.request;throw this.#e
|
|
1
|
+
import{createRequire as e}from"node:module";import{env as t}from"node:process";import n from"axios";import r from"axios-retry";import i from"@autofleet/logger";import a from"deepmerge";import o from"@autofleet/axios-cache-adapter";import{HttpAgent as s,HttpsAgent as c}from"agentkeepalive";const{setup:l}=o,u=r,d=e(import.meta.url);let f;const p=(...e)=>(f??=d(`qs`).stringify,f(...e)),m=[`get`,`post`,`delete`,`head`,`put`,`patch`,`options`],h={arrayFormat:`brackets`},g={timeout:1e4,headers:{"X-AF-AUTH":`ANYONE`,"X-IAF-ORIGIN-SERVICE":t.AF_SERVICE_NAME||null},paramsSerializer:e=>p(e,h),"axios-retry":{shouldResetTimeout:!0},keepAlive:!0},_=e=>`[${(e.method||``).toUpperCase()}] ${e.baseURL??`unknown-base-url`}${e.url??`/unknown-url`}`,v=Number.parseInt(t.FREE_SOCKET_TIMEOUT||``,10)||5e3;var y=class{#e;constructor(e={}){this.#e=e.logger??i(),this.settings=a(g,e),this.settings.keepAlive?(this.settings.httpAgent=new s({freeSocketTimeout:v}),this.settings.httpsAgent=new c({freeSocketTimeout:v}),delete this.settings.keepAlive):this.settings.keepAlive===!1&&process.env.NETWORK_ALLOW_KEEPALIVE_FALSE===`true`&&(this.settings.httpAgent=new s({keepAlive:!1}),this.settings.httpsAgent=new c({keepAlive:!1}),delete this.settings.keepAlive),this.#r(),e.cache&&(this.settings.cache={maxAge:900*1e3,exclude:{query:!1},...e.cache}),this.axios=e.cache?l(this.settings):n.create(this.settings),this.#t(e),this.#i(),this.#n()}#t(e){u(this.axios,{retries:0,retryDelay:r.exponentialDelay,...e})}#n(){this.axios.interceptors.request.use(e=>(this.#e.info(`Start Request: ${_(e)}`),e)),this.axios.interceptors.response.use(e=>(this.#e.info(`Finish Request: ${_(e.config)}`),e),e=>{if(e.request?._currentRequest?.reusedSocket&&[`ECONNRESET`,`EPIPE`].includes(e.code))return this.#e.warn(`${e.code} issue, will retry`,{req:e.request._currentRequest._currentUrl}),this.axios.request(e.config);let t=e.config?.baseURL?e.config:e.request,n=e.response?.status??e.status,r=e.config?.failuresLogLevel??this.settings.failuresLogLevel??(!n||n>=500?`error`:`warn`);throw this.#e[r](`Finish Request with error ${t?_(t):``}`,{status:n,data:e.response?.data}),e})}#r(){if(!this.settings.serviceUrl&&!this.settings.serviceName)throw Error(`At least one of the settings Missing serviceUrl or serviceName`);let{settings:e}=this;e.serviceUrl?e.baseURL=e.serviceUrl:e.serviceName&&(e.baseURL=`http://${t[`${e.serviceName}_SERVICE_HOST`]}`)}#i(){m.forEach(e=>{this[e]=(...t)=>this.axios[e](...t)})}async getAllPages(e,t={}){let n=[],r=null,i=null,{params:{page:a=1,...o}={},...s}=t,c={params:{page:a||1,...o},...s};for(;(c.params.page===1||i===r)&&i!==0;){let{data:t}=await this.get(e,c);i=t.length,c.params.page===1&&(r=t.length),c.params.page+=1,Array.prototype.push.apply(n,t)}return n}async getAllPagesFromQueryEndpoint(e,t={},n=100,r){let i=[],a=!0,o=1;for(;a&&(n===-1||o<n);){let{data:n}=await this.post(e,{...t,page:o},r),{rows:s,count:c}=n;o+=1,Array.prototype.push.apply(i,s),a=i.length<c}return i}};export{y as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["qsStringify: typeof stringify | undefined","qsStringifyOptions: NonNullable<Parameters<typeof stringify>[1]>","defaultSettings: NetworkSettings","#logger","#createBaseUrl","#addRetry","#buildClassHttpMethods","#addLogs","currentResult: T[]","resultsInFirstPage: number | null","lastResultsSize: number | null"],"sources":["../src/index.ts"],"sourcesContent":["import { env } from 'node:process';\nimport { createRequire } from 'node:module';\nimport axios, { type CreateAxiosDefaults, type AxiosRequestConfig, type AxiosInstance, type AxiosResponse, type AxiosRequestHeaders } from 'axios';\nimport axiosRetry, { type IAxiosRetryConfigExtended, type IAxiosRetryConfig, type IAxiosRetryReturn } from 'axios-retry';\nimport Logger, { type LoggerInstanceManager } from '@autofleet/logger';\nimport merge from 'deepmerge';\nimport axiosCacheAdapter from '@autofleet/axios-cache-adapter';\nimport { HttpAgent, HttpsAgent } from 'agentkeepalive';\nimport type { stringify } from 'qs';\nimport type { IAxiosCacheAdapterOptions } from '@autofleet/axios-cache-adapter';\n\ndeclare module 'axios' {\n interface AxiosRequestConfig {\n /** configure how the cached requests will be handled, where they will be stored, etc. */\n cache?: IAxiosCacheAdapterOptions;\n /** force cache invalidation */\n clearCacheEntry?: boolean;\n 'axios-retry'?: IAxiosRetryConfigExtended;\n }\n}\n\nconst { setup } = axiosCacheAdapter as { setup: (options: AxiosRequestConfig) => AxiosInstance; };\nconst correctlyTypedAxiosRetry = axiosRetry as unknown as (axiosInstance: AxiosInstance, axiosRetryConfig?: IAxiosRetryConfig) => IAxiosRetryReturn;\n\nconst safeRequire = createRequire(import.meta.url);\n\nlet qsStringify: typeof stringify | undefined;\nconst lazilyLoadQsStringify = (...args: Parameters<typeof stringify>) => {\n qsStringify ??= safeRequire('qs').stringify;\n return qsStringify!(...args);\n};\n\nconst HTTPMethods = [\n 'get',\n 'post',\n 'delete',\n 'head',\n 'put',\n 'patch',\n 'options',\n] as const;\n\nconst qsStringifyOptions: NonNullable<Parameters<typeof stringify>[1]> = { arrayFormat: 'brackets' };\n\n/**\n * Network client configuration settings\n */\ninterface NetworkSettings extends CreateAxiosDefaults, IAxiosRetryConfig {\n /** Service name for Kubernetes DNS resolution (e.g., 'EXAMPLE_MS' resolves to EXAMPLE_MS_SERVICE_HOST) */\n serviceName?: string;\n /** Direct service URL (alternative to serviceName) */\n serviceUrl?: string;\n /**\n * Enable HTTP keep-alive connections (default: true)\n * @since 1.9.0 - To disable keep-alive, set to false AND set env var NETWORK_ALLOW_KEEPALIVE_FALSE=true\n */\n keepAlive?: boolean;\n /** Logger instance for request/response logging */\n logger?: LoggerInstanceManager;\n /** Request timeout in milliseconds (default: 10000) */\n timeout?: number;\n}\n\nconst defaultSettings: NetworkSettings = {\n timeout: 10_000,\n headers: {\n 'X-AF-AUTH': 'ANYONE',\n 'X-IAF-ORIGIN-SERVICE': env.AF_SERVICE_NAME || null as unknown as string,\n },\n paramsSerializer: params => lazilyLoadQsStringify(params, qsStringifyOptions),\n 'axios-retry': {\n shouldResetTimeout: true,\n },\n keepAlive: true,\n};\n\nconst createRequestString = (request: AxiosRequestConfig): string => `[${(request.method || '').toUpperCase()}] ${request.baseURL ?? 'unknown-base-url'}${request.url ?? '/unknown-url'}`;\n\n/*\n The default free socket keepalive timeout, in milliseconds.\n Setting to 5000 (5 seconds) as default because out grace period is 10 seconds\n and we want to make sure we don't have any socket issues.\n See https://www.npmjs.com/package/agentkeepalive\n\n There is also autoscaling reason for that, if we don't timeout at some point,\n new pods that were auto scaled will not be used.\n*/\nconst FREE_SOCKET_TIMEOUT = Number.parseInt(env.FREE_SOCKET_TIMEOUT || '', 10) || 5_000;\n\n/**\n * HTTP client wrapper built on Axios with keep-alive connection pooling, caching, retry logic, and logging.\n *\n * @example\n * ```typescript\n * const client = new Network({\n * serviceName: 'EXAMPLE_MS',\n * timeout: 10000,\n * retries: 3\n * });\n *\n * const response = await client.get('/endpoint');\n * await client.post('/data', { payload });\n * ```\n */\nexport default class Network {\n readonly #logger: LoggerInstanceManager;\n private readonly settings: NetworkSettings;\n private readonly axios: AxiosInstance;\n\n public get!: AxiosInstance['get'];\n public post!: AxiosInstance['post'];\n public delete!: AxiosInstance['delete'];\n public head!: AxiosInstance['head'];\n public put!: AxiosInstance['put'];\n public patch!: AxiosInstance['patch'];\n public options!: AxiosInstance['options'];\n\n constructor(settings: NetworkSettings = {}) {\n this.#logger = settings.logger ?? Logger();\n this.settings = merge(defaultSettings, settings);\n\n // Configure keep-alive behavior\n if (this.settings.keepAlive) {\n // Enable keep-alive with custom free socket timeout\n this.settings.httpAgent = new HttpAgent({ freeSocketTimeout: FREE_SOCKET_TIMEOUT });\n this.settings.httpsAgent = new HttpsAgent({ freeSocketTimeout: FREE_SOCKET_TIMEOUT });\n delete this.settings.keepAlive;\n } else if (this.settings.keepAlive === false && process.env.NETWORK_ALLOW_KEEPALIVE_FALSE === 'true') {\n // [v1.9.0] Explicitly disable keep-alive\n // Node.js 20+ has keep-alive enabled by default, so we need to explicitly set keepAlive: false\n // This env var is required to prevent silent performance degradation in services that unknowingly relied on keep-alive\n this.settings.httpAgent = new HttpAgent({ keepAlive: false });\n this.settings.httpsAgent = new HttpsAgent({ keepAlive: false });\n delete this.settings.keepAlive;\n }\n\n this.#createBaseUrl();\n\n if (settings.cache) {\n this.settings.cache = {\n maxAge: 15 * 60 * 1000,\n // Store responses from requests with query parameters in cache\n exclude: { query: false },\n ...settings.cache,\n };\n }\n\n this.axios = settings.cache ? setup(this.settings as NetworkSettings & { headers: AxiosRequestHeaders; }) : axios.create(this.settings);\n this.#addRetry(settings);\n this.#buildClassHttpMethods();\n this.#addLogs();\n }\n\n #addRetry(settings: NetworkSettings): void {\n correctlyTypedAxiosRetry(this.axios, {\n retries: 0,\n retryDelay: axiosRetry.exponentialDelay,\n ...settings,\n });\n }\n\n #addLogs(): void {\n this.axios.interceptors.request.use((request) => {\n this.#logger.info(`Start Request: ${createRequestString(request)}`);\n return request;\n });\n\n this.axios.interceptors.response.use((response) => {\n this.#logger.info(`Finish Request: ${createRequestString(response.config)}`);\n return response;\n }, (error) => {\n if (error.request?._currentRequest?.reusedSocket && ['ECONNRESET', 'EPIPE'].includes(error.code)) {\n // See https://www.npmjs.com/package/agentkeepalive\n // Support req.reusedSocket\n // https://code-examples.net/en/q/28a8069\n this.#logger.warn(`${error.code} issue, will retry`, {\n req: error.request._currentRequest._currentUrl,\n // method: error.request._currentRequest._options.method,\n });\n return this.axios.request(error.config);\n }\n const request = error.config?.baseURL ? error.config : error.request;\n this.#logger.error(`Finish Request with error ${request ? createRequestString(request) : ''}`, {\n status: error.status,\n data: error.response?.data,\n });\n throw error;\n });\n }\n\n #createBaseUrl(): void {\n if (!this.settings.serviceUrl && !this.settings.serviceName) {\n throw new Error('At least one of the settings Missing serviceUrl or serviceName');\n }\n\n const { settings } = this;\n if (settings.serviceUrl) {\n settings.baseURL = settings.serviceUrl;\n } else if (settings.serviceName) {\n const envServiceHostName = `${settings.serviceName}_SERVICE_HOST`;\n settings.baseURL = `http://${env[envServiceHostName]}`;\n }\n }\n\n /**\n * Build class methods that wrap axios methods\n */\n #buildClassHttpMethods(): void {\n HTTPMethods.forEach((method) => {\n this[method] = <T = any, R = AxiosResponse<T>>(\n ...args: Parameters<AxiosInstance[typeof method]>\n ): Promise<R> => this.axios[method](...args as [url: string, leaveUsAlone?: AxiosRequestConfig<unknown>]);\n });\n }\n\n /**\n * Fetches all pages from a paginated API endpoint using page-based pagination.\n * Continues fetching until the response size differs from the first page or returns empty.\n *\n * @param url The endpoint URL to send the request to.\n * @param options Additional Axios request options to include (e.g., headers, params).\n * @returns A promise that resolves to an array of all results from all pages.\n *\n * @example\n * ```typescript\n * const allUsers = await client.getAllPages<User>('/users', {\n * params: { status: 'active' }\n * });\n * ```\n */\n public async getAllPages<T>(url: string, options: object = {}): Promise<T[]> {\n const currentResult: T[] = [];\n let resultsInFirstPage: number | null = null;\n let lastResultsSize: number | null = null;\n const { params: { page = 1, ...restParams } = {}, ...rest } = options as any;\n // Ensure `page` is always the first property in params and initialized to 1, even if `options` already had `params`.\n const localOptions = { params: { page: page || 1, ...restParams }, ...rest };\n while ((localOptions.params.page === 1 || lastResultsSize === resultsInFirstPage) && lastResultsSize !== 0) {\n const { data } = await this.get<T[]>(url, localOptions);\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 that uses POST requests with `{ rows, count }` response format.\n * Continues fetching until all results are retrieved or the optional page limit is reached.\n *\n * @param url The endpoint URL to send POST requests to.\n * @param options Additional options to include in the request payload (merged with page number).\n * @param pageLimit The maximum number of pages to fetch (default: 100). Set to -1 for no limit.\n * @param config Optional Axios request configuration (e.g., headers).\n * @returns A promise that resolves to an array of all results from all pages.\n *\n * @example\n * ```typescript\n * const allOrders = await client.getAllPagesFromQueryEndpoint<Order>('/orders/query', {\n * filters: { status: 'pending' }\n * }, 50);\n * ```\n */\n public async getAllPagesFromQueryEndpoint<T>(url: string, options: object = {}, pageLimit = 100, config?: AxiosRequestConfig<unknown>): 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 }, config);\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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["qsStringify: typeof stringify | undefined","qsStringifyOptions: NonNullable<Parameters<typeof stringify>[1]>","defaultSettings: NetworkSettings","#logger","#createBaseUrl","#addRetry","#buildClassHttpMethods","#addLogs","currentResult: T[]","resultsInFirstPage: number | null","lastResultsSize: number | null"],"sources":["../src/index.ts"],"sourcesContent":["import { env } from 'node:process';\nimport { createRequire } from 'node:module';\nimport axios, { type CreateAxiosDefaults, type AxiosRequestConfig, type AxiosInstance, type AxiosResponse, type AxiosRequestHeaders } from 'axios';\nimport axiosRetry, { type IAxiosRetryConfigExtended, type IAxiosRetryConfig, type IAxiosRetryReturn } from 'axios-retry';\nimport Logger, { type LoggerInstanceManager, type LogLevel } from '@autofleet/logger';\nimport merge from 'deepmerge';\nimport axiosCacheAdapter from '@autofleet/axios-cache-adapter';\nimport { HttpAgent, HttpsAgent } from 'agentkeepalive';\nimport type { stringify } from 'qs';\nimport type { IAxiosCacheAdapterOptions } from '@autofleet/axios-cache-adapter';\n\ndeclare module 'axios' {\n interface AxiosRequestConfig {\n /** configure how the cached requests will be handled, where they will be stored, etc. */\n cache?: IAxiosCacheAdapterOptions;\n /** force cache invalidation */\n clearCacheEntry?: boolean;\n 'axios-retry'?: IAxiosRetryConfigExtended;\n /**\n * Override the log level used when this request fails. When set, replaces the default\n * 4xx → warn / 5xx → error split — *all* failures (including 5xx and network errors)\n * will be logged at this level. Leave undefined to use the status-based default.\n */\n failuresLogLevel?: `${LogLevel}`;\n }\n}\n\nconst { setup } = axiosCacheAdapter as { setup: (options: AxiosRequestConfig) => AxiosInstance; };\nconst correctlyTypedAxiosRetry = axiosRetry as unknown as (axiosInstance: AxiosInstance, axiosRetryConfig?: IAxiosRetryConfig) => IAxiosRetryReturn;\n\nconst safeRequire = createRequire(import.meta.url);\n\nlet qsStringify: typeof stringify | undefined;\nconst lazilyLoadQsStringify = (...args: Parameters<typeof stringify>) => {\n qsStringify ??= safeRequire('qs').stringify;\n return qsStringify!(...args);\n};\n\nconst HTTPMethods = [\n 'get',\n 'post',\n 'delete',\n 'head',\n 'put',\n 'patch',\n 'options',\n] as const;\n\nconst qsStringifyOptions: NonNullable<Parameters<typeof stringify>[1]> = { arrayFormat: 'brackets' };\n\n/**\n * Network client configuration settings\n */\ninterface NetworkSettings extends CreateAxiosDefaults, IAxiosRetryConfig {\n /** Service name for Kubernetes DNS resolution (e.g., 'EXAMPLE_MS' resolves to EXAMPLE_MS_SERVICE_HOST) */\n serviceName?: string;\n /** Direct service URL (alternative to serviceName) */\n serviceUrl?: string;\n /**\n * Enable HTTP keep-alive connections (default: true)\n * @since 1.9.0 - To disable keep-alive, set to false AND set env var NETWORK_ALLOW_KEEPALIVE_FALSE=true\n */\n keepAlive?: boolean;\n /** Logger instance for request/response logging */\n logger?: LoggerInstanceManager;\n /** Request timeout in milliseconds (default: 10000) */\n timeout?: number;\n /**\n * Override the log level used when a request fails. When set, replaces the default\n * 4xx → warn / 5xx → error split — *all* failures (including 5xx and network errors)\n * will be logged at this level. Can also be overridden per-request via the same key\n * on AxiosRequestConfig (per-request wins over instance).\n */\n failuresLogLevel?: `${LogLevel}`;\n}\n\nconst defaultSettings: NetworkSettings = {\n timeout: 10_000,\n headers: {\n 'X-AF-AUTH': 'ANYONE',\n 'X-IAF-ORIGIN-SERVICE': env.AF_SERVICE_NAME || null as unknown as string,\n },\n paramsSerializer: params => lazilyLoadQsStringify(params, qsStringifyOptions),\n 'axios-retry': {\n shouldResetTimeout: true,\n },\n keepAlive: true,\n};\n\nconst createRequestString = (request: AxiosRequestConfig): string => `[${(request.method || '').toUpperCase()}] ${request.baseURL ?? 'unknown-base-url'}${request.url ?? '/unknown-url'}`;\n\n/*\n The default free socket keepalive timeout, in milliseconds.\n Setting to 5000 (5 seconds) as default because out grace period is 10 seconds\n and we want to make sure we don't have any socket issues.\n See https://www.npmjs.com/package/agentkeepalive\n\n There is also autoscaling reason for that, if we don't timeout at some point,\n new pods that were auto scaled will not be used.\n*/\nconst FREE_SOCKET_TIMEOUT = Number.parseInt(env.FREE_SOCKET_TIMEOUT || '', 10) || 5_000;\n\n/**\n * HTTP client wrapper built on Axios with keep-alive connection pooling, caching, retry logic, and logging.\n *\n * @example\n * ```typescript\n * const client = new Network({\n * serviceName: 'EXAMPLE_MS',\n * timeout: 10000,\n * retries: 3\n * });\n *\n * const response = await client.get('/endpoint');\n * await client.post('/data', { payload });\n * ```\n */\nexport default class Network {\n readonly #logger: LoggerInstanceManager;\n private readonly settings: NetworkSettings;\n private readonly axios: AxiosInstance;\n\n public get!: AxiosInstance['get'];\n public post!: AxiosInstance['post'];\n public delete!: AxiosInstance['delete'];\n public head!: AxiosInstance['head'];\n public put!: AxiosInstance['put'];\n public patch!: AxiosInstance['patch'];\n public options!: AxiosInstance['options'];\n\n constructor(settings: NetworkSettings = {}) {\n this.#logger = settings.logger ?? Logger();\n this.settings = merge(defaultSettings, settings);\n\n // Configure keep-alive behavior\n if (this.settings.keepAlive) {\n // Enable keep-alive with custom free socket timeout\n this.settings.httpAgent = new HttpAgent({ freeSocketTimeout: FREE_SOCKET_TIMEOUT });\n this.settings.httpsAgent = new HttpsAgent({ freeSocketTimeout: FREE_SOCKET_TIMEOUT });\n delete this.settings.keepAlive;\n } else if (this.settings.keepAlive === false && process.env.NETWORK_ALLOW_KEEPALIVE_FALSE === 'true') {\n // [v1.9.0] Explicitly disable keep-alive\n // Node.js 20+ has keep-alive enabled by default, so we need to explicitly set keepAlive: false\n // This env var is required to prevent silent performance degradation in services that unknowingly relied on keep-alive\n this.settings.httpAgent = new HttpAgent({ keepAlive: false });\n this.settings.httpsAgent = new HttpsAgent({ keepAlive: false });\n delete this.settings.keepAlive;\n }\n\n this.#createBaseUrl();\n\n if (settings.cache) {\n this.settings.cache = {\n maxAge: 15 * 60 * 1000,\n // Store responses from requests with query parameters in cache\n exclude: { query: false },\n ...settings.cache,\n };\n }\n\n this.axios = settings.cache ? setup(this.settings as NetworkSettings & { headers: AxiosRequestHeaders; }) : axios.create(this.settings);\n this.#addRetry(settings);\n this.#buildClassHttpMethods();\n this.#addLogs();\n }\n\n #addRetry(settings: NetworkSettings): void {\n correctlyTypedAxiosRetry(this.axios, {\n retries: 0,\n retryDelay: axiosRetry.exponentialDelay,\n ...settings,\n });\n }\n\n #addLogs(): void {\n this.axios.interceptors.request.use((request) => {\n this.#logger.info(`Start Request: ${createRequestString(request)}`);\n return request;\n });\n\n this.axios.interceptors.response.use((response) => {\n this.#logger.info(`Finish Request: ${createRequestString(response.config)}`);\n return response;\n }, (error) => {\n if (error.request?._currentRequest?.reusedSocket && ['ECONNRESET', 'EPIPE'].includes(error.code)) {\n // See https://www.npmjs.com/package/agentkeepalive\n // Support req.reusedSocket\n // https://code-examples.net/en/q/28a8069\n this.#logger.warn(`${error.code} issue, will retry`, {\n req: error.request._currentRequest._currentUrl,\n // method: error.request._currentRequest._options.method,\n });\n return this.axios.request(error.config);\n }\n const request = error.config?.baseURL ? error.config : error.request;\n const status = error.response?.status ?? error.status;\n const overrideLevel: `${LogLevel}` | undefined = error.config?.failuresLogLevel ?? this.settings.failuresLogLevel;\n const defaultLevel: `${LogLevel}` = !status || status >= 500 ? 'error' : 'warn';\n const level = overrideLevel ?? defaultLevel;\n this.#logger[level](`Finish Request with error ${request ? createRequestString(request) : ''}`, {\n status,\n data: error.response?.data,\n });\n throw error;\n });\n }\n\n #createBaseUrl(): void {\n if (!this.settings.serviceUrl && !this.settings.serviceName) {\n throw new Error('At least one of the settings Missing serviceUrl or serviceName');\n }\n\n const { settings } = this;\n if (settings.serviceUrl) {\n settings.baseURL = settings.serviceUrl;\n } else if (settings.serviceName) {\n const envServiceHostName = `${settings.serviceName}_SERVICE_HOST`;\n settings.baseURL = `http://${env[envServiceHostName]}`;\n }\n }\n\n /**\n * Build class methods that wrap axios methods\n */\n #buildClassHttpMethods(): void {\n HTTPMethods.forEach((method) => {\n this[method] = <T = any, R = AxiosResponse<T>>(\n ...args: Parameters<AxiosInstance[typeof method]>\n ): Promise<R> => this.axios[method](...args as [url: string, leaveUsAlone?: AxiosRequestConfig<unknown>]);\n });\n }\n\n /**\n * Fetches all pages from a paginated API endpoint using page-based pagination.\n * Continues fetching until the response size differs from the first page or returns empty.\n *\n * @param url The endpoint URL to send the request to.\n * @param options Additional Axios request options to include (e.g., headers, params).\n * @returns A promise that resolves to an array of all results from all pages.\n *\n * @example\n * ```typescript\n * const allUsers = await client.getAllPages<User>('/users', {\n * params: { status: 'active' }\n * });\n * ```\n */\n public async getAllPages<T>(url: string, options: object = {}): Promise<T[]> {\n const currentResult: T[] = [];\n let resultsInFirstPage: number | null = null;\n let lastResultsSize: number | null = null;\n const { params: { page = 1, ...restParams } = {}, ...rest } = options as any;\n // Ensure `page` is always the first property in params and initialized to 1, even if `options` already had `params`.\n const localOptions = { params: { page: page || 1, ...restParams }, ...rest };\n while ((localOptions.params.page === 1 || lastResultsSize === resultsInFirstPage) && lastResultsSize !== 0) {\n const { data } = await this.get<T[]>(url, localOptions);\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 that uses POST requests with `{ rows, count }` response format.\n * Continues fetching until all results are retrieved or the optional page limit is reached.\n *\n * @param url The endpoint URL to send POST requests to.\n * @param options Additional options to include in the request payload (merged with page number).\n * @param pageLimit The maximum number of pages to fetch (default: 100). Set to -1 for no limit.\n * @param config Optional Axios request configuration (e.g., headers).\n * @returns A promise that resolves to an array of all results from all pages.\n *\n * @example\n * ```typescript\n * const allOrders = await client.getAllPagesFromQueryEndpoint<Order>('/orders/query', {\n * filters: { status: 'pending' }\n * }, 50);\n * ```\n */\n public async getAllPagesFromQueryEndpoint<T>(url: string, options: object = {}, pageLimit = 100, config?: AxiosRequestConfig<unknown>): 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 }, config);\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"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/network",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.cjs",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
"@types/node": "^18.19.75",
|
|
42
42
|
"@types/qs": "^6.9.18",
|
|
43
43
|
"nock": "^14.0.1",
|
|
44
|
-
"@autofleet/logger": "^4.
|
|
44
|
+
"@autofleet/logger": "^4.7.0"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
47
|
"test": "vitest",
|