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.
- package/README.md +393 -93
- package/dist/adapters/httpAdapter.d.ts +18 -0
- package/dist/adapters/httpAdapter.js +156 -0
- package/dist/adapters/httpAdapter.js.map +1 -1
- package/dist/adapters/index.d.ts +1 -0
- package/dist/adapters/index.js +7 -0
- package/dist/adapters/index.js.map +1 -1
- package/dist/auth/AuthManager.d.ts +100 -0
- package/dist/auth/AuthManager.js +226 -0
- package/dist/auth/AuthManager.js.map +1 -0
- package/dist/core/Azios.d.ts +2 -0
- package/dist/core/Azios.js +45 -30
- package/dist/core/Azios.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/monitoring/RequestMonitor.d.ts +113 -0
- package/dist/monitoring/RequestMonitor.js +264 -0
- package/dist/monitoring/RequestMonitor.js.map +1 -0
- package/dist/runtimes/AdapterFactory.js +15 -1
- package/dist/runtimes/AdapterFactory.js.map +1 -1
- package/dist/types/request.d.ts +2 -0
- package/package.json +62 -49
- package/src/adapters/httpAdapter.ts +152 -0
- package/src/adapters/index.ts +1 -0
- package/src/auth/AuthManager.ts +283 -0
- package/src/core/Azios.ts +51 -31
- package/src/index.ts +16 -6
- package/src/monitoring/RequestMonitor.ts +326 -0
- package/src/runtimes/AdapterFactory.ts +17 -1
- package/src/types/request.ts +4 -0
|
@@ -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
|
-
|
|
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)!
|
package/src/types/request.ts
CHANGED
|
@@ -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
|
}
|