@fluwa-tool/sdk 1.0.31 → 1.0.32
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/dist/features/network/FetchInterceptor.d.ts +3 -1
- package/dist/features/network/FetchInterceptor.js +12 -3
- package/dist/features/network/UrlFilter.d.ts +134 -0
- package/dist/features/network/UrlFilter.js +179 -0
- package/dist/features/network/XMLHttpRequestInterceptor.d.ts +3 -1
- package/dist/features/network/XMLHttpRequestInterceptor.js +9 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +19 -8
- package/dist/types/index.d.ts +2 -0
- package/package.json +1 -1
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { ILogger } from '../../core/Logger';
|
|
6
6
|
import { IRequestLogger } from './RequestLogger';
|
|
7
7
|
import { IMockResolver } from './MockResolver';
|
|
8
|
+
import { IUrlFilter } from './UrlFilter';
|
|
8
9
|
export interface IFetchInterceptor {
|
|
9
10
|
install(): void;
|
|
10
11
|
uninstall(): void;
|
|
@@ -22,7 +23,8 @@ export declare class FetchInterceptor implements IFetchInterceptor {
|
|
|
22
23
|
private originalFetch;
|
|
23
24
|
private isInstalled;
|
|
24
25
|
private isIntercepting;
|
|
25
|
-
|
|
26
|
+
private urlFilter;
|
|
27
|
+
constructor(logger: ILogger, requestLogger: IRequestLogger, mockResolver: IMockResolver, sessionId: string, appName: string, urlFilter?: IUrlFilter);
|
|
26
28
|
/**
|
|
27
29
|
* Instalar o interceptador
|
|
28
30
|
* Substitui fetch global
|
|
@@ -11,7 +11,7 @@ const types_1 = require("../../types");
|
|
|
11
11
|
* Preserva fetch original e sobrescreve com versão interceptada
|
|
12
12
|
*/
|
|
13
13
|
class FetchInterceptor {
|
|
14
|
-
constructor(logger, requestLogger, mockResolver, sessionId, appName) {
|
|
14
|
+
constructor(logger, requestLogger, mockResolver, sessionId, appName, urlFilter) {
|
|
15
15
|
this.logger = logger;
|
|
16
16
|
this.requestLogger = requestLogger;
|
|
17
17
|
this.mockResolver = mockResolver;
|
|
@@ -20,6 +20,8 @@ class FetchInterceptor {
|
|
|
20
20
|
this.originalFetch = null;
|
|
21
21
|
this.isInstalled = false;
|
|
22
22
|
this.isIntercepting = false; // Flag para prevenir re-intercepção
|
|
23
|
+
this.urlFilter = null; // URL filter para evitar loops infinitos
|
|
24
|
+
this.urlFilter = urlFilter || null;
|
|
23
25
|
}
|
|
24
26
|
/**
|
|
25
27
|
* Instalar o interceptador
|
|
@@ -65,18 +67,25 @@ class FetchInterceptor {
|
|
|
65
67
|
return async (...args) => {
|
|
66
68
|
const startTime = performance.now();
|
|
67
69
|
const [resource, init] = args;
|
|
70
|
+
// Extrair URL da requisição (necessário para o filter)
|
|
71
|
+
const url = typeof resource === 'string' ? resource : (resource instanceof Request ? resource.url : resource.toString());
|
|
68
72
|
// Evitar re-intercepção: se já estamos interceptando, usar fetch original
|
|
69
73
|
if (this.isIntercepting) {
|
|
70
74
|
return this.originalFetch.apply(globalThis, args);
|
|
71
75
|
}
|
|
72
|
-
//
|
|
76
|
+
// ✅ Verificar URL Filter: ignorar requisições para servidor Fluwa ou URLs excluídas
|
|
77
|
+
// Isso previne loops infinitos onde o servidor Fluwa faz requisições que são interceptadas
|
|
78
|
+
if (this.urlFilter && !this.urlFilter.shouldIntercept(url)) {
|
|
79
|
+
this.logger.debug(`🔧 [FetchInterceptor] Ignorando URL excluída: ${url} (bypass filtering)`);
|
|
80
|
+
return this.originalFetch.apply(globalThis, args);
|
|
81
|
+
}
|
|
82
|
+
// Ignorar requisições internas do Fluwa (header X-Fluwa-Internal - legacy support)
|
|
73
83
|
if (this.isFluwaInternalRequest(init)) {
|
|
74
84
|
// Usar fetch original para requisições internas
|
|
75
85
|
return this.originalFetch.apply(globalThis, args);
|
|
76
86
|
}
|
|
77
87
|
// Extrair informações da requisição
|
|
78
88
|
const method = (init?.method || 'GET').toUpperCase();
|
|
79
|
-
const url = typeof resource === 'string' ? resource : (resource instanceof Request ? resource.url : resource.toString());
|
|
80
89
|
const requestId = this.generateId();
|
|
81
90
|
const requestMetadata = {
|
|
82
91
|
id: requestId,
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🔧 URL Filter System for Fluwa SDK
|
|
3
|
+
*
|
|
4
|
+
* Provides a robust filtering mechanism to prevent intercepting internal Fluwa server
|
|
5
|
+
* requests, avoiding infinite request loops and ensuring proper request tracking.
|
|
6
|
+
*
|
|
7
|
+
* Problem: Fluwa SDK intercepts ALL HTTP requests, including those made by Fluwa Server
|
|
8
|
+
* itself to the Fluwa server (POST /api/requests, GET /api/scenarios/active).
|
|
9
|
+
* This creates infinite loops where internal requests are tracked and re-triggered.
|
|
10
|
+
*
|
|
11
|
+
* Solution: Filter URLs BEFORE they reach the Fluwa interceptors (fetch, XHR).
|
|
12
|
+
* Only requests NOT in the exclusion list will be tracked by Fluwa.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const filter = createUrlFilter({
|
|
17
|
+
* serverUrl: 'http://192.168.0.6:5555',
|
|
18
|
+
* excludedUrls: ['/api/requests', '/api/scenarios'],
|
|
19
|
+
* mode: 'startsWith',
|
|
20
|
+
* debug: true
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* // Check if URL should be intercepted
|
|
24
|
+
* const shouldIntercept = filter.shouldIntercept('https://api.example.com/users');
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Configuration object for URL filtering
|
|
29
|
+
*/
|
|
30
|
+
export interface UrlFilterConfig {
|
|
31
|
+
/** Base URL of the Fluwa server (e.g., 'http://192.168.0.6:5555') */
|
|
32
|
+
serverUrl: string;
|
|
33
|
+
/** Additional URLs to exclude from interception (optional) */
|
|
34
|
+
excludedUrls?: string[];
|
|
35
|
+
/** Matching strategy for URL comparison */
|
|
36
|
+
mode?: 'startsWith' | 'exact' | 'regex';
|
|
37
|
+
/** Enable debug logging for filter decisions */
|
|
38
|
+
debug?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Result of a URL filtering check
|
|
42
|
+
*/
|
|
43
|
+
export interface FilterCheckResult {
|
|
44
|
+
/** Whether the URL should be intercepted by Fluwa */
|
|
45
|
+
shouldIntercept: boolean;
|
|
46
|
+
/** Reason why the URL was filtered (for debugging) */
|
|
47
|
+
reason?: string;
|
|
48
|
+
/** Which rule matched this URL (for debugging) */
|
|
49
|
+
matchedRule?: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* URL Filter interface with filtering methods
|
|
53
|
+
*/
|
|
54
|
+
export interface IUrlFilter {
|
|
55
|
+
/**
|
|
56
|
+
* Check if a URL should be intercepted by Fluwa
|
|
57
|
+
* @param url - Full URL or path to check
|
|
58
|
+
* @returns Whether the URL should be intercepted
|
|
59
|
+
*/
|
|
60
|
+
shouldIntercept(url: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Get detailed information about why a URL was filtered
|
|
63
|
+
* @param url - Full URL or path to check
|
|
64
|
+
* @returns Detailed filter result with reasoning
|
|
65
|
+
*/
|
|
66
|
+
checkUrl(url: string): FilterCheckResult;
|
|
67
|
+
/**
|
|
68
|
+
* Get the list of all excluded URL patterns
|
|
69
|
+
* @returns Array of excluded patterns
|
|
70
|
+
*/
|
|
71
|
+
getExcludedPatterns(): string[];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* UrlFilter implementation
|
|
75
|
+
* Encapsulates URL filtering logic with support for multiple matching strategies
|
|
76
|
+
*/
|
|
77
|
+
export declare class UrlFilter implements IUrlFilter {
|
|
78
|
+
private normalizedServerUrl;
|
|
79
|
+
private normalizedExcludedUrls;
|
|
80
|
+
private matchMode;
|
|
81
|
+
private debug;
|
|
82
|
+
constructor(config: UrlFilterConfig);
|
|
83
|
+
/**
|
|
84
|
+
* Normalize URLs for consistent comparison
|
|
85
|
+
* - Remove trailing slashes
|
|
86
|
+
* - Handle both full URLs and paths
|
|
87
|
+
*/
|
|
88
|
+
private normalizeUrl;
|
|
89
|
+
/**
|
|
90
|
+
* Check if URL matches using the configured matching mode
|
|
91
|
+
*/
|
|
92
|
+
private matchesPattern;
|
|
93
|
+
/**
|
|
94
|
+
* Detailed URL check with reasoning
|
|
95
|
+
* Returns why a URL was filtered or allowed
|
|
96
|
+
*/
|
|
97
|
+
checkUrl(url: string): FilterCheckResult;
|
|
98
|
+
/**
|
|
99
|
+
* Simple yes/no check for URL interception
|
|
100
|
+
* Useful for early filtering before deeper processing
|
|
101
|
+
*/
|
|
102
|
+
shouldIntercept(url: string): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Get all excluded patterns for debugging and introspection
|
|
105
|
+
*/
|
|
106
|
+
getExcludedPatterns(): string[];
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Standard exclusion patterns for internal Fluwa server requests
|
|
110
|
+
* These are the known endpoints that should NOT be tracked by Fluwa SDK
|
|
111
|
+
*/
|
|
112
|
+
export declare const FLUWA_INTERNAL_PATHS: string[];
|
|
113
|
+
/**
|
|
114
|
+
* Factory function to create a pre-configured filter for Fluwa SDK
|
|
115
|
+
* Automatically excludes known internal server paths
|
|
116
|
+
*
|
|
117
|
+
* @param serverUrl - Base URL of the Fluwa server
|
|
118
|
+
* @param additionalExclusions - Extra URLs to exclude (optional)
|
|
119
|
+
* @param debug - Enable debug logging
|
|
120
|
+
* @returns Configured UrlFilter instance
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* const filter = createFluwaSdkFilter('http://192.168.0.6:5555', [
|
|
125
|
+
* '/custom-internal-endpoint'
|
|
126
|
+
* ]);
|
|
127
|
+
*
|
|
128
|
+
* // Check if request should bypass Fluwa interception
|
|
129
|
+
* if (!filter.shouldIntercept(requestUrl)) {
|
|
130
|
+
* // Make request without Fluwa tracking
|
|
131
|
+
* }
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export declare function createFluwaSdkFilter(serverUrl: string, additionalExclusions?: string[], debug?: boolean): IUrlFilter;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 🔧 URL Filter System for Fluwa SDK
|
|
4
|
+
*
|
|
5
|
+
* Provides a robust filtering mechanism to prevent intercepting internal Fluwa server
|
|
6
|
+
* requests, avoiding infinite request loops and ensuring proper request tracking.
|
|
7
|
+
*
|
|
8
|
+
* Problem: Fluwa SDK intercepts ALL HTTP requests, including those made by Fluwa Server
|
|
9
|
+
* itself to the Fluwa server (POST /api/requests, GET /api/scenarios/active).
|
|
10
|
+
* This creates infinite loops where internal requests are tracked and re-triggered.
|
|
11
|
+
*
|
|
12
|
+
* Solution: Filter URLs BEFORE they reach the Fluwa interceptors (fetch, XHR).
|
|
13
|
+
* Only requests NOT in the exclusion list will be tracked by Fluwa.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const filter = createUrlFilter({
|
|
18
|
+
* serverUrl: 'http://192.168.0.6:5555',
|
|
19
|
+
* excludedUrls: ['/api/requests', '/api/scenarios'],
|
|
20
|
+
* mode: 'startsWith',
|
|
21
|
+
* debug: true
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* // Check if URL should be intercepted
|
|
25
|
+
* const shouldIntercept = filter.shouldIntercept('https://api.example.com/users');
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.FLUWA_INTERNAL_PATHS = exports.UrlFilter = void 0;
|
|
30
|
+
exports.createFluwaSdkFilter = createFluwaSdkFilter;
|
|
31
|
+
/**
|
|
32
|
+
* UrlFilter implementation
|
|
33
|
+
* Encapsulates URL filtering logic with support for multiple matching strategies
|
|
34
|
+
*/
|
|
35
|
+
class UrlFilter {
|
|
36
|
+
constructor(config) {
|
|
37
|
+
const { serverUrl, excludedUrls = [], mode = 'startsWith', debug = false } = config;
|
|
38
|
+
this.normalizedServerUrl = this.normalizeUrl(serverUrl);
|
|
39
|
+
this.normalizedExcludedUrls = excludedUrls.map((url) => this.normalizeUrl(url));
|
|
40
|
+
this.matchMode = mode;
|
|
41
|
+
this.debug = debug;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Normalize URLs for consistent comparison
|
|
45
|
+
* - Remove trailing slashes
|
|
46
|
+
* - Handle both full URLs and paths
|
|
47
|
+
*/
|
|
48
|
+
normalizeUrl(url) {
|
|
49
|
+
try {
|
|
50
|
+
// Handle full URLs
|
|
51
|
+
if (url.startsWith('http://') || url.startsWith('https://')) {
|
|
52
|
+
return url.replace(/\/$/, '');
|
|
53
|
+
}
|
|
54
|
+
// Handle relative paths
|
|
55
|
+
return url.replace(/\/$/, '');
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return url;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if URL matches using the configured matching mode
|
|
63
|
+
*/
|
|
64
|
+
matchesPattern(url, pattern) {
|
|
65
|
+
const normalizedUrl = this.normalizeUrl(url);
|
|
66
|
+
switch (this.matchMode) {
|
|
67
|
+
case 'exact':
|
|
68
|
+
return normalizedUrl === pattern;
|
|
69
|
+
case 'regex': {
|
|
70
|
+
try {
|
|
71
|
+
const regex = new RegExp(pattern);
|
|
72
|
+
return regex.test(normalizedUrl);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
console.warn(`🔧 [UrlFilter] Invalid regex pattern: "${pattern}"`, error);
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
case 'startsWith':
|
|
80
|
+
default:
|
|
81
|
+
return normalizedUrl.startsWith(pattern);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Detailed URL check with reasoning
|
|
86
|
+
* Returns why a URL was filtered or allowed
|
|
87
|
+
*/
|
|
88
|
+
checkUrl(url) {
|
|
89
|
+
const normalizedUrl = this.normalizeUrl(url);
|
|
90
|
+
// Check if URL is the Fluwa server itself
|
|
91
|
+
if (this.matchesPattern(normalizedUrl, this.normalizedServerUrl)) {
|
|
92
|
+
const result = {
|
|
93
|
+
shouldIntercept: false,
|
|
94
|
+
reason: 'URL is Fluwa server (internal request)',
|
|
95
|
+
matchedRule: 'serverUrl',
|
|
96
|
+
};
|
|
97
|
+
if (this.debug) {
|
|
98
|
+
console.log(`🔧 [UrlFilter] Excluded: ${url} - ${result.reason}`);
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
// Check against explicitly excluded URLs
|
|
103
|
+
for (const excludedUrl of this.normalizedExcludedUrls) {
|
|
104
|
+
if (this.matchesPattern(normalizedUrl, excludedUrl)) {
|
|
105
|
+
const result = {
|
|
106
|
+
shouldIntercept: false,
|
|
107
|
+
reason: `URL matches excluded pattern: "${excludedUrl}"`,
|
|
108
|
+
matchedRule: excludedUrl,
|
|
109
|
+
};
|
|
110
|
+
if (this.debug) {
|
|
111
|
+
console.log(`🔧 [UrlFilter] Excluded: ${url} - ${result.reason}`);
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// URL should be intercepted by Fluwa
|
|
117
|
+
const result = {
|
|
118
|
+
shouldIntercept: true,
|
|
119
|
+
reason: 'URL should be tracked by Fluwa',
|
|
120
|
+
};
|
|
121
|
+
if (this.debug) {
|
|
122
|
+
console.log(`🔧 [UrlFilter] Intercepting: ${url}`);
|
|
123
|
+
}
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Simple yes/no check for URL interception
|
|
128
|
+
* Useful for early filtering before deeper processing
|
|
129
|
+
*/
|
|
130
|
+
shouldIntercept(url) {
|
|
131
|
+
return this.checkUrl(url).shouldIntercept;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get all excluded patterns for debugging and introspection
|
|
135
|
+
*/
|
|
136
|
+
getExcludedPatterns() {
|
|
137
|
+
return [this.normalizedServerUrl, ...this.normalizedExcludedUrls];
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.UrlFilter = UrlFilter;
|
|
141
|
+
/**
|
|
142
|
+
* Standard exclusion patterns for internal Fluwa server requests
|
|
143
|
+
* These are the known endpoints that should NOT be tracked by Fluwa SDK
|
|
144
|
+
*/
|
|
145
|
+
exports.FLUWA_INTERNAL_PATHS = [
|
|
146
|
+
'/api/requests', // Request registration endpoint
|
|
147
|
+
'/api/scenarios', // Scenario management
|
|
148
|
+
'/api/recordings', // Recording management
|
|
149
|
+
'/health', // Health check endpoint
|
|
150
|
+
];
|
|
151
|
+
/**
|
|
152
|
+
* Factory function to create a pre-configured filter for Fluwa SDK
|
|
153
|
+
* Automatically excludes known internal server paths
|
|
154
|
+
*
|
|
155
|
+
* @param serverUrl - Base URL of the Fluwa server
|
|
156
|
+
* @param additionalExclusions - Extra URLs to exclude (optional)
|
|
157
|
+
* @param debug - Enable debug logging
|
|
158
|
+
* @returns Configured UrlFilter instance
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* const filter = createFluwaSdkFilter('http://192.168.0.6:5555', [
|
|
163
|
+
* '/custom-internal-endpoint'
|
|
164
|
+
* ]);
|
|
165
|
+
*
|
|
166
|
+
* // Check if request should bypass Fluwa interception
|
|
167
|
+
* if (!filter.shouldIntercept(requestUrl)) {
|
|
168
|
+
* // Make request without Fluwa tracking
|
|
169
|
+
* }
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
function createFluwaSdkFilter(serverUrl, additionalExclusions, debug) {
|
|
173
|
+
return new UrlFilter({
|
|
174
|
+
serverUrl,
|
|
175
|
+
excludedUrls: [...exports.FLUWA_INTERNAL_PATHS, ...(additionalExclusions || [])],
|
|
176
|
+
mode: 'startsWith',
|
|
177
|
+
debug,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { ILogger } from '../../core/Logger';
|
|
6
6
|
import { IRequestLogger } from './RequestLogger';
|
|
7
7
|
import { IMockResolver } from './MockResolver';
|
|
8
|
+
import { IUrlFilter } from './UrlFilter';
|
|
8
9
|
export interface IXMLHttpRequestInterceptor {
|
|
9
10
|
install(): void;
|
|
10
11
|
uninstall(): void;
|
|
@@ -19,7 +20,8 @@ export declare class XMLHttpRequestInterceptor implements IXMLHttpRequestInterce
|
|
|
19
20
|
private originalSend;
|
|
20
21
|
private originalSetRequestHeader;
|
|
21
22
|
private isInstalled;
|
|
22
|
-
|
|
23
|
+
private urlFilter;
|
|
24
|
+
constructor(logger: ILogger, requestLogger: IRequestLogger, mockResolver: IMockResolver, sessionId: string, appName: string, urlFilter?: IUrlFilter);
|
|
23
25
|
install(): void;
|
|
24
26
|
uninstall(): void;
|
|
25
27
|
private safeParseBody;
|
|
@@ -7,13 +7,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.XMLHttpRequestInterceptor = void 0;
|
|
8
8
|
const types_1 = require("../../types");
|
|
9
9
|
class XMLHttpRequestInterceptor {
|
|
10
|
-
constructor(logger, requestLogger, mockResolver, sessionId, appName) {
|
|
10
|
+
constructor(logger, requestLogger, mockResolver, sessionId, appName, urlFilter) {
|
|
11
11
|
this.logger = logger;
|
|
12
12
|
this.requestLogger = requestLogger;
|
|
13
13
|
this.mockResolver = mockResolver;
|
|
14
14
|
this.sessionId = sessionId;
|
|
15
15
|
this.appName = appName;
|
|
16
16
|
this.isInstalled = false;
|
|
17
|
+
this.urlFilter = null; // URL filter para evitar loops infinitos
|
|
18
|
+
this.urlFilter = urlFilter || null;
|
|
17
19
|
}
|
|
18
20
|
install() {
|
|
19
21
|
if (this.isInstalled) {
|
|
@@ -58,6 +60,12 @@ class XMLHttpRequestInterceptor {
|
|
|
58
60
|
const url = xhr._fluwaUrl;
|
|
59
61
|
const requestId = xhr._fluwaRequestId;
|
|
60
62
|
const headers = xhr._fluwaHeaders || {};
|
|
63
|
+
// ✅ Verificar URL Filter: ignorar requisições para servidor Fluwa ou URLs excluídas
|
|
64
|
+
// Isso previne loops infinitos onde o servidor Fluwa faz requisições que são interceptadas
|
|
65
|
+
if (self.urlFilter && !self.urlFilter.shouldIntercept(url)) {
|
|
66
|
+
self.logger.debug(`🔧 [XMLHttpRequestInterceptor] Ignorando URL excluída: ${url} (bypass filtering)`);
|
|
67
|
+
return self.originalSend.apply(this, [body]);
|
|
68
|
+
}
|
|
61
69
|
const requestMetadata = {
|
|
62
70
|
id: requestId,
|
|
63
71
|
method,
|
package/dist/index.d.ts
CHANGED
|
@@ -27,3 +27,4 @@ export declare function isFluwaTooIialized(): boolean;
|
|
|
27
27
|
export * from './types';
|
|
28
28
|
export { Logger, LogLevel } from './core/Logger';
|
|
29
29
|
export { ConfigManager } from './core/Config';
|
|
30
|
+
export { UrlFilter, createFluwaSdkFilter, FLUWA_INTERNAL_PATHS, type UrlFilterConfig, type FilterCheckResult, type IUrlFilter, } from './features/network/UrlFilter';
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
22
22
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.ConfigManager = exports.LogLevel = exports.Logger = void 0;
|
|
25
|
+
exports.FLUWA_INTERNAL_PATHS = exports.createFluwaSdkFilter = exports.UrlFilter = exports.ConfigManager = exports.LogLevel = exports.Logger = void 0;
|
|
26
26
|
exports.initFluwaTool = initFluwaTool;
|
|
27
27
|
exports.disableFluwaTool = disableFluwaTool;
|
|
28
28
|
exports.enableFluwaTool = enableFluwaTool;
|
|
@@ -36,6 +36,7 @@ const FetchInterceptor_1 = require("./features/network/FetchInterceptor");
|
|
|
36
36
|
const XMLHttpRequestInterceptor_1 = require("./features/network/XMLHttpRequestInterceptor");
|
|
37
37
|
const RequestLogger_1 = require("./features/network/RequestLogger");
|
|
38
38
|
const MockResolver_1 = require("./features/network/MockResolver");
|
|
39
|
+
const UrlFilter_1 = require("./features/network/UrlFilter");
|
|
39
40
|
const IdGenerator_1 = require("./core/IdGenerator");
|
|
40
41
|
// ============================================
|
|
41
42
|
// ESTADO GLOBAL
|
|
@@ -49,6 +50,7 @@ let wsClient;
|
|
|
49
50
|
let fetchInterceptor;
|
|
50
51
|
let xmlHttpRequestInterceptor;
|
|
51
52
|
let mockResolver;
|
|
53
|
+
let urlFilter = null; // URL filter para evitar loops infinitos
|
|
52
54
|
// ============================================
|
|
53
55
|
// INICIALIZAÇÃO
|
|
54
56
|
// ============================================
|
|
@@ -82,14 +84,19 @@ async function initFluwaTool(partialConfig = {}) {
|
|
|
82
84
|
mockResolver = new MockResolver_1.MockResolver(httpClient, logger);
|
|
83
85
|
// 5. Criar logger de requisições
|
|
84
86
|
const requestLogger = new RequestLogger_1.RequestLogger(httpClient, logger);
|
|
85
|
-
// 6. Criar
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
// 6. ✅ Criar URL Filter para evitar loops infinitos
|
|
88
|
+
// Automatically excludes Fluwa server URLs and internal endpoints
|
|
89
|
+
const { excludedUrls } = config.getConfig();
|
|
90
|
+
urlFilter = (0, UrlFilter_1.createFluwaSdkFilter)(serverUrl, excludedUrls, config.getConfig().debug);
|
|
91
|
+
logger.debug(`URL Filter configurado com ${urlFilter.getExcludedPatterns().length} padrões excluídos`);
|
|
92
|
+
// 7. Criar interceptador de fetch
|
|
93
|
+
fetchInterceptor = new FetchInterceptor_1.FetchInterceptor(logger, requestLogger, mockResolver, sessionId, config.getAppName(), urlFilter);
|
|
94
|
+
// 7b. Criar interceptador de XMLHttpRequest (para axios, jQuery, etc)
|
|
95
|
+
xmlHttpRequestInterceptor = new XMLHttpRequestInterceptor_1.XMLHttpRequestInterceptor(logger, requestLogger, mockResolver, sessionId, config.getAppName(), urlFilter);
|
|
96
|
+
// 8. Instalar interceptadores
|
|
90
97
|
fetchInterceptor.install();
|
|
91
98
|
xmlHttpRequestInterceptor.install();
|
|
92
|
-
//
|
|
99
|
+
// 9. Conectar WebSocket
|
|
93
100
|
logger.debug('Conectando ao WebSocket...');
|
|
94
101
|
try {
|
|
95
102
|
await wsClient.connect();
|
|
@@ -98,7 +105,7 @@ async function initFluwaTool(partialConfig = {}) {
|
|
|
98
105
|
catch (error) {
|
|
99
106
|
logger.warn('Falha ao conectar WebSocket, continuando em modo offline', error);
|
|
100
107
|
}
|
|
101
|
-
//
|
|
108
|
+
// 10. Enviar init session
|
|
102
109
|
wsClient.send({
|
|
103
110
|
type: types_1.WebSocketMessageType.INIT_SESSION,
|
|
104
111
|
sessionId,
|
|
@@ -182,3 +189,7 @@ Object.defineProperty(exports, "Logger", { enumerable: true, get: function () {
|
|
|
182
189
|
Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return Logger_2.LogLevel; } });
|
|
183
190
|
var Config_2 = require("./core/Config");
|
|
184
191
|
Object.defineProperty(exports, "ConfigManager", { enumerable: true, get: function () { return Config_2.ConfigManager; } });
|
|
192
|
+
var UrlFilter_2 = require("./features/network/UrlFilter");
|
|
193
|
+
Object.defineProperty(exports, "UrlFilter", { enumerable: true, get: function () { return UrlFilter_2.UrlFilter; } });
|
|
194
|
+
Object.defineProperty(exports, "createFluwaSdkFilter", { enumerable: true, get: function () { return UrlFilter_2.createFluwaSdkFilter; } });
|
|
195
|
+
Object.defineProperty(exports, "FLUWA_INTERNAL_PATHS", { enumerable: true, get: function () { return UrlFilter_2.FLUWA_INTERNAL_PATHS; } });
|
package/dist/types/index.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ export interface FluwaConfig {
|
|
|
13
13
|
debug?: boolean;
|
|
14
14
|
/** Timeout para requisições (ms) */
|
|
15
15
|
requestTimeout?: number;
|
|
16
|
+
/** URLs adicionais para excluir da interception (evita loops infinitos) */
|
|
17
|
+
excludedUrls?: string[];
|
|
16
18
|
}
|
|
17
19
|
export declare enum HttpMethod {
|
|
18
20
|
GET = "GET",
|