debug-time-machine
Version:
제로 설정 React 디버깅 도구
773 lines (769 loc) • 29.3 kB
JavaScript
// Debug Time Machine Unified Package
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
MessageType: () => MessageType,
useDebugTimeMachine: () => useDebugTimeMachine
});
module.exports = __toCommonJS(index_exports);
// src/useDebugTimeMachine.ts
var import_react = require("react");
// src/types.ts
var MessageType = /* @__PURE__ */ ((MessageType2) => {
MessageType2["CONNECTION"] = "CONNECTION";
MessageType2["USER_ACTION"] = "USER_ACTION";
MessageType2["STATE_CHANGE"] = "STATE_CHANGE";
MessageType2["ERROR"] = "ERROR";
MessageType2["PING"] = "PING";
MessageType2["PONG"] = "PONG";
return MessageType2;
})(MessageType || {});
// src/useDebugTimeMachine.ts
var DEFAULT_CONFIG = {
websocketUrl: "ws://localhost:4000/ws",
debugMode: true,
// 🔥 기본값을 true로 변경
captureUserActions: true,
captureErrors: true,
captureStateChanges: true,
maxReconnectAttempts: 5,
reconnectInterval: 5e3,
developmentOnly: false,
autoConnect: true,
enableTimeTravelEngine: true,
enableMemoryManagement: true,
enableDOMSnapshots: false,
enableMetrics: true,
timeTravelConfig: {},
memoryConfig: {},
domSnapshotConfig: {}
};
var CONSOLE_STYLES = {
info: "color: #2196F3; font-weight: bold;",
success: "color: #4CAF50; font-weight: bold;",
warning: "color: #FF9800; font-weight: bold;",
error: "color: #F44336; font-weight: bold;"
};
function useDebugTimeMachine(userConfig = {}) {
const config = { ...DEFAULT_CONFIG, ...userConfig };
const wsRef = (0, import_react.useRef)(null);
const isInitializedRef = (0, import_react.useRef)(false);
const isConnectingRef = (0, import_react.useRef)(false);
const reconnectAttemptsRef = (0, import_react.useRef)(0);
const reconnectTimeoutRef = (0, import_react.useRef)(null);
const [isConnected, setIsConnected] = (0, import_react.useState)(false);
const [clientId, setClientId] = (0, import_react.useState)(null);
const [connectionInfo, setConnectionInfo] = (0, import_react.useState)({
connectedAt: null,
reconnectAttempts: 0,
lastError: null
});
const [performanceMetrics, setPerformanceMetrics] = (0, import_react.useState)(null);
const [systemMetrics, setSystemMetrics] = (0, import_react.useState)(null);
const [memoryUsage, setMemoryUsage] = (0, import_react.useState)(null);
const [networkRequests, setNetworkRequests] = (0, import_react.useState)([]);
const [networkResponses, setNetworkResponses] = (0, import_react.useState)([]);
const writeLog = (0, import_react.useCallback)(
(message, type = "info", data) => {
if (!config.debugMode) return;
const style = CONSOLE_STYLES[type];
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
if (data) {
console.groupCollapsed(`%c[Debug Time Machine ${timestamp}] ${message}`, style);
console.log("Data:", data);
console.groupEnd();
} else {
console.log(`%c[Debug Time Machine ${timestamp}] ${message}`, style);
}
},
[config.debugMode]
);
const sendMessage = (0, import_react.useCallback)(
(type, data) => {
if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {
writeLog(`\u274C Cannot send message: WebSocket not ready`, "warning");
return false;
}
const message = {
type,
payload: data,
timestamp: Date.now(),
clientId: clientId || void 0
};
try {
const messageStr = JSON.stringify(message);
wsRef.current.send(messageStr);
writeLog(`\u2705 Message sent successfully: ${type}`, "success");
return true;
} catch (error) {
writeLog(`\u274C Failed to send message: ${type}`, "error");
return false;
}
},
[clientId, writeLog]
);
const captureError = (0, import_react.useCallback)(
(error, errorInfo) => {
writeLog(`\u{1F534} Manual error capture: ${error.message}`, "error");
const isWsConnected = wsRef.current?.readyState === WebSocket.OPEN;
writeLog(`Debug: isWsConnected=${isWsConnected}, captureErrors=${config.captureErrors}`, "info");
if (!isWsConnected || !config.captureErrors) {
writeLog("Cannot capture error: WebSocket not connected or errors disabled", "warning");
return;
}
const errorData = {
message: error.message || "Unknown error",
stack: error.stack || "No stack trace available",
timestamp: Date.now(),
url: window.location.href,
userAgent: navigator.userAgent
};
if (errorInfo) {
errorData.errorInfo = errorInfo;
}
const success = sendMessage("ERROR" /* ERROR */, errorData);
writeLog(`Error message send result: ${success}`, success ? "success" : "error");
},
[config.captureErrors, sendMessage, writeLog]
);
const captureStateChange = (0, import_react.useCallback)(
(componentName, prevState, newState, props) => {
const isWsConnected = wsRef.current?.readyState === WebSocket.OPEN;
if (!isWsConnected || !config.captureStateChanges) {
writeLog("Cannot capture state change: WebSocket not connected or disabled", "warning");
return;
}
const stateChangeData = {
componentName,
prevState,
newState,
props,
timestamp: Date.now(),
url: window.location.href
};
sendMessage("STATE_CHANGE" /* STATE_CHANGE */, stateChangeData);
},
[config.captureStateChanges, sendMessage, writeLog]
);
const handleMessage = (0, import_react.useCallback)(
(event) => {
try {
const message = JSON.parse(event.data);
if (!message || typeof message !== "object" || !message.type) {
return;
}
const messageData = message.payload || message.data;
switch (message.type) {
case "CONNECTION" /* CONNECTION */:
if (messageData && messageData.type === "welcome" && messageData.clientId) {
setClientId(messageData.clientId);
writeLog(`Assigned client ID: ${messageData.clientId}`, "success");
}
break;
case "ping":
case "PING":
case "PING" /* PING */:
sendMessage("PONG" /* PONG */, {});
break;
case "ERROR" /* ERROR */:
writeLog("Server error:", "error", messageData);
break;
default:
break;
}
} catch (error) {
writeLog("Failed to parse incoming message", "error");
}
},
[sendMessage, writeLog]
);
const connect = (0, import_react.useCallback)(() => {
if (isConnectingRef.current || wsRef.current?.readyState === WebSocket.OPEN) {
return;
}
try {
writeLog("Connecting to Time Machine...", "info");
isConnectingRef.current = true;
if (wsRef.current) {
wsRef.current.close();
wsRef.current = null;
}
wsRef.current = new WebSocket(config.websocketUrl);
wsRef.current.onopen = () => {
isConnectingRef.current = false;
setIsConnected(true);
reconnectAttemptsRef.current = 0;
setConnectionInfo((prev) => ({
...prev,
connectedAt: /* @__PURE__ */ new Date(),
reconnectAttempts: 0,
lastError: null
}));
writeLog("Connected to Debug Time Machine!", "success");
const connectionData = {
type: "client_ready",
url: window.location.href,
userAgent: navigator.userAgent,
timestamp: Date.now()
};
setTimeout(() => {
if (wsRef.current?.readyState === WebSocket.OPEN) {
try {
wsRef.current.send(JSON.stringify({
type: "CONNECTION" /* CONNECTION */,
payload: connectionData,
timestamp: Date.now(),
clientId: clientId || void 0
}));
} catch (sendError) {
writeLog("Failed to send initial message", "error");
}
}
}, 300);
};
wsRef.current.onmessage = handleMessage;
wsRef.current.onclose = (event) => {
isConnectingRef.current = false;
setIsConnected(false);
setClientId(null);
if (event.code === 1e3 || event.code === 1001) {
return;
}
if (reconnectAttemptsRef.current < config.maxReconnectAttempts) {
reconnectAttemptsRef.current++;
setConnectionInfo((prev) => ({
...prev,
reconnectAttempts: reconnectAttemptsRef.current,
lastError: null
}));
reconnectTimeoutRef.current = window.setTimeout(() => {
connect();
}, config.reconnectInterval);
}
};
wsRef.current.onerror = () => {
isConnectingRef.current = false;
setConnectionInfo((prev) => ({
...prev,
lastError: "WebSocket connection error"
}));
};
} catch (error) {
writeLog("Failed to create WebSocket connection", "error");
isConnectingRef.current = false;
}
}, [config.websocketUrl, config.maxReconnectAttempts, config.reconnectInterval, handleMessage, writeLog, clientId]);
const reconnect = (0, import_react.useCallback)(() => {
if (reconnectTimeoutRef.current) {
clearTimeout(reconnectTimeoutRef.current);
}
if (wsRef.current) {
wsRef.current.close();
}
reconnectAttemptsRef.current = 0;
connect();
}, [connect]);
const checkDebugServer = (0, import_react.useCallback)(async () => {
if (!config.autoConnect) {
return false;
}
try {
const baseUrl = config.websocketUrl.replace("ws://", "http://").replace("/ws", "");
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 2e3);
try {
const response = await fetch(`${baseUrl}/health`, {
method: "GET",
signal: controller.signal
});
clearTimeout(timeoutId);
if (response.ok) {
const data = await response.json();
writeLog(`\u{1F3AF} Debug \uC11C\uBC84 \uBC1C\uACAC!`, "success");
return true;
}
} catch (fetchError) {
clearTimeout(timeoutId);
throw fetchError;
}
} catch (error) {
if (config.debugMode) {
writeLog(`Debug \uC11C\uBC84 \uC5C6\uC74C`, "info");
}
}
return false;
}, [config.websocketUrl, config.autoConnect, config.debugMode, writeLog]);
const setupEnhancedNetworkInterceptor = (0, import_react.useCallback)(() => {
if (typeof window === "undefined") return;
writeLog("\u{1F310} Setting up enhanced network interceptor...", "info");
const originalFetch = window.fetch;
const originalXHROpen = XMLHttpRequest.prototype.open;
const originalXHRSend = XMLHttpRequest.prototype.send;
const generateRequestId = () => `req_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
const shouldCaptureUrl = (url) => {
const excludePatterns = [
/localhost:4000/,
/localhost:8080/,
/127\.0\.0\.1:4000/,
/127\.0\.0\.1:8080/,
/webpack-hmr/,
/hot-update/,
/sockjs-node/,
/@vite\/client/,
/react-devtools/,
/chrome-extension:/,
/moz-extension:/,
/favicon\.ico/,
/manifest\.json/,
/\.(js|css|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)(\?|$)/
];
if (excludePatterns.some((pattern) => pattern.test(url))) {
return false;
}
const includePatterns = [
/\/api\//,
/\/graphql/,
/\/v\d+\//,
/jsonplaceholder\.typicode\.com/,
/reqres\.in/,
/httpbin\.org/,
/api\./
];
return includePatterns.some((pattern) => pattern.test(url));
};
const sanitizeRequestData = (data) => {
if (!data) return data;
if (typeof data === "string") {
try {
const parsed = JSON.parse(data);
return sanitizeRequestData(parsed);
} catch {
return data.replace(/"password"\s*:\s*"[^"]*"/gi, '"password":"***"').replace(/"token"\s*:\s*"[^"]*"/gi, '"token":"***"').replace(/"secret"\s*:\s*"[^"]*"/gi, '"secret":"***"');
}
}
if (typeof data === "object" && data !== null) {
const sanitized = { ...data };
Object.keys(sanitized).forEach((key) => {
if (/password|token|secret|auth|key/i.test(key)) {
sanitized[key] = "***";
}
});
return sanitized;
}
return data;
};
window.fetch = async (...args) => {
const [input, init = {}] = args;
const url = typeof input === "string" ? input : input.url;
const method = init.method || "GET";
const requestId = generateRequestId();
const startTime = Date.now();
const shouldCapture = shouldCaptureUrl(url) || ["POST", "PUT", "DELETE", "PATCH"].includes(method.toUpperCase());
if (!shouldCapture) {
return originalFetch.apply(window, args);
}
writeLog(`\u{1F4E4} API Request: ${method} ${url}`, "info");
const requestData = {
id: requestId,
type: "request",
method: method.toUpperCase(),
url,
timestamp: startTime,
headers: init.headers ? Object.fromEntries(new Headers(init.headers).entries()) : {},
body: init.body ? sanitizeRequestData(init.body) : void 0
};
setNetworkRequests((prev) => [...prev, {
...requestData,
status: "pending",
duration: 0
}].slice(-100));
try {
const response = await originalFetch.apply(window, args);
const endTime = Date.now();
const duration = endTime - startTime;
const responseHeaders = Object.fromEntries(response.headers.entries());
let responseBody = void 0;
try {
const clonedResponse = response.clone();
const contentType = response.headers.get("content-type") || "";
if (contentType.includes("application/json")) {
responseBody = await clonedResponse.json();
} else if (contentType.includes("text/")) {
const text = await clonedResponse.text();
responseBody = text.length > 1e3 ? text.substring(0, 1e3) + "..." : text;
}
} catch (bodyError) {
}
const responseData = {
id: requestId,
type: "response",
method: method.toUpperCase(),
url,
status: response.status,
statusText: response.statusText,
ok: response.ok,
duration,
timestamp: endTime,
requestTimestamp: startTime,
headers: responseHeaders,
body: responseBody,
size: responseHeaders["content-length"] || "unknown"
};
setNetworkRequests((prev) => prev.map(
(req) => req.id === requestId ? { ...req, ...responseData, status: response.status, success: response.ok } : req
));
if (wsRef.current?.readyState === WebSocket.OPEN) {
writeLog(`\u{1F525} Sending NETWORK_REQUEST to server`, "info");
const requestSuccess = sendMessage("NETWORK_REQUEST", requestData);
const responseSuccess = sendMessage("NETWORK_RESPONSE", responseData);
writeLog(`Network message results: request=${requestSuccess}, response=${responseSuccess}`, "info");
} else {
writeLog(`\u274C WebSocket not ready for network data: readyState=${wsRef.current?.readyState}`, "warning");
}
if (response.ok) {
writeLog(`\u2705 API Success: ${method} ${url} (${response.status}, ${duration}ms)`, "success");
} else {
writeLog(`\u274C API Error: ${method} ${url} (${response.status}, ${duration}ms)`, "error");
captureError(new Error(`HTTP ${response.status}: ${response.statusText}`), {
type: "network_error",
url,
method,
status: response.status,
statusText: response.statusText,
duration,
requestId,
responseBody
});
}
return response;
} catch (error) {
const endTime = Date.now();
const duration = endTime - startTime;
const errorData = {
id: requestId,
type: "error",
method: method.toUpperCase(),
url,
duration,
timestamp: endTime,
requestTimestamp: startTime,
error: error instanceof Error ? error.message : String(error),
errorType: error instanceof Error ? error.name : "Unknown"
};
setNetworkRequests((prev) => prev.map(
(req) => req.id === requestId ? { ...req, ...errorData, status: "error", success: false } : req
));
if (wsRef.current?.readyState === WebSocket.OPEN) {
writeLog(`\u{1F525} Sending NETWORK_ERROR to server`, "error");
const requestSuccess = sendMessage("NETWORK_REQUEST", requestData);
const errorSuccess = sendMessage("NETWORK_ERROR", errorData);
writeLog(`Network error message results: request=${requestSuccess}, error=${errorSuccess}`, "info");
} else {
writeLog(`\u274C WebSocket not ready for error data: readyState=${wsRef.current?.readyState}`, "warning");
}
captureError(error instanceof Error ? error : new Error(String(error)), {
type: "network_error",
url,
method,
duration,
requestId
});
throw error;
}
};
XMLHttpRequest.prototype.open = function(method, url, async, username, password) {
const urlString = url.toString();
const shouldCapture = shouldCaptureUrl(urlString) || ["POST", "PUT", "DELETE", "PATCH"].includes(method.toUpperCase());
if (shouldCapture) {
const requestId = generateRequestId();
this._debugTM = {
requestId,
method: method.toUpperCase(),
url: urlString,
startTime: Date.now(),
shouldCapture: true
};
writeLog(`\u{1F4E4} XHR Request: ${method} ${urlString}`, "info");
}
return originalXHROpen.call(this, method, url, async || true, username, password);
};
XMLHttpRequest.prototype.send = function(body) {
if (this._debugTM && this._debugTM.shouldCapture) {
const { requestId, method, url, startTime } = this._debugTM;
const requestData = {
id: requestId,
type: "request",
method,
url,
timestamp: startTime,
headers: {},
body: body ? sanitizeRequestData(body) : void 0
};
setNetworkRequests((prev) => [...prev, {
...requestData,
status: "pending",
duration: 0
}].slice(-100));
this.addEventListener("loadend", () => {
const endTime = Date.now();
const duration = endTime - startTime;
let responseBody = void 0;
try {
if (this.responseText && this.getResponseHeader("content-type")?.includes("application/json")) {
responseBody = JSON.parse(this.responseText);
} else if (this.responseText) {
const text = this.responseText;
responseBody = text.length > 1e3 ? text.substring(0, 1e3) + "..." : text;
}
} catch {
}
const responseData = {
id: requestId,
type: "response",
method,
url,
status: this.status,
statusText: this.statusText,
ok: this.status >= 200 && this.status < 300,
duration,
timestamp: endTime,
requestTimestamp: startTime,
headers: {},
body: responseBody
};
setNetworkRequests((prev) => prev.map(
(req) => req.id === requestId ? { ...req, ...responseData, status: this.status, success: this.status >= 200 && this.status < 300 } : req
));
if (wsRef.current?.readyState === WebSocket.OPEN) {
writeLog(`\u{1F525} Sending XHR data to server`, "info");
const requestSuccess = sendMessage("NETWORK_REQUEST", requestData);
if (this.status === 0) {
const errorSuccess = sendMessage("NETWORK_ERROR", {
id: requestId,
type: "error",
method,
url,
duration,
timestamp: endTime,
requestTimestamp: startTime,
error: "Network Error",
errorType: "NetworkError"
});
writeLog(`XHR error message results: request=${requestSuccess}, error=${errorSuccess}`, "info");
} else {
const responseSuccess = sendMessage("NETWORK_RESPONSE", responseData);
writeLog(`XHR message results: request=${requestSuccess}, response=${responseSuccess}`, "info");
}
} else {
writeLog(`\u274C WebSocket not ready for XHR data: readyState=${wsRef.current?.readyState}`, "warning");
}
if (this.status >= 200 && this.status < 300) {
writeLog(`\u2705 XHR Success: ${method} ${url} (${this.status}, ${duration}ms)`, "success");
} else {
writeLog(`\u274C XHR Error: ${method} ${url} (${this.status}, ${duration}ms)`, "error");
if (this.status >= 400) {
captureError(new Error(`XHR ${this.status}: ${this.statusText}`), {
type: "network_error",
url,
method,
status: this.status,
statusText: this.statusText,
duration,
requestId,
responseBody
});
}
}
});
this.addEventListener("error", () => {
const endTime = Date.now();
const duration = endTime - startTime;
const errorData = {
id: requestId,
type: "error",
method,
url,
duration,
timestamp: endTime,
requestTimestamp: startTime,
error: "Network Error",
errorType: "NetworkError"
};
setNetworkRequests((prev) => prev.map(
(req) => req.id === requestId ? { ...req, ...errorData, status: "error", success: false } : req
));
if (wsRef.current?.readyState === WebSocket.OPEN) {
writeLog(`\u{1F525} Sending XHR error to server`, "error");
const requestSuccess = sendMessage("NETWORK_REQUEST", requestData);
const errorSuccess = sendMessage("NETWORK_ERROR", errorData);
writeLog(`XHR error message results: request=${requestSuccess}, error=${errorSuccess}`, "info");
} else {
writeLog(`\u274C WebSocket not ready for XHR error: readyState=${wsRef.current?.readyState}`, "warning");
}
captureError(new Error("XHR Network Error"), {
type: "network_error",
url,
method,
duration,
requestId
});
});
}
return originalXHRSend.call(this, body);
};
writeLog("\u2705 Enhanced network interceptor setup complete", "success");
return () => {
window.fetch = originalFetch;
XMLHttpRequest.prototype.open = originalXHROpen;
XMLHttpRequest.prototype.send = originalXHRSend;
writeLog("\u{1F9F9} Enhanced network interceptor cleaned up", "info");
};
}, [writeLog, sendMessage, captureError, isConnected]);
const autoConnectToServer = (0, import_react.useCallback)(async () => {
if (!config.autoConnect) {
return null;
}
writeLog("\u{1F50D} Debug Time Machine \uC11C\uBC84 \uAC80\uC0C9 \uC911...", "info");
const serverExists = await checkDebugServer();
if (serverExists) {
writeLog("\u2705 Debug Time Machine \uC11C\uBC84 \uBC1C\uACAC! \uC5F0\uACB0\uC744 \uC2DC\uC791\uD569\uB2C8\uB2E4.", "success");
connect();
return null;
} else {
writeLog("\u{1F937} Debug Time Machine \uC11C\uBC84\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC77C\uBC18 \uBAA8\uB4DC\uB85C \uC2E4\uD589\uB429\uB2C8\uB2E4.", "info");
return null;
}
}, [config.autoConnect, checkDebugServer, connect, writeLog]);
(0, import_react.useEffect)(() => {
if (isInitializedRef.current || wsRef.current) {
return;
}
isInitializedRef.current = true;
writeLog("\u{1F680} Initializing Debug Time Machine client...", "info");
const cleanupNetworkInterceptor = setupEnhancedNetworkInterceptor();
autoConnectToServer().catch((error) => {
writeLog("\uC790\uB3D9 \uC5F0\uACB0 \uC911 \uC624\uB958 \uBC1C\uC0DD", "error", error);
});
writeLog("\u2705 Debug Time Machine client initialized!", "success");
return () => {
writeLog("\u{1F9F9} Cleaning up Debug Time Machine client...", "info");
isInitializedRef.current = false;
if (cleanupNetworkInterceptor) {
cleanupNetworkInterceptor();
}
if (reconnectTimeoutRef.current) {
clearTimeout(reconnectTimeoutRef.current);
reconnectTimeoutRef.current = null;
}
if (wsRef.current) {
wsRef.current.close(1e3, "Component unmounting");
wsRef.current = null;
}
};
}, []);
(0, import_react.useEffect)(() => {
return () => {
if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
wsRef.current.close();
}
};
}, []);
const createSnapshot = (0, import_react.useCallback)((state, actionType) => {
writeLog(`\u{1F4F8} Snapshot created: ${actionType}`, "success");
return { id: Date.now().toString(), state, actionType, timestamp: Date.now() };
}, [writeLog]);
const restoreSnapshot = (0, import_react.useCallback)((snapshotId) => {
writeLog(`\u23EE\uFE0F Snapshot restored: ${snapshotId}`, "success");
return true;
}, [writeLog]);
const getPerformanceMetrics = (0, import_react.useCallback)(() => {
return performanceMetrics;
}, [performanceMetrics]);
const getSystemMetrics = (0, import_react.useCallback)(() => {
return systemMetrics;
}, [systemMetrics]);
const getMemoryUsage = (0, import_react.useCallback)(() => {
return memoryUsage;
}, [memoryUsage]);
const clearSnapshots = (0, import_react.useCallback)(() => {
writeLog("\u{1F5D1}\uFE0F All snapshots cleared", "info");
}, [writeLog]);
const exportMetrics = (0, import_react.useCallback)(() => {
return { exported: true, timestamp: Date.now() };
}, []);
const getNetworkMetrics = (0, import_react.useCallback)(() => {
return {
totalRequests: networkRequests.length,
successfulRequests: networkRequests.filter((req) => req.success === true).length,
failedRequests: networkRequests.filter((req) => req.success === false).length,
requests: networkRequests
};
}, [networkRequests]);
const clearNetworkHistory = (0, import_react.useCallback)(() => {
setNetworkRequests([]);
setNetworkResponses([]);
writeLog("\u{1F5D1}\uFE0F Network history cleared", "info");
}, [writeLog]);
const exportNetworkData = (0, import_react.useCallback)(() => {
return {
requests: networkRequests,
responses: networkResponses,
metrics: getNetworkMetrics(),
exportedAt: (/* @__PURE__ */ new Date()).toISOString()
};
}, [networkRequests, networkResponses, getNetworkMetrics]);
return {
isConnected,
clientId,
reconnect,
sendMessage,
captureError,
captureStateChange,
connectionInfo,
shouldCaptureNetworkRequest: () => true,
shouldCaptureNetworkResponse: () => true,
createSnapshot,
restoreSnapshot,
getPerformanceMetrics,
getSystemMetrics,
getMemoryUsage,
clearSnapshots,
exportMetrics,
getNetworkMetrics,
clearNetworkHistory,
exportNetworkData,
timeTravelEngine: null,
metricsCollector: null,
domSnapshotOptimizer: null,
networkInterceptor: null,
performanceMetrics,
systemMetrics,
memoryUsage,
networkRequests,
networkResponses
};
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
MessageType,
useDebugTimeMachine
});
//# sourceMappingURL=index.js.map