@nmakarov/cli-toolkit 0.14.2 → 0.16.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.
Files changed (45) hide show
  1. package/dist/args.cjs +49 -9
  2. package/dist/args.cjs.map +1 -1
  3. package/dist/args.js +49 -9
  4. package/dist/args.js.map +1 -1
  5. package/dist/db.cjs +9 -2
  6. package/dist/db.cjs.map +1 -1
  7. package/dist/db.js +9 -2
  8. package/dist/db.js.map +1 -1
  9. package/dist/errors.cjs +17 -0
  10. package/dist/errors.cjs.map +1 -1
  11. package/dist/errors.js +15 -0
  12. package/dist/errors.js.map +1 -1
  13. package/dist/filedatabase.cjs +16 -24
  14. package/dist/filedatabase.cjs.map +1 -1
  15. package/dist/filedatabase.js +16 -23
  16. package/dist/filedatabase.js.map +1 -1
  17. package/dist/http-client.cjs +44 -34
  18. package/dist/http-client.cjs.map +1 -1
  19. package/dist/http-client.js +44 -34
  20. package/dist/http-client.js.map +1 -1
  21. package/dist/http-client2.cjs +368 -0
  22. package/dist/http-client2.cjs.map +1 -0
  23. package/dist/http-client2.js +340 -0
  24. package/dist/http-client2.js.map +1 -0
  25. package/dist/index.cjs +212 -91
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.js +212 -90
  28. package/dist/index.js.map +1 -1
  29. package/dist/init.cjs +190 -76
  30. package/dist/init.cjs.map +1 -1
  31. package/dist/init.js +190 -76
  32. package/dist/init.js.map +1 -1
  33. package/dist/logger.cjs +19 -36
  34. package/dist/logger.cjs.map +1 -1
  35. package/dist/logger.js +19 -36
  36. package/dist/logger.js.map +1 -1
  37. package/dist/mock-server.cjs +13 -16
  38. package/dist/mock-server.cjs.map +1 -1
  39. package/dist/mock-server.js +13 -16
  40. package/dist/mock-server.js.map +1 -1
  41. package/dist/params.cjs +114 -15
  42. package/dist/params.cjs.map +1 -1
  43. package/dist/params.js +114 -15
  44. package/dist/params.js.map +1 -1
  45. package/package.json +9 -2
