@fluwa-tool/sdk 1.0.0
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/core/Config.d.ts +28 -0
- package/dist/core/Config.js +74 -0
- package/dist/core/IdGenerator.d.ts +19 -0
- package/dist/core/IdGenerator.js +25 -0
- package/dist/core/Logger.d.ts +38 -0
- package/dist/core/Logger.js +76 -0
- package/dist/features/communication/HttpClient.d.ts +41 -0
- package/dist/features/communication/HttpClient.js +88 -0
- package/dist/features/communication/WebSocketClient.d.ts +61 -0
- package/dist/features/communication/WebSocketClient.js +158 -0
- package/dist/features/network/FetchInterceptor.d.ts +51 -0
- package/dist/features/network/FetchInterceptor.js +172 -0
- package/dist/features/network/MockResolver.d.ts +49 -0
- package/dist/features/network/MockResolver.js +129 -0
- package/dist/features/network/RequestLogger.d.ts +28 -0
- package/dist/features/network/RequestLogger.js +42 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +177 -0
- package/dist/types/index.d.ts +107 -0
- package/dist/types/index.js +39 -0
- package/package.json +39 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Interceptador de fetch nativo do navegador
|
|
4
|
+
* Responsabilidade única: interceptar e logar requisições fetch
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.FetchInterceptor = void 0;
|
|
8
|
+
const types_1 = require("../../types");
|
|
9
|
+
/**
|
|
10
|
+
* Implementação de interceptador de fetch
|
|
11
|
+
* Preserva fetch original e sobrescreve com versão interceptada
|
|
12
|
+
*/
|
|
13
|
+
class FetchInterceptor {
|
|
14
|
+
constructor(logger, requestLogger, mockResolver, sessionId, appName) {
|
|
15
|
+
this.logger = logger;
|
|
16
|
+
this.requestLogger = requestLogger;
|
|
17
|
+
this.mockResolver = mockResolver;
|
|
18
|
+
this.sessionId = sessionId;
|
|
19
|
+
this.appName = appName;
|
|
20
|
+
this.originalFetch = null;
|
|
21
|
+
this.isInstalled = false;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Instalar o interceptador
|
|
25
|
+
* Substitui fetch global
|
|
26
|
+
*/
|
|
27
|
+
install() {
|
|
28
|
+
if (this.isInstalled) {
|
|
29
|
+
this.logger.warn('Fetch interceptor já foi instalado');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// Detectar ambiente (navegador ou Node.js)
|
|
33
|
+
const isBrowser = typeof window !== 'undefined';
|
|
34
|
+
const globalObj = isBrowser ? window : globalThis;
|
|
35
|
+
if (typeof globalObj.fetch === 'undefined') {
|
|
36
|
+
this.logger.warn('Fetch não disponível nesse ambiente');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
this.originalFetch = globalObj.fetch;
|
|
40
|
+
// Sobrescrever fetch global
|
|
41
|
+
globalObj.fetch = this.createInterceptedFetch();
|
|
42
|
+
this.isInstalled = true;
|
|
43
|
+
this.logger.success('Fetch interceptor instalado');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Desinstalar o interceptador
|
|
47
|
+
* Restaura fetch original
|
|
48
|
+
*/
|
|
49
|
+
uninstall() {
|
|
50
|
+
if (!this.isInstalled || !this.originalFetch) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const isBrowser = typeof window !== 'undefined';
|
|
54
|
+
const globalObj = isBrowser ? window : globalThis;
|
|
55
|
+
globalObj.fetch = this.originalFetch;
|
|
56
|
+
this.originalFetch = null;
|
|
57
|
+
this.isInstalled = false;
|
|
58
|
+
this.logger.success('Fetch interceptor desinstalado');
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Criar versão interceptada de fetch
|
|
62
|
+
*/
|
|
63
|
+
createInterceptedFetch() {
|
|
64
|
+
return async (...args) => {
|
|
65
|
+
const startTime = performance.now();
|
|
66
|
+
const [resource, init] = args;
|
|
67
|
+
// Ignorar requisições internas do Fluwa (header X-Fluwa-Internal)
|
|
68
|
+
if (init?.headers && typeof init.headers === 'object') {
|
|
69
|
+
const headers = init.headers;
|
|
70
|
+
if (headers['X-Fluwa-Internal'] === 'true') {
|
|
71
|
+
// Usar fetch original para requisições internas
|
|
72
|
+
return this.originalFetch.apply(globalThis, args);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Extrair informações da requisição
|
|
76
|
+
const method = (init?.method || 'GET').toUpperCase();
|
|
77
|
+
const url = typeof resource === 'string' ? resource : (resource instanceof Request ? resource.url : resource.toString());
|
|
78
|
+
const requestId = this.generateId();
|
|
79
|
+
const requestMetadata = {
|
|
80
|
+
id: requestId,
|
|
81
|
+
method,
|
|
82
|
+
url,
|
|
83
|
+
headers: init?.headers || {},
|
|
84
|
+
body: init?.body ? this.safeParseBody(init.body) : undefined,
|
|
85
|
+
timestamp: new Date().toISOString(),
|
|
86
|
+
sessionId: this.sessionId,
|
|
87
|
+
appName: this.appName,
|
|
88
|
+
source: types_1.RequestSource.REAL, // Default, pode mudar se usar mock
|
|
89
|
+
};
|
|
90
|
+
try {
|
|
91
|
+
// Registrar que começou
|
|
92
|
+
await this.requestLogger.logStart(requestMetadata);
|
|
93
|
+
// Verificar se há mock disponível
|
|
94
|
+
const mockResponse = await this.mockResolver.resolve(method, url);
|
|
95
|
+
if (mockResponse) {
|
|
96
|
+
// Usar mock
|
|
97
|
+
requestMetadata.source = types_1.RequestSource.MOCK;
|
|
98
|
+
requestMetadata.response = mockResponse.response;
|
|
99
|
+
requestMetadata.status = mockResponse.status;
|
|
100
|
+
// Aplicar delay se configurado
|
|
101
|
+
if (mockResponse.delay) {
|
|
102
|
+
await this.delay(mockResponse.delay);
|
|
103
|
+
}
|
|
104
|
+
const duration = performance.now() - startTime;
|
|
105
|
+
requestMetadata.duration = duration;
|
|
106
|
+
// Registrar completamento
|
|
107
|
+
await this.requestLogger.logComplete(requestMetadata);
|
|
108
|
+
// Retornar mock como Response
|
|
109
|
+
return new Response(JSON.stringify(mockResponse.response), {
|
|
110
|
+
status: mockResponse.status || 200,
|
|
111
|
+
statusText: 'Mock',
|
|
112
|
+
headers: { 'Content-Type': 'application/json' },
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
// Fazer request real
|
|
116
|
+
const response = await this.originalFetch.apply(globalThis, args);
|
|
117
|
+
const responseClone = response.clone();
|
|
118
|
+
requestMetadata.source = types_1.RequestSource.REAL;
|
|
119
|
+
requestMetadata.status = response.status;
|
|
120
|
+
// Tentar extrair body da resposta
|
|
121
|
+
try {
|
|
122
|
+
const responseBody = await responseClone.json();
|
|
123
|
+
requestMetadata.response = responseBody;
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
// Se não conseguir parsear JSON, deixa vazio
|
|
127
|
+
}
|
|
128
|
+
const duration = performance.now() - startTime;
|
|
129
|
+
requestMetadata.duration = duration;
|
|
130
|
+
// Registrar completamento
|
|
131
|
+
await this.requestLogger.logComplete(requestMetadata);
|
|
132
|
+
return response;
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
const duration = performance.now() - startTime;
|
|
136
|
+
requestMetadata.source = types_1.RequestSource.ERROR;
|
|
137
|
+
requestMetadata.duration = duration;
|
|
138
|
+
requestMetadata.error = error instanceof Error ? error.message : String(error);
|
|
139
|
+
// Registrar erro
|
|
140
|
+
await this.requestLogger.logComplete(requestMetadata);
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Parse seguro do body (string ou object)
|
|
147
|
+
*/
|
|
148
|
+
safeParseBody(body) {
|
|
149
|
+
if (typeof body === 'string') {
|
|
150
|
+
try {
|
|
151
|
+
return JSON.parse(body);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return body;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return body;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Gerar ID único para requisição
|
|
161
|
+
*/
|
|
162
|
+
generateId() {
|
|
163
|
+
return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Sleep (para delays de mock)
|
|
167
|
+
*/
|
|
168
|
+
delay(ms) {
|
|
169
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
exports.FetchInterceptor = FetchInterceptor;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolvedor de mocks
|
|
3
|
+
* Responsabilidade única: encontrar e retornar mock baseado em URL/método
|
|
4
|
+
*/
|
|
5
|
+
import { ILogger } from '../../core/Logger';
|
|
6
|
+
import { HttpMethod, MockRoute } from '../../types';
|
|
7
|
+
import { IHttpClient } from '../communication/HttpClient';
|
|
8
|
+
export interface IMockResolver {
|
|
9
|
+
resolve(method: HttpMethod, url: string): Promise<MockRoute | null>;
|
|
10
|
+
setActiveScenario(scenarioId: string | null): void;
|
|
11
|
+
refreshActiveScenario(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Implementação do resolvedor de mocks
|
|
15
|
+
* Busca cenário ativo do servidor e faz matching local
|
|
16
|
+
*/
|
|
17
|
+
export declare class MockResolver implements IMockResolver {
|
|
18
|
+
private httpClient;
|
|
19
|
+
private logger;
|
|
20
|
+
private cachedScenario;
|
|
21
|
+
private lastFetchTime;
|
|
22
|
+
private cacheTimeout;
|
|
23
|
+
constructor(httpClient: IHttpClient, logger: ILogger);
|
|
24
|
+
/**
|
|
25
|
+
* Resolver mock para método e URL
|
|
26
|
+
* Retorna null se não houver mock
|
|
27
|
+
*/
|
|
28
|
+
resolve(method: HttpMethod, url: string): Promise<MockRoute | null>;
|
|
29
|
+
/**
|
|
30
|
+
* Atualizar cenário ativo do servidor
|
|
31
|
+
*/
|
|
32
|
+
refreshActiveScenario(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Atualizar cenário ativo (interface anterior)
|
|
35
|
+
*/
|
|
36
|
+
setActiveScenario(scenarioId: string | null): void;
|
|
37
|
+
/**
|
|
38
|
+
* Encontrar rota que corresponde ao método e URL
|
|
39
|
+
*/
|
|
40
|
+
private findMatchingRoute;
|
|
41
|
+
/**
|
|
42
|
+
* Verificar se a URL atual corresponde ao padrão da rota
|
|
43
|
+
*/
|
|
44
|
+
private urlMatches;
|
|
45
|
+
/**
|
|
46
|
+
* Verificar correspondência com parâmetros
|
|
47
|
+
*/
|
|
48
|
+
private matchesParamPattern;
|
|
49
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Resolvedor de mocks
|
|
4
|
+
* Responsabilidade única: encontrar e retornar mock baseado em URL/método
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.MockResolver = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* Implementação do resolvedor de mocks
|
|
10
|
+
* Busca cenário ativo do servidor e faz matching local
|
|
11
|
+
*/
|
|
12
|
+
class MockResolver {
|
|
13
|
+
constructor(httpClient, logger) {
|
|
14
|
+
this.httpClient = httpClient;
|
|
15
|
+
this.logger = logger;
|
|
16
|
+
this.cachedScenario = null;
|
|
17
|
+
this.lastFetchTime = 0;
|
|
18
|
+
this.cacheTimeout = 5000; // 5 segundos
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Resolver mock para método e URL
|
|
22
|
+
* Retorna null se não houver mock
|
|
23
|
+
*/
|
|
24
|
+
async resolve(method, url) {
|
|
25
|
+
try {
|
|
26
|
+
// Atualizar scenario do servidor se necessário
|
|
27
|
+
await this.refreshActiveScenario();
|
|
28
|
+
if (!this.cachedScenario) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
// Encontrar rota correspondente
|
|
32
|
+
const matchingRoute = this.findMatchingRoute(method, url, this.cachedScenario.routes);
|
|
33
|
+
if (matchingRoute) {
|
|
34
|
+
this.logger.debug(`Mock encontrado para ${method} ${url}`);
|
|
35
|
+
return matchingRoute;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
this.logger.warn(`Erro ao resolver mock: ${error}`);
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Atualizar cenário ativo do servidor
|
|
46
|
+
*/
|
|
47
|
+
async refreshActiveScenario() {
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
// Usar cache se recente
|
|
50
|
+
if (this.lastFetchTime && now - this.lastFetchTime < this.cacheTimeout) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const response = await this.httpClient.get('/api/scenarios/active');
|
|
55
|
+
this.cachedScenario = response.data || null;
|
|
56
|
+
this.lastFetchTime = now;
|
|
57
|
+
if (this.cachedScenario) {
|
|
58
|
+
this.logger.debug(`Cenário ativo atualizado: ${this.cachedScenario.name}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
this.logger.debug('Nenhum cenário ativo no servidor');
|
|
63
|
+
this.cachedScenario = null;
|
|
64
|
+
this.lastFetchTime = now;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Atualizar cenário ativo (interface anterior)
|
|
69
|
+
*/
|
|
70
|
+
setActiveScenario(scenarioId) {
|
|
71
|
+
// Invalidar cache para forçar atualização do servidor
|
|
72
|
+
this.lastFetchTime = 0;
|
|
73
|
+
if (scenarioId) {
|
|
74
|
+
this.logger.info(`Cenário ativo definido para: ${scenarioId}`);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
this.logger.info('Mocks desativados');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Encontrar rota que corresponde ao método e URL
|
|
82
|
+
*/
|
|
83
|
+
findMatchingRoute(method, url, routes) {
|
|
84
|
+
return routes.find((route) => {
|
|
85
|
+
// Verificar se o método corresponde
|
|
86
|
+
if (route.method.toString() !== method.toString()) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
// Verificar se a URL corresponde
|
|
90
|
+
return this.urlMatches(url, route.url);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Verificar se a URL atual corresponde ao padrão da rota
|
|
95
|
+
*/
|
|
96
|
+
urlMatches(actualUrl, routePattern) {
|
|
97
|
+
// Remover query string e hash
|
|
98
|
+
const actualUrlPath = actualUrl.split('?')[0].split('#')[0];
|
|
99
|
+
// Correspondência exata
|
|
100
|
+
if (routePattern === actualUrlPath) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
// Correspondência com wildcard
|
|
104
|
+
if (routePattern.endsWith('/*')) {
|
|
105
|
+
const basePath = routePattern.slice(0, -2);
|
|
106
|
+
return actualUrlPath.startsWith(basePath);
|
|
107
|
+
}
|
|
108
|
+
// Correspondência com :param (ex: /api/users/:id)
|
|
109
|
+
return this.matchesParamPattern(actualUrlPath, routePattern);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Verificar correspondência com parâmetros
|
|
113
|
+
*/
|
|
114
|
+
matchesParamPattern(actualUrl, pattern) {
|
|
115
|
+
const actualParts = actualUrl.split('/').filter(Boolean);
|
|
116
|
+
const patternParts = pattern.split('/').filter(Boolean);
|
|
117
|
+
if (actualParts.length !== patternParts.length) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
return patternParts.every((patternPart, index) => {
|
|
121
|
+
const actualPart = actualParts[index];
|
|
122
|
+
if (patternPart.startsWith(':')) {
|
|
123
|
+
return actualPart !== undefined;
|
|
124
|
+
}
|
|
125
|
+
return patternPart === actualPart;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
exports.MockResolver = MockResolver;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger de requisições
|
|
3
|
+
* Responsabilidade única: enviar requisições para o servidor Fluwa
|
|
4
|
+
*/
|
|
5
|
+
import { ILogger } from '../../core/Logger';
|
|
6
|
+
import { RequestMetadata } from '../../types';
|
|
7
|
+
import { IHttpClient } from '../communication/HttpClient';
|
|
8
|
+
export interface IRequestLogger {
|
|
9
|
+
logStart(request: RequestMetadata): Promise<void>;
|
|
10
|
+
logComplete(request: RequestMetadata): Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Implementação do logger de requisições
|
|
14
|
+
* Envia dados para servidor via HTTP
|
|
15
|
+
*/
|
|
16
|
+
export declare class RequestLogger implements IRequestLogger {
|
|
17
|
+
private httpClient;
|
|
18
|
+
private logger;
|
|
19
|
+
constructor(httpClient: IHttpClient, logger: ILogger);
|
|
20
|
+
/**
|
|
21
|
+
* Logar início de uma requisição
|
|
22
|
+
*/
|
|
23
|
+
logStart(request: RequestMetadata): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Logar completamento de uma requisição
|
|
26
|
+
*/
|
|
27
|
+
logComplete(request: RequestMetadata): Promise<void>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Logger de requisições
|
|
4
|
+
* Responsabilidade única: enviar requisições para o servidor Fluwa
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.RequestLogger = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* Implementação do logger de requisições
|
|
10
|
+
* Envia dados para servidor via HTTP
|
|
11
|
+
*/
|
|
12
|
+
class RequestLogger {
|
|
13
|
+
constructor(httpClient, logger) {
|
|
14
|
+
this.httpClient = httpClient;
|
|
15
|
+
this.logger = logger;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Logar início de uma requisição
|
|
19
|
+
*/
|
|
20
|
+
async logStart(request) {
|
|
21
|
+
try {
|
|
22
|
+
await this.httpClient.post('/api/requests', request);
|
|
23
|
+
this.logger.debug(`Request iniciado: ${request.method} ${request.url}`);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
this.logger.warn(`Falha ao logar request start`, error);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Logar completamento de uma requisição
|
|
31
|
+
*/
|
|
32
|
+
async logComplete(request) {
|
|
33
|
+
try {
|
|
34
|
+
await this.httpClient.put(`/api/requests/${request.id}`, request);
|
|
35
|
+
this.logger.debug(`Request completado: ${request.method} ${request.url}`);
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
this.logger.warn(`Falha ao logar request complete`, error);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.RequestLogger = RequestLogger;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🔧 Fluwa SDK
|
|
3
|
+
* Entry point principal do SDK
|
|
4
|
+
*
|
|
5
|
+
* Uso:
|
|
6
|
+
* import { initFluwaTool } from '@fluwa-tool/sdk';
|
|
7
|
+
* initFluwaTool({ serverUrl: 'http://localhost:5555' });
|
|
8
|
+
*/
|
|
9
|
+
import { FluwaConfig } from './types';
|
|
10
|
+
/**
|
|
11
|
+
* Inicializar Fluwa-Tool
|
|
12
|
+
* Deve ser chamado no início da aplicação
|
|
13
|
+
*/
|
|
14
|
+
export declare function initFluwaTool(partialConfig?: Partial<FluwaConfig>): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Desativar Fluwa
|
|
17
|
+
*/
|
|
18
|
+
export declare function disableFluwaTool(): void;
|
|
19
|
+
/**
|
|
20
|
+
* Habilitar Fluwa
|
|
21
|
+
*/
|
|
22
|
+
export declare function enableFluwaTool(): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Verificar se Fluwa está ativo
|
|
25
|
+
*/
|
|
26
|
+
export declare function isFluwaTooIialized(): boolean;
|
|
27
|
+
export * from './types';
|
|
28
|
+
export { Logger, LogLevel } from './core/Logger';
|
|
29
|
+
export { ConfigManager } from './core/Config';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 🔧 Fluwa SDK
|
|
4
|
+
* Entry point principal do SDK
|
|
5
|
+
*
|
|
6
|
+
* Uso:
|
|
7
|
+
* import { initFluwaTool } from '@fluwa-tool/sdk';
|
|
8
|
+
* initFluwaTool({ serverUrl: 'http://localhost:5555' });
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
22
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.ConfigManager = exports.LogLevel = exports.Logger = void 0;
|
|
26
|
+
exports.initFluwaTool = initFluwaTool;
|
|
27
|
+
exports.disableFluwaTool = disableFluwaTool;
|
|
28
|
+
exports.enableFluwaTool = enableFluwaTool;
|
|
29
|
+
exports.isFluwaTooIialized = isFluwaTooIialized;
|
|
30
|
+
const types_1 = require("./types");
|
|
31
|
+
const Logger_1 = require("./core/Logger");
|
|
32
|
+
const Config_1 = require("./core/Config");
|
|
33
|
+
const HttpClient_1 = require("./features/communication/HttpClient");
|
|
34
|
+
const WebSocketClient_1 = require("./features/communication/WebSocketClient");
|
|
35
|
+
const FetchInterceptor_1 = require("./features/network/FetchInterceptor");
|
|
36
|
+
const RequestLogger_1 = require("./features/network/RequestLogger");
|
|
37
|
+
const MockResolver_1 = require("./features/network/MockResolver");
|
|
38
|
+
const IdGenerator_1 = require("./core/IdGenerator");
|
|
39
|
+
// ============================================
|
|
40
|
+
// ESTADO GLOBAL
|
|
41
|
+
// ============================================
|
|
42
|
+
let isInitialized = false;
|
|
43
|
+
let logger = Logger_1.defaultLogger;
|
|
44
|
+
let config;
|
|
45
|
+
let sessionId;
|
|
46
|
+
let httpClient;
|
|
47
|
+
let wsClient;
|
|
48
|
+
let fetchInterceptor;
|
|
49
|
+
let mockResolver;
|
|
50
|
+
// ============================================
|
|
51
|
+
// INICIALIZAÇÃO
|
|
52
|
+
// ============================================
|
|
53
|
+
/**
|
|
54
|
+
* Inicializar Fluwa-Tool
|
|
55
|
+
* Deve ser chamado no início da aplicação
|
|
56
|
+
*/
|
|
57
|
+
async function initFluwaTool(partialConfig = {}) {
|
|
58
|
+
if (isInitialized) {
|
|
59
|
+
logger.warn('Fluwa já foi inicializado');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
// 1. Configurar
|
|
64
|
+
config = (0, Config_1.getConfigManager)(partialConfig);
|
|
65
|
+
logger = new Logger_1.Logger('Fluwa', config.getConfig().debug ? Logger_1.LogLevel.DEBUG : Logger_1.LogLevel.INFO);
|
|
66
|
+
logger.success('Inicializando Fluwa-Tool');
|
|
67
|
+
logger.debug('Configuração', config.getConfig());
|
|
68
|
+
if (!config.isEnabled()) {
|
|
69
|
+
logger.warn('Fluwa desativado via config.enabled=false');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
// 2. Gerar session ID
|
|
73
|
+
sessionId = IdGenerator_1.idGenerator.generate();
|
|
74
|
+
logger.debug(`Session ID: ${sessionId}`);
|
|
75
|
+
// 3. Criar clientes HTTP e WebSocket
|
|
76
|
+
const { requestTimeout, serverUrl } = config.getConfig();
|
|
77
|
+
httpClient = new HttpClient_1.HttpClient(serverUrl, logger, requestTimeout || 5000);
|
|
78
|
+
wsClient = new WebSocketClient_1.WebSocketClient(serverUrl, logger, config.getAppName());
|
|
79
|
+
// 4. Criar resolvedor de mocks
|
|
80
|
+
mockResolver = new MockResolver_1.MockResolver(httpClient, logger);
|
|
81
|
+
// 5. Criar logger de requisições
|
|
82
|
+
const requestLogger = new RequestLogger_1.RequestLogger(httpClient, logger);
|
|
83
|
+
// 6. Criar interceptador de fetch
|
|
84
|
+
fetchInterceptor = new FetchInterceptor_1.FetchInterceptor(logger, requestLogger, mockResolver, sessionId, config.getAppName());
|
|
85
|
+
// 7. Instalar interceptadores
|
|
86
|
+
fetchInterceptor.install();
|
|
87
|
+
// 8. Conectar WebSocket
|
|
88
|
+
logger.debug('Conectando ao WebSocket...');
|
|
89
|
+
try {
|
|
90
|
+
await wsClient.connect();
|
|
91
|
+
setupWebSocketListeners();
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
logger.warn('Falha ao conectar WebSocket, continuando em modo offline', error);
|
|
95
|
+
}
|
|
96
|
+
// 9. Enviar init session
|
|
97
|
+
wsClient.send({
|
|
98
|
+
type: types_1.WebSocketMessageType.INIT_SESSION,
|
|
99
|
+
sessionId,
|
|
100
|
+
appName: config.getAppName(),
|
|
101
|
+
});
|
|
102
|
+
isInitialized = true;
|
|
103
|
+
logger.success('Fluwa-Tool inicializado com sucesso!');
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
logger.error('Erro ao inicializar Fluwa', error);
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Configurar listeners do WebSocket
|
|
112
|
+
*/
|
|
113
|
+
function setupWebSocketListeners() {
|
|
114
|
+
wsClient.on('message', (message) => {
|
|
115
|
+
try {
|
|
116
|
+
if (message?.type === types_1.WebSocketMessageType.SCENARIO_CHANGED) {
|
|
117
|
+
mockResolver.setActiveScenario(message.scenario || null);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
logger.warn('Erro ao processar mensagem WebSocket', error);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
wsClient.on('disconnected', () => {
|
|
125
|
+
logger.warn('WebSocket desconectado');
|
|
126
|
+
});
|
|
127
|
+
wsClient.on('error', (error) => {
|
|
128
|
+
logger.error('Erro no WebSocket', error);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
// ============================================
|
|
132
|
+
// CONTROLE
|
|
133
|
+
// ============================================
|
|
134
|
+
/**
|
|
135
|
+
* Desativar Fluwa
|
|
136
|
+
*/
|
|
137
|
+
function disableFluwaTool() {
|
|
138
|
+
if (!isInitialized) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
fetchInterceptor.uninstall();
|
|
142
|
+
wsClient.disconnect();
|
|
143
|
+
isInitialized = false;
|
|
144
|
+
logger.success('Fluwa-Tool desativado');
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Habilitar Fluwa
|
|
148
|
+
*/
|
|
149
|
+
async function enableFluwaTool() {
|
|
150
|
+
if (isInitialized) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
fetchInterceptor.install();
|
|
154
|
+
try {
|
|
155
|
+
await wsClient.connect();
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
logger.warn('Falha ao reconectar WebSocket', error);
|
|
159
|
+
}
|
|
160
|
+
isInitialized = true;
|
|
161
|
+
logger.success('Fluwa-Tool habilitado');
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Verificar se Fluwa está ativo
|
|
165
|
+
*/
|
|
166
|
+
function isFluwaTooIialized() {
|
|
167
|
+
return isInitialized;
|
|
168
|
+
}
|
|
169
|
+
// ============================================
|
|
170
|
+
// EXPORTS
|
|
171
|
+
// ============================================
|
|
172
|
+
__exportStar(require("./types"), exports);
|
|
173
|
+
var Logger_2 = require("./core/Logger");
|
|
174
|
+
Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return Logger_2.Logger; } });
|
|
175
|
+
Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return Logger_2.LogLevel; } });
|
|
176
|
+
var Config_2 = require("./core/Config");
|
|
177
|
+
Object.defineProperty(exports, "ConfigManager", { enumerable: true, get: function () { return Config_2.ConfigManager; } });
|