-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbrowser-debug.js
More file actions
169 lines (151 loc) · 5.91 KB
/
browser-debug.js
File metadata and controls
169 lines (151 loc) · 5.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/**
* browser-debug.js - Diagnostic instrumentation for BrowserApp
*
* Wraps BrowserApp methods to trace event flow with correlation IDs.
* Outputs structured logs to console and collects for analysis.
*/
const DEBUG_LOG = [];
let correlationCounter = 0;
const DEBUG_CONSOLE_ENABLED = false;
function debugConsole(method, ...args) {
if (!DEBUG_CONSOLE_ENABLED) return;
console[method](...args);
}
function generateCorrelationId() {
return `evt-${++correlationCounter}-${Date.now()}`;
}
function debugLog(correlationId, event, data) {
const entry = {
correlationId,
timestamp: new Date().toISOString(),
event,
data,
stack: new Error().stack.split('\n').slice(2, 6).join('\n')
};
DEBUG_LOG.push(entry);
debugConsole('log', `[DEBUG ${correlationId}] ${event}`, JSON.stringify(data, null, 2));
return entry;
}
// Expose for console inspection
window.DEBUG_LOG = DEBUG_LOG;
window.getDebugLog = () => JSON.stringify(DEBUG_LOG, null, 2);
window.clearDebugLog = () => { DEBUG_LOG.length = 0; correlationCounter = 0; };
window.printDebugSummary = () => {
const summary = {};
DEBUG_LOG.forEach(e => {
summary[e.event] = (summary[e.event] || 0) + 1;
});
console.table(summary);
return summary;
};
/**
* Instruments a BrowserApp instance for debugging.
* Call this after BrowserApp is constructed.
*/
export function instrumentBrowserApp(browserApp) {
const webviewEl = browserApp.webviewEl;
const webviewId = browserApp.webviewId;
if (!webviewEl) {
debugConsole('error', '[DEBUG] Cannot instrument: webviewEl is null for', webviewId);
return browserApp;
}
debugConsole('log', `[DEBUG] Instrumenting BrowserApp for webviewId=${webviewId}`);
// Check if createTab exists
if (typeof webviewEl.createTab !== 'function') {
debugConsole('error', '[DEBUG] webviewEl.createTab is not a function:', typeof webviewEl.createTab);
return browserApp;
}
// Track all createTab calls with stack trace
const originalCreateTab = webviewEl.createTab.bind(webviewEl);
let createTabCallCount = 0;
webviewEl.createTab = function(url) {
const callNum = ++createTabCallCount;
const cid = generateCorrelationId();
const stack = new Error().stack;
debugLog(cid, 'createTab:called', {
url,
webviewId,
callNumber: callNum,
callerStack: stack.split('\n').slice(1, 5).join('\n')
});
return originalCreateTab(url).then(result => {
debugLog(cid, 'createTab:resolved', { result, callNumber: callNum });
return result;
}).catch(err => {
debugLog(cid, 'createTab:rejected', { error: err.message, callNumber: callNum });
throw err;
});
};
// Track all switchToTab calls
const originalSwitchToTab = webviewEl.switchToTab.bind(webviewEl);
webviewEl.switchToTab = function(index) {
const cid = generateCorrelationId();
debugLog(cid, 'switchToTab:called', { index, webviewId });
return originalSwitchToTab(index).then(result => {
debugLog(cid, 'switchToTab:resolved', { result });
return result;
}).catch(err => {
debugLog(cid, 'switchToTab:rejected', { error: err.message });
throw err;
});
};
// Track all closeTab calls
const originalCloseTab = webviewEl.closeTab.bind(webviewEl);
webviewEl.closeTab = function(index) {
const cid = generateCorrelationId();
debugLog(cid, 'closeTab:called', { index, webviewId });
return originalCloseTab(index).then(result => {
debugLog(cid, 'closeTab:resolved', { result });
return result;
}).catch(err => {
debugLog(cid, 'closeTab:rejected', { error: err.message });
throw err;
});
};
// Track ALL events from webview (in capture phase to see before app handlers)
const eventsToTrack = [
'ready', 'api-ready', 'tab-created', 'tab-closed',
'active-tab-changed', 'did-start-loading', 'did-stop-loading',
'did-navigate', 'policy-denied'
];
eventsToTrack.forEach(eventName => {
webviewEl.addEventListener(eventName, (e) => {
const cid = generateCorrelationId();
debugLog(cid, `event:${eventName}`, {
detail: e.detail,
eventPhase: e.eventPhase
});
}, true); // Capture phase
});
// Track click events on tab bar with full target info
const tabBar = browserApp.ui.tabBar;
if (tabBar) {
tabBar.addEventListener('click', (e) => {
const cid = generateCorrelationId();
debugLog(cid, 'tabBar:click:capture', {
targetTagName: e.target.tagName,
targetClassName: e.target.className,
targetDataset: { ...e.target.dataset },
closestTab: e.target.closest('.browser-tab-ie')?.dataset || null,
closestTabClass: e.target.closest('.browser-tab-ie')?.className || null,
isNewTabBtn: e.target.classList.contains('browser-new-tab-btn-ie'),
eventPhase: e.eventPhase,
});
}, true); // Capture phase to see before other handlers
}
// Track new tab button clicks
const newTabBtn = browserApp.ui.newTabButton;
if (newTabBtn) {
newTabBtn.addEventListener('click', (e) => {
const cid = generateCorrelationId();
debugLog(cid, 'newTabBtn:click:capture', {
eventPhase: e.eventPhase,
});
}, true); // Capture phase
}
debugConsole('log', '[DEBUG] BrowserApp instrumented. Commands:');
debugConsole('log', ' window.getDebugLog() - get full log as JSON');
debugConsole('log', ' window.printDebugSummary() - show event counts');
debugConsole('log', ' window.clearDebugLog() - clear log');
return browserApp;
}