@@ -0,0 +1,340 @@
1
+ // src/errors.ts
2
+ var FrameworkError = class extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "FrameworkError";
6
+ }
7
+ };
8
+ var HttpClientError = class extends FrameworkError {
9
+ constructor(message, cause) {
10
+ super(message);
11
+ this.cause = cause;
12
+ this.name = "HttpClientError";
13
+ }
14
+ };
15
+
16
+ // src/http-client2/errors.ts
17
+ function classifyError(error) {
18
+ if (error.response) {
19
+ const { status } = error.response;
20
+ switch (status) {
21
+ case 400:
22
+ return { type: "badRequest", retryable: false, isAuth: false, status: "clientError" };
23
+ case 401:
24
+ return { type: "unauthorized", retryable: false, isAuth: true, status: "authRequired" };
25
+ case 403:
26
+ return { type: "forbidden", retryable: false, isAuth: true, status: "authFailed" };
27
+ case 404:
28
+ return { type: "notFound", retryable: false, isAuth: false, status: "clientError" };
29
+ case 405:
30
+ return { type: "methodNotAllowed", retryable: false, isAuth: false, status: "clientError" };
31
+ case 409:
32
+ return { type: "conflict", retryable: false, isAuth: false, status: "clientError" };
33
+ case 422:
34
+ return { type: "unprocessableEntity", retryable: false, isAuth: false, status: "clientError" };
35
+ case 429:
36
+ return { type: "tooManyRequests", retryable: true, isAuth: false, status: "clientError" };
37
+ case 500:
38
+ return { type: "internalServerError", retryable: true, isAuth: false, status: "serverError" };
39
+ case 502:
40
+ return { type: "badGateway", retryable: true, isAuth: false, status: "serverError" };
41
+ case 503:
42
+ return { type: "serviceUnavailable", retryable: true, isAuth: false, status: "serverError" };
43
+ case 504:
44
+ return { type: "gatewayTimeout", retryable: true, isAuth: false, status: "serverError" };
45
+ default:
46
+ if (status >= 400 && status < 500) return { type: "clientError", retryable: false, isAuth: false, status: "clientError" };
47
+ if (status >= 500) return { type: "serverError", retryable: true, isAuth: false, status: "serverError" };
48
+ }
49
+ }
50
+ if (error.name === "AbortError" || error.code === 20 || error.code === "ABORT_ERR") {
51
+ return error.isTimeout === true ? { type: "timeout", retryable: true, isAuth: false, status: "timeout" } : { type: "requestCancelled", retryable: false, isAuth: false, status: "unknown" };
52
+ }
53
+ if (error.code) {
54
+ switch (error.code) {
55
+ case "ECONNREFUSED":
56
+ case "ECONNRESET":
57
+ case "EPIPE":
58
+ case "ENOTFOUND":
59
+ case "EHOSTUNREACH":
60
+ case "ENETUNREACH":
61
+ return { type: "connectionFailed", retryable: true, isAuth: false, status: "networkError" };
62
+ case "ETIMEDOUT":
63
+ case "ECONNABORTED":
64
+ case "ESOCKETTIMEDOUT":
65
+ return { type: "timeout", retryable: true, isAuth: false, status: "timeout" };
66
+ case "EAUTH":
67
+ case "EACCES":
68
+ return { type: "unauthorized", retryable: false, isAuth: true, status: "authRequired" };
69
+ default:
70
+ return { type: "networkError", retryable: true, isAuth: false, status: "networkError" };
71
+ }
72
+ }
73
+ if (error.message && /timeout|TIMEOUT|aborted/i.test(String(error.message))) {
74
+ return { type: "timeout", retryable: true, isAuth: false, status: "timeout" };
75
+ }
76
+ return { type: "unknown", retryable: false, isAuth: false, status: "unknown" };
77
+ }
78
+ function getErrorDescription(errorType) {
79
+ const descriptions = {
80
+ connectionFailed: "Failed to establish a connection to the server",
81
+ timeout: "Request timed out before completing",
82
+ networkError: "Network connection issue occurred",
83
+ badRequest: "Request was malformed or invalid",
84
+ unauthorized: "Authentication credentials are required",
85
+ forbidden: "Access to the requested resource is forbidden",
86
+ notFound: "The requested resource was not found",
87
+ methodNotAllowed: "HTTP method not allowed for this resource",
88
+ conflict: "Request conflicts with current server state",
89
+ unprocessableEntity: "Request data could not be processed",
90
+ tooManyRequests: "Too many requests sent in a short time",
91
+ internalServerError: "Server encountered an internal error",
92
+ badGateway: "Invalid response from upstream server",
93
+ serviceUnavailable: "Server is temporarily unavailable",
94
+ gatewayTimeout: "Upstream server timed out",
95
+ unknown: "An unknown error occurred",
96
+ requestCancelled: "Request was cancelled before completion"
97
+ };
98
+ return descriptions[errorType] || "An unknown error occurred";
99
+ }
100
+
101
+ // src/http-client2/retry.ts
102
+ function calculateRetryDelay(attempt, baseDelay, maxDelay, jitterFactor = 0.1) {
103
+ const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);
104
+ const cappedDelay = Math.min(exponentialDelay, maxDelay);
105
+ const jitter = cappedDelay * jitterFactor * Math.random();
106
+ return Math.floor(cappedDelay + jitter);
107
+ }
108
+ function sleep(ms) {
109
+ return new Promise((resolve) => setTimeout(resolve, ms));
110
+ }
111
+ function shouldRetryError(classification) {
112
+ if (classification.isAuth) return false;
113
+ return classification.retryable;
114
+ }
115
+
116
+ // src/http-client2/index.ts
117
+ function buildUrl(baseURL, url, params) {
118
+ let full = url;
119
+ if (baseURL) {
120
+ try {
121
+ full = new URL(url, baseURL).href;
122
+ } catch {
123
+ full = baseURL.replace(/\/$/, "") + (url.startsWith("/") ? url : "/" + url);
124
+ }
125
+ }
126
+ if (params && Object.keys(params).length > 0) {
127
+ const u = new URL(full);
128
+ for (const [k, v] of Object.entries(params)) {
129
+ if (v != null && v !== "") u.searchParams.set(k, String(v));
130
+ }
131
+ full = u.href;
132
+ }
133
+ return full;
134
+ }
135
+ function headersToRecord(h) {
136
+ const r = {};
137
+ h.forEach((v, k) => {
138
+ r[k.toLowerCase()] = v;
139
+ });
140
+ return r;
141
+ }
142
+ async function parseBody(response) {
143
+ const text = await response.text();
144
+ if (!text) return null;
145
+ const ct = (response.headers.get("content-type") || "").toLowerCase();
146
+ if (ct.includes("application/json")) {
147
+ try {
148
+ return JSON.parse(text);
149
+ } catch {
150
+ return text;
151
+ }
152
+ }
153
+ try {
154
+ const parsed = JSON.parse(text);
155
+ if (typeof parsed === "object" && parsed !== null) return parsed;
156
+ } catch {
157
+ }
158
+ return text;
159
+ }
160
+ function mapStatusToCustom(httpStatus) {
161
+ if (httpStatus >= 200 && httpStatus < 300) return "success";
162
+ if (httpStatus === 401) return "authRequired";
163
+ if (httpStatus === 403) return "authFailed";
164
+ if (httpStatus >= 400 && httpStatus < 500) return "clientError";
165
+ if (httpStatus >= 500) return "serverError";
166
+ return "unknown";
167
+ }
168
+ var HttpClient = class _HttpClient {
169
+ context;
170
+ config;
171
+ logger;
172
+ constructor(context, options = {}) {
173
+ this.context = context;
174
+ this.config = options;
175
+ this.logger = options.logger ?? context?.logger ?? console;
176
+ }
177
+ /**
178
+ * Static init - discovers params via context.params.getAllForModule("http-client2", defs). Whatever is in options goes.
179
+ */
180
+ static init(context, options = {}) {
181
+ const defs = {
182
+ timeout: "number default 30000",
183
+ retryCount: "number default 3",
184
+ retryDelay: "number default 1000",
185
+ maxRetryDelay: "number default 30000",
186
+ retryJitter: "number default 0.1",
187
+ userAgent: "string default HttpClient/v1.0",
188
+ baseURL: "string"
189
+ };
190
+ const discovered = context?.params?.getAllForModule?.(defs) ?? {};
191
+ const merged = { ...discovered, ...options };
192
+ return new _HttpClient(context, merged);
193
+ }
194
+ async request(method, url, options = {}) {
195
+ const startTime = Date.now();
196
+ const timeout = options.timeout ?? this.config.timeout;
197
+ const retryCount = options.retryCount ?? this.config.retryCount;
198
+ const retryDelay = options.retryDelay ?? this.config.retryDelay;
199
+ const fullUrl = buildUrl(this.config.baseURL, url, options.params);
200
+ const headers = {
201
+ "User-Agent": options.userAgent ?? this.config.userAgent,
202
+ ...options.headers
203
+ };
204
+ let body;
205
+ if (options.data != null && ["POST", "PUT", "PATCH"].includes(method)) {
206
+ body = typeof options.data === "string" ? options.data : JSON.stringify(options.data);
207
+ if (!headers["content-type"]) headers["Content-Type"] = "application/json";
208
+ }
209
+ let lastError = null;
210
+ for (let attempt = 1; attempt <= retryCount + 1; attempt++) {
211
+ let abortedByTimeout = false;
212
+ try {
213
+ if (options.debug) {
214
+ this.logger.debug?.(`[HttpClient] ${method} ${fullUrl} (attempt ${attempt}/${retryCount + 1})`);
215
+ }
216
+ const controller = new AbortController();
217
+ const timeoutId = setTimeout(() => {
218
+ abortedByTimeout = true;
219
+ controller.abort();
220
+ }, timeout);
221
+ const response = await fetch(fullUrl, {
222
+ method,
223
+ headers,
224
+ body: method !== "GET" && method !== "HEAD" ? body : void 0,
225
+ signal: controller.signal,
226
+ redirect: "follow"
227
+ });
228
+ clearTimeout(timeoutId);
229
+ const duration = Date.now() - startTime;
230
+ const resHeaders = headersToRecord(response.headers);
231
+ if (response.ok) {
232
+ const data2 = await parseBody(response);
233
+ if (options.debug) {
234
+ this.logger.debug?.(`[HttpClient] ${method} ${fullUrl} \u2192 ${response.status} success (${duration}ms)`);
235
+ }
236
+ return {
237
+ status: mapStatusToCustom(response.status),
238
+ code: response.status,
239
+ headers: resHeaders,
240
+ data: data2,
241
+ duration,
242
+ retryCount: attempt - 1,
243
+ finalUrl: response.url || fullUrl
244
+ };
245
+ }
246
+ const data = await parseBody(response);
247
+ const classification2 = classifyError({ response: { status: response.status, headers: resHeaders, data } });
248
+ if (options.debug) {
249
+ this.logger.debug?.(`[HttpClient] ${method} ${fullUrl} \u2192 ${response.status} ${classification2.status} (${duration}ms)`);
250
+ }
251
+ if (attempt <= retryCount && shouldRetryError(classification2)) {
252
+ const delay = calculateRetryDelay(attempt, retryDelay, this.config.maxRetryDelay, this.config.retryJitter);
253
+ this.logger.warn?.(`[HttpClient] ${method} ${fullUrl} failed (${classification2.type}). Retrying in ${delay}ms...`);
254
+ if (options.debug) this.logger.debug?.(`[HttpClient] Waiting ${delay}ms before retry ${attempt + 1}`);
255
+ await sleep(delay);
256
+ continue;
257
+ }
258
+ return {
259
+ status: classification2.status,
260
+ code: response.status,
261
+ error: classification2.type,
262
+ headers: resHeaders,
263
+ data,
264
+ duration,
265
+ retryCount: attempt - 1,
266
+ finalUrl: response.url || fullUrl
267
+ };
268
+ } catch (error) {
269
+ if (abortedByTimeout) {
270
+ lastError = { ...error || {}, name: "AbortError", isTimeout: true };
271
+ } else {
272
+ lastError = error;
273
+ }
274
+ const duration = Date.now() - startTime;
275
+ const classification2 = classifyError(lastError);
276
+ if (classification2.retryable && attempt <= retryCount) {
277
+ this.logger.warn?.(`[HttpClient] ${method} ${fullUrl} failed (${classification2.type}): ${getErrorDescription(classification2.type)}. Retrying...`);
278
+ } else {
279
+ this.logger.error?.(`[HttpClient] ${method} ${fullUrl} failed (${classification2.type}): ${getErrorDescription(classification2.type)}`);
280
+ }
281
+ if (attempt <= retryCount && shouldRetryError(classification2)) {
282
+ const delay = calculateRetryDelay(attempt, retryDelay, this.config.maxRetryDelay, this.config.retryJitter);
283
+ if (options.debug) this.logger.debug?.(`[HttpClient] Waiting ${delay}ms before retry ${attempt + 1}`);
284
+ await sleep(delay);
285
+ continue;
286
+ }
287
+ return {
288
+ status: classification2.status,
289
+ code: null,
290
+ error: classification2.type,
291
+ headers: null,
292
+ data: null,
293
+ duration,
294
+ retryCount: attempt - 1,
295
+ finalUrl: fullUrl
296
+ };
297
+ }
298
+ }
299
+ const classification = lastError ? classifyError(lastError) : { status: "unknown", type: "unknown" };
300
+ return {
301
+ status: classification.status,
302
+ code: null,
303
+ error: classification.type,
304
+ headers: null,
305
+ data: null,
306
+ duration: Date.now() - startTime,
307
+ retryCount,
308
+ finalUrl: fullUrl
309
+ };
310
+ }
311
+ async get(url, options = {}) {
312
+ return this.request("GET", url, options);
313
+ }
314
+ async post(url, options = {}) {
315
+ return this.request("POST", url, options);
316
+ }
317
+ async put(url, options = {}) {
318
+ return this.request("PUT", url, options);
319
+ }
320
+ async delete(url, options = {}) {
321
+ return this.request("DELETE", url, options);
322
+ }
323
+ async patch(url, options = {}) {
324
+ return this.request("PATCH", url, options);
325
+ }
326
+ async head(url, options = {}) {
327
+ return this.request("HEAD", url, options);
328
+ }
329
+ async options(url, options = {}) {
330
+ return this.request("OPTIONS", url, options);
331
+ }
332
+ getConfig() {
333
+ return { ...this.config };
334
+ }
335
+ };
336
+ export {
337
+ HttpClient,
338
+ HttpClientError
339
+ };
340
+ //# sourceMappingURL=http-client2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/http-client2/errors.ts","../src/http-client2/retry.ts","../src/http-client2/index.ts"],"sourcesContent":["/**\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 (http-client2 - same as http-client)\n */\n\nimport type { HttpClientErrorType, HttpClientStatus, ErrorClassification } from './types.js';\n\nexport function classifyError(error: any): ErrorClassification {\n if (error.response) {\n const { status } = error.response;\n switch (status) {\n case 400: return { type: 'badRequest', retryable: false, isAuth: false, status: 'clientError' };\n case 401: return { type: 'unauthorized', retryable: false, isAuth: true, status: 'authRequired' };\n case 403: return { type: 'forbidden', retryable: false, isAuth: true, status: 'authFailed' };\n case 404: return { type: 'notFound', retryable: false, isAuth: false, status: 'clientError' };\n case 405: return { type: 'methodNotAllowed', retryable: false, isAuth: false, status: 'clientError' };\n case 409: return { type: 'conflict', retryable: false, isAuth: false, status: 'clientError' };\n case 422: return { type: 'unprocessableEntity', retryable: false, isAuth: false, status: 'clientError' };\n case 429: return { type: 'tooManyRequests', retryable: true, isAuth: false, status: 'clientError' };\n case 500: return { type: 'internalServerError', retryable: true, isAuth: false, status: 'serverError' };\n case 502: return { type: 'badGateway', retryable: true, isAuth: false, status: 'serverError' };\n case 503: return { type: 'serviceUnavailable', retryable: true, isAuth: false, status: 'serverError' };\n case 504: return { type: 'gatewayTimeout', retryable: true, isAuth: false, status: 'serverError' };\n default:\n if (status >= 400 && status < 500) return { type: 'clientError' as HttpClientErrorType, retryable: false, isAuth: false, status: 'clientError' };\n if (status >= 500) return { type: 'serverError' as HttpClientErrorType, retryable: true, isAuth: false, status: 'serverError' };\n }\n }\n\n if (error.name === 'AbortError' || error.code === 20 || error.code === 'ABORT_ERR') {\n return error.isTimeout === true\n ? { type: 'timeout', retryable: true, isAuth: false, status: 'timeout' }\n : { type: 'requestCancelled', retryable: false, isAuth: false, status: 'unknown' };\n }\n\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 case 'ETIMEDOUT':\n case 'ECONNABORTED':\n case 'ESOCKETTIMEDOUT':\n return { type: 'timeout', retryable: true, isAuth: false, status: 'timeout' };\n case 'EAUTH':\n case 'EACCES':\n return { type: 'unauthorized', retryable: false, isAuth: true, status: 'authRequired' };\n default:\n return { type: 'networkError', retryable: true, isAuth: false, status: 'networkError' };\n }\n }\n\n\n if (error.message && /timeout|TIMEOUT|aborted/i.test(String(error.message))) {\n return { type: 'timeout', retryable: true, isAuth: false, status: 'timeout' };\n }\n\n return { type: 'unknown', retryable: false, isAuth: false, status: 'unknown' };\n}\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 return descriptions[errorType] || 'An unknown error occurred';\n}\n","/**\n * HttpClient Retry Logic (http-client2 - same as http-client)\n */\n\nimport type { RetryContext } from './types.js';\n\nexport function calculateRetryDelay(attempt: number, baseDelay: number, maxDelay: number, jitterFactor = 0.1): number {\n const exponentialDelay = baseDelay * Math.pow(2, attempt - 1);\n const cappedDelay = Math.min(exponentialDelay, maxDelay);\n const jitter = cappedDelay * jitterFactor * Math.random();\n return Math.floor(cappedDelay + jitter);\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\nexport function shouldRetryError(classification: { retryable: boolean; isAuth: boolean }): boolean {\n if (classification.isAuth) return false;\n return classification.retryable;\n}\n\nexport function createRetryContext(maxAttempts: number, baseDelay: number, maxDelay: number, jitterFactor: number): 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\nexport function updateRetryContext(context: RetryContext, lastError: Error, baseDelay: number, maxDelay: number, jitterFactor: number): RetryContext {\n const nextAttempt = context.attempt + 1;\n return {\n attempt: nextAttempt,\n maxAttempts: context.maxAttempts,\n lastError,\n totalDelay: context.totalDelay + context.nextDelay,\n nextDelay: calculateRetryDelay(nextAttempt, baseDelay, maxDelay, jitterFactor)\n };\n}\n","/**\n * HttpClient2 - Resilient HTTP Client (fetch-based, no external deps)\n *\n * Drop-in replacement for http-client. Uses native fetch instead of axios.\n * Same API: retry logic, error classification, unified response format.\n */\n\nimport type {\n HttpClientConfig,\n RequestOptions,\n HttpClientResponse,\n HttpMethod,\n HttpClientStatus,\n} from './types.js';\nimport { HttpClientError } from '../errors.js';\nimport { classifyError, getErrorDescription } from './errors.js';\nimport { calculateRetryDelay, sleep, shouldRetryError } from './retry.js';\n\nexport { HttpClientError };\n\nfunction buildUrl(baseURL: string | undefined, url: string, params?: Record<string, any>): string {\n let full = url;\n if (baseURL) {\n try {\n full = new URL(url, baseURL).href;\n } catch {\n full = baseURL.replace(/\\/$/, '') + (url.startsWith('/') ? url : '/' + url);\n }\n }\n if (params && Object.keys(params).length > 0) {\n const u = new URL(full);\n for (const [k, v] of Object.entries(params)) {\n if (v != null && v !== '') u.searchParams.set(k, String(v));\n }\n full = u.href;\n }\n return full;\n}\n\nfunction headersToRecord(h: Headers): Record<string, string> {\n const r: Record<string, string> = {};\n h.forEach((v, k) => { r[k.toLowerCase()] = v; });\n return r;\n}\n\nasync function parseBody(response: Response): Promise<any> {\n const text = await response.text();\n if (!text) return null;\n const ct = (response.headers.get('content-type') || '').toLowerCase();\n if (ct.includes('application/json')) {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }\n try {\n const parsed = JSON.parse(text);\n if (typeof parsed === 'object' && parsed !== null) return parsed;\n } catch {\n /* not json */\n }\n return text;\n}\n\nfunction mapStatusToCustom(httpStatus: number): HttpClientStatus {\n if (httpStatus >= 200 && httpStatus < 300) return 'success';\n if (httpStatus === 401) return 'authRequired';\n if (httpStatus === 403) return 'authFailed';\n if (httpStatus >= 400 && httpStatus < 500) return 'clientError';\n if (httpStatus >= 500) return 'serverError';\n return 'unknown';\n}\n\nexport class HttpClient {\n private context: any;\n private config: HttpClientConfig;\n private logger: any;\n\n constructor(context: any, options: HttpClientConfig = {}) {\n this.context = context;\n this.config = options;\n this.logger = options.logger ?? context?.logger ?? console;\n }\n\n /**\n * Static init - discovers params via context.params.getAllForModule(\"http-client2\", 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 baseURL: 'string',\n };\n const discovered = context?.params?.getAllForModule?.(defs) ?? {};\n const merged: HttpClientConfig = { ...discovered, ...options };\n return new HttpClient(context, merged);\n }\n\n async request(method: HttpMethod, url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n const startTime = Date.now();\n const timeout = options.timeout ?? this.config.timeout;\n const retryCount = options.retryCount ?? this.config.retryCount;\n const retryDelay = options.retryDelay ?? this.config.retryDelay;\n const fullUrl = buildUrl(this.config.baseURL, url, options.params);\n\n const headers: Record<string, string> = {\n 'User-Agent': options.userAgent ?? this.config.userAgent,\n ...options.headers\n };\n\n let body: string | undefined;\n if (options.data != null && ['POST', 'PUT', 'PATCH'].includes(method)) {\n body = typeof options.data === 'string' ? options.data : JSON.stringify(options.data);\n if (!headers['content-type']) headers['Content-Type'] = 'application/json';\n }\n\n let lastError: any = null;\n\n for (let attempt = 1; attempt <= retryCount + 1; attempt++) {\n let abortedByTimeout = false;\n try {\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] ${method} ${fullUrl} (attempt ${attempt}/${retryCount + 1})`);\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n abortedByTimeout = true;\n controller.abort();\n }, timeout);\n\n const response = await fetch(fullUrl, {\n method,\n headers,\n body: method !== 'GET' && method !== 'HEAD' ? body : undefined,\n signal: controller.signal,\n redirect: 'follow'\n });\n\n clearTimeout(timeoutId);\n\n const duration = Date.now() - startTime;\n const resHeaders = headersToRecord(response.headers);\n\n if (response.ok) {\n const data = await parseBody(response);\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] ${method} ${fullUrl} → ${response.status} success (${duration}ms)`);\n }\n return {\n status: mapStatusToCustom(response.status),\n code: response.status,\n headers: resHeaders,\n data,\n duration,\n retryCount: attempt - 1,\n finalUrl: response.url || fullUrl\n };\n }\n\n const data = await parseBody(response);\n const classification = classifyError({ response: { status: response.status, headers: resHeaders, data } });\n\n if (options.debug) {\n this.logger.debug?.(`[HttpClient] ${method} ${fullUrl} → ${response.status} ${classification.status} (${duration}ms)`);\n }\n\n if (attempt <= retryCount && shouldRetryError(classification)) {\n const delay = calculateRetryDelay(attempt, retryDelay, this.config.maxRetryDelay, this.config.retryJitter);\n this.logger.warn?.(`[HttpClient] ${method} ${fullUrl} failed (${classification.type}). Retrying in ${delay}ms...`);\n if (options.debug) this.logger.debug?.(`[HttpClient] Waiting ${delay}ms before retry ${attempt + 1}`);\n await sleep(delay);\n continue;\n }\n\n return {\n status: classification.status,\n code: response.status,\n error: classification.type,\n headers: resHeaders,\n data,\n duration,\n retryCount: attempt - 1,\n finalUrl: response.url || fullUrl\n };\n\n } catch (error: any) {\n if (abortedByTimeout) {\n lastError = { ...(error || {}), name: 'AbortError', isTimeout: true };\n } else {\n lastError = error;\n }\n const duration = Date.now() - startTime;\n const classification = classifyError(lastError);\n\n if (classification.retryable && attempt <= retryCount) {\n this.logger.warn?.(`[HttpClient] ${method} ${fullUrl} failed (${classification.type}): ${getErrorDescription(classification.type)}. Retrying...`);\n } else {\n this.logger.error?.(`[HttpClient] ${method} ${fullUrl} failed (${classification.type}): ${getErrorDescription(classification.type)}`);\n }\n\n if (attempt <= retryCount && shouldRetryError(classification)) {\n const delay = calculateRetryDelay(attempt, retryDelay, this.config.maxRetryDelay, this.config.retryJitter);\n if (options.debug) this.logger.debug?.(`[HttpClient] Waiting ${delay}ms before retry ${attempt + 1}`);\n await sleep(delay);\n continue;\n }\n\n return {\n status: classification.status,\n code: null,\n error: classification.type,\n headers: null,\n data: null,\n duration,\n retryCount: attempt - 1,\n finalUrl: fullUrl\n };\n }\n }\n\n const classification = lastError ? classifyError(lastError) : { status: 'unknown' as HttpClientStatus, type: 'unknown' as any };\n return {\n status: classification.status,\n code: null,\n error: classification.type,\n headers: null,\n data: null,\n duration: Date.now() - startTime,\n retryCount: retryCount,\n finalUrl: fullUrl\n };\n }\n\n async get(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('GET', url, options);\n }\n\n async post(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('POST', url, options);\n }\n\n async put(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('PUT', url, options);\n }\n\n async delete(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('DELETE', url, options);\n }\n\n async patch(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('PATCH', url, options);\n }\n\n async head(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('HEAD', url, options);\n }\n\n async options(url: string, options: RequestOptions = {}): Promise<HttpClientResponse> {\n return this.request('OPTIONS', url, options);\n }\n\n getConfig(): Readonly<HttpClientConfig> {\n return { ...this.config };\n }\n}\n"],"mappings":"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","names":["data","classification"]}