@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.
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Gerenciamento centralizado de configuração
3
+ * Responsabilidade única: manter e validar configurações
4
+ */
5
+ import { FluwaConfig } from '../types';
6
+ export interface IConfigManager {
7
+ getConfig(): FluwaConfig;
8
+ updateConfig(partial: Partial<FluwaConfig>): void;
9
+ isEnabled(): boolean;
10
+ getServerUrl(): string;
11
+ getAppName(): string;
12
+ }
13
+ /**
14
+ * Gerenciador de configuração
15
+ * Implementa pattern: Configuration Object
16
+ */
17
+ export declare class ConfigManager implements IConfigManager {
18
+ private config;
19
+ constructor(initialConfig?: Partial<FluwaConfig>);
20
+ private validate;
21
+ getConfig(): FluwaConfig;
22
+ updateConfig(partial: Partial<FluwaConfig>): void;
23
+ isEnabled(): boolean;
24
+ getServerUrl(): string;
25
+ getAppName(): string;
26
+ }
27
+ export declare function getConfigManager(initialConfig?: Partial<FluwaConfig>): ConfigManager;
28
+ export declare function resetConfig(): void;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ /**
3
+ * Gerenciamento centralizado de configuração
4
+ * Responsabilidade única: manter e validar configurações
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ConfigManager = void 0;
8
+ exports.getConfigManager = getConfigManager;
9
+ exports.resetConfig = resetConfig;
10
+ const DEFAULT_CONFIG = {
11
+ serverUrl: 'http://localhost:5555',
12
+ enabled: true,
13
+ appName: 'DefaultApp',
14
+ debug: false,
15
+ requestTimeout: 5000,
16
+ };
17
+ /**
18
+ * Gerenciador de configuração
19
+ * Implementa pattern: Configuration Object
20
+ */
21
+ class ConfigManager {
22
+ constructor(initialConfig) {
23
+ this.config = {
24
+ ...DEFAULT_CONFIG,
25
+ ...initialConfig,
26
+ };
27
+ this.validate();
28
+ }
29
+ validate() {
30
+ if (!this.config.serverUrl || typeof this.config.serverUrl !== 'string') {
31
+ throw new Error('serverUrl inválida');
32
+ }
33
+ if (typeof this.config.enabled !== 'boolean') {
34
+ throw new Error('enabled deve ser boolean');
35
+ }
36
+ if (!this.config.appName || typeof this.config.appName !== 'string') {
37
+ throw new Error('appName inválida');
38
+ }
39
+ if (this.config.requestTimeout && this.config.requestTimeout < 0) {
40
+ throw new Error('requestTimeout não pode ser negativa');
41
+ }
42
+ }
43
+ getConfig() {
44
+ return { ...this.config };
45
+ }
46
+ updateConfig(partial) {
47
+ this.config = {
48
+ ...this.config,
49
+ ...partial,
50
+ };
51
+ this.validate();
52
+ }
53
+ isEnabled() {
54
+ return this.config.enabled;
55
+ }
56
+ getServerUrl() {
57
+ return this.config.serverUrl;
58
+ }
59
+ getAppName() {
60
+ return this.config.appName;
61
+ }
62
+ }
63
+ exports.ConfigManager = ConfigManager;
64
+ // Instância singleton (lazy-loaded)
65
+ let configInstance = null;
66
+ function getConfigManager(initialConfig) {
67
+ if (!configInstance) {
68
+ configInstance = new ConfigManager(initialConfig);
69
+ }
70
+ return configInstance;
71
+ }
72
+ function resetConfig() {
73
+ configInstance = null;
74
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Gerador de IDs únicos
3
+ * Responsabilidade única: gerar identificadores
4
+ */
5
+ export interface IIdGenerator {
6
+ generate(): string;
7
+ }
8
+ /**
9
+ * Implementação de gerador de IDs
10
+ * Usa combinação de timestamp + random para garantir unicidade
11
+ */
12
+ export declare class IdGenerator implements IIdGenerator {
13
+ /**
14
+ * Gera ID único no formato: timestamp_random
15
+ * Exemplo: 1710000000000_abc123def456
16
+ */
17
+ generate(): string;
18
+ }
19
+ export declare const idGenerator: IdGenerator;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ /**
3
+ * Gerador de IDs únicos
4
+ * Responsabilidade única: gerar identificadores
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.idGenerator = exports.IdGenerator = void 0;
8
+ /**
9
+ * Implementação de gerador de IDs
10
+ * Usa combinação de timestamp + random para garantir unicidade
11
+ */
12
+ class IdGenerator {
13
+ /**
14
+ * Gera ID único no formato: timestamp_random
15
+ * Exemplo: 1710000000000_abc123def456
16
+ */
17
+ generate() {
18
+ const timestamp = Date.now();
19
+ const random = Math.random().toString(36).substr(2, 9);
20
+ return `${timestamp}_${random}`;
21
+ }
22
+ }
23
+ exports.IdGenerator = IdGenerator;
24
+ // Instância singleton
25
+ exports.idGenerator = new IdGenerator();
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Logger centralizado com níveis de severidade
3
+ * Responsabilidade única: logging estruturado
4
+ */
5
+ export declare enum LogLevel {
6
+ DEBUG = "DEBUG",
7
+ INFO = "INFO",
8
+ WARN = "WARN",
9
+ ERROR = "ERROR",
10
+ SUCCESS = "SUCCESS"
11
+ }
12
+ export interface ILogger {
13
+ debug(message: string, data?: unknown): void;
14
+ info(message: string, data?: unknown): void;
15
+ warn(message: string, data?: unknown): void;
16
+ error(message: string, error?: Error | unknown): void;
17
+ success(message: string): void;
18
+ setLevel(level: LogLevel): void;
19
+ }
20
+ /**
21
+ * Implementação do logger
22
+ * Permite ativar/desativar diferentes níveis
23
+ */
24
+ export declare class Logger implements ILogger {
25
+ private namespace;
26
+ private minLevel;
27
+ private readonly levelOrder;
28
+ constructor(namespace?: string, minLevel?: LogLevel);
29
+ private shouldLog;
30
+ private formatMessage;
31
+ debug(message: string, data?: unknown): void;
32
+ info(message: string, data?: unknown): void;
33
+ warn(message: string, data?: unknown): void;
34
+ error(message: string, error?: Error | unknown): void;
35
+ success(message: string): void;
36
+ setLevel(level: LogLevel): void;
37
+ }
38
+ export declare const defaultLogger: Logger;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ /**
3
+ * Logger centralizado com níveis de severidade
4
+ * Responsabilidade única: logging estruturado
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.defaultLogger = exports.Logger = exports.LogLevel = void 0;
8
+ var LogLevel;
9
+ (function (LogLevel) {
10
+ LogLevel["DEBUG"] = "DEBUG";
11
+ LogLevel["INFO"] = "INFO";
12
+ LogLevel["WARN"] = "WARN";
13
+ LogLevel["ERROR"] = "ERROR";
14
+ LogLevel["SUCCESS"] = "SUCCESS";
15
+ })(LogLevel || (exports.LogLevel = LogLevel = {}));
16
+ /**
17
+ * Implementação do logger
18
+ * Permite ativar/desativar diferentes níveis
19
+ */
20
+ class Logger {
21
+ constructor(namespace = 'Fluwa', minLevel = LogLevel.INFO) {
22
+ this.levelOrder = {
23
+ [LogLevel.DEBUG]: 0,
24
+ [LogLevel.INFO]: 1,
25
+ [LogLevel.WARN]: 2,
26
+ [LogLevel.ERROR]: 3,
27
+ [LogLevel.SUCCESS]: 1,
28
+ };
29
+ this.namespace = namespace;
30
+ this.minLevel = minLevel;
31
+ }
32
+ shouldLog(level) {
33
+ return this.levelOrder[level] >= this.levelOrder[this.minLevel];
34
+ }
35
+ formatMessage(level, message) {
36
+ const timestamp = new Date().toISOString();
37
+ return `[${timestamp}] [${this.namespace}:${level}] ${message}`;
38
+ }
39
+ debug(message, data) {
40
+ if (!this.shouldLog(LogLevel.DEBUG))
41
+ return;
42
+ console.log(this.formatMessage(LogLevel.DEBUG, message), data || '');
43
+ }
44
+ info(message, data) {
45
+ if (!this.shouldLog(LogLevel.INFO))
46
+ return;
47
+ console.log(this.formatMessage(LogLevel.INFO, message), data || '');
48
+ }
49
+ warn(message, data) {
50
+ if (!this.shouldLog(LogLevel.WARN))
51
+ return;
52
+ console.warn(this.formatMessage(LogLevel.WARN, message), data || '');
53
+ }
54
+ error(message, error) {
55
+ if (!this.shouldLog(LogLevel.ERROR))
56
+ return;
57
+ console.error(this.formatMessage(LogLevel.ERROR, message));
58
+ if (error instanceof Error) {
59
+ console.error(`Stack: ${error.stack}`);
60
+ }
61
+ else if (error) {
62
+ console.error('Details:', error);
63
+ }
64
+ }
65
+ success(message) {
66
+ if (!this.shouldLog(LogLevel.SUCCESS))
67
+ return;
68
+ console.log(`✓ ${this.formatMessage(LogLevel.SUCCESS, message)}`);
69
+ }
70
+ setLevel(level) {
71
+ this.minLevel = level;
72
+ }
73
+ }
74
+ exports.Logger = Logger;
75
+ // Instância singleton do logger padrão
76
+ exports.defaultLogger = new Logger('Fluwa', LogLevel.INFO);
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Cliente HTTP para comunicação com Fluwa Server
3
+ * Responsabilidade única: fazer requisições HTTP
4
+ */
5
+ import { ILogger } from '../../core/Logger';
6
+ export interface IHttpClient {
7
+ post<T>(endpoint: string, data: unknown): Promise<T>;
8
+ get<T>(endpoint: string, params?: Record<string, string>): Promise<T>;
9
+ put<T>(endpoint: string, data: unknown): Promise<T>;
10
+ }
11
+ /**
12
+ * Implementação do cliente HTTP
13
+ * Usa fetch nativo do navegador/Node.js
14
+ */
15
+ export declare class HttpClient implements IHttpClient {
16
+ private baseUrl;
17
+ private logger;
18
+ private timeout;
19
+ constructor(baseUrl: string, logger: ILogger, timeout?: number);
20
+ /**
21
+ * Fazer POST request
22
+ * Implementa timeout automático
23
+ */
24
+ post<T>(endpoint: string, data: unknown): Promise<T>;
25
+ /**
26
+ * Fazer GET request com query parameters
27
+ */
28
+ get<T>(endpoint: string, params?: Record<string, string>): Promise<T>;
29
+ /**
30
+ * Fazer PUT request
31
+ */
32
+ put<T>(endpoint: string, data: unknown): Promise<T>;
33
+ /**
34
+ * Request genérica com timeout
35
+ */
36
+ private request;
37
+ /**
38
+ * Construir URL com query parameters
39
+ */
40
+ private buildUrl;
41
+ }
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ /**
3
+ * Cliente HTTP para comunicação com Fluwa Server
4
+ * Responsabilidade única: fazer requisições HTTP
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.HttpClient = void 0;
8
+ /**
9
+ * Implementação do cliente HTTP
10
+ * Usa fetch nativo do navegador/Node.js
11
+ */
12
+ class HttpClient {
13
+ constructor(baseUrl, logger, timeout = 5000) {
14
+ this.baseUrl = baseUrl;
15
+ this.logger = logger;
16
+ this.timeout = timeout;
17
+ }
18
+ /**
19
+ * Fazer POST request
20
+ * Implementa timeout automático
21
+ */
22
+ async post(endpoint, data) {
23
+ return this.request('POST', endpoint, { body: JSON.stringify(data) });
24
+ }
25
+ /**
26
+ * Fazer GET request com query parameters
27
+ */
28
+ async get(endpoint, params) {
29
+ const url = this.buildUrl(endpoint, params);
30
+ return this.request('GET', url);
31
+ }
32
+ /**
33
+ * Fazer PUT request
34
+ */
35
+ async put(endpoint, data) {
36
+ return this.request('PUT', endpoint, { body: JSON.stringify(data) });
37
+ }
38
+ /**
39
+ * Request genérica com timeout
40
+ */
41
+ async request(method, endpoint, options = {}) {
42
+ const url = endpoint.startsWith('http')
43
+ ? endpoint
44
+ : `${this.baseUrl}${endpoint}`;
45
+ const controller = new AbortController();
46
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
47
+ try {
48
+ const response = await fetch(url, {
49
+ method,
50
+ headers: {
51
+ 'Content-Type': 'application/json',
52
+ 'X-Fluwa-Internal': 'true', // Marcar como requisição interna do Fluwa
53
+ ...options.headers,
54
+ },
55
+ ...options,
56
+ signal: controller.signal,
57
+ });
58
+ if (!response.ok) {
59
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
60
+ }
61
+ return (await response.json());
62
+ }
63
+ catch (error) {
64
+ const isTimeout = error instanceof Error && error.name === 'AbortError';
65
+ if (isTimeout) {
66
+ this.logger.warn(`Request timeout: ${endpoint}`);
67
+ }
68
+ else {
69
+ this.logger.error(`HTTP request failed: ${endpoint}`, error);
70
+ }
71
+ throw error;
72
+ }
73
+ finally {
74
+ clearTimeout(timeoutId);
75
+ }
76
+ }
77
+ /**
78
+ * Construir URL com query parameters
79
+ */
80
+ buildUrl(endpoint, params) {
81
+ if (!params || Object.keys(params).length === 0) {
82
+ return endpoint;
83
+ }
84
+ const queryString = new URLSearchParams(params).toString();
85
+ return `${endpoint}?${queryString}`;
86
+ }
87
+ }
88
+ exports.HttpClient = HttpClient;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Cliente WebSocket para comunicação bidirecional em tempo real
3
+ * Responsabilidade única: gerenciar conexão WebSocket
4
+ */
5
+ import { ILogger } from '../../core/Logger';
6
+ import { WebSocketMessage } from '../../types';
7
+ export declare enum WebSocketState {
8
+ CONNECTING = "CONNECTING",
9
+ CONNECTED = "CONNECTED",
10
+ DISCONNECTED = "DISCONNECTED",
11
+ ERROR = "ERROR"
12
+ }
13
+ export interface IWebSocketClient {
14
+ connect(): Promise<void>;
15
+ disconnect(): void;
16
+ send(message: WebSocketMessage): void;
17
+ isConnected(): boolean;
18
+ on(event: 'message' | 'connected' | 'disconnected' | 'error', callback: (data?: unknown) => void): void;
19
+ }
20
+ /**
21
+ * Implementação do cliente WebSocket
22
+ * Implementa pattern: Observer
23
+ */
24
+ export declare class WebSocketClient implements IWebSocketClient {
25
+ private logger;
26
+ private ws;
27
+ private url;
28
+ private state;
29
+ private reconnectAttempts;
30
+ private maxReconnectAttempts;
31
+ private reconnectDelay;
32
+ private messageListeners;
33
+ private connectedListeners;
34
+ private disconnectedListeners;
35
+ private errorListeners;
36
+ constructor(serverUrl: string, logger: ILogger, appName?: string);
37
+ /**
38
+ * Conectar ao servidor WebSocket
39
+ */
40
+ connect(): Promise<void>;
41
+ /**
42
+ * Desconectar do WebSocket
43
+ */
44
+ disconnect(): void;
45
+ /**
46
+ * Enviar mensagem via WebSocket
47
+ */
48
+ send(message: WebSocketMessage): void;
49
+ /**
50
+ * Verificar se está conectado
51
+ */
52
+ isConnected(): boolean;
53
+ /**
54
+ * Registrar listener para evento
55
+ */
56
+ on(event: 'message' | 'connected' | 'disconnected' | 'error', callback: (data?: unknown) => void): void;
57
+ /**
58
+ * Tentar reconectar com backoff exponencial
59
+ */
60
+ private reconnect;
61
+ }
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ /**
3
+ * Cliente WebSocket para comunicação bidirecional em tempo real
4
+ * Responsabilidade única: gerenciar conexão WebSocket
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.WebSocketClient = exports.WebSocketState = void 0;
8
+ var WebSocketState;
9
+ (function (WebSocketState) {
10
+ WebSocketState["CONNECTING"] = "CONNECTING";
11
+ WebSocketState["CONNECTED"] = "CONNECTED";
12
+ WebSocketState["DISCONNECTED"] = "DISCONNECTED";
13
+ WebSocketState["ERROR"] = "ERROR";
14
+ })(WebSocketState || (exports.WebSocketState = WebSocketState = {}));
15
+ /**
16
+ * Implementação do cliente WebSocket
17
+ * Implementa pattern: Observer
18
+ */
19
+ class WebSocketClient {
20
+ constructor(serverUrl, logger, appName) {
21
+ this.logger = logger;
22
+ this.ws = null;
23
+ this.state = WebSocketState.DISCONNECTED;
24
+ this.reconnectAttempts = 0;
25
+ this.maxReconnectAttempts = 5;
26
+ this.reconnectDelay = 3000;
27
+ // Listeners para eventos
28
+ this.messageListeners = new Set();
29
+ this.connectedListeners = new Set();
30
+ this.disconnectedListeners = new Set();
31
+ this.errorListeners = new Set();
32
+ // Converter http:// para ws:// ou https:// para wss://
33
+ const wsUrl = serverUrl
34
+ .replace(/^https?:\/\//, (match) => {
35
+ return match.startsWith('https') ? 'wss://' : 'ws://';
36
+ })
37
+ .concat('/ws');
38
+ // Adicionar appName como query string se fornecido
39
+ this.url = appName ? `${wsUrl}?appName=${encodeURIComponent(appName)}` : wsUrl;
40
+ }
41
+ /**
42
+ * Conectar ao servidor WebSocket
43
+ */
44
+ async connect() {
45
+ if (this.state === WebSocketState.CONNECTED || this.state === WebSocketState.CONNECTING) {
46
+ return;
47
+ }
48
+ this.state = WebSocketState.CONNECTING;
49
+ this.logger.debug(`Conectando ao WebSocket: ${this.url}`);
50
+ return new Promise((resolve, reject) => {
51
+ try {
52
+ this.ws = new WebSocket(this.url);
53
+ this.ws.onopen = () => {
54
+ this.state = WebSocketState.CONNECTED;
55
+ this.reconnectAttempts = 0;
56
+ this.logger.success('WebSocket conectado');
57
+ this.connectedListeners.forEach((cb) => cb());
58
+ resolve();
59
+ };
60
+ this.ws.onmessage = (event) => {
61
+ try {
62
+ const message = JSON.parse(event.data);
63
+ this.messageListeners.forEach((cb) => cb(message));
64
+ }
65
+ catch (error) {
66
+ this.logger.warn('Erro ao parsear mensagem WebSocket', error);
67
+ }
68
+ };
69
+ this.ws.onerror = (error) => {
70
+ this.state = WebSocketState.ERROR;
71
+ this.logger.error('Erro WebSocket', error);
72
+ this.errorListeners.forEach((cb) => cb(error));
73
+ };
74
+ this.ws.onclose = () => {
75
+ this.state = WebSocketState.DISCONNECTED;
76
+ this.logger.warn('WebSocket desconectado');
77
+ this.disconnectedListeners.forEach((cb) => cb());
78
+ // Tentar reconectar
79
+ this.reconnect();
80
+ };
81
+ }
82
+ catch (error) {
83
+ this.state = WebSocketState.ERROR;
84
+ this.logger.error('Erro ao criar WebSocket', error);
85
+ reject(error);
86
+ }
87
+ });
88
+ }
89
+ /**
90
+ * Desconectar do WebSocket
91
+ */
92
+ disconnect() {
93
+ if (this.ws) {
94
+ this.ws.close();
95
+ this.ws = null;
96
+ this.state = WebSocketState.DISCONNECTED;
97
+ this.maxReconnectAttempts = 0; // Previne reconexão automática
98
+ }
99
+ }
100
+ /**
101
+ * Enviar mensagem via WebSocket
102
+ */
103
+ send(message) {
104
+ if (!this.isConnected()) {
105
+ this.logger.warn('WebSocket não está conectado');
106
+ return;
107
+ }
108
+ try {
109
+ this.ws.send(JSON.stringify(message));
110
+ }
111
+ catch (error) {
112
+ this.logger.error('Erro ao enviar mensagem WebSocket', error);
113
+ }
114
+ }
115
+ /**
116
+ * Verificar se está conectado
117
+ */
118
+ isConnected() {
119
+ return this.state === WebSocketState.CONNECTED;
120
+ }
121
+ /**
122
+ * Registrar listener para evento
123
+ */
124
+ on(event, callback) {
125
+ switch (event) {
126
+ case 'message':
127
+ this.messageListeners.add(callback);
128
+ break;
129
+ case 'connected':
130
+ this.connectedListeners.add(callback);
131
+ break;
132
+ case 'disconnected':
133
+ this.disconnectedListeners.add(callback);
134
+ break;
135
+ case 'error':
136
+ this.errorListeners.add(callback);
137
+ break;
138
+ }
139
+ }
140
+ /**
141
+ * Tentar reconectar com backoff exponencial
142
+ */
143
+ reconnect() {
144
+ if (this.reconnectAttempts >= this.maxReconnectAttempts) {
145
+ this.logger.error(`Falha ao reconectar após ${this.maxReconnectAttempts} tentativas`);
146
+ return;
147
+ }
148
+ this.reconnectAttempts++;
149
+ const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
150
+ this.logger.warn(`Tentando reconectar em ${delay}ms (tentativa ${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
151
+ setTimeout(() => {
152
+ this.connect().catch((error) => {
153
+ this.logger.error('Reconexão falhou', error);
154
+ });
155
+ }, delay);
156
+ }
157
+ }
158
+ exports.WebSocketClient = WebSocketClient;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Interceptador de fetch nativo do navegador
3
+ * Responsabilidade única: interceptar e logar requisições fetch
4
+ */
5
+ import { ILogger } from '../../core/Logger';
6
+ import { IRequestLogger } from './RequestLogger';
7
+ import { IMockResolver } from './MockResolver';
8
+ export interface IFetchInterceptor {
9
+ install(): void;
10
+ uninstall(): void;
11
+ }
12
+ /**
13
+ * Implementação de interceptador de fetch
14
+ * Preserva fetch original e sobrescreve com versão interceptada
15
+ */
16
+ export declare class FetchInterceptor implements IFetchInterceptor {
17
+ private logger;
18
+ private requestLogger;
19
+ private mockResolver;
20
+ private sessionId;
21
+ private appName;
22
+ private originalFetch;
23
+ private isInstalled;
24
+ constructor(logger: ILogger, requestLogger: IRequestLogger, mockResolver: IMockResolver, sessionId: string, appName: string);
25
+ /**
26
+ * Instalar o interceptador
27
+ * Substitui fetch global
28
+ */
29
+ install(): void;
30
+ /**
31
+ * Desinstalar o interceptador
32
+ * Restaura fetch original
33
+ */
34
+ uninstall(): void;
35
+ /**
36
+ * Criar versão interceptada de fetch
37
+ */
38
+ private createInterceptedFetch;
39
+ /**
40
+ * Parse seguro do body (string ou object)
41
+ */
42
+ private safeParseBody;
43
+ /**
44
+ * Gerar ID único para requisição
45
+ */
46
+ private generateId;
47
+ /**
48
+ * Sleep (para delays de mock)
49
+ */
50
+ private delay;
51
+ }