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,152 @@
|
|
|
1
|
+
import * as http from 'http'
|
|
2
|
+
import * as https from 'https'
|
|
3
|
+
import { URL } from 'url'
|
|
4
|
+
import type { AziosRequestConfig } from '../types/config'
|
|
5
|
+
import type { AziosResponse } from '../types/response'
|
|
6
|
+
import { BaseAdapter } from '../runtimes/HttpAdapter'
|
|
7
|
+
import AziosError from '../errors/AziosError'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Node.js HTTP adapter using built-in http/https modules
|
|
11
|
+
* Compatible with Node.js 16+ (before global fetch was available)
|
|
12
|
+
*/
|
|
13
|
+
export class NodeHttpAdapter extends BaseAdapter {
|
|
14
|
+
/**
|
|
15
|
+
* Check if this adapter is supported (Node.js environment)
|
|
16
|
+
*/
|
|
17
|
+
isSupported(): boolean {
|
|
18
|
+
// In Node.js, this adapter is always supported
|
|
19
|
+
return true
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Execute HTTP request using Node.js http/https modules
|
|
24
|
+
*/
|
|
25
|
+
async request(config: AziosRequestConfig): Promise<AziosResponse> {
|
|
26
|
+
if (!this.isSupported()) {
|
|
27
|
+
throw new AziosError(
|
|
28
|
+
'Node HTTP adapter is not supported in this runtime',
|
|
29
|
+
'UNSUPPORTED_RUNTIME',
|
|
30
|
+
config
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Check if request is already cancelled
|
|
35
|
+
if (config.signal && config.signal.aborted) {
|
|
36
|
+
throw new AziosError(
|
|
37
|
+
'Request aborted',
|
|
38
|
+
'ABORTED',
|
|
39
|
+
config
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
const { url, method = 'GET', headers = {}, data, timeout, signal } = config
|
|
45
|
+
|
|
46
|
+
const baseURL = config.baseURL || ''
|
|
47
|
+
const fullURL = new URL(baseURL + url)
|
|
48
|
+
|
|
49
|
+
// Add query parameters
|
|
50
|
+
if (config.params) {
|
|
51
|
+
Object.entries(config.params).forEach(([key, value]) => {
|
|
52
|
+
if (value !== null && value !== undefined) {
|
|
53
|
+
if (Array.isArray(value)) {
|
|
54
|
+
value.forEach(v => fullURL.searchParams.append(key, String(v)))
|
|
55
|
+
} else {
|
|
56
|
+
fullURL.searchParams.set(key, String(value))
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const isHttps = fullURL.protocol === 'https:'
|
|
63
|
+
const client = isHttps ? https : http
|
|
64
|
+
|
|
65
|
+
const options: http.RequestOptions = {
|
|
66
|
+
hostname: fullURL.hostname,
|
|
67
|
+
port: fullURL.port || (isHttps ? 443 : 80),
|
|
68
|
+
path: fullURL.pathname + fullURL.search,
|
|
69
|
+
method: method.toUpperCase(),
|
|
70
|
+
headers: {
|
|
71
|
+
'Content-Type': 'application/json',
|
|
72
|
+
...headers
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Handle timeout
|
|
77
|
+
let timeoutId: NodeJS.Timeout | undefined
|
|
78
|
+
if (timeout) {
|
|
79
|
+
timeoutId = setTimeout(() => {
|
|
80
|
+
req.destroy(new Error('Request timeout'))
|
|
81
|
+
}, timeout)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Handle abort signal
|
|
85
|
+
if (signal) {
|
|
86
|
+
signal.addEventListener('abort', () => {
|
|
87
|
+
req.destroy(new Error('Request aborted'))
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const req = client.request(options, (res) => {
|
|
92
|
+
let body = ''
|
|
93
|
+
|
|
94
|
+
res.on('data', (chunk) => {
|
|
95
|
+
body += chunk
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
res.on('end', () => {
|
|
99
|
+
if (timeoutId) {
|
|
100
|
+
clearTimeout(timeoutId)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
let responseData: any = body
|
|
104
|
+
|
|
105
|
+
// Parse JSON if content-type is application/json
|
|
106
|
+
const contentType = res.headers['content-type']
|
|
107
|
+
if (contentType?.includes('application/json') && body) {
|
|
108
|
+
try {
|
|
109
|
+
responseData = JSON.parse(body)
|
|
110
|
+
} catch (e) {
|
|
111
|
+
// Keep as string if parsing fails
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const response: AziosResponse = {
|
|
116
|
+
data: responseData,
|
|
117
|
+
status: res.statusCode || 200,
|
|
118
|
+
statusText: res.statusMessage || '',
|
|
119
|
+
headers: res.headers as Record<string, string>,
|
|
120
|
+
config
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
resolve(response)
|
|
124
|
+
})
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
req.on('error', (error) => {
|
|
128
|
+
if (timeoutId) {
|
|
129
|
+
clearTimeout(timeoutId)
|
|
130
|
+
}
|
|
131
|
+
const errorCode = error.message.includes('aborted') ? 'ABORTED' : 'NETWORK_ERROR'
|
|
132
|
+
reject(new AziosError(
|
|
133
|
+
`Request failed: ${error.message}`,
|
|
134
|
+
errorCode,
|
|
135
|
+
config,
|
|
136
|
+
undefined,
|
|
137
|
+
error
|
|
138
|
+
))
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
// Send request body
|
|
142
|
+
if (data) {
|
|
143
|
+
const body = typeof data === 'string' ? data : JSON.stringify(data)
|
|
144
|
+
req.write(body)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
req.end()
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export default NodeHttpAdapter
|
package/src/adapters/index.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as NodeHttpAdapter } from './httpAdapter'
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import type { AziosInstance } from "../types/request"
|
|
2
|
+
import type { AziosRequestConfig } from "../types/config"
|
|
3
|
+
import type { AziosResponse } from "../types/response"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Token storage and refresh configuration
|
|
7
|
+
*/
|
|
8
|
+
export interface TokenConfig {
|
|
9
|
+
accessToken: string
|
|
10
|
+
refreshToken?: string
|
|
11
|
+
expiresIn?: number
|
|
12
|
+
tokenType?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Auth endpoints configuration
|
|
17
|
+
*/
|
|
18
|
+
export interface AuthEndpoints {
|
|
19
|
+
refreshUrl: string
|
|
20
|
+
logoutUrl?: string
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Auth Manager - Handle authentication, token refresh, and 401 responses
|
|
25
|
+
* Production-grade auth system with automatic token refresh and global 401 handling
|
|
26
|
+
*/
|
|
27
|
+
export default class AuthManager {
|
|
28
|
+
private token: TokenConfig | null = null
|
|
29
|
+
private endpoints: AuthEndpoints | null = null
|
|
30
|
+
private instance: AziosInstance | null = null
|
|
31
|
+
private isRefreshing: boolean = false
|
|
32
|
+
private refreshSubscribers: ((token: string) => void)[] = []
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Initialize the auth manager with endpoints
|
|
36
|
+
*/
|
|
37
|
+
initialize(endpoints: AuthEndpoints): void {
|
|
38
|
+
this.endpoints = endpoints
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Set the Azios instance for making refresh requests
|
|
43
|
+
*/
|
|
44
|
+
setInstance(instance: AziosInstance): void {
|
|
45
|
+
this.instance = instance
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Store token
|
|
50
|
+
*/
|
|
51
|
+
setToken(token: TokenConfig): void {
|
|
52
|
+
this.token = token
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Get current token
|
|
57
|
+
*/
|
|
58
|
+
getToken(): TokenConfig | null {
|
|
59
|
+
return this.token
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get access token string
|
|
64
|
+
*/
|
|
65
|
+
getAccessToken(): string | null {
|
|
66
|
+
return this.token?.accessToken || null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Check if token exists
|
|
71
|
+
*/
|
|
72
|
+
hasToken(): boolean {
|
|
73
|
+
return this.token !== null && this.token.accessToken !== ""
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Check if token is expired
|
|
78
|
+
*/
|
|
79
|
+
isTokenExpired(): boolean {
|
|
80
|
+
if (!this.token || !this.token.expiresIn) {
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Check if expiry time has passed (with 60s buffer)
|
|
85
|
+
return Date.now() > this.token.expiresIn - 60000
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Clear token
|
|
90
|
+
*/
|
|
91
|
+
clearToken(): void {
|
|
92
|
+
this.token = null
|
|
93
|
+
this.refreshSubscribers = []
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Refresh the access token
|
|
98
|
+
*/
|
|
99
|
+
async refreshAccessToken(): Promise<boolean> {
|
|
100
|
+
if (!this.instance || !this.endpoints) {
|
|
101
|
+
console.warn("AuthManager not properly initialized")
|
|
102
|
+
return false
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!this.token?.refreshToken) {
|
|
106
|
+
console.warn("No refresh token available")
|
|
107
|
+
return false
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
// Prevent multiple simultaneous refresh requests
|
|
112
|
+
if (this.isRefreshing) {
|
|
113
|
+
return new Promise(resolve => {
|
|
114
|
+
this.refreshSubscribers.push(() => {
|
|
115
|
+
resolve(true)
|
|
116
|
+
})
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
this.isRefreshing = true
|
|
121
|
+
|
|
122
|
+
const response = await this.instance.post(
|
|
123
|
+
this.endpoints.refreshUrl,
|
|
124
|
+
{ refreshToken: this.token.refreshToken }
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if (response.data?.accessToken) {
|
|
128
|
+
this.token = {
|
|
129
|
+
...this.token,
|
|
130
|
+
accessToken: response.data.accessToken,
|
|
131
|
+
expiresIn: Date.now() + (response.data.expiresIn || 3600000)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Notify all subscribers
|
|
135
|
+
this.refreshSubscribers.forEach(cb => cb(this.token!.accessToken))
|
|
136
|
+
this.refreshSubscribers = []
|
|
137
|
+
|
|
138
|
+
this.isRefreshing = false
|
|
139
|
+
return true
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
this.isRefreshing = false
|
|
143
|
+
return false
|
|
144
|
+
} catch (error) {
|
|
145
|
+
this.isRefreshing = false
|
|
146
|
+
console.error("Token refresh failed:", error)
|
|
147
|
+
return false
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Get Authorization header value
|
|
153
|
+
*/
|
|
154
|
+
getAuthHeader(): string | null {
|
|
155
|
+
if (!this.hasToken()) {
|
|
156
|
+
return null
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const tokenType = this.token?.tokenType || "Bearer"
|
|
160
|
+
return `${tokenType} ${this.token?.accessToken}`
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Attach auth header to request
|
|
165
|
+
*/
|
|
166
|
+
attachAuthHeader(config: AziosRequestConfig): AziosRequestConfig {
|
|
167
|
+
const authHeader = this.getAuthHeader()
|
|
168
|
+
|
|
169
|
+
if (authHeader) {
|
|
170
|
+
return {
|
|
171
|
+
...config,
|
|
172
|
+
headers: {
|
|
173
|
+
...config.headers,
|
|
174
|
+
Authorization: authHeader
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return config
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Handle 401 response (unauthorized)
|
|
184
|
+
*/
|
|
185
|
+
async handle401(config: AziosRequestConfig): Promise<boolean> {
|
|
186
|
+
if (!this.hasToken()) {
|
|
187
|
+
// No token to refresh
|
|
188
|
+
return false
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const refreshed = await this.refreshAccessToken()
|
|
192
|
+
|
|
193
|
+
if (refreshed) {
|
|
194
|
+
// Update the failed request with new token
|
|
195
|
+
return true
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Token refresh failed, logout
|
|
199
|
+
await this.logout()
|
|
200
|
+
return false
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Logout user
|
|
205
|
+
*/
|
|
206
|
+
async logout(): Promise<void> {
|
|
207
|
+
if (this.instance && this.endpoints?.logoutUrl) {
|
|
208
|
+
try {
|
|
209
|
+
await this.instance.post(this.endpoints.logoutUrl)
|
|
210
|
+
} catch (error) {
|
|
211
|
+
console.error("Logout failed:", error)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
this.clearToken()
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Get auth status summary
|
|
220
|
+
*/
|
|
221
|
+
getStatus(): {
|
|
222
|
+
authenticated: boolean
|
|
223
|
+
tokenExpired: boolean
|
|
224
|
+
refreshToken: boolean
|
|
225
|
+
} {
|
|
226
|
+
return {
|
|
227
|
+
authenticated: this.hasToken(),
|
|
228
|
+
tokenExpired: this.isTokenExpired(),
|
|
229
|
+
refreshToken: this.token?.refreshToken !== undefined
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Create auth plugin that integrates with Azios
|
|
236
|
+
*/
|
|
237
|
+
export function createAuthPlugin(endpoints: AuthEndpoints) {
|
|
238
|
+
const authManager = new AuthManager()
|
|
239
|
+
authManager.initialize(endpoints)
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
name: "auth",
|
|
243
|
+
version: "1.0.0",
|
|
244
|
+
hooks: {
|
|
245
|
+
onInstall: async (instance: AziosInstance) => {
|
|
246
|
+
authManager.setInstance(instance)
|
|
247
|
+
|
|
248
|
+
// Add response interceptor to handle 401
|
|
249
|
+
instance.interceptors.response.use(
|
|
250
|
+
(response: AziosResponse) => response,
|
|
251
|
+
async (error: any) => {
|
|
252
|
+
const originalRequest = error.config
|
|
253
|
+
|
|
254
|
+
// Check if error is 401 and retry hasn't been attempted
|
|
255
|
+
if (
|
|
256
|
+
error.response?.status === 401 &&
|
|
257
|
+
!originalRequest._retry &&
|
|
258
|
+
authManager.hasToken()
|
|
259
|
+
) {
|
|
260
|
+
originalRequest._retry = true
|
|
261
|
+
|
|
262
|
+
try {
|
|
263
|
+
const refreshed = await authManager.handle401(originalRequest)
|
|
264
|
+
|
|
265
|
+
if (refreshed) {
|
|
266
|
+
// Retry original request with new token
|
|
267
|
+
const newConfig = authManager.attachAuthHeader(originalRequest)
|
|
268
|
+
return instance.request(newConfig)
|
|
269
|
+
}
|
|
270
|
+
} catch (refreshError) {
|
|
271
|
+
console.error("Auth refresh failed:", refreshError)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
throw error
|
|
276
|
+
}
|
|
277
|
+
)
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export type { AuthManager }
|
package/src/core/Azios.ts
CHANGED
|
@@ -6,6 +6,7 @@ import InterceptorManager from "../interceptors/InterceptorManager"
|
|
|
6
6
|
import PluginManager from "../plugins/pluginManager"
|
|
7
7
|
import MiddlewareManager from "../middleware/middlewareManager"
|
|
8
8
|
import { compose } from "../middleware/compose"
|
|
9
|
+
import RequestMonitor from "../monitoring/RequestMonitor"
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Core Azios HTTP client class
|
|
@@ -21,6 +22,7 @@ export default class Azios {
|
|
|
21
22
|
|
|
22
23
|
middlewares: MiddlewareManager
|
|
23
24
|
plugins: PluginManager
|
|
25
|
+
monitor: RequestMonitor
|
|
24
26
|
|
|
25
27
|
constructor(config: AziosRequestConfig) {
|
|
26
28
|
this.defaults = config
|
|
@@ -32,6 +34,7 @@ export default class Azios {
|
|
|
32
34
|
|
|
33
35
|
this.middlewares = new MiddlewareManager()
|
|
34
36
|
this.plugins = new PluginManager()
|
|
37
|
+
this.monitor = new RequestMonitor(100, false) // Disabled by default
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
/**
|
|
@@ -63,52 +66,69 @@ export default class Azios {
|
|
|
63
66
|
config = { ...this.defaults, ...config }
|
|
64
67
|
|
|
65
68
|
// -------------------------
|
|
66
|
-
//
|
|
69
|
+
// MONITORING: START TRACKING
|
|
67
70
|
// -------------------------
|
|
68
|
-
|
|
71
|
+
const requestId = this.monitor.startRequest(config)
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
await fn(context)
|
|
76
|
-
config = context.config
|
|
73
|
+
try {
|
|
74
|
+
// -------------------------
|
|
75
|
+
// PLUGIN: PRE-REQUEST HOOKS
|
|
76
|
+
// -------------------------
|
|
77
|
+
config = await this.plugins.executeBeforeRequestHooks(config)
|
|
77
78
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
// -------------------------
|
|
80
|
+
// MIDDLEWARE PIPELINE
|
|
81
|
+
// -------------------------
|
|
82
|
+
const context = { config }
|
|
83
|
+
const fn = compose(this.middlewares.middlewares)
|
|
84
|
+
await fn(context)
|
|
85
|
+
config = context.config
|
|
82
86
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
// -------------------------
|
|
88
|
+
// INTERCEPTOR PIPELINE
|
|
89
|
+
// -------------------------
|
|
90
|
+
const chain: any[] = []
|
|
87
91
|
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
// Request interceptors (reverse order)
|
|
93
|
+
this.interceptors.request.forEach(interceptor => {
|
|
94
|
+
chain.unshift(interceptor.fulfilled, interceptor.rejected)
|
|
95
|
+
})
|
|
90
96
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
chain.push(interceptor.fulfilled, interceptor.rejected)
|
|
94
|
-
})
|
|
97
|
+
// Main dispatch
|
|
98
|
+
chain.push(dispatchRequest, undefined)
|
|
95
99
|
|
|
96
|
-
|
|
100
|
+
// Response interceptors (normal order)
|
|
101
|
+
this.interceptors.response.forEach(interceptor => {
|
|
102
|
+
chain.push(interceptor.fulfilled, interceptor.rejected)
|
|
103
|
+
})
|
|
97
104
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
let promise = Promise.resolve(config)
|
|
106
|
+
|
|
107
|
+
while (chain.length) {
|
|
108
|
+
const fulfilled = chain.shift()
|
|
109
|
+
const rejected = chain.shift()
|
|
110
|
+
promise = promise.then(fulfilled, rejected)
|
|
111
|
+
}
|
|
103
112
|
|
|
104
|
-
try {
|
|
105
113
|
const response = await promise as any
|
|
106
114
|
|
|
107
115
|
// -------------------------
|
|
108
116
|
// PLUGIN: POST-RESPONSE HOOKS
|
|
109
117
|
// -------------------------
|
|
110
|
-
|
|
118
|
+
const finalResponse = await this.plugins.executeAfterResponseHooks(response)
|
|
119
|
+
|
|
120
|
+
// -------------------------
|
|
121
|
+
// MONITORING: END TRACKING (SUCCESS)
|
|
122
|
+
// -------------------------
|
|
123
|
+
this.monitor.endRequest(requestId, config, finalResponse)
|
|
124
|
+
|
|
125
|
+
return finalResponse
|
|
111
126
|
} catch (error) {
|
|
127
|
+
// -------------------------
|
|
128
|
+
// MONITORING: END TRACKING (ERROR)
|
|
129
|
+
// -------------------------
|
|
130
|
+
this.monitor.endRequestWithError(requestId, config, error)
|
|
131
|
+
|
|
112
132
|
// -------------------------
|
|
113
133
|
// PLUGIN: ERROR HOOKS
|
|
114
134
|
// -------------------------
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,8 @@ const azios = createInstance({
|
|
|
5
5
|
url: ""
|
|
6
6
|
})
|
|
7
7
|
|
|
8
|
+
export default azios
|
|
9
|
+
|
|
8
10
|
// ============================================
|
|
9
11
|
// Type Exports
|
|
10
12
|
// ============================================
|
|
@@ -48,17 +50,25 @@ export {
|
|
|
48
50
|
isBrowserRuntime,
|
|
49
51
|
RuntimeType
|
|
50
52
|
} from "./runtimes/detectRuntime"
|
|
51
|
-
export { default as AdapterFactory } from "./runtimes/AdapterFactory"
|
|
52
53
|
|
|
53
54
|
// ============================================
|
|
54
|
-
//
|
|
55
|
+
// NEW: Monitoring System Exports
|
|
55
56
|
// ============================================
|
|
56
57
|
|
|
57
|
-
export {
|
|
58
|
-
export {
|
|
58
|
+
export { default as RequestMonitor } from "./monitoring/RequestMonitor"
|
|
59
|
+
export type { RequestLog } from "./monitoring/RequestMonitor"
|
|
59
60
|
|
|
60
61
|
// ============================================
|
|
61
|
-
//
|
|
62
|
+
// NEW: Authentication System Exports
|
|
62
63
|
// ============================================
|
|
63
64
|
|
|
64
|
-
export default
|
|
65
|
+
export { default as AuthManager, createAuthPlugin } from "./auth/AuthManager"
|
|
66
|
+
export type { TokenConfig, AuthEndpoints, AuthManager as IAuthManager } from "./auth/AuthManager"
|
|
67
|
+
export { default as AdapterFactory } from "./runtimes/AdapterFactory"
|
|
68
|
+
|
|
69
|
+
// ============================================
|
|
70
|
+
// Cache & Rate Limit Exports
|
|
71
|
+
// ============================================
|
|
72
|
+
|
|
73
|
+
export { getCache, setCache, clearCache } from "./cache/memoryCache"
|
|
74
|
+
export { schedule } from "./rateLimiter/rateLimiter"
|