aziosxjs 1.0.0 → 1.0.2

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.
@@ -0,0 +1,326 @@
1
+ import { AziosRequestConfig } from "../types/config"
2
+ import { AziosResponse } from "../types/response"
3
+
4
+ /**
5
+ * Represents a single tracked request/response cycle
6
+ */
7
+ export interface RequestLog {
8
+ id: string
9
+ timestamp: number
10
+ method: string
11
+ url: string
12
+ status?: number
13
+ statusText?: string
14
+ duration: number
15
+ retries: number
16
+ cached: boolean
17
+ error?: {
18
+ message: string
19
+ code?: string
20
+ }
21
+ requestHeaders?: Record<string, any>
22
+ responseHeaders?: Record<string, any>
23
+ dataSize?: number
24
+ }
25
+
26
+ /**
27
+ * Request Monitor - Track all requests for debugging and monitoring
28
+ * Production-grade request tracking system with history, filtering, and export
29
+ */
30
+ export default class RequestMonitor {
31
+ private enabled: boolean = false
32
+ private maxEntries: number = 100
33
+ private logs: Map<string, RequestLog> = new Map()
34
+ private requestMetadata: Map<string, { startTime: number; retries: number; cached: boolean }> = new Map()
35
+
36
+ constructor(maxEntries: number = 100, enabled: boolean = false) {
37
+ this.maxEntries = maxEntries
38
+ this.enabled = enabled
39
+ }
40
+
41
+ /**
42
+ * Enable monitoring
43
+ */
44
+ enable(): void {
45
+ this.enabled = true
46
+ }
47
+
48
+ /**
49
+ * Disable monitoring
50
+ */
51
+ disable(): void {
52
+ this.enabled = false
53
+ }
54
+
55
+ /**
56
+ * Check if monitoring is enabled
57
+ */
58
+ isEnabled(): boolean {
59
+ return this.enabled
60
+ }
61
+
62
+ /**
63
+ * Mark the start of a request
64
+ */
65
+ startRequest(config: AziosRequestConfig): string {
66
+ if (!this.enabled) return ""
67
+
68
+ const requestId = this.generateId()
69
+ this.requestMetadata.set(requestId, {
70
+ startTime: Date.now(),
71
+ retries: config.retry || 0,
72
+ cached: config.cache || false
73
+ })
74
+
75
+ return requestId
76
+ }
77
+
78
+ /**
79
+ * Mark the end of a successful request
80
+ */
81
+ endRequest(requestId: string, config: AziosRequestConfig, response: AziosResponse): void {
82
+ if (!this.enabled || !requestId) return
83
+
84
+ const metadata = this.requestMetadata.get(requestId)
85
+ if (!metadata) return
86
+
87
+ const duration = Date.now() - metadata.startTime
88
+
89
+ const log: RequestLog = {
90
+ id: requestId,
91
+ timestamp: Date.now(),
92
+ method: config.method || "GET",
93
+ url: config.url || "",
94
+ status: response.status,
95
+ statusText: response.statusText,
96
+ duration,
97
+ retries: metadata.retries,
98
+ cached: metadata.cached,
99
+ requestHeaders: config.headers,
100
+ responseHeaders: response.headers,
101
+ dataSize: this.estimateSize(response.data)
102
+ }
103
+
104
+ this.addLog(log)
105
+ this.requestMetadata.delete(requestId)
106
+ }
107
+
108
+ /**
109
+ * Mark the end of a failed request
110
+ */
111
+ endRequestWithError(requestId: string, config: AziosRequestConfig, error: Error | any): void {
112
+ if (!this.enabled || !requestId) return
113
+
114
+ const metadata = this.requestMetadata.get(requestId)
115
+ if (!metadata) return
116
+
117
+ const duration = Date.now() - metadata.startTime
118
+
119
+ const log: RequestLog = {
120
+ id: requestId,
121
+ timestamp: Date.now(),
122
+ method: config.method || "GET",
123
+ url: config.url || "",
124
+ duration,
125
+ retries: metadata.retries,
126
+ cached: metadata.cached,
127
+ error: {
128
+ message: error?.message || "Unknown error",
129
+ code: error?.code
130
+ },
131
+ requestHeaders: config.headers
132
+ }
133
+
134
+ this.addLog(log)
135
+ this.requestMetadata.delete(requestId)
136
+ }
137
+
138
+ /**
139
+ * Add a log entry and maintain maxEntries limit
140
+ */
141
+ private addLog(log: RequestLog): void {
142
+ this.logs.set(log.id, log)
143
+
144
+ // Remove oldest entries if we exceed maxEntries
145
+ if (this.logs.size > this.maxEntries) {
146
+ const entriesToRemove = this.logs.size - this.maxEntries
147
+ let removed = 0
148
+
149
+ for (const [id, _] of this.logs) {
150
+ if (removed >= entriesToRemove) break
151
+ this.logs.delete(id)
152
+ removed++
153
+ }
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Get all logged requests
159
+ */
160
+ getHistory(): RequestLog[] {
161
+ return Array.from(this.logs.values())
162
+ }
163
+
164
+ /**
165
+ * Get logs filtered by method
166
+ */
167
+ getByMethod(method: string): RequestLog[] {
168
+ return this.getHistory().filter(log => log.method.toUpperCase() === method.toUpperCase())
169
+ }
170
+
171
+ /**
172
+ * Get logs filtered by URL pattern
173
+ */
174
+ getByUrl(pattern: string | RegExp): RequestLog[] {
175
+ const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern
176
+ return this.getHistory().filter(log => regex.test(log.url))
177
+ }
178
+
179
+ /**
180
+ * Get logs with errors
181
+ */
182
+ getErrors(): RequestLog[] {
183
+ return this.getHistory().filter(log => log.error !== undefined)
184
+ }
185
+
186
+ /**
187
+ * Get statistics
188
+ */
189
+ getStats(): {
190
+ totalRequests: number
191
+ totalErrors: number
192
+ totalCached: number
193
+ averageDuration: number
194
+ slowestRequest: number
195
+ fastestRequest: number
196
+ } {
197
+ const history = this.getHistory()
198
+
199
+ if (history.length === 0) {
200
+ return {
201
+ totalRequests: 0,
202
+ totalErrors: 0,
203
+ totalCached: 0,
204
+ averageDuration: 0,
205
+ slowestRequest: 0,
206
+ fastestRequest: 0
207
+ }
208
+ }
209
+
210
+ const errors = history.filter(log => log.error).length
211
+ const cached = history.filter(log => log.cached).length
212
+ const durations = history.map(log => log.duration)
213
+ const avgDuration = durations.reduce((a, b) => a + b, 0) / durations.length
214
+
215
+ return {
216
+ totalRequests: history.length,
217
+ totalErrors: errors,
218
+ totalCached: cached,
219
+ averageDuration: Math.round(avgDuration),
220
+ slowestRequest: Math.max(...durations),
221
+ fastestRequest: Math.min(...durations)
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Clear all logs
227
+ */
228
+ clear(): void {
229
+ this.logs.clear()
230
+ this.requestMetadata.clear()
231
+ }
232
+
233
+ /**
234
+ * Export logs as JSON
235
+ */
236
+ exportJSON(): string {
237
+ return JSON.stringify(this.getHistory(), null, 2)
238
+ }
239
+
240
+ /**
241
+ * Export logs as CSV
242
+ */
243
+ exportCSV(): string {
244
+ const history = this.getHistory()
245
+
246
+ if (history.length === 0) {
247
+ return "No logs to export"
248
+ }
249
+
250
+ const headers = [
251
+ "Timestamp",
252
+ "Method",
253
+ "URL",
254
+ "Status",
255
+ "Duration (ms)",
256
+ "Cached",
257
+ "Error"
258
+ ]
259
+
260
+ const rows = history.map(log => [
261
+ new Date(log.timestamp).toISOString(),
262
+ log.method,
263
+ log.url,
264
+ log.status || "N/A",
265
+ log.duration,
266
+ log.cached ? "Yes" : "No",
267
+ log.error ? log.error.message : "None"
268
+ ])
269
+
270
+ const csvContent = [headers, ...rows]
271
+ .map(row => row.map(cell => `"${cell}"`).join(","))
272
+ .join("\n")
273
+
274
+ return csvContent
275
+ }
276
+
277
+ /**
278
+ * Get a formatted debug summary
279
+ */
280
+ getSummary(): string {
281
+ const stats = this.getStats()
282
+ const errors = this.getErrors()
283
+
284
+ let summary = `
285
+ ╔══════════════════════════════════════════════╗
286
+ ║ 📊 AZIOS REQUEST MONITOR ║
287
+ ╚══════════════════════════════════════════════╝
288
+
289
+ 📈 Statistics:
290
+ • Total Requests: ${stats.totalRequests}
291
+ • Errors: ${stats.totalErrors}
292
+ • Cached: ${stats.totalCached}
293
+ • Avg Duration: ${stats.averageDuration}ms
294
+ • Slowest: ${stats.slowestRequest}ms
295
+ • Fastest: ${stats.fastestRequest}ms
296
+ `
297
+
298
+ if (errors.length > 0) {
299
+ summary += `\n❌ Recent Errors:\n`
300
+ errors.slice(-5).forEach(log => {
301
+ summary += ` • ${log.method} ${log.url}: ${log.error?.message}\n`
302
+ })
303
+ }
304
+
305
+ return summary
306
+ }
307
+
308
+ /**
309
+ * Generate unique request ID
310
+ */
311
+ private generateId(): string {
312
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`
313
+ }
314
+
315
+ /**
316
+ * Estimate data size in KB
317
+ */
318
+ private estimateSize(data: any): number {
319
+ try {
320
+ const json = JSON.stringify(data)
321
+ return Math.round(json.length / 1024 * 100) / 100 // KB with 2 decimals
322
+ } catch {
323
+ return 0
324
+ }
325
+ }
326
+ }
@@ -1,6 +1,7 @@
1
1
  import type { HttpAdapter } from './HttpAdapter'
2
2
  import { currentRuntime, RuntimeType } from './detectRuntime'
3
3
  import UniversalHttpAdapter from './UniversalHttpAdapter'
4
+ import { NodeHttpAdapter } from '../adapters'
4
5
 
5
6
  /**
6
7
  * Adapter factory for selecting the appropriate HTTP adapter
@@ -14,7 +15,22 @@ export class AdapterFactory {
14
15
  */
15
16
  static getAdapter(): HttpAdapter {
16
17
  if (!this.adapters.has(currentRuntime)) {
17
- this.adapters.set(currentRuntime, new UniversalHttpAdapter())
18
+ let adapter: HttpAdapter
19
+
20
+ // Try UniversalHttpAdapter first (works in Node 18+, browsers, etc.)
21
+ const universalAdapter = new UniversalHttpAdapter()
22
+ if (universalAdapter.isSupported()) {
23
+ adapter = universalAdapter
24
+ } else if (currentRuntime === RuntimeType.Node) {
25
+ // Fallback to NodeHttpAdapter for Node.js < 18
26
+ adapter = new NodeHttpAdapter()
27
+ } else {
28
+ throw new Error(
29
+ `No supported HTTP adapter found for runtime: ${currentRuntime}`
30
+ )
31
+ }
32
+
33
+ this.adapters.set(currentRuntime, adapter)
18
34
  }
19
35
 
20
36
  const adapter = this.adapters.get(currentRuntime)!
@@ -1,6 +1,7 @@
1
1
  import { AziosRequestConfig } from "./config"
2
2
  import { AziosResponse } from "./response"
3
3
  import InterceptorManager from "../interceptors/InterceptorManager"
4
+ import RequestMonitor from "../monitoring/RequestMonitor"
4
5
  import type { AziosPlugin } from "./plugin"
5
6
  import type { AziosMiddleware } from "./middleware"
6
7
 
@@ -36,4 +37,7 @@ export interface AziosInstance {
36
37
  // Middleware system
37
38
  use(middleware: AziosMiddleware): void
38
39
 
40
+ // Monitoring system (NEW)
41
+ monitor: RequestMonitor
42
+
39
43
  }