@fluwa-tool/sdk 1.0.0 → 1.0.1
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,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interceptador de XMLHttpRequest
|
|
3
|
+
* Intercepta requisições axios, jQuery, XMLHttpRequest nativo
|
|
4
|
+
*/
|
|
5
|
+
import { ILogger } from '../../core/Logger';
|
|
6
|
+
import { IRequestLogger } from './RequestLogger';
|
|
7
|
+
import { IMockResolver } from './MockResolver';
|
|
8
|
+
export interface IXMLHttpRequestInterceptor {
|
|
9
|
+
install(): void;
|
|
10
|
+
uninstall(): void;
|
|
11
|
+
}
|
|
12
|
+
export declare class XMLHttpRequestInterceptor implements IXMLHttpRequestInterceptor {
|
|
13
|
+
private logger;
|
|
14
|
+
private requestLogger;
|
|
15
|
+
private mockResolver;
|
|
16
|
+
private sessionId;
|
|
17
|
+
private appName;
|
|
18
|
+
private originalOpen;
|
|
19
|
+
private originalSend;
|
|
20
|
+
private originalSetRequestHeader;
|
|
21
|
+
private isInstalled;
|
|
22
|
+
constructor(logger: ILogger, requestLogger: IRequestLogger, mockResolver: IMockResolver, sessionId: string, appName: string);
|
|
23
|
+
install(): void;
|
|
24
|
+
uninstall(): void;
|
|
25
|
+
private safeParseBody;
|
|
26
|
+
private generateId;
|
|
27
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Interceptador de XMLHttpRequest
|
|
4
|
+
* Intercepta requisições axios, jQuery, XMLHttpRequest nativo
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.XMLHttpRequestInterceptor = void 0;
|
|
8
|
+
const types_1 = require("../../types");
|
|
9
|
+
class XMLHttpRequestInterceptor {
|
|
10
|
+
constructor(logger, requestLogger, mockResolver, sessionId, appName) {
|
|
11
|
+
this.logger = logger;
|
|
12
|
+
this.requestLogger = requestLogger;
|
|
13
|
+
this.mockResolver = mockResolver;
|
|
14
|
+
this.sessionId = sessionId;
|
|
15
|
+
this.appName = appName;
|
|
16
|
+
this.isInstalled = false;
|
|
17
|
+
}
|
|
18
|
+
install() {
|
|
19
|
+
if (this.isInstalled) {
|
|
20
|
+
this.logger.warn('XMLHttpRequest interceptor já foi instalado');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
// Verificar se XMLHttpRequest está disponível (apenas em navegadores)
|
|
24
|
+
if (typeof XMLHttpRequest === 'undefined') {
|
|
25
|
+
this.logger.debug('XMLHttpRequest não disponível nesse ambiente (requer navegador)');
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const self = this;
|
|
29
|
+
const originalXHR = XMLHttpRequest.prototype;
|
|
30
|
+
// Armazenar referência ao open original
|
|
31
|
+
this.originalOpen = originalXHR.open;
|
|
32
|
+
this.originalSend = originalXHR.send;
|
|
33
|
+
this.originalSetRequestHeader = originalXHR.setRequestHeader;
|
|
34
|
+
// Interceptar open()
|
|
35
|
+
originalXHR.open = function (method, url, ...args) {
|
|
36
|
+
const xhr = this;
|
|
37
|
+
xhr._fluwaMethod = method.toUpperCase();
|
|
38
|
+
xhr._fluwaUrl = url;
|
|
39
|
+
xhr._fluwaRequestId = self.generateId();
|
|
40
|
+
xhr._fluwaHeaders = {};
|
|
41
|
+
xhr._fluwaStartTime = Date.now();
|
|
42
|
+
return self.originalOpen.apply(this, [method, url, ...args]);
|
|
43
|
+
};
|
|
44
|
+
// Interceptar setRequestHeader()
|
|
45
|
+
originalXHR.setRequestHeader = function (header, value) {
|
|
46
|
+
const xhr = this;
|
|
47
|
+
if (!xhr._fluwaHeaders) {
|
|
48
|
+
xhr._fluwaHeaders = {};
|
|
49
|
+
}
|
|
50
|
+
xhr._fluwaHeaders[header] = value;
|
|
51
|
+
return self.originalSetRequestHeader.apply(this, [header, value]);
|
|
52
|
+
};
|
|
53
|
+
// Interceptar send()
|
|
54
|
+
this.originalSend = originalXHR.send;
|
|
55
|
+
originalXHR.send = function (body) {
|
|
56
|
+
const xhr = this;
|
|
57
|
+
const method = (xhr._fluwaMethod || 'GET');
|
|
58
|
+
const url = xhr._fluwaUrl;
|
|
59
|
+
const requestId = xhr._fluwaRequestId;
|
|
60
|
+
const headers = xhr._fluwaHeaders || {};
|
|
61
|
+
const requestMetadata = {
|
|
62
|
+
id: requestId,
|
|
63
|
+
method,
|
|
64
|
+
url,
|
|
65
|
+
headers,
|
|
66
|
+
body: body ? self.safeParseBody(body) : undefined,
|
|
67
|
+
timestamp: new Date().toISOString(),
|
|
68
|
+
sessionId: self.sessionId,
|
|
69
|
+
appName: self.appName,
|
|
70
|
+
source: types_1.RequestSource.REAL,
|
|
71
|
+
};
|
|
72
|
+
// Verificar se há mock
|
|
73
|
+
self.mockResolver.resolve(method, url)
|
|
74
|
+
.then((mockResponse) => {
|
|
75
|
+
if (mockResponse) {
|
|
76
|
+
// Há mock disponível
|
|
77
|
+
requestMetadata.source = types_1.RequestSource.MOCK;
|
|
78
|
+
requestMetadata.status = mockResponse.status || 200;
|
|
79
|
+
requestMetadata.response = mockResponse.response;
|
|
80
|
+
// Logar
|
|
81
|
+
self.requestLogger.logStart(requestMetadata).catch(() => { });
|
|
82
|
+
// Aplicar delay se configurado
|
|
83
|
+
if (mockResponse.delay) {
|
|
84
|
+
return new Promise(resolve => setTimeout(resolve, mockResponse.delay));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Sem mock, será requisição real
|
|
89
|
+
self.requestLogger.logStart(requestMetadata).catch(() => { });
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
.catch(() => {
|
|
93
|
+
self.requestLogger.logStart(requestMetadata).catch(() => { });
|
|
94
|
+
});
|
|
95
|
+
// Interceptar mudanças de estado
|
|
96
|
+
const originalOnReadyStateChange = xhr.onreadystatechange;
|
|
97
|
+
xhr.onreadystatechange = function () {
|
|
98
|
+
if (xhr.readyState === 4) {
|
|
99
|
+
// Requisição completou
|
|
100
|
+
requestMetadata.status = xhr.status;
|
|
101
|
+
// Tentar extrair response
|
|
102
|
+
try {
|
|
103
|
+
if (xhr.responseText) {
|
|
104
|
+
requestMetadata.response = self.safeParseBody(xhr.responseText);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
requestMetadata.response = xhr.responseText;
|
|
109
|
+
}
|
|
110
|
+
const duration = Date.now() - (xhr._fluwaStartTime || 0);
|
|
111
|
+
requestMetadata.duration = duration;
|
|
112
|
+
self.requestLogger.logComplete(requestMetadata).catch(() => { });
|
|
113
|
+
}
|
|
114
|
+
// Chamar handler original
|
|
115
|
+
if (originalOnReadyStateChange) {
|
|
116
|
+
originalOnReadyStateChange.call(this);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
// Chamar send original
|
|
120
|
+
return self.originalSend.apply(this, [body]);
|
|
121
|
+
};
|
|
122
|
+
this.isInstalled = true;
|
|
123
|
+
this.logger.success('XMLHttpRequest interceptor instalado');
|
|
124
|
+
}
|
|
125
|
+
uninstall() {
|
|
126
|
+
if (!this.isInstalled || !this.originalOpen) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const originalXHR = XMLHttpRequest.prototype;
|
|
130
|
+
originalXHR.open = this.originalOpen;
|
|
131
|
+
originalXHR.send = this.originalSend;
|
|
132
|
+
originalXHR.setRequestHeader = this.originalSetRequestHeader;
|
|
133
|
+
this.isInstalled = false;
|
|
134
|
+
this.logger.success('XMLHttpRequest interceptor desinstalado');
|
|
135
|
+
}
|
|
136
|
+
safeParseBody(body) {
|
|
137
|
+
if (typeof body === 'string') {
|
|
138
|
+
try {
|
|
139
|
+
return JSON.parse(body);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return body;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return body;
|
|
146
|
+
}
|
|
147
|
+
generateId() {
|
|
148
|
+
return `${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
exports.XMLHttpRequestInterceptor = XMLHttpRequestInterceptor;
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,7 @@ const Config_1 = require("./core/Config");
|
|
|
33
33
|
const HttpClient_1 = require("./features/communication/HttpClient");
|
|
34
34
|
const WebSocketClient_1 = require("./features/communication/WebSocketClient");
|
|
35
35
|
const FetchInterceptor_1 = require("./features/network/FetchInterceptor");
|
|
36
|
+
const XMLHttpRequestInterceptor_1 = require("./features/network/XMLHttpRequestInterceptor");
|
|
36
37
|
const RequestLogger_1 = require("./features/network/RequestLogger");
|
|
37
38
|
const MockResolver_1 = require("./features/network/MockResolver");
|
|
38
39
|
const IdGenerator_1 = require("./core/IdGenerator");
|
|
@@ -46,6 +47,7 @@ let sessionId;
|
|
|
46
47
|
let httpClient;
|
|
47
48
|
let wsClient;
|
|
48
49
|
let fetchInterceptor;
|
|
50
|
+
let xmlHttpRequestInterceptor;
|
|
49
51
|
let mockResolver;
|
|
50
52
|
// ============================================
|
|
51
53
|
// INICIALIZAÇÃO
|
|
@@ -82,8 +84,11 @@ async function initFluwaTool(partialConfig = {}) {
|
|
|
82
84
|
const requestLogger = new RequestLogger_1.RequestLogger(httpClient, logger);
|
|
83
85
|
// 6. Criar interceptador de fetch
|
|
84
86
|
fetchInterceptor = new FetchInterceptor_1.FetchInterceptor(logger, requestLogger, mockResolver, sessionId, config.getAppName());
|
|
87
|
+
// 6b. Criar interceptador de XMLHttpRequest (para axios, jQuery, etc)
|
|
88
|
+
xmlHttpRequestInterceptor = new XMLHttpRequestInterceptor_1.XMLHttpRequestInterceptor(logger, requestLogger, mockResolver, sessionId, config.getAppName());
|
|
85
89
|
// 7. Instalar interceptadores
|
|
86
90
|
fetchInterceptor.install();
|
|
91
|
+
xmlHttpRequestInterceptor.install();
|
|
87
92
|
// 8. Conectar WebSocket
|
|
88
93
|
logger.debug('Conectando ao WebSocket...');
|
|
89
94
|
try {
|
|
@@ -139,6 +144,7 @@ function disableFluwaTool() {
|
|
|
139
144
|
return;
|
|
140
145
|
}
|
|
141
146
|
fetchInterceptor.uninstall();
|
|
147
|
+
xmlHttpRequestInterceptor.uninstall();
|
|
142
148
|
wsClient.disconnect();
|
|
143
149
|
isInitialized = false;
|
|
144
150
|
logger.success('Fluwa-Tool desativado');
|
|
@@ -151,6 +157,7 @@ async function enableFluwaTool() {
|
|
|
151
157
|
return;
|
|
152
158
|
}
|
|
153
159
|
fetchInterceptor.install();
|
|
160
|
+
xmlHttpRequestInterceptor.install();
|
|
154
161
|
try {
|
|
155
162
|
await wsClient.connect();
|
|
156
163
|
}
|