@nmakarov/cli-toolkit 0.18.0 → 0.23.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 +9 -0
- package/dist/args.cjs +1 -4
- package/dist/args.cjs.map +1 -1
- package/dist/args.js +1 -1
- package/dist/args.js.map +1 -1
- package/dist/cli-runner.cjs +1493 -516
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +1509 -531
- package/dist/cli-runner.js.map +1 -1
- package/dist/db.cjs +85 -157
- package/dist/db.cjs.map +1 -1
- package/dist/db.js +84 -150
- package/dist/db.js.map +1 -1
- package/dist/errors.cjs +2 -2
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.js +2 -1
- package/dist/errors.js.map +1 -1
- package/dist/filedatabase.cjs +19 -19
- package/dist/filedatabase.cjs.map +1 -1
- package/dist/filedatabase.js +19 -16
- package/dist/filedatabase.js.map +1 -1
- package/dist/http-client.cjs +9 -11
- package/dist/http-client.cjs.map +1 -1
- package/dist/http-client.js +10 -9
- package/dist/http-client.js.map +1 -1
- package/dist/http-client2.cjs +34 -33
- package/dist/http-client2.cjs.map +1 -1
- package/dist/http-client2.js +34 -30
- package/dist/http-client2.js.map +1 -1
- package/dist/index.cjs +2063 -658
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2063 -663
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +97 -69
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +112 -83
- package/dist/init.js.map +1 -1
- package/dist/logger.cjs +5 -5
- package/dist/logger.cjs.map +1 -1
- package/dist/logger.js +5 -4
- package/dist/logger.js.map +1 -1
- package/dist/mock-server.cjs +21 -33
- package/dist/mock-server.cjs.map +1 -1
- package/dist/mock-server.js +21 -28
- package/dist/mock-server.js.map +1 -1
- package/dist/params.cjs +22 -10
- package/dist/params.cjs.map +1 -1
- package/dist/params.js +22 -7
- package/dist/params.js.map +1 -1
- package/dist/s3.cjs +286 -0
- package/dist/s3.cjs.map +1 -0
- package/dist/s3.js +273 -0
- package/dist/s3.js.map +1 -0
- package/dist/screen.cjs +34 -39
- package/dist/screen.cjs.map +1 -1
- package/dist/screen.js +48 -46
- package/dist/screen.js.map +1 -1
- package/dist/tasks.cjs +1640 -416
- package/dist/tasks.cjs.map +1 -1
- package/dist/tasks.js +1614 -412
- package/dist/tasks.js.map +1 -1
- package/dist/utils.cjs +7 -8
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.js +6 -6
- package/dist/utils.js.map +1 -1
- package/package.json +36 -44
- package/scripts/ssm/parse-cli.js +35 -0
- package/scripts/ssm/ssm-admin.js +151 -0
- package/scripts/ssm/ssm-pull.js +147 -0
package/dist/http-client.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/http-client.ts","../src/http-client/index.ts","../src/errors.ts","../src/http-client/errors.ts","../src/http-client/retry.ts"],"sourcesContent":["// HttpClient module exports\nexport { HttpClient, HttpClientError } from './http-client/index.js';\nexport type {\n HttpClientConfig,\n RequestOptions,\n HttpClientResponse,\n HttpMethod,\n HttpClientErrorType,\n HttpClientStatus\n} from './http-client/types.js';\n","/**\n * HttpClient - Resilient HTTP Client with Retry Logic\n *\n * A production-ready HTTP client that:\n * - Wraps axios with enhanced error handling and retry logic\n * - Never throws exceptions - always returns unified response format\n * - Uses exponential backoff with jitter for retries\n * - Provides human-readable error classifications\n * - Supports comprehensive logging\n * - Handles all HTTP methods consistently\n */\n\nimport axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';\nimport type {\n HttpClientConfig,\n RequestOptions,\n HttpClientResponse,\n HttpMethod,\n HttpClientStatus,\n RetryContext\n} from './types.js';\nimport { HttpClientError } from '../errors.js';\nimport { classifyError, getErrorDescription } from './errors.js';\nimport { calculateRetryDelay, sleep, shouldRetryError, createRetryContext, updateRetryContext } from './retry.js';\n\nexport { HttpClientError };\n\n/**\n * Resilient HTTP Client with automatic retry logic.\n * Use HttpClient.init(context, options) when running with init/context; constructor(config) for standalone.\n */\nexport class HttpClient {\n private axiosInstance: AxiosInstance;\n private config: HttpClientConfig;\n private logger: any;\n\n constructor(contextOrConfig: any = {}, config?: HttpClientConfig) {\n const hasContext = config !== undefined;\n const options: HttpClientConfig = hasContext ? config! : (contextOrConfig || {});\n const context = hasContext ? contextOrConfig : undefined;\n\n this.config = {\n ...options,\n logger: context?.logger ?? options.logger ?? console,\n };\n this.logger = this.config.logger;\n\n this.axiosInstance = axios.create({\n timeout: this.config.timeout,\n validateStatus: () => true,\n maxRedirects: this.config.maxRedirects,\n headers: { 'User-Agent': this.config.userAgent },\n httpsAgent: this.config.validateSSL ? undefined : { rejectUnauthorized: false } as any,\n });\n\n // Add response interceptor for logging (optional - only if debug enabled)\n this.axiosInstance.interceptors.response.use(\n (response) => response,\n (error) => {\n // Log network-level errors here if needed\n // (HTTP errors are handled in the request method)\n return Promise.reject(error);\n }\n );\n }\n\n /**\n * Static init - discovers params via getAllForModule(defs). Whatever is in options goes.\n */\n static init(context: any, options: HttpClientConfig = {}): HttpClient {\n const defs: Record<string, string> = {\n timeout: 'number default 30000',\n retryCount: 'number default 3',\n retryDelay: 'number default 1000',\n maxRetryDelay: 'number default 30000',\n retryJitter: 'number default 0.1',\n userAgent: 'string default HttpClient/v1.0',\n validateSSL: 'boolean default true',\n maxRedirects: 'number default 5',\n };\n const discovered = context?.params?.getAllForModule?.(defs) ?? {};\n const merged: HttpClientConfig = { ...discovered, ...options, logger: options.logger ?? context?.logger };\n return new HttpClient(context, merged);\n }\n\n /**\n * Make an HTTP request with automatic retry logic\n * Never throws - always returns HttpClientResponse\n */\n async request(\n method: HttpMethod,\n url: string,\n options: RequestOptions = {}\n ): Promise<HttpClientResponse> {\n const startTime = Date.now();\n\n // Merge request options with defaults\n const requestConfig: AxiosRequestConfig = {\n method,\n url,\n timeout: options.timeout ?? this.config.timeout,\n headers: {\n 'User-Agent': options.userAgent ?? this.config.userAgent,\n ...options.headers\n },\n params: options.params,\n data: options.data\n };\n\n const retryCount = options.retryCount ?? this.config.retryCount;\n const retryDelay = options.retryDelay ?? this.config.retryDelay;\n\n // Initialize retry context\n let retryContext: RetryContext | null = null;\n let lastError: any = null;\n\n // Attempt the request with retries\n for (let attempt = 1; attempt <= retryCount + 1; attempt++) {\n try {\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] ${method} ${url} (attempt ${attempt}/${retryCount + 1})`);\n }\n\n const response: AxiosResponse = await this.axiosInstance.request(requestConfig);\n const duration = Date.now() - startTime;\n\n // Success! Return unified response format\n const customStatus = this.mapHttpStatusToCustomStatus(response.status);\n\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] ${method} ${url} → ${response.status} ${customStatus} (${duration}ms)`);\n }\n\n return {\n status: customStatus,\n code: response.status,\n headers: response.headers as Record<string, string>,\n data: response.data,\n duration,\n retryCount: attempt - 1,\n finalUrl: response.request?.res?.responseUrl || url\n };\n\n } catch (error: any) {\n lastError = error;\n const duration = Date.now() - startTime;\n\n // Classify the error\n const classification = classifyError(error);\n const errorDescription = getErrorDescription(classification.type);\n\n // Log the error\n if (classification.retryable && attempt <= retryCount) {\n this.logger.warn?.(`[HttpClient] ${method} ${url} failed (${classification.type}): ${errorDescription}. Retrying in ${retryDelay}ms...`);\n } else if (!classification.retryable || attempt > retryCount) {\n this.logger.error?.(`[HttpClient] ${method} ${url} failed (${classification.type}): ${errorDescription}`);\n }\n\n // Check if we should retry\n if (attempt <= retryCount && shouldRetryError(classification)) {\n // Calculate delay and wait\n const delay = calculateRetryDelay(\n attempt,\n retryDelay,\n this.config.maxRetryDelay,\n this.config.retryJitter\n );\n\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] Waiting ${delay}ms before retry ${attempt + 1}`);\n }\n\n await sleep(delay);\n continue;\n }\n\n // No more retries or not retryable - return error response\n return {\n status: classification.status,\n code: error.response?.status || null,\n error: classification.type,\n headers: error.response?.headers || null,\n data: error.response?.data || null,\n duration,\n retryCount: attempt - 1,\n finalUrl: url\n };\n }\n }\n\n // This should never be reached, but just in case\n return {\n status: 'unknown',\n code: null,\n error: 'unknown',\n headers: null,\n data: null,\n duration: Date.now() - startTime,\n retryCount: retryCount,\n finalUrl: url\n };\n }\n\n /**\n * GET request\n */\n async get(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('GET', url, options);\n }\n\n /**\n * POST request\n */\n async post(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('POST', url, options);\n }\n\n /**\n * PUT request\n */\n async put(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('PUT', url, options);\n }\n\n /**\n * DELETE request\n */\n async delete(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('DELETE', url, options);\n }\n\n /**\n * PATCH request\n */\n async patch(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('PATCH', url, options);\n }\n\n /**\n * HEAD request\n */\n async head(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('HEAD', url, options);\n }\n\n /**\n * OPTIONS request\n */\n async options(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('OPTIONS', url, options);\n }\n\n /**\n * Map HTTP status code to custom status\n */\n private mapHttpStatusToCustomStatus(httpStatus: number): HttpClientStatus {\n if (httpStatus >= 200 && httpStatus < 300) {\n return 'success';\n } else if (httpStatus === 401) {\n return 'authRequired';\n } else if (httpStatus === 403) {\n return 'authFailed';\n } else if (httpStatus >= 400 && httpStatus < 500) {\n return 'clientError';\n } else if (httpStatus >= 500) {\n return 'serverError';\n }\n return 'unknown';\n }\n\n /**\n * Get current configuration (for debugging)\n */\n getConfig(): Readonly<HttpClientConfig> {\n return { ...this.config };\n }\n}\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\nexport class HttpClientError extends FrameworkError {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = \"HttpClientError\";\n }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"FileDatabaseError\";\n }\n}\n\n","/**\n * HttpClient Error Classification\n *\n * Maps technical errors to human-readable, use-case oriented error types\n */\n\nimport type { HttpClientErrorType, HttpClientStatus, ErrorClassification } from './types.js';\n\n/**\n * Classify an error and determine retry behavior\n */\nexport function classifyError(error: any): ErrorClassification {\n // Handle axios response errors (HTTP errors)\n if (error.response) {\n const { status } = error.response;\n\n switch (status) {\n case 400:\n return { type: 'badRequest', retryable: false, isAuth: false, status: 'clientError' };\n case 401:\n return { type: 'unauthorized', retryable: false, isAuth: true, status: 'authRequired' };\n case 403:\n return { type: 'forbidden', retryable: false, isAuth: true, status: 'authFailed' };\n case 404:\n return { type: 'notFound', retryable: false, isAuth: false, status: 'clientError' };\n case 405:\n return { type: 'methodNotAllowed', retryable: false, isAuth: false, status: 'clientError' };\n case 409:\n return { type: 'conflict', retryable: false, isAuth: false, status: 'clientError' };\n case 422:\n return { type: 'unprocessableEntity', retryable: false, isAuth: false, status: 'clientError' };\n case 429:\n return { type: 'tooManyRequests', retryable: true, isAuth: false, status: 'clientError' };\n case 500:\n return { type: 'internalServerError', retryable: true, isAuth: false, status: 'serverError' };\n case 502:\n return { type: 'badGateway', retryable: true, isAuth: false, status: 'serverError' };\n case 503:\n return { type: 'serviceUnavailable', retryable: true, isAuth: false, status: 'serverError' };\n case 504:\n return { type: 'gatewayTimeout', retryable: true, isAuth: false, status: 'serverError' };\n default:\n if (status >= 400 && status < 500) {\n return { type: 'clientError' as HttpClientErrorType, retryable: false, isAuth: false, status: 'clientError' };\n } else if (status >= 500) {\n return { type: 'serverError' as HttpClientErrorType, retryable: true, isAuth: false, status: 'serverError' };\n }\n break;\n }\n }\n\n // Handle network/connection errors (no response)\n if (error.code) {\n switch (error.code) {\n case 'ECONNREFUSED':\n case 'ECONNRESET':\n case 'EPIPE':\n case 'ENOTFOUND':\n case 'EHOSTUNREACH':\n case 'ENETUNREACH':\n return { type: 'connectionFailed', retryable: true, isAuth: false, status: 'networkError' };\n\n case 'ETIMEDOUT':\n case 'ECONNABORTED':\n case 'ESOCKETTIMEDOUT':\n return { type: 'timeout', retryable: true, isAuth: false, status: 'timeout' };\n\n case 'EAUTH':\n case 'EACCES':\n return { type: 'unauthorized', retryable: false, isAuth: true, status: 'authRequired' };\n\n default:\n return { type: 'networkError', retryable: true, isAuth: false, status: 'networkError' };\n }\n }\n\n // Handle timeout errors\n if (error.message && (\n error.message.includes('timeout') ||\n error.message.includes('TIMEOUT') ||\n error.message.includes('aborted')\n )) {\n return { type: 'timeout', retryable: true, isAuth: false, status: 'timeout' };\n }\n\n // Handle cancellation\n if (error.name === 'AbortError' || error.message?.includes('cancelled')) {\n return { type: 'requestCancelled', retryable: false, isAuth: false, status: 'unknown' };\n }\n\n // Default fallback\n return { type: 'unknown', retryable: false, isAuth: false, status: 'unknown' };\n}\n\n/**\n * Get a human-readable description for an error type\n */\nexport function getErrorDescription(errorType: HttpClientErrorType): string {\n const descriptions: Record<HttpClientErrorType, string> = {\n connectionFailed: 'Failed to establish a connection to the server',\n timeout: 'Request timed out before completing',\n networkError: 'Network connection issue occurred',\n badRequest: 'Request was malformed or invalid',\n unauthorized: 'Authentication credentials are required',\n forbidden: 'Access to the requested resource is forbidden',\n notFound: 'The requested resource was not found',\n methodNotAllowed: 'HTTP method not allowed for this resource',\n conflict: 'Request conflicts with current server state',\n unprocessableEntity: 'Request data could not be processed',\n tooManyRequests: 'Too many requests sent in a short time',\n internalServerError: 'Server encountered an internal error',\n badGateway: 'Invalid response from upstream server',\n serviceUnavailable: 'Server is temporarily unavailable',\n gatewayTimeout: 'Upstream server timed out',\n unknown: 'An unknown error occurred',\n requestCancelled: 'Request was cancelled before completion'\n };\n\n return descriptions[errorType] || 'An unknown error occurred';\n}\n","/**\n * HttpClient Retry Logic\n *\n * Implements exponential backoff with jitter to prevent thundering herd problems\n */\n\nimport type { RetryContext } from './types.js';\n\n/**\n * Calculate the next retry delay using exponential backoff with jitter\n *\n * Formula: delay = baseDelay * (2 ^ (attempt - 1)) + randomJitter\n *\n * Jitter prevents the \"thundering herd\" problem where multiple failed requests\n * all retry at the exact same time, overwhelming the server.\n */\nexport function calculateRetryDelay(\n attempt: number,\n baseDelay: number,\n maxDelay: number,\n jitterFactor: number = 0.1\n): number {\n // Exponential backoff: baseDelay * (2 ^ (attempt - 1))\n const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);\n\n // Cap at maximum delay\n const cappedDelay = Math.min(exponentialDelay, maxDelay);\n\n // Add jitter: random variation up to jitterFactor of the delay\n const jitter = cappedDelay * jitterFactor * Math.random();\n\n return Math.floor(cappedDelay + jitter);\n}\n\n/**\n * Sleep for the specified number of milliseconds\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Determine if an error should be retried based on classification\n */\nexport function shouldRetryError(classification: { retryable: boolean; isAuth: boolean }): boolean {\n // Never retry auth errors (they won't succeed with the same credentials)\n if (classification.isAuth) {\n return false;\n }\n\n // Retry if the error is classified as retryable\n return classification.retryable;\n}\n\n/**\n * Create a retry context for tracking retry attempts\n */\nexport function createRetryContext(\n maxAttempts: number,\n baseDelay: number,\n maxDelay: number,\n jitterFactor: number\n): RetryContext {\n return {\n attempt: 1,\n maxAttempts,\n lastError: new Error('Initial attempt'),\n totalDelay: 0,\n nextDelay: calculateRetryDelay(1, baseDelay, maxDelay, jitterFactor)\n };\n}\n\n/**\n * Update retry context for the next attempt\n */\nexport function updateRetryContext(\n context: RetryContext,\n lastError: Error,\n baseDelay: number,\n maxDelay: number,\n jitterFactor: number\n): RetryContext {\n const nextAttempt = context.attempt + 1;\n const nextDelay = calculateRetryDelay(nextAttempt, baseDelay, maxDelay, jitterFactor);\n\n return {\n attempt: nextAttempt,\n maxAttempts: context.maxAttempts,\n lastError,\n totalDelay: context.totalDelay + context.nextDelay,\n nextDelay\n };\n}\n"],"mappings":"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","names":["axios"]}
|
|
1
|
+
{"version":3,"sources":["../src/http-client/index.js","../src/errors.js","../src/http-client/errors.js","../src/http-client/retry.js"],"sourcesContent":["/**\n * HttpClient - Resilient HTTP Client with Retry Logic\n *\n * A production-ready HTTP client that:\n * - Wraps axios with enhanced error handling and retry logic\n * - Never throws exceptions - always returns unified response format\n * - Uses exponential backoff with jitter for retries\n * - Provides human-readable error classifications\n * - Supports comprehensive logging\n * - Handles all HTTP methods consistently\n */\n\nimport axios, { } from \"axios\";\n\n\n\n\n\n\n\n\nimport { HttpClientError } from \"../errors.js\";\nimport { classifyError, getErrorDescription } from \"./errors.js\";\nimport { calculateRetryDelay, sleep, shouldRetryError, } from \"./retry.js\";\n\nexport { HttpClientError };\n\n/**\n * Resilient HTTP Client with automatic retry logic.\n * Use HttpClient.init(context, options) when running with init/context; constructor(config) for standalone.\n */\nexport class HttpClient {\n axiosInstance;\n config;\n logger;\n\n constructor(contextOrConfig = {}, config) {\n const hasContext = config !== undefined;\n const options = hasContext ? config : (contextOrConfig || {});\n const context = hasContext ? contextOrConfig : undefined;\n\n this.config = {\n ...options,\n logger: context?.logger ?? options.logger ?? console,\n };\n this.logger = this.config.logger;\n\n this.axiosInstance = axios.create({\n timeout: this.config.timeout,\n validateStatus: () => true,\n maxRedirects: this.config.maxRedirects,\n headers: { \"User-Agent\": this.config.userAgent },\n httpsAgent: this.config.validateSSL ? undefined : { rejectUnauthorized: false } ,\n });\n\n // Add response interceptor for logging (optional - only if debug enabled)\n this.axiosInstance.interceptors.response.use(\n (response) => response,\n (error) => {\n // Log network-level errors here if needed\n // (HTTP errors are handled in the request method)\n return Promise.reject(error);\n }\n );\n }\n\n /**\n * Static init - discovers params via getAllForModule(defs). Whatever is in options goes.\n */\n static init(context, options = {}) {\n const defs = {\n timeout: \"number default 30000\",\n retryCount: \"number default 3\",\n retryDelay: \"number default 1000\",\n maxRetryDelay: \"number default 30000\",\n retryJitter: \"number default 0.1\",\n userAgent: \"string default HttpClient/v1.0\",\n validateSSL: \"boolean default true\",\n maxRedirects: \"number default 5\",\n };\n const discovered = context?.params?.getAllForModule?.(defs) ?? {};\n const merged = { ...discovered, ...options, logger: options.logger ?? context?.logger };\n return new HttpClient(context, merged);\n }\n\n /**\n * Make an HTTP request with automatic retry logic\n * Never throws - always returns HttpClientResponse\n */\n async request(\n method,\n url,\n options = {}\n ) {\n const startTime = Date.now();\n\n // Merge request options with defaults\n const requestConfig = {\n method,\n url,\n timeout: options.timeout ?? this.config.timeout,\n headers: {\n \"User-Agent\": options.userAgent ?? this.config.userAgent,\n ...options.headers\n },\n params: options.params,\n data: options.data\n };\n\n const retryCount = options.retryCount ?? this.config.retryCount;\n const retryDelay = options.retryDelay ?? this.config.retryDelay;\n\n // Initialize retry context\n const _retryContext = null;\n let _lastError = null;\n\n // Attempt the request with retries\n for (let attempt = 1; attempt <= retryCount + 1; attempt++) {\n try {\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] ${method} ${url} (attempt ${attempt}/${retryCount + 1})`);\n }\n\n const response = await this.axiosInstance.request(requestConfig);\n const duration = Date.now() - startTime;\n\n // Success! Return unified response format\n const customStatus = this.mapHttpStatusToCustomStatus(response.status);\n\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] ${method} ${url} → ${response.status} ${customStatus} (${duration}ms)`);\n }\n\n return {\n status: customStatus,\n code: response.status,\n headers: response.headers ,\n data: response.data,\n duration,\n retryCount: attempt - 1,\n finalUrl: response.request?.res?.responseUrl || url\n };\n\n } catch (error) {\n _lastError = error;\n const duration = Date.now() - startTime;\n\n // Classify the error\n const classification = classifyError(error);\n const errorDescription = getErrorDescription(classification.type);\n\n // Log the error\n if (classification.retryable && attempt <= retryCount) {\n this.logger.warn?.(`[HttpClient] ${method} ${url} failed (${classification.type}): ${errorDescription}. Retrying in ${retryDelay}ms...`);\n } else if (!classification.retryable || attempt > retryCount) {\n this.logger.error?.(`[HttpClient] ${method} ${url} failed (${classification.type}): ${errorDescription}`);\n }\n\n // Check if we should retry\n if (attempt <= retryCount && shouldRetryError(classification)) {\n // Calculate delay and wait\n const delay = calculateRetryDelay(\n attempt,\n retryDelay,\n this.config.maxRetryDelay,\n this.config.retryJitter\n );\n\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] Waiting ${delay}ms before retry ${attempt + 1}`);\n }\n\n await sleep(delay);\n continue;\n }\n\n // No more retries or not retryable - return error response\n return {\n status: classification.status,\n code: error.response?.status || null,\n error: classification.type,\n headers: error.response?.headers || null,\n data: error.response?.data || null,\n duration,\n retryCount: attempt - 1,\n finalUrl: url\n };\n }\n }\n\n // This should never be reached, but just in case\n return {\n status: \"unknown\",\n code: null,\n error: \"unknown\",\n headers: null,\n data: null,\n duration: Date.now() - startTime,\n retryCount: retryCount,\n finalUrl: url\n };\n }\n\n /**\n * GET request\n */\n async get(url, options = {}) {\n return this.request(\"GET\", url, options);\n }\n\n /**\n * POST request\n */\n async post(url, options = {}) {\n return this.request(\"POST\", url, options);\n }\n\n /**\n * PUT request\n */\n async put(url, options = {}) {\n return this.request(\"PUT\", url, options);\n }\n\n /**\n * DELETE request\n */\n async delete(url, options = {}) {\n return this.request(\"DELETE\", url, options);\n }\n\n /**\n * PATCH request\n */\n async patch(url, options = {}) {\n return this.request(\"PATCH\", url, options);\n }\n\n /**\n * HEAD request\n */\n async head(url, options = {}) {\n return this.request(\"HEAD\", url, options);\n }\n\n /**\n * OPTIONS request\n */\n async options(url, options = {}) {\n return this.request(\"OPTIONS\", url, options);\n }\n\n /**\n * Map HTTP status code to custom status\n */\n mapHttpStatusToCustomStatus(httpStatus) {\n if (httpStatus >= 200 && httpStatus < 300) {\n return \"success\";\n } else if (httpStatus === 401) {\n return \"authRequired\";\n } else if (httpStatus === 403) {\n return \"authFailed\";\n } else if (httpStatus >= 400 && httpStatus < 500) {\n return \"clientError\";\n } else if (httpStatus >= 500) {\n return \"serverError\";\n }\n return \"unknown\";\n }\n\n /**\n * Get current configuration (for debugging)\n */\n getConfig() {\n return { ...this.config };\n }\n}\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n constructor(message) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\nexport class HttpClientError extends FrameworkError {\n constructor(message, cause) {\n super(message);this.cause = cause;;\n this.name = \"HttpClientError\";\n }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"FileDatabaseError\";\n }\n}\n\n","\n\n\n\n\n\n\n\n/**\n * Classify an error and determine retry behavior\n */\nexport function classifyError(error) {\n // Handle axios response errors (HTTP errors)\n if (error.response) {\n const { status } = error.response;\n\n switch (status) {\n case 400:\n return { type: \"badRequest\", retryable: false, isAuth: false, status: \"clientError\" };\n case 401:\n return { type: \"unauthorized\", retryable: false, isAuth: true, status: \"authRequired\" };\n case 403:\n return { type: \"forbidden\", retryable: false, isAuth: true, status: \"authFailed\" };\n case 404:\n return { type: \"notFound\", retryable: false, isAuth: false, status: \"clientError\" };\n case 405:\n return { type: \"methodNotAllowed\", retryable: false, isAuth: false, status: \"clientError\" };\n case 409:\n return { type: \"conflict\", retryable: false, isAuth: false, status: \"clientError\" };\n case 422:\n return { type: \"unprocessableEntity\", retryable: false, isAuth: false, status: \"clientError\" };\n case 429:\n return { type: \"tooManyRequests\", retryable: true, isAuth: false, status: \"clientError\" };\n case 500:\n return { type: \"internalServerError\", retryable: true, isAuth: false, status: \"serverError\" };\n case 502:\n return { type: \"badGateway\", retryable: true, isAuth: false, status: \"serverError\" };\n case 503:\n return { type: \"serviceUnavailable\", retryable: true, isAuth: false, status: \"serverError\" };\n case 504:\n return { type: \"gatewayTimeout\", retryable: true, isAuth: false, status: \"serverError\" };\n default:\n if (status >= 400 && status < 500) {\n return { type: \"clientError\" , retryable: false, isAuth: false, status: \"clientError\" };\n } else if (status >= 500) {\n return { type: \"serverError\" , retryable: true, isAuth: false, status: \"serverError\" };\n }\n break;\n }\n }\n\n // Handle network/connection errors (no response)\n if (error.code) {\n switch (error.code) {\n case \"ECONNREFUSED\":\n case \"ECONNRESET\":\n case \"EPIPE\":\n case \"ENOTFOUND\":\n case \"EHOSTUNREACH\":\n case \"ENETUNREACH\":\n return { type: \"connectionFailed\", retryable: true, isAuth: false, status: \"networkError\" };\n\n case \"ETIMEDOUT\":\n case \"ECONNABORTED\":\n case \"ESOCKETTIMEDOUT\":\n return { type: \"timeout\", retryable: true, isAuth: false, status: \"timeout\" };\n\n case \"EAUTH\":\n case \"EACCES\":\n return { type: \"unauthorized\", retryable: false, isAuth: true, status: \"authRequired\" };\n\n default:\n return { type: \"networkError\", retryable: true, isAuth: false, status: \"networkError\" };\n }\n }\n\n // Handle timeout errors\n if (error.message && (\n error.message.includes(\"timeout\") ||\n error.message.includes(\"TIMEOUT\") ||\n error.message.includes(\"aborted\")\n )) {\n return { type: \"timeout\", retryable: true, isAuth: false, status: \"timeout\" };\n }\n\n // Handle cancellation\n if (error.name === \"AbortError\" || error.message?.includes(\"cancelled\")) {\n return { type: \"requestCancelled\", retryable: false, isAuth: false, status: \"unknown\" };\n }\n\n // Default fallback\n return { type: \"unknown\", retryable: false, isAuth: false, status: \"unknown\" };\n}\n\n/**\n * Get a human-readable description for an error type\n */\nexport function getErrorDescription(errorType) {\n const descriptions = {\n connectionFailed: \"Failed to establish a connection to the server\",\n timeout: \"Request timed out before completing\",\n networkError: \"Network connection issue occurred\",\n badRequest: \"Request was malformed or invalid\",\n unauthorized: \"Authentication credentials are required\",\n forbidden: \"Access to the requested resource is forbidden\",\n notFound: \"The requested resource was not found\",\n methodNotAllowed: \"HTTP method not allowed for this resource\",\n conflict: \"Request conflicts with current server state\",\n unprocessableEntity: \"Request data could not be processed\",\n tooManyRequests: \"Too many requests sent in a short time\",\n internalServerError: \"Server encountered an internal error\",\n badGateway: \"Invalid response from upstream server\",\n serviceUnavailable: \"Server is temporarily unavailable\",\n gatewayTimeout: \"Upstream server timed out\",\n unknown: \"An unknown error occurred\",\n requestCancelled: \"Request was cancelled before completion\"\n };\n\n return descriptions[errorType] || \"An unknown error occurred\";\n}\n","\n\n\n\n\n\n\n\n/**\n * Calculate the next retry delay using exponential backoff with jitter\n *\n * Formula: delay = baseDelay * (2 ^ (attempt - 1)) + randomJitter\n *\n * Jitter prevents the \"thundering herd\" problem where multiple failed requests\n * all retry at the exact same time, overwhelming the server.\n */\nexport function calculateRetryDelay(\n attempt,\n baseDelay,\n maxDelay,\n jitterFactor = 0.1\n) {\n // Exponential backoff: baseDelay * (2 ^ (attempt - 1))\n const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);\n\n // Cap at maximum delay\n const cappedDelay = Math.min(exponentialDelay, maxDelay);\n\n // Add jitter: random variation up to jitterFactor of the delay\n const jitter = cappedDelay * jitterFactor * Math.random();\n\n return Math.floor(cappedDelay + jitter);\n}\n\n/**\n * Sleep for the specified number of milliseconds\n */\nexport function sleep(ms) {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Determine if an error should be retried based on classification\n */\nexport function shouldRetryError(classification) {\n // Never retry auth errors (they won't succeed with the same credentials)\n if (classification.isAuth) {\n return false;\n }\n\n // Retry if the error is classified as retryable\n return classification.retryable;\n}\n\n/**\n * Create a retry context for tracking retry attempts\n */\nexport function createRetryContext(\n maxAttempts,\n baseDelay,\n maxDelay,\n jitterFactor\n) {\n return {\n attempt: 1,\n maxAttempts,\n lastError: new Error(\"Initial attempt\"),\n totalDelay: 0,\n nextDelay: calculateRetryDelay(1, baseDelay, maxDelay, jitterFactor)\n };\n}\n\n/**\n * Update retry context for the next attempt\n */\nexport function updateRetryContext(\n context,\n lastError,\n baseDelay,\n maxDelay,\n jitterFactor\n) {\n const nextAttempt = context.attempt + 1;\n const nextDelay = calculateRetryDelay(nextAttempt, baseDelay, maxDelay, jitterFactor);\n\n return {\n attempt: nextAttempt,\n maxAttempts: context.maxAttempts,\n lastError,\n totalDelay: context.totalDelay + context.nextDelay,\n nextDelay\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA,mBAAuB;;;ACRhB,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACtC,YAAY,SAAS;AACjB,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EAChB;AACJ;AA8BO,IAAM,kBAAN,cAA8B,eAAe;AAAA,EAChD,YAAY,SAAW,OAAO;AAC1B,UAAM,OAAO;AAAE,SAAK,QAAQ;AAAM;AAClC,SAAK,OAAO;AAAA,EAChB;AACJ;;;ACjCO,SAAS,cAAc,OAAO;AAEjC,MAAI,MAAM,UAAU;AAChB,UAAM,EAAE,OAAO,IAAI,MAAM;AAEzB,YAAQ,QAAQ;AAAA,MACZ,KAAK;AACD,eAAO,EAAE,MAAM,cAAc,WAAW,OAAO,QAAQ,OAAO,QAAQ,cAAc;AAAA,MACxF,KAAK;AACD,eAAO,EAAE,MAAM,gBAAgB,WAAW,OAAO,QAAQ,MAAM,QAAQ,eAAe;AAAA,MAC1F,KAAK;AACD,eAAO,EAAE,MAAM,aAAa,WAAW,OAAO,QAAQ,MAAM,QAAQ,aAAa;AAAA,MACrF,KAAK;AACD,eAAO,EAAE,MAAM,YAAY,WAAW,OAAO,QAAQ,OAAO,QAAQ,cAAc;AAAA,MACtF,KAAK;AACD,eAAO,EAAE,MAAM,oBAAoB,WAAW,OAAO,QAAQ,OAAO,QAAQ,cAAc;AAAA,MAC9F,KAAK;AACD,eAAO,EAAE,MAAM,YAAY,WAAW,OAAO,QAAQ,OAAO,QAAQ,cAAc;AAAA,MACtF,KAAK;AACD,eAAO,EAAE,MAAM,uBAAuB,WAAW,OAAO,QAAQ,OAAO,QAAQ,cAAc;AAAA,MACjG,KAAK;AACD,eAAO,EAAE,MAAM,mBAAmB,WAAW,MAAM,QAAQ,OAAO,QAAQ,cAAc;AAAA,MAC5F,KAAK;AACD,eAAO,EAAE,MAAM,uBAAuB,WAAW,MAAM,QAAQ,OAAO,QAAQ,cAAc;AAAA,MAChG,KAAK;AACD,eAAO,EAAE,MAAM,cAAc,WAAW,MAAM,QAAQ,OAAO,QAAQ,cAAc;AAAA,MACvF,KAAK;AACD,eAAO,EAAE,MAAM,sBAAsB,WAAW,MAAM,QAAQ,OAAO,QAAQ,cAAc;AAAA,MAC/F,KAAK;AACD,eAAO,EAAE,MAAM,kBAAkB,WAAW,MAAM,QAAQ,OAAO,QAAQ,cAAc;AAAA,MAC3F;AACI,YAAI,UAAU,OAAO,SAAS,KAAK;AAC/B,iBAAO,EAAE,MAAM,eAAgB,WAAW,OAAO,QAAQ,OAAO,QAAQ,cAAc;AAAA,QAC1F,WAAW,UAAU,KAAK;AACtB,iBAAO,EAAE,MAAM,eAAgB,WAAW,MAAM,QAAQ,OAAO,QAAQ,cAAc;AAAA,QACzF;AACA;AAAA,IACR;AAAA,EACJ;AAGA,MAAI,MAAM,MAAM;AACZ,YAAQ,MAAM,MAAM;AAAA,MAChB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACD,eAAO,EAAE,MAAM,oBAAoB,WAAW,MAAM,QAAQ,OAAO,QAAQ,eAAe;AAAA,MAE9F,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACD,eAAO,EAAE,MAAM,WAAW,WAAW,MAAM,QAAQ,OAAO,QAAQ,UAAU;AAAA,MAEhF,KAAK;AAAA,MACL,KAAK;AACD,eAAO,EAAE,MAAM,gBAAgB,WAAW,OAAO,QAAQ,MAAM,QAAQ,eAAe;AAAA,MAE1F;AACI,eAAO,EAAE,MAAM,gBAAgB,WAAW,MAAM,QAAQ,OAAO,QAAQ,eAAe;AAAA,IAC9F;AAAA,EACJ;AAGA,MAAI,MAAM,YACN,MAAM,QAAQ,SAAS,SAAS,KAChC,MAAM,QAAQ,SAAS,SAAS,KAChC,MAAM,QAAQ,SAAS,SAAS,IACjC;AACC,WAAO,EAAE,MAAM,WAAW,WAAW,MAAM,QAAQ,OAAO,QAAQ,UAAU;AAAA,EAChF;AAGA,MAAI,MAAM,SAAS,gBAAgB,MAAM,SAAS,SAAS,WAAW,GAAG;AACrE,WAAO,EAAE,MAAM,oBAAoB,WAAW,OAAO,QAAQ,OAAO,QAAQ,UAAU;AAAA,EAC1F;AAGA,SAAO,EAAE,MAAM,WAAW,WAAW,OAAO,QAAQ,OAAO,QAAQ,UAAU;AACjF;AAKO,SAAS,oBAAoB,WAAW;AAC3C,QAAM,eAAe;AAAA,IACjB,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,WAAW;AAAA,IACX,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,qBAAqB;AAAA,IACrB,iBAAiB;AAAA,IACjB,qBAAqB;AAAA,IACrB,YAAY;AAAA,IACZ,oBAAoB;AAAA,IACpB,gBAAgB;AAAA,IAChB,SAAS;AAAA,IACT,kBAAkB;AAAA,EACtB;AAEA,SAAO,aAAa,SAAS,KAAK;AACtC;;;ACvGO,SAAS,oBACZ,SACA,WACA,UACA,eAAe,KACjB;AAEE,QAAM,mBAAmB,YAAY,KAAK,IAAI,GAAG,UAAU,CAAC;AAG5D,QAAM,cAAc,KAAK,IAAI,kBAAkB,QAAQ;AAGvD,QAAM,SAAS,cAAc,eAAe,KAAK,OAAO;AAExD,SAAO,KAAK,MAAM,cAAc,MAAM;AAC1C;AAKO,SAAS,MAAM,IAAI;AACtB,SAAO,IAAI,QAAQ,aAAW,WAAW,SAAS,EAAE,CAAC;AACzD;AAKO,SAAS,iBAAiB,gBAAgB;AAE7C,MAAI,eAAe,QAAQ;AACvB,WAAO;AAAA,EACX;AAGA,SAAO,eAAe;AAC1B;;;AHrBO,IAAM,aAAN,MAAM,YAAW;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,kBAAkB,CAAC,GAAG,QAAQ;AACtC,UAAM,aAAa,WAAW;AAC9B,UAAM,UAAU,aAAa,SAAU,mBAAmB,CAAC;AAC3D,UAAM,UAAU,aAAa,kBAAkB;AAE/C,SAAK,SAAS;AAAA,MACV,GAAG;AAAA,MACH,QAAQ,SAAS,UAAU,QAAQ,UAAU;AAAA,IACjD;AACA,SAAK,SAAS,KAAK,OAAO;AAE1B,SAAK,gBAAgB,aAAAA,QAAM,OAAO;AAAA,MAC9B,SAAS,KAAK,OAAO;AAAA,MACrB,gBAAgB,MAAM;AAAA,MACtB,cAAc,KAAK,OAAO;AAAA,MAC1B,SAAS,EAAE,cAAc,KAAK,OAAO,UAAU;AAAA,MAC/C,YAAY,KAAK,OAAO,cAAc,SAAY,EAAE,oBAAoB,MAAM;AAAA,IAClF,CAAC;AAGD,SAAK,cAAc,aAAa,SAAS;AAAA,MACrC,CAAC,aAAa;AAAA,MACd,CAAC,UAAU;AAGP,eAAO,QAAQ,OAAO,KAAK;AAAA,MAC/B;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO,KAAK,SAAS,UAAU,CAAC,GAAG;AAC/B,UAAM,OAAO;AAAA,MACT,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,aAAa;AAAA,MACb,WAAW;AAAA,MACX,aAAa;AAAA,MACb,cAAc;AAAA,IAClB;AACA,UAAM,aAAa,SAAS,QAAQ,kBAAkB,IAAI,KAAK,CAAC;AAChE,UAAM,SAAS,EAAE,GAAG,YAAY,GAAG,SAAS,QAAQ,QAAQ,UAAU,SAAS,OAAO;AACtF,WAAO,IAAI,YAAW,SAAS,MAAM;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QACF,QACA,KACA,UAAU,CAAC,GACb;AACE,UAAM,YAAY,KAAK,IAAI;AAG3B,UAAM,gBAAgB;AAAA,MAClB;AAAA,MACA;AAAA,MACA,SAAS,QAAQ,WAAW,KAAK,OAAO;AAAA,MACxC,SAAS;AAAA,QACL,cAAc,QAAQ,aAAa,KAAK,OAAO;AAAA,QAC/C,GAAG,QAAQ;AAAA,MACf;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB,MAAM,QAAQ;AAAA,IAClB;AAEA,UAAM,aAAa,QAAQ,cAAc,KAAK,OAAO;AACrD,UAAM,aAAa,QAAQ,cAAc,KAAK,OAAO;AAGrD,UAAM,gBAAgB;AACtB,QAAI,aAAa;AAGjB,aAAS,UAAU,GAAG,WAAW,aAAa,GAAG,WAAW;AACxD,UAAI;AACA,YAAI,QAAQ,OAAO;AACf,eAAK,OAAO,QAAQ,gBAAgB,MAAM,IAAI,GAAG,aAAa,OAAO,IAAI,aAAa,CAAC,GAAG;AAAA,QAC9F;AAEA,cAAM,WAAW,MAAM,KAAK,cAAc,QAAQ,aAAa;AAC/D,cAAM,WAAW,KAAK,IAAI,IAAI;AAG9B,cAAM,eAAe,KAAK,4BAA4B,SAAS,MAAM;AAErE,YAAI,QAAQ,OAAO;AACf,eAAK,OAAO,QAAQ,gBAAgB,MAAM,IAAI,GAAG,WAAM,SAAS,MAAM,IAAI,YAAY,KAAK,QAAQ,KAAK;AAAA,QAC5G;AAEA,eAAO;AAAA,UACH,QAAQ;AAAA,UACR,MAAM,SAAS;AAAA,UACf,SAAS,SAAS;AAAA,UAClB,MAAM,SAAS;AAAA,UACf;AAAA,UACA,YAAY,UAAU;AAAA,UACtB,UAAU,SAAS,SAAS,KAAK,eAAe;AAAA,QACpD;AAAA,MAEJ,SAAS,OAAO;AACZ,qBAAa;AACb,cAAM,WAAW,KAAK,IAAI,IAAI;AAG9B,cAAM,iBAAiB,cAAc,KAAK;AAC1C,cAAM,mBAAmB,oBAAoB,eAAe,IAAI;AAGhE,YAAI,eAAe,aAAa,WAAW,YAAY;AACnD,eAAK,OAAO,OAAO,gBAAgB,MAAM,IAAI,GAAG,YAAY,eAAe,IAAI,MAAM,gBAAgB,iBAAiB,UAAU,OAAO;AAAA,QAC3I,WAAW,CAAC,eAAe,aAAa,UAAU,YAAY;AAC1D,eAAK,OAAO,QAAQ,gBAAgB,MAAM,IAAI,GAAG,YAAY,eAAe,IAAI,MAAM,gBAAgB,EAAE;AAAA,QAC5G;AAGA,YAAI,WAAW,cAAc,iBAAiB,cAAc,GAAG;AAE3D,gBAAM,QAAQ;AAAA,YACV;AAAA,YACA;AAAA,YACA,KAAK,OAAO;AAAA,YACZ,KAAK,OAAO;AAAA,UAChB;AAEA,cAAI,QAAQ,OAAO;AACf,iBAAK,OAAO,QAAQ,wBAAwB,KAAK,mBAAmB,UAAU,CAAC,EAAE;AAAA,UACrF;AAEA,gBAAM,MAAM,KAAK;AACjB;AAAA,QACJ;AAGA,eAAO;AAAA,UACH,QAAQ,eAAe;AAAA,UACvB,MAAM,MAAM,UAAU,UAAU;AAAA,UAChC,OAAO,eAAe;AAAA,UACtB,SAAS,MAAM,UAAU,WAAW;AAAA,UACpC,MAAM,MAAM,UAAU,QAAQ;AAAA,UAC9B;AAAA,UACA,YAAY,UAAU;AAAA,UACtB,UAAU;AAAA,QACd;AAAA,MACJ;AAAA,IACJ;AAGA,WAAO;AAAA,MACH,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,MAAM;AAAA,MACN,UAAU,KAAK,IAAI,IAAI;AAAA,MACvB;AAAA,MACA,UAAU;AAAA,IACd;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,KAAK,UAAU,CAAC,GAAG;AACzB,WAAO,KAAK,QAAQ,OAAO,KAAK,OAAO;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,KAAK,UAAU,CAAC,GAAG;AAC1B,WAAO,KAAK,QAAQ,QAAQ,KAAK,OAAO;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IAAI,KAAK,UAAU,CAAC,GAAG;AACzB,WAAO,KAAK,QAAQ,OAAO,KAAK,OAAO;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,KAAK,UAAU,CAAC,GAAG;AAC5B,WAAO,KAAK,QAAQ,UAAU,KAAK,OAAO;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,KAAK,UAAU,CAAC,GAAG;AAC3B,WAAO,KAAK,QAAQ,SAAS,KAAK,OAAO;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,KAAK,UAAU,CAAC,GAAG;AAC1B,WAAO,KAAK,QAAQ,QAAQ,KAAK,OAAO;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,KAAK,UAAU,CAAC,GAAG;AAC7B,WAAO,KAAK,QAAQ,WAAW,KAAK,OAAO;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,4BAA4B,YAAY;AACpC,QAAI,cAAc,OAAO,aAAa,KAAK;AACvC,aAAO;AAAA,IACX,WAAW,eAAe,KAAK;AAC3B,aAAO;AAAA,IACX,WAAW,eAAe,KAAK;AAC3B,aAAO;AAAA,IACX,WAAW,cAAc,OAAO,aAAa,KAAK;AAC9C,aAAO;AAAA,IACX,WAAW,cAAc,KAAK;AAC1B,aAAO;AAAA,IACX;AACA,WAAO;AAAA,EACX;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY;AACR,WAAO,EAAE,GAAG,KAAK,OAAO;AAAA,EAC5B;AACJ;","names":["axios"]}
|
package/dist/http-client.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// src/http-client/index.
|
|
2
|
-
import axios from "axios";
|
|
1
|
+
// src/http-client/index.js
|
|
2
|
+
import axios, {} from "axios";
|
|
3
3
|
|
|
4
|
-
// src/errors.
|
|
4
|
+
// src/errors.js
|
|
5
5
|
var FrameworkError = class extends Error {
|
|
6
6
|
constructor(message) {
|
|
7
7
|
super(message);
|
|
@@ -12,11 +12,12 @@ var HttpClientError = class extends FrameworkError {
|
|
|
12
12
|
constructor(message, cause) {
|
|
13
13
|
super(message);
|
|
14
14
|
this.cause = cause;
|
|
15
|
+
;
|
|
15
16
|
this.name = "HttpClientError";
|
|
16
17
|
}
|
|
17
18
|
};
|
|
18
19
|
|
|
19
|
-
// src/http-client/errors.
|
|
20
|
+
// src/http-client/errors.js
|
|
20
21
|
function classifyError(error) {
|
|
21
22
|
if (error.response) {
|
|
22
23
|
const { status } = error.response;
|
|
@@ -105,7 +106,7 @@ function getErrorDescription(errorType) {
|
|
|
105
106
|
return descriptions[errorType] || "An unknown error occurred";
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
// src/http-client/retry.
|
|
109
|
+
// src/http-client/retry.js
|
|
109
110
|
function calculateRetryDelay(attempt, baseDelay, maxDelay, jitterFactor = 0.1) {
|
|
110
111
|
const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);
|
|
111
112
|
const cappedDelay = Math.min(exponentialDelay, maxDelay);
|
|
@@ -122,7 +123,7 @@ function shouldRetryError(classification) {
|
|
|
122
123
|
return classification.retryable;
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
// src/http-client/index.
|
|
126
|
+
// src/http-client/index.js
|
|
126
127
|
var HttpClient = class _HttpClient {
|
|
127
128
|
axiosInstance;
|
|
128
129
|
config;
|
|
@@ -187,8 +188,8 @@ var HttpClient = class _HttpClient {
|
|
|
187
188
|
};
|
|
188
189
|
const retryCount = options.retryCount ?? this.config.retryCount;
|
|
189
190
|
const retryDelay = options.retryDelay ?? this.config.retryDelay;
|
|
190
|
-
|
|
191
|
-
let
|
|
191
|
+
const _retryContext = null;
|
|
192
|
+
let _lastError = null;
|
|
192
193
|
for (let attempt = 1; attempt <= retryCount + 1; attempt++) {
|
|
193
194
|
try {
|
|
194
195
|
if (options.debug) {
|
|
@@ -210,7 +211,7 @@ var HttpClient = class _HttpClient {
|
|
|
210
211
|
finalUrl: response.request?.res?.responseUrl || url
|
|
211
212
|
};
|
|
212
213
|
} catch (error) {
|
|
213
|
-
|
|
214
|
+
_lastError = error;
|
|
214
215
|
const duration = Date.now() - startTime;
|
|
215
216
|
const classification = classifyError(error);
|
|
216
217
|
const errorDescription = getErrorDescription(classification.type);
|
package/dist/http-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/http-client/index.ts","../src/errors.ts","../src/http-client/errors.ts","../src/http-client/retry.ts"],"sourcesContent":["/**\n * HttpClient - Resilient HTTP Client with Retry Logic\n *\n * A production-ready HTTP client that:\n * - Wraps axios with enhanced error handling and retry logic\n * - Never throws exceptions - always returns unified response format\n * - Uses exponential backoff with jitter for retries\n * - Provides human-readable error classifications\n * - Supports comprehensive logging\n * - Handles all HTTP methods consistently\n */\n\nimport axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';\nimport type {\n HttpClientConfig,\n RequestOptions,\n HttpClientResponse,\n HttpMethod,\n HttpClientStatus,\n RetryContext\n} from './types.js';\nimport { HttpClientError } from '../errors.js';\nimport { classifyError, getErrorDescription } from './errors.js';\nimport { calculateRetryDelay, sleep, shouldRetryError, createRetryContext, updateRetryContext } from './retry.js';\n\nexport { HttpClientError };\n\n/**\n * Resilient HTTP Client with automatic retry logic.\n * Use HttpClient.init(context, options) when running with init/context; constructor(config) for standalone.\n */\nexport class HttpClient {\n private axiosInstance: AxiosInstance;\n private config: HttpClientConfig;\n private logger: any;\n\n constructor(contextOrConfig: any = {}, config?: HttpClientConfig) {\n const hasContext = config !== undefined;\n const options: HttpClientConfig = hasContext ? config! : (contextOrConfig || {});\n const context = hasContext ? contextOrConfig : undefined;\n\n this.config = {\n ...options,\n logger: context?.logger ?? options.logger ?? console,\n };\n this.logger = this.config.logger;\n\n this.axiosInstance = axios.create({\n timeout: this.config.timeout,\n validateStatus: () => true,\n maxRedirects: this.config.maxRedirects,\n headers: { 'User-Agent': this.config.userAgent },\n httpsAgent: this.config.validateSSL ? undefined : { rejectUnauthorized: false } as any,\n });\n\n // Add response interceptor for logging (optional - only if debug enabled)\n this.axiosInstance.interceptors.response.use(\n (response) => response,\n (error) => {\n // Log network-level errors here if needed\n // (HTTP errors are handled in the request method)\n return Promise.reject(error);\n }\n );\n }\n\n /**\n * Static init - discovers params via getAllForModule(defs). Whatever is in options goes.\n */\n static init(context: any, options: HttpClientConfig = {}): HttpClient {\n const defs: Record<string, string> = {\n timeout: 'number default 30000',\n retryCount: 'number default 3',\n retryDelay: 'number default 1000',\n maxRetryDelay: 'number default 30000',\n retryJitter: 'number default 0.1',\n userAgent: 'string default HttpClient/v1.0',\n validateSSL: 'boolean default true',\n maxRedirects: 'number default 5',\n };\n const discovered = context?.params?.getAllForModule?.(defs) ?? {};\n const merged: HttpClientConfig = { ...discovered, ...options, logger: options.logger ?? context?.logger };\n return new HttpClient(context, merged);\n }\n\n /**\n * Make an HTTP request with automatic retry logic\n * Never throws - always returns HttpClientResponse\n */\n async request(\n method: HttpMethod,\n url: string,\n options: RequestOptions = {}\n ): Promise<HttpClientResponse> {\n const startTime = Date.now();\n\n // Merge request options with defaults\n const requestConfig: AxiosRequestConfig = {\n method,\n url,\n timeout: options.timeout ?? this.config.timeout,\n headers: {\n 'User-Agent': options.userAgent ?? this.config.userAgent,\n ...options.headers\n },\n params: options.params,\n data: options.data\n };\n\n const retryCount = options.retryCount ?? this.config.retryCount;\n const retryDelay = options.retryDelay ?? this.config.retryDelay;\n\n // Initialize retry context\n let retryContext: RetryContext | null = null;\n let lastError: any = null;\n\n // Attempt the request with retries\n for (let attempt = 1; attempt <= retryCount + 1; attempt++) {\n try {\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] ${method} ${url} (attempt ${attempt}/${retryCount + 1})`);\n }\n\n const response: AxiosResponse = await this.axiosInstance.request(requestConfig);\n const duration = Date.now() - startTime;\n\n // Success! Return unified response format\n const customStatus = this.mapHttpStatusToCustomStatus(response.status);\n\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] ${method} ${url} → ${response.status} ${customStatus} (${duration}ms)`);\n }\n\n return {\n status: customStatus,\n code: response.status,\n headers: response.headers as Record<string, string>,\n data: response.data,\n duration,\n retryCount: attempt - 1,\n finalUrl: response.request?.res?.responseUrl || url\n };\n\n } catch (error: any) {\n lastError = error;\n const duration = Date.now() - startTime;\n\n // Classify the error\n const classification = classifyError(error);\n const errorDescription = getErrorDescription(classification.type);\n\n // Log the error\n if (classification.retryable && attempt <= retryCount) {\n this.logger.warn?.(`[HttpClient] ${method} ${url} failed (${classification.type}): ${errorDescription}. Retrying in ${retryDelay}ms...`);\n } else if (!classification.retryable || attempt > retryCount) {\n this.logger.error?.(`[HttpClient] ${method} ${url} failed (${classification.type}): ${errorDescription}`);\n }\n\n // Check if we should retry\n if (attempt <= retryCount && shouldRetryError(classification)) {\n // Calculate delay and wait\n const delay = calculateRetryDelay(\n attempt,\n retryDelay,\n this.config.maxRetryDelay,\n this.config.retryJitter\n );\n\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] Waiting ${delay}ms before retry ${attempt + 1}`);\n }\n\n await sleep(delay);\n continue;\n }\n\n // No more retries or not retryable - return error response\n return {\n status: classification.status,\n code: error.response?.status || null,\n error: classification.type,\n headers: error.response?.headers || null,\n data: error.response?.data || null,\n duration,\n retryCount: attempt - 1,\n finalUrl: url\n };\n }\n }\n\n // This should never be reached, but just in case\n return {\n status: 'unknown',\n code: null,\n error: 'unknown',\n headers: null,\n data: null,\n duration: Date.now() - startTime,\n retryCount: retryCount,\n finalUrl: url\n };\n }\n\n /**\n * GET request\n */\n async get(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('GET', url, options);\n }\n\n /**\n * POST request\n */\n async post(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('POST', url, options);\n }\n\n /**\n * PUT request\n */\n async put(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('PUT', url, options);\n }\n\n /**\n * DELETE request\n */\n async delete(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('DELETE', url, options);\n }\n\n /**\n * PATCH request\n */\n async patch(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('PATCH', url, options);\n }\n\n /**\n * HEAD request\n */\n async head(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('HEAD', url, options);\n }\n\n /**\n * OPTIONS request\n */\n async options(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('OPTIONS', url, options);\n }\n\n /**\n * Map HTTP status code to custom status\n */\n private mapHttpStatusToCustomStatus(httpStatus: number): HttpClientStatus {\n if (httpStatus >= 200 && httpStatus < 300) {\n return 'success';\n } else if (httpStatus === 401) {\n return 'authRequired';\n } else if (httpStatus === 403) {\n return 'authFailed';\n } else if (httpStatus >= 400 && httpStatus < 500) {\n return 'clientError';\n } else if (httpStatus >= 500) {\n return 'serverError';\n }\n return 'unknown';\n }\n\n /**\n * Get current configuration (for debugging)\n */\n getConfig(): Readonly<HttpClientConfig> {\n return { ...this.config };\n }\n}\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\nexport class HttpClientError extends FrameworkError {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = \"HttpClientError\";\n }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"FileDatabaseError\";\n }\n}\n\n","/**\n * HttpClient Error Classification\n *\n * Maps technical errors to human-readable, use-case oriented error types\n */\n\nimport type { HttpClientErrorType, HttpClientStatus, ErrorClassification } from './types.js';\n\n/**\n * Classify an error and determine retry behavior\n */\nexport function classifyError(error: any): ErrorClassification {\n // Handle axios response errors (HTTP errors)\n if (error.response) {\n const { status } = error.response;\n\n switch (status) {\n case 400:\n return { type: 'badRequest', retryable: false, isAuth: false, status: 'clientError' };\n case 401:\n return { type: 'unauthorized', retryable: false, isAuth: true, status: 'authRequired' };\n case 403:\n return { type: 'forbidden', retryable: false, isAuth: true, status: 'authFailed' };\n case 404:\n return { type: 'notFound', retryable: false, isAuth: false, status: 'clientError' };\n case 405:\n return { type: 'methodNotAllowed', retryable: false, isAuth: false, status: 'clientError' };\n case 409:\n return { type: 'conflict', retryable: false, isAuth: false, status: 'clientError' };\n case 422:\n return { type: 'unprocessableEntity', retryable: false, isAuth: false, status: 'clientError' };\n case 429:\n return { type: 'tooManyRequests', retryable: true, isAuth: false, status: 'clientError' };\n case 500:\n return { type: 'internalServerError', retryable: true, isAuth: false, status: 'serverError' };\n case 502:\n return { type: 'badGateway', retryable: true, isAuth: false, status: 'serverError' };\n case 503:\n return { type: 'serviceUnavailable', retryable: true, isAuth: false, status: 'serverError' };\n case 504:\n return { type: 'gatewayTimeout', retryable: true, isAuth: false, status: 'serverError' };\n default:\n if (status >= 400 && status < 500) {\n return { type: 'clientError' as HttpClientErrorType, retryable: false, isAuth: false, status: 'clientError' };\n } else if (status >= 500) {\n return { type: 'serverError' as HttpClientErrorType, retryable: true, isAuth: false, status: 'serverError' };\n }\n break;\n }\n }\n\n // Handle network/connection errors (no response)\n if (error.code) {\n switch (error.code) {\n case 'ECONNREFUSED':\n case 'ECONNRESET':\n case 'EPIPE':\n case 'ENOTFOUND':\n case 'EHOSTUNREACH':\n case 'ENETUNREACH':\n return { type: 'connectionFailed', retryable: true, isAuth: false, status: 'networkError' };\n\n case 'ETIMEDOUT':\n case 'ECONNABORTED':\n case 'ESOCKETTIMEDOUT':\n return { type: 'timeout', retryable: true, isAuth: false, status: 'timeout' };\n\n case 'EAUTH':\n case 'EACCES':\n return { type: 'unauthorized', retryable: false, isAuth: true, status: 'authRequired' };\n\n default:\n return { type: 'networkError', retryable: true, isAuth: false, status: 'networkError' };\n }\n }\n\n // Handle timeout errors\n if (error.message && (\n error.message.includes('timeout') ||\n error.message.includes('TIMEOUT') ||\n error.message.includes('aborted')\n )) {\n return { type: 'timeout', retryable: true, isAuth: false, status: 'timeout' };\n }\n\n // Handle cancellation\n if (error.name === 'AbortError' || error.message?.includes('cancelled')) {\n return { type: 'requestCancelled', retryable: false, isAuth: false, status: 'unknown' };\n }\n\n // Default fallback\n return { type: 'unknown', retryable: false, isAuth: false, status: 'unknown' };\n}\n\n/**\n * Get a human-readable description for an error type\n */\nexport function getErrorDescription(errorType: HttpClientErrorType): string {\n const descriptions: Record<HttpClientErrorType, string> = {\n connectionFailed: 'Failed to establish a connection to the server',\n timeout: 'Request timed out before completing',\n networkError: 'Network connection issue occurred',\n badRequest: 'Request was malformed or invalid',\n unauthorized: 'Authentication credentials are required',\n forbidden: 'Access to the requested resource is forbidden',\n notFound: 'The requested resource was not found',\n methodNotAllowed: 'HTTP method not allowed for this resource',\n conflict: 'Request conflicts with current server state',\n unprocessableEntity: 'Request data could not be processed',\n tooManyRequests: 'Too many requests sent in a short time',\n internalServerError: 'Server encountered an internal error',\n badGateway: 'Invalid response from upstream server',\n serviceUnavailable: 'Server is temporarily unavailable',\n gatewayTimeout: 'Upstream server timed out',\n unknown: 'An unknown error occurred',\n requestCancelled: 'Request was cancelled before completion'\n };\n\n return descriptions[errorType] || 'An unknown error occurred';\n}\n","/**\n * HttpClient Retry Logic\n *\n * Implements exponential backoff with jitter to prevent thundering herd problems\n */\n\nimport type { RetryContext } from './types.js';\n\n/**\n * Calculate the next retry delay using exponential backoff with jitter\n *\n * Formula: delay = baseDelay * (2 ^ (attempt - 1)) + randomJitter\n *\n * Jitter prevents the \"thundering herd\" problem where multiple failed requests\n * all retry at the exact same time, overwhelming the server.\n */\nexport function calculateRetryDelay(\n attempt: number,\n baseDelay: number,\n maxDelay: number,\n jitterFactor: number = 0.1\n): number {\n // Exponential backoff: baseDelay * (2 ^ (attempt - 1))\n const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);\n\n // Cap at maximum delay\n const cappedDelay = Math.min(exponentialDelay, maxDelay);\n\n // Add jitter: random variation up to jitterFactor of the delay\n const jitter = cappedDelay * jitterFactor * Math.random();\n\n return Math.floor(cappedDelay + jitter);\n}\n\n/**\n * Sleep for the specified number of milliseconds\n */\nexport function sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Determine if an error should be retried based on classification\n */\nexport function shouldRetryError(classification: { retryable: boolean; isAuth: boolean }): boolean {\n // Never retry auth errors (they won't succeed with the same credentials)\n if (classification.isAuth) {\n return false;\n }\n\n // Retry if the error is classified as retryable\n return classification.retryable;\n}\n\n/**\n * Create a retry context for tracking retry attempts\n */\nexport function createRetryContext(\n maxAttempts: number,\n baseDelay: number,\n maxDelay: number,\n jitterFactor: number\n): RetryContext {\n return {\n attempt: 1,\n maxAttempts,\n lastError: new Error('Initial attempt'),\n totalDelay: 0,\n nextDelay: calculateRetryDelay(1, baseDelay, maxDelay, jitterFactor)\n };\n}\n\n/**\n * Update retry context for the next attempt\n */\nexport function updateRetryContext(\n context: RetryContext,\n lastError: Error,\n baseDelay: number,\n maxDelay: number,\n jitterFactor: number\n): RetryContext {\n const nextAttempt = context.attempt + 1;\n const nextDelay = calculateRetryDelay(nextAttempt, baseDelay, maxDelay, jitterFactor);\n\n return {\n attempt: nextAttempt,\n maxAttempts: context.maxAttempts,\n lastError,\n totalDelay: context.totalDelay + context.nextDelay,\n nextDelay\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/http-client/index.js","../src/errors.js","../src/http-client/errors.js","../src/http-client/retry.js"],"sourcesContent":["/**\n * HttpClient - Resilient HTTP Client with Retry Logic\n *\n * A production-ready HTTP client that:\n * - Wraps axios with enhanced error handling and retry logic\n * - Never throws exceptions - always returns unified response format\n * - Uses exponential backoff with jitter for retries\n * - Provides human-readable error classifications\n * - Supports comprehensive logging\n * - Handles all HTTP methods consistently\n */\n\nimport axios, { } from \"axios\";\n\n\n\n\n\n\n\n\nimport { HttpClientError } from \"../errors.js\";\nimport { classifyError, getErrorDescription } from \"./errors.js\";\nimport { calculateRetryDelay, sleep, shouldRetryError, } from \"./retry.js\";\n\nexport { HttpClientError };\n\n/**\n * Resilient HTTP Client with automatic retry logic.\n * Use HttpClient.init(context, options) when running with init/context; constructor(config) for standalone.\n */\nexport class HttpClient {\n axiosInstance;\n config;\n logger;\n\n constructor(contextOrConfig = {}, config) {\n const hasContext = config !== undefined;\n const options = hasContext ? config : (contextOrConfig || {});\n const context = hasContext ? contextOrConfig : undefined;\n\n this.config = {\n ...options,\n logger: context?.logger ?? options.logger ?? console,\n };\n this.logger = this.config.logger;\n\n this.axiosInstance = axios.create({\n timeout: this.config.timeout,\n validateStatus: () => true,\n maxRedirects: this.config.maxRedirects,\n headers: { \"User-Agent\": this.config.userAgent },\n httpsAgent: this.config.validateSSL ? undefined : { rejectUnauthorized: false } ,\n });\n\n // Add response interceptor for logging (optional - only if debug enabled)\n this.axiosInstance.interceptors.response.use(\n (response) => response,\n (error) => {\n // Log network-level errors here if needed\n // (HTTP errors are handled in the request method)\n return Promise.reject(error);\n }\n );\n }\n\n /**\n * Static init - discovers params via getAllForModule(defs). Whatever is in options goes.\n */\n static init(context, options = {}) {\n const defs = {\n timeout: \"number default 30000\",\n retryCount: \"number default 3\",\n retryDelay: \"number default 1000\",\n maxRetryDelay: \"number default 30000\",\n retryJitter: \"number default 0.1\",\n userAgent: \"string default HttpClient/v1.0\",\n validateSSL: \"boolean default true\",\n maxRedirects: \"number default 5\",\n };\n const discovered = context?.params?.getAllForModule?.(defs) ?? {};\n const merged = { ...discovered, ...options, logger: options.logger ?? context?.logger };\n return new HttpClient(context, merged);\n }\n\n /**\n * Make an HTTP request with automatic retry logic\n * Never throws - always returns HttpClientResponse\n */\n async request(\n method,\n url,\n options = {}\n ) {\n const startTime = Date.now();\n\n // Merge request options with defaults\n const requestConfig = {\n method,\n url,\n timeout: options.timeout ?? this.config.timeout,\n headers: {\n \"User-Agent\": options.userAgent ?? this.config.userAgent,\n ...options.headers\n },\n params: options.params,\n data: options.data\n };\n\n const retryCount = options.retryCount ?? this.config.retryCount;\n const retryDelay = options.retryDelay ?? this.config.retryDelay;\n\n // Initialize retry context\n const _retryContext = null;\n let _lastError = null;\n\n // Attempt the request with retries\n for (let attempt = 1; attempt <= retryCount + 1; attempt++) {\n try {\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] ${method} ${url} (attempt ${attempt}/${retryCount + 1})`);\n }\n\n const response = await this.axiosInstance.request(requestConfig);\n const duration = Date.now() - startTime;\n\n // Success! Return unified response format\n const customStatus = this.mapHttpStatusToCustomStatus(response.status);\n\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] ${method} ${url} → ${response.status} ${customStatus} (${duration}ms)`);\n }\n\n return {\n status: customStatus,\n code: response.status,\n headers: response.headers ,\n data: response.data,\n duration,\n retryCount: attempt - 1,\n finalUrl: response.request?.res?.responseUrl || url\n };\n\n } catch (error) {\n _lastError = error;\n const duration = Date.now() - startTime;\n\n // Classify the error\n const classification = classifyError(error);\n const errorDescription = getErrorDescription(classification.type);\n\n // Log the error\n if (classification.retryable && attempt <= retryCount) {\n this.logger.warn?.(`[HttpClient] ${method} ${url} failed (${classification.type}): ${errorDescription}. Retrying in ${retryDelay}ms...`);\n } else if (!classification.retryable || attempt > retryCount) {\n this.logger.error?.(`[HttpClient] ${method} ${url} failed (${classification.type}): ${errorDescription}`);\n }\n\n // Check if we should retry\n if (attempt <= retryCount && shouldRetryError(classification)) {\n // Calculate delay and wait\n const delay = calculateRetryDelay(\n attempt,\n retryDelay,\n this.config.maxRetryDelay,\n this.config.retryJitter\n );\n\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] Waiting ${delay}ms before retry ${attempt + 1}`);\n }\n\n await sleep(delay);\n continue;\n }\n\n // No more retries or not retryable - return error response\n return {\n status: classification.status,\n code: error.response?.status || null,\n error: classification.type,\n headers: error.response?.headers || null,\n data: error.response?.data || null,\n duration,\n retryCount: attempt - 1,\n finalUrl: url\n };\n }\n }\n\n // This should never be reached, but just in case\n return {\n status: \"unknown\",\n code: null,\n error: \"unknown\",\n headers: null,\n data: null,\n duration: Date.now() - startTime,\n retryCount: retryCount,\n finalUrl: url\n };\n }\n\n /**\n * GET request\n */\n async get(url, options = {}) {\n return this.request(\"GET\", url, options);\n }\n\n /**\n * POST request\n */\n async post(url, options = {}) {\n return this.request(\"POST\", url, options);\n }\n\n /**\n * PUT request\n */\n async put(url, options = {}) {\n return this.request(\"PUT\", url, options);\n }\n\n /**\n * DELETE request\n */\n async delete(url, options = {}) {\n return this.request(\"DELETE\", url, options);\n }\n\n /**\n * PATCH request\n */\n async patch(url, options = {}) {\n return this.request(\"PATCH\", url, options);\n }\n\n /**\n * HEAD request\n */\n async head(url, options = {}) {\n return this.request(\"HEAD\", url, options);\n }\n\n /**\n * OPTIONS request\n */\n async options(url, options = {}) {\n return this.request(\"OPTIONS\", url, options);\n }\n\n /**\n * Map HTTP status code to custom status\n */\n mapHttpStatusToCustomStatus(httpStatus) {\n if (httpStatus >= 200 && httpStatus < 300) {\n return \"success\";\n } else if (httpStatus === 401) {\n return \"authRequired\";\n } else if (httpStatus === 403) {\n return \"authFailed\";\n } else if (httpStatus >= 400 && httpStatus < 500) {\n return \"clientError\";\n } else if (httpStatus >= 500) {\n return \"serverError\";\n }\n return \"unknown\";\n }\n\n /**\n * Get current configuration (for debugging)\n */\n getConfig() {\n return { ...this.config };\n }\n}\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n constructor(message) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\nexport class HttpClientError extends FrameworkError {\n constructor(message, cause) {\n super(message);this.cause = cause;;\n this.name = \"HttpClientError\";\n }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"FileDatabaseError\";\n }\n}\n\n","\n\n\n\n\n\n\n\n/**\n * Classify an error and determine retry behavior\n */\nexport function classifyError(error) {\n // Handle axios response errors (HTTP errors)\n if (error.response) {\n const { status } = error.response;\n\n switch (status) {\n case 400:\n return { type: \"badRequest\", retryable: false, isAuth: false, status: \"clientError\" };\n case 401:\n return { type: \"unauthorized\", retryable: false, isAuth: true, status: \"authRequired\" };\n case 403:\n return { type: \"forbidden\", retryable: false, isAuth: true, status: \"authFailed\" };\n case 404:\n return { type: \"notFound\", retryable: false, isAuth: false, status: \"clientError\" };\n case 405:\n return { type: \"methodNotAllowed\", retryable: false, isAuth: false, status: \"clientError\" };\n case 409:\n return { type: \"conflict\", retryable: false, isAuth: false, status: \"clientError\" };\n case 422:\n return { type: \"unprocessableEntity\", retryable: false, isAuth: false, status: \"clientError\" };\n case 429:\n return { type: \"tooManyRequests\", retryable: true, isAuth: false, status: \"clientError\" };\n case 500:\n return { type: \"internalServerError\", retryable: true, isAuth: false, status: \"serverError\" };\n case 502:\n return { type: \"badGateway\", retryable: true, isAuth: false, status: \"serverError\" };\n case 503:\n return { type: \"serviceUnavailable\", retryable: true, isAuth: false, status: \"serverError\" };\n case 504:\n return { type: \"gatewayTimeout\", retryable: true, isAuth: false, status: \"serverError\" };\n default:\n if (status >= 400 && status < 500) {\n return { type: \"clientError\" , retryable: false, isAuth: false, status: \"clientError\" };\n } else if (status >= 500) {\n return { type: \"serverError\" , retryable: true, isAuth: false, status: \"serverError\" };\n }\n break;\n }\n }\n\n // Handle network/connection errors (no response)\n if (error.code) {\n switch (error.code) {\n case \"ECONNREFUSED\":\n case \"ECONNRESET\":\n case \"EPIPE\":\n case \"ENOTFOUND\":\n case \"EHOSTUNREACH\":\n case \"ENETUNREACH\":\n return { type: \"connectionFailed\", retryable: true, isAuth: false, status: \"networkError\" };\n\n case \"ETIMEDOUT\":\n case \"ECONNABORTED\":\n case \"ESOCKETTIMEDOUT\":\n return { type: \"timeout\", retryable: true, isAuth: false, status: \"timeout\" };\n\n case \"EAUTH\":\n case \"EACCES\":\n return { type: \"unauthorized\", retryable: false, isAuth: true, status: \"authRequired\" };\n\n default:\n return { type: \"networkError\", retryable: true, isAuth: false, status: \"networkError\" };\n }\n }\n\n // Handle timeout errors\n if (error.message && (\n error.message.includes(\"timeout\") ||\n error.message.includes(\"TIMEOUT\") ||\n error.message.includes(\"aborted\")\n )) {\n return { type: \"timeout\", retryable: true, isAuth: false, status: \"timeout\" };\n }\n\n // Handle cancellation\n if (error.name === \"AbortError\" || error.message?.includes(\"cancelled\")) {\n return { type: \"requestCancelled\", retryable: false, isAuth: false, status: \"unknown\" };\n }\n\n // Default fallback\n return { type: \"unknown\", retryable: false, isAuth: false, status: \"unknown\" };\n}\n\n/**\n * Get a human-readable description for an error type\n */\nexport function getErrorDescription(errorType) {\n const descriptions = {\n connectionFailed: \"Failed to establish a connection to the server\",\n timeout: \"Request timed out before completing\",\n networkError: \"Network connection issue occurred\",\n badRequest: \"Request was malformed or invalid\",\n unauthorized: \"Authentication credentials are required\",\n forbidden: \"Access to the requested resource is forbidden\",\n notFound: \"The requested resource was not found\",\n methodNotAllowed: \"HTTP method not allowed for this resource\",\n conflict: \"Request conflicts with current server state\",\n unprocessableEntity: \"Request data could not be processed\",\n tooManyRequests: \"Too many requests sent in a short time\",\n internalServerError: \"Server encountered an internal error\",\n badGateway: \"Invalid response from upstream server\",\n serviceUnavailable: \"Server is temporarily unavailable\",\n gatewayTimeout: \"Upstream server timed out\",\n unknown: \"An unknown error occurred\",\n requestCancelled: \"Request was cancelled before completion\"\n };\n\n return descriptions[errorType] || \"An unknown error occurred\";\n}\n","\n\n\n\n\n\n\n\n/**\n * Calculate the next retry delay using exponential backoff with jitter\n *\n * Formula: delay = baseDelay * (2 ^ (attempt - 1)) + randomJitter\n *\n * Jitter prevents the \"thundering herd\" problem where multiple failed requests\n * all retry at the exact same time, overwhelming the server.\n */\nexport function calculateRetryDelay(\n attempt,\n baseDelay,\n maxDelay,\n jitterFactor = 0.1\n) {\n // Exponential backoff: baseDelay * (2 ^ (attempt - 1))\n const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);\n\n // Cap at maximum delay\n const cappedDelay = Math.min(exponentialDelay, maxDelay);\n\n // Add jitter: random variation up to jitterFactor of the delay\n const jitter = cappedDelay * jitterFactor * Math.random();\n\n return Math.floor(cappedDelay + jitter);\n}\n\n/**\n * Sleep for the specified number of milliseconds\n */\nexport function sleep(ms) {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Determine if an error should be retried based on classification\n */\nexport function shouldRetryError(classification) {\n // Never retry auth errors (they won't succeed with the same credentials)\n if (classification.isAuth) {\n return false;\n }\n\n // Retry if the error is classified as retryable\n return classification.retryable;\n}\n\n/**\n * Create a retry context for tracking retry attempts\n */\nexport function createRetryContext(\n maxAttempts,\n baseDelay,\n maxDelay,\n jitterFactor\n) {\n return {\n attempt: 1,\n maxAttempts,\n lastError: new Error(\"Initial attempt\"),\n totalDelay: 0,\n nextDelay: calculateRetryDelay(1, baseDelay, maxDelay, jitterFactor)\n };\n}\n\n/**\n * Update retry context for the next attempt\n */\nexport function updateRetryContext(\n context,\n lastError,\n baseDelay,\n maxDelay,\n jitterFactor\n) {\n const nextAttempt = context.attempt + 1;\n const nextDelay = calculateRetryDelay(nextAttempt, baseDelay, maxDelay, jitterFactor);\n\n return {\n attempt: nextAttempt,\n maxAttempts: context.maxAttempts,\n lastError,\n totalDelay: context.totalDelay + context.nextDelay,\n nextDelay\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/http-client2.cjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -27,18 +26,16 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
26
|
));
|
|
28
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
28
|
|
|
30
|
-
// src/http-client2.
|
|
29
|
+
// src/http-client2/index.js
|
|
31
30
|
var http_client2_exports = {};
|
|
32
31
|
__export(http_client2_exports, {
|
|
33
32
|
HttpClient: () => HttpClient,
|
|
34
33
|
HttpClientError: () => HttpClientError
|
|
35
34
|
});
|
|
36
35
|
module.exports = __toCommonJS(http_client2_exports);
|
|
37
|
-
|
|
38
|
-
// src/http-client2/index.ts
|
|
39
36
|
var import_path4 = __toESM(require("path"), 1);
|
|
40
37
|
|
|
41
|
-
// src/errors.
|
|
38
|
+
// src/errors.js
|
|
42
39
|
var FrameworkError = class extends Error {
|
|
43
40
|
constructor(message) {
|
|
44
41
|
super(message);
|
|
@@ -55,6 +52,7 @@ var HttpClientError = class extends FrameworkError {
|
|
|
55
52
|
constructor(message, cause) {
|
|
56
53
|
super(message);
|
|
57
54
|
this.cause = cause;
|
|
55
|
+
;
|
|
58
56
|
this.name = "HttpClientError";
|
|
59
57
|
}
|
|
60
58
|
};
|
|
@@ -65,7 +63,7 @@ var FileDatabaseError = class extends FrameworkError {
|
|
|
65
63
|
}
|
|
66
64
|
};
|
|
67
65
|
|
|
68
|
-
// src/http-client2/errors.
|
|
66
|
+
// src/http-client2/errors.js
|
|
69
67
|
function classifyError(error) {
|
|
70
68
|
if (error.response) {
|
|
71
69
|
const { status } = error.response;
|
|
@@ -150,7 +148,7 @@ function getErrorDescription(errorType) {
|
|
|
150
148
|
return descriptions[errorType] || "An unknown error occurred";
|
|
151
149
|
}
|
|
152
150
|
|
|
153
|
-
// src/http-client2/retry.
|
|
151
|
+
// src/http-client2/retry.js
|
|
154
152
|
function calculateRetryDelay(attempt, baseDelay, maxDelay, jitterFactor = 0.1) {
|
|
155
153
|
const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);
|
|
156
154
|
const cappedDelay = Math.min(exponentialDelay, maxDelay);
|
|
@@ -165,11 +163,11 @@ function shouldRetryError(classification) {
|
|
|
165
163
|
return classification.retryable;
|
|
166
164
|
}
|
|
167
165
|
|
|
168
|
-
// src/filedatabase/index.
|
|
166
|
+
// src/filedatabase/index.js
|
|
169
167
|
var import_fs3 = __toESM(require("fs"), 1);
|
|
170
168
|
var import_path3 = __toESM(require("path"), 1);
|
|
171
169
|
|
|
172
|
-
// src/utils/os-utils.
|
|
170
|
+
// src/utils/os-utils.js
|
|
173
171
|
var import_fs = __toESM(require("fs"), 1);
|
|
174
172
|
var import_path = __toESM(require("path"), 1);
|
|
175
173
|
var import_child_process = require("child_process");
|
|
@@ -198,7 +196,7 @@ function getFreeDiskSpace(targetPath) {
|
|
|
198
196
|
}
|
|
199
197
|
}
|
|
200
198
|
|
|
201
|
-
// src/utils/fs-utils.
|
|
199
|
+
// src/utils/fs-utils.js
|
|
202
200
|
var import_fs2 = __toESM(require("fs"), 1);
|
|
203
201
|
var import_path2 = __toESM(require("path"), 1);
|
|
204
202
|
async function ensurePath(...pathParts) {
|
|
@@ -222,7 +220,7 @@ function getFileExtension(dataType) {
|
|
|
222
220
|
}
|
|
223
221
|
}
|
|
224
222
|
|
|
225
|
-
// src/utils/format-utils.
|
|
223
|
+
// src/utils/format-utils.js
|
|
226
224
|
function bytesToHumanReadable(bytes) {
|
|
227
225
|
if (bytes === 0) return "0 B";
|
|
228
226
|
const k = 1024;
|
|
@@ -231,7 +229,7 @@ function bytesToHumanReadable(bytes) {
|
|
|
231
229
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
232
230
|
}
|
|
233
231
|
|
|
234
|
-
// src/utils/date-utils.
|
|
232
|
+
// src/utils/date-utils.js
|
|
235
233
|
function isTimestampFolder(folderName) {
|
|
236
234
|
const isoRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(Z|\.\d{3}Z)$/;
|
|
237
235
|
if (!isoRegex.test(folderName)) {
|
|
@@ -241,7 +239,7 @@ function isTimestampFolder(folderName) {
|
|
|
241
239
|
return !isNaN(date.getTime()) && date.getTime() > 0;
|
|
242
240
|
}
|
|
243
241
|
|
|
244
|
-
// src/filedatabase/serializers.
|
|
242
|
+
// src/filedatabase/serializers.js
|
|
245
243
|
function detectDataType(data) {
|
|
246
244
|
if (Array.isArray(data)) {
|
|
247
245
|
return "json-array";
|
|
@@ -273,7 +271,7 @@ function deserializeData(rawData, dataType) {
|
|
|
273
271
|
}
|
|
274
272
|
}
|
|
275
273
|
|
|
276
|
-
// src/filedatabase/index.
|
|
274
|
+
// src/filedatabase/index.js
|
|
277
275
|
var FileDatabase = class _FileDatabase {
|
|
278
276
|
basePath;
|
|
279
277
|
namespace;
|
|
@@ -359,7 +357,7 @@ var FileDatabase = class _FileDatabase {
|
|
|
359
357
|
if (errors.length) {
|
|
360
358
|
throw new FileDatabaseError(`[FileDatabase] ${errors.join("; ")}`);
|
|
361
359
|
}
|
|
362
|
-
|
|
360
|
+
const parts = [this.basePath, this.namespace];
|
|
363
361
|
if (this.tableName) {
|
|
364
362
|
parts.push(...this.tableName.split("/"));
|
|
365
363
|
}
|
|
@@ -852,14 +850,17 @@ var FileDatabase = class _FileDatabase {
|
|
|
852
850
|
* Prepare the instance for read or write operations
|
|
853
851
|
* This discovers state and sets up internal members based on mode and current data
|
|
854
852
|
*/
|
|
855
|
-
async prepare(
|
|
853
|
+
async prepare(options) {
|
|
854
|
+
const { write, read, version, deferInitialVersion } = options;
|
|
856
855
|
if (write) {
|
|
857
856
|
if (this.versioned) {
|
|
858
857
|
if (this.currentVersion === null) {
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
858
|
+
if (!deferInitialVersion) {
|
|
859
|
+
await this.makeNewVersion();
|
|
860
|
+
this.metadata = this.getDefaultMetadata();
|
|
861
|
+
this.metadata.version = this.currentVersion;
|
|
862
|
+
this.makeNewFile();
|
|
863
|
+
}
|
|
863
864
|
} else {
|
|
864
865
|
if (!this.metadata.files.length) {
|
|
865
866
|
this.metadata = await this.figureMetadata(this.currentVersion);
|
|
@@ -969,7 +970,7 @@ var FileDatabase = class _FileDatabase {
|
|
|
969
970
|
if (options.forceNewVersion && !this.versioned) {
|
|
970
971
|
throw new FileDatabaseError("Cannot use forceNewVersion in non-versioned mode");
|
|
971
972
|
}
|
|
972
|
-
await this.prepare({ write: true });
|
|
973
|
+
await this.prepare({ write: true, deferInitialVersion: !!(options.forceNewVersion && this.versioned) });
|
|
973
974
|
const incomingDataType = detectDataType(data);
|
|
974
975
|
this.metadata.dataType = incomingDataType;
|
|
975
976
|
if (options.forceNewVersion) {
|
|
@@ -1263,7 +1264,7 @@ var FileDatabase = class _FileDatabase {
|
|
|
1263
1264
|
}
|
|
1264
1265
|
};
|
|
1265
1266
|
|
|
1266
|
-
// src/mock-server/mock-storage.
|
|
1267
|
+
// src/mock-server/mock-storage.js
|
|
1267
1268
|
function stableStringify(obj) {
|
|
1268
1269
|
if (obj === null) return "null";
|
|
1269
1270
|
if (obj === void 0) return "undefined";
|
|
@@ -1360,7 +1361,7 @@ var MockStorage = class {
|
|
|
1360
1361
|
}
|
|
1361
1362
|
};
|
|
1362
1363
|
|
|
1363
|
-
// src/http-client2/index.
|
|
1364
|
+
// src/http-client2/index.js
|
|
1364
1365
|
function buildUrl(baseURL, url, params) {
|
|
1365
1366
|
let full = url;
|
|
1366
1367
|
if (baseURL) {
|
|
@@ -1458,7 +1459,8 @@ var HttpClient = class _HttpClient {
|
|
|
1458
1459
|
}
|
|
1459
1460
|
}
|
|
1460
1461
|
/**
|
|
1461
|
-
* Static init - discovers params via context.params.getAllForModule("http-client2", defs).
|
|
1462
|
+
* Static init - discovers params via context.params.getAllForModule("http-client2", defs).
|
|
1463
|
+
* Whatever is in options wins. Params are grouped under `http-client2` for --showUsedParams.
|
|
1462
1464
|
*/
|
|
1463
1465
|
static init(context, options = {}) {
|
|
1464
1466
|
const defs = {
|
|
@@ -1481,7 +1483,7 @@ var HttpClient = class _HttpClient {
|
|
|
1481
1483
|
showMaxArrayItems: "number default 5",
|
|
1482
1484
|
showMaxChars: "number default 300"
|
|
1483
1485
|
};
|
|
1484
|
-
const discovered = context?.params?.getAllForModule?.(defs) ?? {};
|
|
1486
|
+
const discovered = context?.params?.getAllForModule?.("http-client2", defs) ?? {};
|
|
1485
1487
|
const merged = { ...discovered, ...options };
|
|
1486
1488
|
if ((merged.saveMock || merged.useMock) && !merged.mocksPath) {
|
|
1487
1489
|
throw new ParamError("[http-client2] mocksPath is required when saveMock or useMock is set");
|
|
@@ -1496,7 +1498,7 @@ var HttpClient = class _HttpClient {
|
|
|
1496
1498
|
const timeout = options.timeout ?? this.config.timeout;
|
|
1497
1499
|
const retryCount = options.retryCount ?? this.config.retryCount ?? 3;
|
|
1498
1500
|
const retryDelay = options.retryDelay ?? this.config.retryDelay ?? 1e3;
|
|
1499
|
-
|
|
1501
|
+
const fullUrl = buildUrl(this.config.baseURL, url, options.params);
|
|
1500
1502
|
if (this.config.useMock && this.mockStorage) {
|
|
1501
1503
|
try {
|
|
1502
1504
|
const urlObj = new URL(fullUrl);
|
|
@@ -1677,21 +1679,20 @@ var HttpClient = class _HttpClient {
|
|
|
1677
1679
|
const maxKeys = this.config.showMaxKeys ?? 20;
|
|
1678
1680
|
const maxArray = this.config.showMaxArrayItems ?? 5;
|
|
1679
1681
|
const maxChars = this.config.showMaxChars ?? 300;
|
|
1680
|
-
|
|
1681
|
-
log(`[HttpClient] ${method} ${url}`);
|
|
1682
|
+
this.logger.info(`[HttpClient] ${method} ${url}`);
|
|
1682
1683
|
if (this.config.showRequestHeaders && reqHeaders && Object.keys(reqHeaders).length > 0) {
|
|
1683
|
-
|
|
1684
|
+
this.logger.info(` Request headers: ${formatForDisplay(reqHeaders, maxKeys, maxArray, maxChars)}`);
|
|
1684
1685
|
}
|
|
1685
1686
|
if (options.data != null) {
|
|
1686
|
-
|
|
1687
|
+
this.logger.info(` Request body: ${formatForDisplay(options.data, maxKeys, maxArray, maxChars)}`);
|
|
1687
1688
|
}
|
|
1688
1689
|
if (res) {
|
|
1689
|
-
|
|
1690
|
+
this.logger.info(` \u2192 ${res.status}${fromMock ? " (from mock)" : ""} ${durationMs}ms`);
|
|
1690
1691
|
if (this.config.showResponseHeaders && res.headers && Object.keys(res.headers).length > 0) {
|
|
1691
|
-
|
|
1692
|
+
this.logger.info(` Response headers: ${formatForDisplay(res.headers, maxKeys, maxArray, maxChars)}`);
|
|
1692
1693
|
}
|
|
1693
1694
|
if (res.data != null) {
|
|
1694
|
-
|
|
1695
|
+
this.logger.info(` Response body: ${formatForDisplay(res.data, maxKeys, maxArray, maxChars)}`);
|
|
1695
1696
|
}
|
|
1696
1697
|
}
|
|
1697
1698
|
}
|