@jshookmcp/jshook 0.2.7 → 0.2.9

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.
Files changed (157) hide show
  1. package/README.md +36 -5
  2. package/README.zh.md +36 -5
  3. package/dist/{AntiCheatDetector-S8VRj-dD.mjs → AntiCheatDetector-BNk-EoBt.mjs} +3 -3
  4. package/dist/{CodeInjector-4Z3ngPoX.mjs → CodeInjector-Cq8q01kp.mjs} +5 -5
  5. package/dist/ConsoleMonitor-CPVQW1Y-.mjs +2201 -0
  6. package/dist/{DarwinAPI-B8hg_yhz.mjs → DarwinAPI-BNPxu0RH.mjs} +1 -1
  7. package/dist/DetailedDataManager-BQQcxh64.mjs +217 -0
  8. package/dist/EventBus-DgPmwpeu.mjs +141 -0
  9. package/dist/EvidenceGraphBridge-SFesNera.mjs +153 -0
  10. package/dist/{ExtensionManager-CZ6IveoV.mjs → ExtensionManager-CWYgw0YW.mjs} +13 -6
  11. package/dist/{FingerprintManager-BVxFJL2-.mjs → FingerprintManager-gzWtkKuf.mjs} +1 -1
  12. package/dist/{HardwareBreakpoint-DK1yjWkV.mjs → HardwareBreakpoint-B9gZCdFP.mjs} +3 -3
  13. package/dist/{HeapAnalyzer-CEbo10xU.mjs → HeapAnalyzer-BLDH0dCv.mjs} +4 -4
  14. package/dist/HookGeneratorBuilders.core.generators.storage-CtcdK78Q.mjs +639 -0
  15. package/dist/InstrumentationSession-CvPC7Jwy.mjs +244 -0
  16. package/dist/{MemoryController-DdtnBdD4.mjs → MemoryController-CbVdCIJF.mjs} +3 -3
  17. package/dist/{MemoryScanSession-RMixN3bX.mjs → MemoryScanSession-BsDZbLYm.mjs} +81 -78
  18. package/dist/{MemoryScanner-QjK4ld0B.mjs → MemoryScanner-Bcpml6II.mjs} +44 -18
  19. package/dist/{NativeMemoryManager.impl-CB6gJ0NM.mjs → NativeMemoryManager.impl-dZtA1ZGn.mjs} +14 -53
  20. package/dist/{NativeMemoryManager.utils-BML4q1ry.mjs → NativeMemoryManager.utils-B-FjA2mJ.mjs} +1 -1
  21. package/dist/{PEAnalyzer-CK0xe0Fs.mjs → PEAnalyzer-D1lzJ_VG.mjs} +2 -2
  22. package/dist/PageController-Bqm2kZ_X.mjs +417 -0
  23. package/dist/{PointerChainEngine-Cd73qu5b.mjs → PointerChainEngine-BOhyVsjx.mjs} +4 -4
  24. package/dist/PrerequisiteError-Dl33Svkz.mjs +20 -0
  25. package/dist/ResponseBuilder-D3iFYx2N.mjs +143 -0
  26. package/dist/ReverseEvidenceGraph-Dlsk94LC.mjs +269 -0
  27. package/dist/ScriptManager-aHHq0X7U.mjs +3000 -0
  28. package/dist/{Speedhack-CeF0XmEz.mjs → Speedhack-CqdIFlQl.mjs} +2 -2
  29. package/dist/{StructureAnalyzer-D4GkMduU.mjs → StructureAnalyzer-DhFaPvRO.mjs} +3 -3
  30. package/dist/ToolCatalog-C0JGZoOm.mjs +582 -0
  31. package/dist/ToolError-jh9whhMd.mjs +15 -0
  32. package/dist/ToolProbe-oC7aPrkv.mjs +45 -0
  33. package/dist/ToolRegistry-BjaF4oNz.mjs +131 -0
  34. package/dist/ToolRouter.policy-BWV67ZK-.mjs +304 -0
  35. package/dist/TraceRecorder-DgxyVbdQ.mjs +519 -0
  36. package/dist/{Win32API-Bc0QnQsN.mjs → Win32API-CePkipZY.mjs} +1 -1
  37. package/dist/{Win32Debug-DUHt9XUn.mjs → Win32Debug-BvKs-gxc.mjs} +2 -2
  38. package/dist/WorkflowEngine-CuvkZtWu.mjs +598 -0
  39. package/dist/analysis-CL9uACt9.mjs +463 -0
  40. package/dist/antidebug-CqDTB_uk.mjs +1081 -0
  41. package/dist/artifactRetention-CFEprwPw.mjs +591 -0
  42. package/dist/artifacts-Bk2-_uPq.mjs +59 -0
  43. package/dist/betterSqlite3-0pqusHHH.mjs +74 -0
  44. package/dist/binary-instrument-CXfpx6fT.mjs +979 -0
  45. package/dist/bind-helpers-xFfRF-qm.mjs +22 -0
  46. package/dist/boringssl-inspector-BH2D3VKc.mjs +180 -0
  47. package/dist/browser-BpOr5PEx.mjs +4082 -0
  48. package/dist/concurrency-Bt0yv1kJ.mjs +41 -0
  49. package/dist/{constants-CCvsN80K.mjs → constants-B0OANIBL.mjs} +88 -46
  50. package/dist/coordination-qUbyF8KU.mjs +259 -0
  51. package/dist/debugger-gnKxRSN0.mjs +1271 -0
  52. package/dist/definitions-6M-eejaT.mjs +53 -0
  53. package/dist/definitions-B18eyf0B.mjs +18 -0
  54. package/dist/definitions-B3QdlrHv.mjs +34 -0
  55. package/dist/definitions-B4rAvHNZ.mjs +63 -0
  56. package/dist/definitions-BB_4jnmy.mjs +37 -0
  57. package/dist/definitions-BMfYXoNC.mjs +43 -0
  58. package/dist/definitions-Beid2EB3.mjs +27 -0
  59. package/dist/definitions-C1UvM5Iy.mjs +126 -0
  60. package/dist/definitions-CXEI7QC72.mjs +216 -0
  61. package/dist/definitions-C_4r7Fo-2.mjs +14 -0
  62. package/dist/definitions-CkFDALoa.mjs +26 -0
  63. package/dist/definitions-Cke7zEb8.mjs +94 -0
  64. package/dist/definitions-ClJLzsJQ.mjs +25 -0
  65. package/dist/definitions-Cq-zroAU.mjs +28 -0
  66. package/dist/definitions-Cy3Sl6gV.mjs +34 -0
  67. package/dist/definitions-D3VsGcvz.mjs +47 -0
  68. package/dist/definitions-DVGfrn7y.mjs +96 -0
  69. package/dist/definitions-LKpC3-nL.mjs +9 -0
  70. package/dist/definitions-bAhHQJq9.mjs +359 -0
  71. package/dist/encoding-Bvz5jLRv.mjs +1065 -0
  72. package/dist/evidence-graph-bridge-C_fv9PuC.mjs +135 -0
  73. package/dist/{factory-CibqTNC8.mjs → factory-DxlGh9Xf.mjs} +37 -52
  74. package/dist/graphql-DYWzJ29s.mjs +1026 -0
  75. package/dist/handlers-9sAbfIg-.mjs +2552 -0
  76. package/dist/handlers-Bl8zkwz1.mjs +2716 -0
  77. package/dist/handlers-C67ktuRN.mjs +710 -0
  78. package/dist/handlers-C87g8oCe.mjs +276 -0
  79. package/dist/handlers-CTsDAO6p.mjs +681 -0
  80. package/dist/handlers-Cgyg6c0U.mjs +645 -0
  81. package/dist/handlers-D6j6yka7.mjs +2124 -0
  82. package/dist/handlers-DdFzXLvF.mjs +446 -0
  83. package/dist/handlers-DeLOCd5m.mjs +799 -0
  84. package/dist/handlers-DlCJN4Td.mjs +757 -0
  85. package/dist/handlers-DxGIq15_2.mjs +917 -0
  86. package/dist/handlers-U6L4xhuF.mjs +585 -0
  87. package/dist/handlers-tB9Mp9ZK.mjs +84 -0
  88. package/dist/handlers-tiy7EIBp.mjs +572 -0
  89. package/dist/handlers.impl-DS0d9fUw.mjs +761 -0
  90. package/dist/hooks-CzCWByww.mjs +898 -0
  91. package/dist/index.mjs +384 -155
  92. package/dist/{logger-BmWzC2lM.mjs → logger-Dh_xb7_2.mjs} +14 -6
  93. package/dist/maintenance-P7ePRXQC.mjs +830 -0
  94. package/dist/manifest-2ToTpjv8.mjs +106 -0
  95. package/dist/manifest-3g71z6Bg.mjs +79 -0
  96. package/dist/manifest-82baTv4U.mjs +45 -0
  97. package/dist/manifest-B3QVVeBS.mjs +82 -0
  98. package/dist/manifest-BB2J8IMJ.mjs +149 -0
  99. package/dist/manifest-BKbgbSiY.mjs +60 -0
  100. package/dist/manifest-Bcf-TJzH.mjs +848 -0
  101. package/dist/manifest-BmtZzQiQ2.mjs +45 -0
  102. package/dist/manifest-Bnd7kqEY.mjs +55 -0
  103. package/dist/manifest-BqQX6OQC2.mjs +65 -0
  104. package/dist/manifest-BqrQ4Tpj.mjs +81 -0
  105. package/dist/manifest-Br4RPFt5.mjs +370 -0
  106. package/dist/manifest-C5qDjysN.mjs +107 -0
  107. package/dist/manifest-C9RT5nk32.mjs +34 -0
  108. package/dist/manifest-CAhOuvSl.mjs +204 -0
  109. package/dist/manifest-CBYWCUBJ.mjs +51 -0
  110. package/dist/manifest-CFADCRa1.mjs +37 -0
  111. package/dist/manifest-CQVhavRF.mjs +114 -0
  112. package/dist/manifest-CT7zZBV1.mjs +48 -0
  113. package/dist/manifest-CV12bcrF.mjs +121 -0
  114. package/dist/manifest-CXsRWjjI.mjs +224 -0
  115. package/dist/manifest-CZLUCfG02.mjs +95 -0
  116. package/dist/manifest-D6phHKFd.mjs +131 -0
  117. package/dist/manifest-DCyjf4n2.mjs +294 -0
  118. package/dist/manifest-DHsnKgP6.mjs +60 -0
  119. package/dist/manifest-Df_dliIe.mjs +55 -0
  120. package/dist/manifest-Dh8WBmEW.mjs +129 -0
  121. package/dist/manifest-DhKRAT8_.mjs +92 -0
  122. package/dist/manifest-DlpTj4ic2.mjs +193 -0
  123. package/dist/manifest-DrbmZcFl2.mjs +253 -0
  124. package/dist/manifest-DuwHjUa5.mjs +70 -0
  125. package/dist/manifest-DzwvxPJX.mjs +38 -0
  126. package/dist/manifest-NXctwWQq.mjs +68 -0
  127. package/dist/manifest-Sc_0JQ13.mjs +418 -0
  128. package/dist/manifest-gZ4s_UtG.mjs +96 -0
  129. package/dist/manifest-qSleDqdO.mjs +1023 -0
  130. package/dist/modules-C184v-S9.mjs +11365 -0
  131. package/dist/mojo-ipc-B_H61Afw.mjs +525 -0
  132. package/dist/network-671Cw6hV.mjs +3346 -0
  133. package/dist/{artifacts-BbdOMET5.mjs → outputPaths-B1uGmrWZ.mjs} +219 -212
  134. package/dist/parse-args-BlRjqlkL.mjs +39 -0
  135. package/dist/platform-WmNn8Sxb.mjs +2070 -0
  136. package/dist/process-QcbIy5Zq.mjs +1401 -0
  137. package/dist/proxy-DqNs0bAd.mjs +170 -0
  138. package/dist/registry-D-6e18lB.mjs +34 -0
  139. package/dist/response-BQVP-xUn.mjs +28 -0
  140. package/dist/server/plugin-api.mjs +2 -2
  141. package/dist/shared-state-board-DV-dpHFJ.mjs +586 -0
  142. package/dist/sourcemap-Dq8ez8vS.mjs +650 -0
  143. package/dist/ssrf-policy-ZaUfvhq7.mjs +166 -0
  144. package/dist/streaming-BUQ0VJsg.mjs +725 -0
  145. package/dist/tool-builder-DCbIC5Eo.mjs +186 -0
  146. package/dist/transform-CiYJfNX0.mjs +1007 -0
  147. package/dist/types-Bx92KJfT.mjs +4 -0
  148. package/dist/wasm-DQTnHDs4.mjs +531 -0
  149. package/dist/workflow-f3xJOcjx.mjs +725 -0
  150. package/package.json +48 -78
  151. package/dist/ExtensionManager-DqUSOamB.mjs +0 -2
  152. package/dist/ToolCatalog-CnwmMIw3.mjs +0 -61483
  153. package/dist/{CacheAdapters-CzFNpD9a.mjs → CacheAdapters-CDe5WPSV.mjs} +0 -0
  154. package/dist/{StealthVerifier-BzBCFiwx.mjs → StealthVerifier-Bo4T3bz8.mjs} +0 -0
  155. package/dist/{VersionDetector-CNXcvD46.mjs → VersionDetector-CwVLVdDM.mjs} +0 -0
  156. package/dist/{formatAddress-ChCSIRWT.mjs → formatAddress-DVkj9kpI.mjs} +0 -0
  157. package/dist/{types-BBjOqye-.mjs → types-CPhOReNX.mjs} +1 -1
@@ -0,0 +1,2201 @@
1
+ import { t as __exportAll } from "./chunk-CjcI7cDX.mjs";
2
+ import { t as logger } from "./logger-Dh_xb7_2.mjs";
3
+ import { t as PrerequisiteError } from "./PrerequisiteError-Dl33Svkz.mjs";
4
+ import { randomUUID } from "node:crypto";
5
+ //#region src/modules/monitor/NetworkMonitor.interceptors.ts
6
+ function buildXHRInterceptorCode(maxRecords) {
7
+ return `
8
+ (function() {
9
+ if (window.__xhrInterceptorInstalled) {
10
+ console.log('[XHRInterceptor] Already installed');
11
+ return;
12
+ }
13
+ window.__xhrInterceptorInstalled = true;
14
+
15
+ const originalXHR = window.__originalXMLHttpRequestForHook || window.XMLHttpRequest;
16
+ window.__originalXMLHttpRequestForHook = originalXHR;
17
+ if (!window.__xhrRequests) {
18
+ window.__xhrRequests = [];
19
+ }
20
+ const xhrRequests = window.__xhrRequests;
21
+
22
+ window.XMLHttpRequest = function() {
23
+ const xhr = new originalXHR();
24
+ const requestInfo = {
25
+ method: '',
26
+ url: '',
27
+ requestHeaders: {},
28
+ responseHeaders: {},
29
+ status: 0,
30
+ response: null,
31
+ timestamp: Date.now(),
32
+ };
33
+
34
+ const originalOpen = xhr.open;
35
+ xhr.open = function(method, url, ...args) {
36
+ requestInfo.method = method;
37
+ requestInfo.url = url;
38
+ console.log('[XHRInterceptor] XHR opened:', method, url);
39
+ return originalOpen.call(xhr, method, url, ...args);
40
+ };
41
+
42
+ const originalSetRequestHeader = xhr.setRequestHeader;
43
+ xhr.setRequestHeader = function(header, value) {
44
+ requestInfo.requestHeaders[header] = value;
45
+ return originalSetRequestHeader.call(xhr, header, value);
46
+ };
47
+
48
+ const originalSend = xhr.send;
49
+ xhr.send = function(body) {
50
+ let bodySize = 0;
51
+ try {
52
+ if (typeof body === 'string') bodySize = body.length;
53
+ else if (body && typeof body.byteLength === 'number') bodySize = body.byteLength;
54
+ else if (body && typeof body.size === 'number') bodySize = body.size;
55
+ } catch {}
56
+ console.log('[XHRInterceptor] XHR sent:', requestInfo.url, 'BodySize:', bodySize);
57
+
58
+ xhr.addEventListener('load', function() {
59
+ requestInfo.status = xhr.status;
60
+ requestInfo.response = xhr.response;
61
+ requestInfo.responseHeaders = xhr.getAllResponseHeaders();
62
+
63
+ xhrRequests.push(requestInfo);
64
+ if (xhrRequests.length > ${maxRecords}) {
65
+ xhrRequests.splice(0, xhrRequests.length - ${maxRecords});
66
+ }
67
+ console.log('[XHRInterceptor] XHR completed:', requestInfo.url, 'Status:', xhr.status);
68
+ });
69
+
70
+ return originalSend.call(xhr, body);
71
+ };
72
+
73
+ return xhr;
74
+ };
75
+
76
+ window.__getXHRRequests = function() {
77
+ return window.__xhrRequests || [];
78
+ };
79
+
80
+ console.log('[XHRInterceptor] XHR interceptor installed');
81
+ })();
82
+ `;
83
+ }
84
+ function buildFetchInterceptorCode(maxRecords) {
85
+ return `
86
+ (function() {
87
+ if (window.__fetchInterceptorInstalled) {
88
+ console.log('[FetchInterceptor] Already installed');
89
+ return;
90
+ }
91
+ window.__fetchInterceptorInstalled = true;
92
+
93
+ const originalFetch = window.__originalFetchForHook || window.fetch;
94
+ window.__originalFetchForHook = originalFetch;
95
+ if (!window.__fetchRequests) {
96
+ window.__fetchRequests = [];
97
+ }
98
+ const fetchRequests = window.__fetchRequests;
99
+
100
+ window.fetch = function(url, options = {}) {
101
+ const requestInfo = {
102
+ url: typeof url === 'string' ? url : url.url,
103
+ method: options.method || 'GET',
104
+ headers: options.headers || {},
105
+ body: options.body,
106
+ timestamp: Date.now(),
107
+ response: null,
108
+ status: 0,
109
+ };
110
+
111
+ console.log('[FetchInterceptor] Fetch called:', requestInfo.method, requestInfo.url);
112
+
113
+ return originalFetch.call(window, url, options).then(async (response) => {
114
+ requestInfo.status = response.status;
115
+
116
+ const clonedResponse = response.clone();
117
+ try {
118
+ requestInfo.response = await clonedResponse.text();
119
+ } catch (e) {
120
+ requestInfo.response = '[Unable to read response]';
121
+ }
122
+
123
+ fetchRequests.push(requestInfo);
124
+ if (fetchRequests.length > ${maxRecords}) {
125
+ fetchRequests.splice(0, fetchRequests.length - ${maxRecords});
126
+ }
127
+ // Auto-persist compact summary to localStorage so data survives context compression
128
+ try {
129
+ const summary = { url: requestInfo.url, method: requestInfo.method, status: requestInfo.status, ts: requestInfo.timestamp };
130
+ const prev = JSON.parse(localStorage.getItem('__capturedAPIs') || '[]');
131
+ prev.push(summary);
132
+ if (prev.length > 500) prev.splice(0, prev.length - 500);
133
+ localStorage.setItem('__capturedAPIs', JSON.stringify(prev));
134
+ } catch(e) {
135
+ // best-effort persistence only; ignore quota or serialization failures
136
+ }
137
+ console.log('[FetchInterceptor] Fetch completed:', requestInfo.url, 'Status:', response.status);
138
+
139
+ return response;
140
+ }).catch((error) => {
141
+ console.error('[FetchInterceptor] Fetch failed:', requestInfo.url, error);
142
+ throw error;
143
+ });
144
+ };
145
+
146
+ window.__getFetchRequests = function() {
147
+ return window.__fetchRequests || [];
148
+ };
149
+
150
+ console.log('[FetchInterceptor] Fetch interceptor installed');
151
+ })();
152
+ `;
153
+ }
154
+ const CLEAR_INJECTED_BUFFERS_EXPRESSION = `
155
+ (() => {
156
+ const xhrStore = Array.isArray(window.__xhrRequests)
157
+ ? window.__xhrRequests
158
+ : (typeof window.__getXHRRequests === 'function' ? window.__getXHRRequests() : null);
159
+ const fetchStore = Array.isArray(window.__fetchRequests)
160
+ ? window.__fetchRequests
161
+ : (typeof window.__getFetchRequests === 'function' ? window.__getFetchRequests() : null);
162
+
163
+ const xhrCleared = Array.isArray(xhrStore) ? xhrStore.length : 0;
164
+ const fetchCleared = Array.isArray(fetchStore) ? fetchStore.length : 0;
165
+
166
+ if (Array.isArray(xhrStore)) xhrStore.length = 0;
167
+ if (Array.isArray(fetchStore)) fetchStore.length = 0;
168
+
169
+ return { xhrCleared, fetchCleared };
170
+ })()
171
+ `;
172
+ const RESET_INJECTED_INTERCEPTORS_EXPRESSION = `
173
+ (() => {
174
+ let xhrReset = false;
175
+ let fetchReset = false;
176
+
177
+ if (window.__originalXMLHttpRequestForHook) {
178
+ window.XMLHttpRequest = window.__originalXMLHttpRequestForHook;
179
+ xhrReset = true;
180
+ }
181
+
182
+ if (window.__originalFetchForHook) {
183
+ window.fetch = window.__originalFetchForHook;
184
+ fetchReset = true;
185
+ }
186
+
187
+ if (Array.isArray(window.__xhrRequests)) window.__xhrRequests.length = 0;
188
+ if (Array.isArray(window.__fetchRequests)) window.__fetchRequests.length = 0;
189
+
190
+ window.__xhrInterceptorInstalled = false;
191
+ window.__fetchInterceptorInstalled = false;
192
+ delete window.__getXHRRequests;
193
+ delete window.__getFetchRequests;
194
+
195
+ return { xhrReset, fetchReset };
196
+ })()
197
+ `;
198
+ //#endregion
199
+ //#region src/modules/monitor/NetworkMonitor.impl.ts
200
+ const isObjectRecord = (value) => typeof value === "object" && value !== null;
201
+ const isRequestWillBeSentPayload = (value) => {
202
+ if (!isObjectRecord(value) || typeof value.requestId !== "string") return false;
203
+ if (!isObjectRecord(value.request)) return false;
204
+ if (typeof value.request.url !== "string" || typeof value.request.method !== "string") return false;
205
+ if (value.request.postData !== void 0 && typeof value.request.postData !== "string") return false;
206
+ return typeof value.timestamp === "number";
207
+ };
208
+ const isResponseReceivedPayload = (value) => {
209
+ if (!isObjectRecord(value) || typeof value.requestId !== "string") return false;
210
+ if (!isObjectRecord(value.response)) return false;
211
+ if (typeof value.response.url !== "string" || typeof value.response.status !== "number" || typeof value.response.statusText !== "string" || typeof value.response.mimeType !== "string") return false;
212
+ return typeof value.timestamp === "number";
213
+ };
214
+ const isLoadingFinishedPayload = (value) => isObjectRecord(value) && typeof value.requestId === "string";
215
+ const isResponseBodyPayload = (value) => isObjectRecord(value) && typeof value.body === "string" && typeof value.base64Encoded === "boolean";
216
+ const asStringRecord = (value) => isObjectRecord(value) ? value : {};
217
+ const toRuntimeEvaluateValue = (value) => {
218
+ if (!isObjectRecord(value)) return;
219
+ const runtimeResult = value.result;
220
+ if (!isObjectRecord(runtimeResult)) return;
221
+ return runtimeResult.value;
222
+ };
223
+ const toFiniteNumber = (value, fallback = 0) => typeof value === "number" && Number.isFinite(value) ? value : fallback;
224
+ const toBoolean = (value, fallback) => typeof value === "boolean" ? value : fallback;
225
+ var NetworkMonitor = class {
226
+ networkEnabled = false;
227
+ requests = /* @__PURE__ */ new Map();
228
+ responses = /* @__PURE__ */ new Map();
229
+ MAX_NETWORK_RECORDS = 500;
230
+ MAX_INJECTED_RECORDS = 500;
231
+ JS_RESPONSE_CONCURRENCY = 6;
232
+ /** LRU cache for response bodies, auto-captured on loadingFinished. */
233
+ responseBodyCache = /* @__PURE__ */ new Map();
234
+ MAX_BODY_CACHE_ENTRIES = 200;
235
+ networkListeners = {};
236
+ constructor(cdpSession) {
237
+ this.cdpSession = cdpSession;
238
+ this.cdpSession.on("disconnected", () => {
239
+ logger.warn("NetworkMonitor: CDP session disconnected");
240
+ this.networkEnabled = false;
241
+ this.networkListeners = {};
242
+ });
243
+ }
244
+ async enable() {
245
+ if (!this.cdpSession) throw new Error("CDP session not initialized");
246
+ if (this.networkEnabled) {
247
+ logger.warn("Network monitoring already enabled");
248
+ return;
249
+ }
250
+ try {
251
+ await this.cdpSession.send("Network.enable", {
252
+ maxTotalBufferSize: 1e7,
253
+ maxResourceBufferSize: 5e6,
254
+ maxPostDataSize: 65536
255
+ });
256
+ logger.info("Network domain enabled");
257
+ this.networkListeners.requestWillBeSent = (params) => {
258
+ if (!isRequestWillBeSentPayload(params)) {
259
+ logger.debug("Skipping malformed Network.requestWillBeSent payload");
260
+ return;
261
+ }
262
+ const request = {
263
+ requestId: params.requestId,
264
+ url: params.request.url,
265
+ method: params.request.method,
266
+ headers: asStringRecord(params.request.headers),
267
+ postData: params.request.postData,
268
+ timestamp: params.timestamp,
269
+ type: params.type,
270
+ initiator: params.initiator
271
+ };
272
+ this.requests.set(params.requestId, request);
273
+ if (this.requests.size > this.MAX_NETWORK_RECORDS) {
274
+ const firstKey = this.requests.keys().next().value;
275
+ if (firstKey) this.requests.delete(firstKey);
276
+ }
277
+ logger.debug(`Network request captured: ${params.request.method} ${params.request.url}`);
278
+ };
279
+ this.networkListeners.responseReceived = (params) => {
280
+ if (!isResponseReceivedPayload(params)) {
281
+ logger.debug("Skipping malformed Network.responseReceived payload");
282
+ return;
283
+ }
284
+ const response = {
285
+ requestId: params.requestId,
286
+ url: params.response.url,
287
+ status: params.response.status,
288
+ statusText: params.response.statusText,
289
+ headers: asStringRecord(params.response.headers),
290
+ mimeType: params.response.mimeType,
291
+ timestamp: params.timestamp,
292
+ fromCache: params.response.fromDiskCache || params.response.fromServiceWorker,
293
+ timing: params.response.timing
294
+ };
295
+ this.responses.set(params.requestId, response);
296
+ if (this.responses.size > this.MAX_NETWORK_RECORDS) {
297
+ const firstKey = this.responses.keys().next().value;
298
+ if (firstKey) this.responses.delete(firstKey);
299
+ }
300
+ logger.debug(`Network response captured: ${params.response.status} ${params.response.url}`);
301
+ };
302
+ this.networkListeners.loadingFinished = (params) => {
303
+ if (!isLoadingFinishedPayload(params)) {
304
+ logger.debug("Skipping malformed Network.loadingFinished payload");
305
+ return;
306
+ }
307
+ logger.debug(`Network loading finished: ${params.requestId}`);
308
+ this.captureResponseBody(params.requestId).catch((err) => {
309
+ logger.debug(`[BodyCache] Auto-capture failed for ${params.requestId}: ${err instanceof Error ? err.message : String(err)}`);
310
+ });
311
+ };
312
+ this.cdpSession.on("Network.requestWillBeSent", this.networkListeners.requestWillBeSent);
313
+ this.cdpSession.on("Network.responseReceived", this.networkListeners.responseReceived);
314
+ this.cdpSession.on("Network.loadingFinished", this.networkListeners.loadingFinished);
315
+ this.networkEnabled = true;
316
+ logger.info(" Network monitoring enabled successfully", {
317
+ requestListeners: !!this.networkListeners.requestWillBeSent,
318
+ responseListeners: !!this.networkListeners.responseReceived,
319
+ loadingListeners: !!this.networkListeners.loadingFinished
320
+ });
321
+ } catch (error) {
322
+ logger.error(" Failed to enable network monitoring:", error);
323
+ this.networkEnabled = false;
324
+ throw error;
325
+ }
326
+ }
327
+ /**
328
+ * Auto-capture a response body into the LRU cache.
329
+ * Called from the loadingFinished listener so bodies are available
330
+ * even after Chrome's internal buffer is reclaimed.
331
+ */
332
+ async captureResponseBody(requestId) {
333
+ if (this.responseBodyCache.has(requestId)) return;
334
+ const response = this.responses.get(requestId);
335
+ if (!response) return;
336
+ if (response.fromCache) return;
337
+ try {
338
+ const rawResult = await this.cdpSession.send("Network.getResponseBody", { requestId });
339
+ if (!isResponseBodyPayload(rawResult)) return;
340
+ if (rawResult.body.length > 1048576) {
341
+ logger.debug(`[BodyCache] Skipping oversized body for ${requestId} (${rawResult.body.length} chars)`);
342
+ return;
343
+ }
344
+ if (this.responseBodyCache.size >= this.MAX_BODY_CACHE_ENTRIES) {
345
+ const oldestKey = this.responseBodyCache.keys().next().value;
346
+ if (oldestKey) this.responseBodyCache.delete(oldestKey);
347
+ }
348
+ this.responseBodyCache.set(requestId, {
349
+ body: rawResult.body,
350
+ base64Encoded: rawResult.base64Encoded
351
+ });
352
+ logger.debug(`[BodyCache] Cached body for ${requestId} (${rawResult.body.length} chars, url=${response.url})`);
353
+ } catch (err) {
354
+ logger.debug(`[BodyCache] Could not capture body for ${requestId}: ${err instanceof Error ? err.message : String(err)}`);
355
+ }
356
+ }
357
+ async disable() {
358
+ if (!this.networkEnabled) return;
359
+ if (this.networkListeners.requestWillBeSent) this.cdpSession.off("Network.requestWillBeSent", this.networkListeners.requestWillBeSent);
360
+ if (this.networkListeners.responseReceived) this.cdpSession.off("Network.responseReceived", this.networkListeners.responseReceived);
361
+ if (this.networkListeners.loadingFinished) this.cdpSession.off("Network.loadingFinished", this.networkListeners.loadingFinished);
362
+ try {
363
+ await this.cdpSession.send("Network.disable");
364
+ } catch (error) {
365
+ logger.warn("Failed to disable Network domain:", error);
366
+ }
367
+ this.networkListeners = {};
368
+ this.networkEnabled = false;
369
+ logger.info("Network monitoring disabled");
370
+ }
371
+ isEnabled() {
372
+ return this.networkEnabled;
373
+ }
374
+ getStatus() {
375
+ return {
376
+ enabled: this.networkEnabled,
377
+ requestCount: this.requests.size,
378
+ responseCount: this.responses.size,
379
+ listenerCount: Object.keys(this.networkListeners).filter((key) => this.networkListeners[key] !== void 0).length,
380
+ cdpSessionActive: true
381
+ };
382
+ }
383
+ getRequests(filter) {
384
+ let requests = Array.from(this.requests.values());
385
+ if (filter?.url) requests = requests.filter((req) => req.url.includes(filter.url));
386
+ if (filter?.method) requests = requests.filter((req) => req.method === filter.method);
387
+ if (filter?.limit) requests = requests.slice(-filter.limit);
388
+ return requests;
389
+ }
390
+ getResponses(filter) {
391
+ let responses = Array.from(this.responses.values());
392
+ if (filter?.url) responses = responses.filter((res) => res.url.includes(filter.url));
393
+ if (filter?.status) responses = responses.filter((res) => res.status === filter.status);
394
+ if (filter?.limit) responses = responses.slice(-filter.limit);
395
+ return responses;
396
+ }
397
+ getActivity(requestId) {
398
+ return {
399
+ request: this.requests.get(requestId),
400
+ response: this.responses.get(requestId)
401
+ };
402
+ }
403
+ async getResponseBody(requestId) {
404
+ if (!this.cdpSession) throw new Error("CDP session not initialized");
405
+ if (!this.networkEnabled) {
406
+ logger.error("Network monitoring is not enabled. Call enable() with enableNetwork: true first.");
407
+ return null;
408
+ }
409
+ const cached = this.responseBodyCache.get(requestId);
410
+ if (cached) {
411
+ this.responseBodyCache.delete(requestId);
412
+ this.responseBodyCache.set(requestId, cached);
413
+ logger.debug(`[BodyCache] Cache hit for ${requestId}`);
414
+ return cached;
415
+ }
416
+ const request = this.requests.get(requestId);
417
+ const response = this.responses.get(requestId);
418
+ if (!request) {
419
+ logger.error(`Request not found: ${requestId}. Make sure network monitoring was enabled before the request.`);
420
+ return null;
421
+ }
422
+ if (!response) {
423
+ logger.warn(`Response not yet received for request: ${requestId}. The request may still be pending.`);
424
+ return null;
425
+ }
426
+ try {
427
+ const rawResult = await this.cdpSession.send("Network.getResponseBody", { requestId });
428
+ if (!isResponseBodyPayload(rawResult)) {
429
+ logger.error(`Unexpected response body payload for ${requestId}`);
430
+ return null;
431
+ }
432
+ logger.info(`Response body retrieved for request: ${requestId}`, {
433
+ url: response.url,
434
+ status: response.status,
435
+ size: rawResult.body.length,
436
+ base64: rawResult.base64Encoded
437
+ });
438
+ return {
439
+ body: rawResult.body,
440
+ base64Encoded: rawResult.base64Encoded
441
+ };
442
+ } catch (error) {
443
+ const errorMessage = error instanceof Error ? error.message : String(error);
444
+ logger.error(`Failed to get response body for ${requestId}:`, {
445
+ url: response.url,
446
+ status: response.status,
447
+ error: errorMessage,
448
+ hint: "The response body may not be available for this request type (e.g., cached, redirected, or failed requests)"
449
+ });
450
+ return null;
451
+ }
452
+ }
453
+ async getAllJavaScriptResponses() {
454
+ const candidates = Array.from(this.responses.entries()).filter(([, response]) => {
455
+ return response.mimeType.includes("javascript") || response.url.endsWith(".js") || response.url.includes(".js?");
456
+ });
457
+ const jsResponses = [];
458
+ for (let i = 0; i < candidates.length; i += this.JS_RESPONSE_CONCURRENCY) {
459
+ const batch = candidates.slice(i, i + this.JS_RESPONSE_CONCURRENCY);
460
+ const batchResults = await Promise.all(batch.map(async ([requestId, response]) => {
461
+ const bodyResult = await this.getResponseBody(requestId);
462
+ if (!bodyResult) return null;
463
+ const content = bodyResult.base64Encoded ? Buffer.from(bodyResult.body, "base64").toString("utf-8") : bodyResult.body;
464
+ return {
465
+ url: response.url,
466
+ content,
467
+ size: content.length,
468
+ requestId
469
+ };
470
+ }));
471
+ jsResponses.push(...batchResults.filter((value) => value !== null));
472
+ }
473
+ logger.info(`Collected ${jsResponses.length} JavaScript responses`);
474
+ return jsResponses;
475
+ }
476
+ clearRecords() {
477
+ this.requests.clear();
478
+ this.responses.clear();
479
+ this.responseBodyCache.clear();
480
+ logger.info("Network records cleared");
481
+ }
482
+ getStats() {
483
+ const byMethod = {};
484
+ const byStatus = {};
485
+ const byType = {};
486
+ for (const request of this.requests.values()) {
487
+ byMethod[request.method] = (byMethod[request.method] || 0) + 1;
488
+ if (request.type) byType[request.type] = (byType[request.type] || 0) + 1;
489
+ }
490
+ for (const response of this.responses.values()) byStatus[response.status] = (byStatus[response.status] || 0) + 1;
491
+ return {
492
+ totalRequests: this.requests.size,
493
+ totalResponses: this.responses.size,
494
+ byMethod,
495
+ byStatus,
496
+ byType
497
+ };
498
+ }
499
+ async injectXHRInterceptor(options) {
500
+ if (!this.cdpSession) throw new Error("CDP session not initialized");
501
+ const interceptorCode = buildXHRInterceptorCode(this.MAX_INJECTED_RECORDS);
502
+ if (options?.persistent) {
503
+ await this.cdpSession.send("Page.addScriptToEvaluateOnNewDocument", { source: interceptorCode });
504
+ logger.info("XHR interceptor injected (persistent)");
505
+ } else {
506
+ await this.cdpSession.send("Runtime.evaluate", { expression: interceptorCode });
507
+ logger.info("XHR interceptor injected");
508
+ }
509
+ }
510
+ async injectFetchInterceptor(options) {
511
+ if (!this.cdpSession) throw new Error("CDP session not initialized");
512
+ const interceptorCode = buildFetchInterceptorCode(this.MAX_INJECTED_RECORDS);
513
+ if (options?.persistent) {
514
+ await this.cdpSession.send("Page.addScriptToEvaluateOnNewDocument", { source: interceptorCode });
515
+ logger.info("Fetch interceptor injected (persistent)");
516
+ } else {
517
+ await this.cdpSession.send("Runtime.evaluate", { expression: interceptorCode });
518
+ logger.info("Fetch interceptor injected");
519
+ }
520
+ }
521
+ async getXHRRequests() {
522
+ if (!this.cdpSession) throw new Error("CDP session not initialized");
523
+ try {
524
+ const value = toRuntimeEvaluateValue(await this.cdpSession.send("Runtime.evaluate", {
525
+ expression: "window.__getXHRRequests ? window.__getXHRRequests() : []",
526
+ returnByValue: true
527
+ }));
528
+ if (!Array.isArray(value)) return [];
529
+ return value.filter((entry) => isObjectRecord(entry));
530
+ } catch (error) {
531
+ logger.error("Failed to get XHR requests:", error);
532
+ return [];
533
+ }
534
+ }
535
+ async getFetchRequests() {
536
+ if (!this.cdpSession) throw new Error("CDP session not initialized");
537
+ try {
538
+ const value = toRuntimeEvaluateValue(await this.cdpSession.send("Runtime.evaluate", {
539
+ expression: "window.__getFetchRequests ? window.__getFetchRequests() : []",
540
+ returnByValue: true
541
+ }));
542
+ if (!Array.isArray(value)) return [];
543
+ return value.filter((entry) => isObjectRecord(entry));
544
+ } catch (error) {
545
+ logger.error("Failed to get Fetch requests:", error);
546
+ return [];
547
+ }
548
+ }
549
+ async clearInjectedBuffers() {
550
+ if (!this.cdpSession) throw new Error("CDP session not initialized");
551
+ try {
552
+ const value = toRuntimeEvaluateValue(await this.cdpSession.send("Runtime.evaluate", {
553
+ expression: CLEAR_INJECTED_BUFFERS_EXPRESSION,
554
+ returnByValue: true
555
+ }));
556
+ if (!isObjectRecord(value)) return {
557
+ xhrCleared: 0,
558
+ fetchCleared: 0
559
+ };
560
+ return {
561
+ xhrCleared: toFiniteNumber(value.xhrCleared),
562
+ fetchCleared: toFiniteNumber(value.fetchCleared)
563
+ };
564
+ } catch (error) {
565
+ logger.error("Failed to clear injected network buffers:", error);
566
+ return {
567
+ xhrCleared: 0,
568
+ fetchCleared: 0
569
+ };
570
+ }
571
+ }
572
+ async resetInjectedInterceptors() {
573
+ if (!this.cdpSession) throw new Error("CDP session not initialized");
574
+ try {
575
+ const value = toRuntimeEvaluateValue(await this.cdpSession.send("Runtime.evaluate", {
576
+ expression: RESET_INJECTED_INTERCEPTORS_EXPRESSION,
577
+ returnByValue: true
578
+ }));
579
+ if (!isObjectRecord(value)) return {
580
+ xhrReset: false,
581
+ fetchReset: false
582
+ };
583
+ return {
584
+ xhrReset: toBoolean(value.xhrReset, false),
585
+ fetchReset: toBoolean(value.fetchReset, false)
586
+ };
587
+ } catch (error) {
588
+ logger.error("Failed to reset injected network interceptors:", error);
589
+ return {
590
+ xhrReset: false,
591
+ fetchReset: false
592
+ };
593
+ }
594
+ }
595
+ };
596
+ //#endregion
597
+ //#region src/modules/monitor/PlaywrightNetworkMonitor.ts
598
+ /**
599
+ * Lightweight network monitor for Playwright-based browsers (Camoufox/Firefox).
600
+ * Uses page.on('request'/'response') instead of CDP Network domain.
601
+ */
602
+ var PlaywrightNetworkMonitor = class {
603
+ networkEnabled = false;
604
+ requests = /* @__PURE__ */ new Map();
605
+ responses = /* @__PURE__ */ new Map();
606
+ MAX_NETWORK_RECORDS = 500;
607
+ MAX_INJECTED_RECORDS = 500;
608
+ requestCounter = 0;
609
+ /** LRU cache for response bodies, auto-captured on response event. */
610
+ responseBodyCache = /* @__PURE__ */ new Map();
611
+ MAX_BODY_CACHE_ENTRIES = 200;
612
+ requestIdMap = /* @__PURE__ */ new WeakMap();
613
+ boundOnRequest = null;
614
+ boundOnResponse = null;
615
+ constructor(page) {
616
+ this.page = page;
617
+ }
618
+ setPage(page) {
619
+ if (this.page === page) return;
620
+ const previousPage = this.page;
621
+ const wasEnabled = this.networkEnabled;
622
+ const onRequest = this.boundOnRequest;
623
+ const onResponse = this.boundOnResponse;
624
+ if (wasEnabled && previousPage && onRequest) try {
625
+ previousPage.off("request", onRequest);
626
+ } catch {}
627
+ if (wasEnabled && previousPage && onResponse) try {
628
+ previousPage.off("response", onResponse);
629
+ } catch {}
630
+ this.page = page;
631
+ if (!wasEnabled || !this.page) {
632
+ if (!this.page) this.networkEnabled = false;
633
+ return;
634
+ }
635
+ if (onRequest) this.page.on("request", onRequest);
636
+ if (onResponse) this.page.on("response", onResponse);
637
+ }
638
+ getPageOrThrow() {
639
+ if (!this.page) throw new Error("Playwright page not initialized");
640
+ return this.page;
641
+ }
642
+ async evaluateInPage(pageFunction) {
643
+ const page = this.getPageOrThrow();
644
+ if (!page.evaluate) throw new Error("Playwright page.evaluate is not available");
645
+ return page.evaluate(pageFunction);
646
+ }
647
+ async evaluateOnNewDocumentInPage(pageFunction) {
648
+ const page = this.getPageOrThrow();
649
+ if (!page.evaluateOnNewDocument) throw new Error("Playwright page.evaluateOnNewDocument is not available");
650
+ return page.evaluateOnNewDocument(pageFunction);
651
+ }
652
+ isUnknownArray(value) {
653
+ return Array.isArray(value);
654
+ }
655
+ isClearedBuffersResult(value) {
656
+ if (!value || typeof value !== "object") return false;
657
+ const candidate = value;
658
+ return typeof candidate.xhrCleared === "number" && typeof candidate.fetchCleared === "number";
659
+ }
660
+ isResetInterceptorsResult(value) {
661
+ if (!value || typeof value !== "object") return false;
662
+ const candidate = value;
663
+ return typeof candidate.xhrReset === "boolean" && typeof candidate.fetchReset === "boolean";
664
+ }
665
+ isPlaywrightLikeRequest(value) {
666
+ if (!value || typeof value !== "object") return false;
667
+ const candidate = value;
668
+ return typeof candidate.url === "function" && typeof candidate.method === "function" && typeof candidate.headers === "function" && typeof candidate.postData === "function" && typeof candidate.resourceType === "function";
669
+ }
670
+ isPlaywrightLikeResponse(value) {
671
+ if (!value || typeof value !== "object") return false;
672
+ const candidate = value;
673
+ return typeof candidate.request === "function" && typeof candidate.url === "function" && typeof candidate.status === "function" && typeof candidate.statusText === "function" && typeof candidate.headers === "function";
674
+ }
675
+ async enable() {
676
+ if (this.networkEnabled) {
677
+ logger.warn("PlaywrightNetworkMonitor already enabled");
678
+ return;
679
+ }
680
+ this.boundOnRequest = (req) => {
681
+ if (!this.isPlaywrightLikeRequest(req)) return;
682
+ const requestId = `pw-${++this.requestCounter}`;
683
+ this.requestIdMap.set(req, requestId);
684
+ const request = {
685
+ requestId,
686
+ url: req.url(),
687
+ method: req.method(),
688
+ headers: req.headers(),
689
+ postData: req.postData() ?? void 0,
690
+ timestamp: Date.now(),
691
+ type: req.resourceType()
692
+ };
693
+ this.requests.set(requestId, request);
694
+ if (this.requests.size > this.MAX_NETWORK_RECORDS) {
695
+ const firstKey = this.requests.keys().next().value;
696
+ if (firstKey) this.requests.delete(firstKey);
697
+ }
698
+ };
699
+ this.boundOnResponse = (res) => {
700
+ if (!this.isPlaywrightLikeResponse(res)) return;
701
+ const req = res.request();
702
+ const fallbackRequestId = `pw-res-${Date.now()}-${Math.random()}`;
703
+ const requestId = this.isPlaywrightLikeRequest(req) ? this.requestIdMap.get(req) ?? fallbackRequestId : fallbackRequestId;
704
+ const response = {
705
+ requestId,
706
+ url: res.url(),
707
+ status: res.status(),
708
+ statusText: res.statusText(),
709
+ headers: res.headers(),
710
+ mimeType: res.headers()["content-type"] ?? "unknown",
711
+ timestamp: Date.now()
712
+ };
713
+ this.responses.set(requestId, response);
714
+ if (this.responses.size > this.MAX_NETWORK_RECORDS) {
715
+ const firstKey = this.responses.keys().next().value;
716
+ if (firstKey) this.responses.delete(firstKey);
717
+ }
718
+ if (typeof res.body === "function") {
719
+ const captureId = requestId;
720
+ res.body().then((buf) => {
721
+ if (buf.length > 1048576) {
722
+ logger.debug(`[PW-BodyCache] Skipping oversized body for ${captureId} (${buf.length} bytes)`);
723
+ return;
724
+ }
725
+ if (this.responseBodyCache.size >= this.MAX_BODY_CACHE_ENTRIES) {
726
+ const oldestKey = this.responseBodyCache.keys().next().value;
727
+ if (oldestKey) this.responseBodyCache.delete(oldestKey);
728
+ }
729
+ if (/^(text\/|application\/(json|javascript|xml|x-www-form-urlencoded))/i.test(response.mimeType)) this.responseBodyCache.set(captureId, {
730
+ body: buf.toString("utf-8"),
731
+ base64Encoded: false
732
+ });
733
+ else this.responseBodyCache.set(captureId, {
734
+ body: buf.toString("base64"),
735
+ base64Encoded: true
736
+ });
737
+ logger.debug(`[PW-BodyCache] Cached body for ${captureId} (${buf.length} bytes)`);
738
+ }).catch((err) => {
739
+ logger.debug(`[PW-BodyCache] Could not capture body for ${captureId}: ${err instanceof Error ? err.message : String(err)}`);
740
+ });
741
+ }
742
+ };
743
+ const page = this.getPageOrThrow();
744
+ page.on("request", this.boundOnRequest);
745
+ page.on("response", this.boundOnResponse);
746
+ this.networkEnabled = true;
747
+ logger.info("PlaywrightNetworkMonitor enabled");
748
+ }
749
+ async disable() {
750
+ const page = this.getPageOrThrow();
751
+ if (this.boundOnRequest) {
752
+ try {
753
+ page.off("request", this.boundOnRequest);
754
+ } catch {}
755
+ this.boundOnRequest = null;
756
+ }
757
+ if (this.boundOnResponse) {
758
+ try {
759
+ page.off("response", this.boundOnResponse);
760
+ } catch {}
761
+ this.boundOnResponse = null;
762
+ }
763
+ this.networkEnabled = false;
764
+ logger.info("PlaywrightNetworkMonitor disabled");
765
+ }
766
+ isEnabled() {
767
+ return this.networkEnabled;
768
+ }
769
+ getRequests(filter) {
770
+ let requests = Array.from(this.requests.values());
771
+ if (filter?.url) requests = requests.filter((r) => r.url.includes(filter.url));
772
+ if (filter?.method) requests = requests.filter((r) => r.method.toUpperCase() === filter.method.toUpperCase());
773
+ if (filter?.limit) requests = requests.slice(-filter.limit);
774
+ return requests;
775
+ }
776
+ getResponses(filter) {
777
+ let responses = Array.from(this.responses.values());
778
+ if (filter?.url) responses = responses.filter((r) => r.url.includes(filter.url));
779
+ if (filter?.status) responses = responses.filter((r) => r.status === filter.status);
780
+ if (filter?.limit) responses = responses.slice(-filter.limit);
781
+ return responses;
782
+ }
783
+ getStatus() {
784
+ return {
785
+ enabled: this.networkEnabled,
786
+ requestCount: this.requests.size,
787
+ responseCount: this.responses.size,
788
+ listenerCount: this.networkEnabled ? 2 : 0,
789
+ cdpSessionActive: false
790
+ };
791
+ }
792
+ getActivity(requestId) {
793
+ return {
794
+ request: this.requests.get(requestId),
795
+ response: this.responses.get(requestId)
796
+ };
797
+ }
798
+ clearRecords() {
799
+ this.requests.clear();
800
+ this.responses.clear();
801
+ this.responseBodyCache.clear();
802
+ }
803
+ getStats() {
804
+ const requests = Array.from(this.requests.values());
805
+ const responses = Array.from(this.responses.values());
806
+ const byMethod = {};
807
+ requests.forEach((r) => {
808
+ byMethod[r.method] = (byMethod[r.method] || 0) + 1;
809
+ });
810
+ const byStatus = {};
811
+ responses.forEach((r) => {
812
+ byStatus[r.status] = (byStatus[r.status] || 0) + 1;
813
+ });
814
+ const byType = {};
815
+ requests.forEach((r) => {
816
+ const type = r.type || "unknown";
817
+ byType[type] = (byType[type] || 0) + 1;
818
+ });
819
+ return {
820
+ totalRequests: requests.length,
821
+ totalResponses: responses.length,
822
+ byMethod,
823
+ byStatus,
824
+ byType
825
+ };
826
+ }
827
+ /** Response body retrieval from LRU cache. */
828
+ async getResponseBody(requestId) {
829
+ const cached = this.responseBodyCache.get(requestId);
830
+ if (cached) {
831
+ this.responseBodyCache.delete(requestId);
832
+ this.responseBodyCache.set(requestId, cached);
833
+ logger.debug(`[PW-BodyCache] Cache hit for ${requestId}`);
834
+ return cached;
835
+ }
836
+ logger.warn(`getResponseBody: no cached body for ${requestId} in Playwright mode`);
837
+ return null;
838
+ }
839
+ /** Inject a script via page.evaluate (Playwright equivalent of CDP Runtime.evaluate). */
840
+ async injectScript(script) {
841
+ await this.evaluateInPage(script);
842
+ }
843
+ async injectXHRInterceptor(options) {
844
+ const script = `
845
+ (function() {
846
+ if (window.__xhrInterceptorInjected) return;
847
+ window.__xhrInterceptorInjected = true;
848
+ const maxRecords = ${this.MAX_INJECTED_RECORDS};
849
+ const OrigXHR = window.__pwOriginalXMLHttpRequest || window.XMLHttpRequest;
850
+ window.__pwOriginalXMLHttpRequest = OrigXHR;
851
+ if (!window.__xhrRequests) window.__xhrRequests = [];
852
+ window.XMLHttpRequest = function() {
853
+ const xhr = new OrigXHR();
854
+ const origOpen = xhr.open.bind(xhr);
855
+ const origSend = xhr.send.bind(xhr);
856
+ xhr.open = function(method, url, ...rest) {
857
+ xhr.__hookMeta = { method, url, timestamp: Date.now() };
858
+ return origOpen(method, url, ...rest);
859
+ };
860
+ xhr.send = function(body) {
861
+ xhr.addEventListener('load', function() {
862
+ window.__xhrRequests.push({
863
+ ...xhr.__hookMeta, body: body ? String(body).slice(0, 2048) : null,
864
+ status: xhr.status, response: xhr.responseText.slice(0, 2048),
865
+ });
866
+ if (window.__xhrRequests.length > maxRecords) {
867
+ window.__xhrRequests.splice(0, window.__xhrRequests.length - maxRecords);
868
+ }
869
+ });
870
+ return origSend(body);
871
+ };
872
+ return xhr;
873
+ };
874
+ console.log('[PlaywrightXHR] XHR interceptor injected');
875
+ })();
876
+ `;
877
+ if (options?.persistent) await this.evaluateOnNewDocumentInPage(script);
878
+ else await this.evaluateInPage(script);
879
+ }
880
+ async injectFetchInterceptor(options) {
881
+ const script = `
882
+ (function() {
883
+ if (window.__fetchInterceptorInjected) return;
884
+ window.__fetchInterceptorInjected = true;
885
+ const maxRecords = ${this.MAX_INJECTED_RECORDS};
886
+ const origFetch = window.__pwOriginalFetch || window.fetch;
887
+ window.__pwOriginalFetch = origFetch;
888
+ if (!window.__fetchRequests) window.__fetchRequests = [];
889
+ window.fetch = function(...args) {
890
+ const [url, opts] = args;
891
+ const entry = { url: String(url), method: opts?.method || 'GET', timestamp: Date.now() };
892
+ return origFetch.apply(this, args).then(res => {
893
+ entry.status = res.status;
894
+ window.__fetchRequests.push(entry);
895
+ if (window.__fetchRequests.length > maxRecords) {
896
+ window.__fetchRequests.splice(0, window.__fetchRequests.length - maxRecords);
897
+ }
898
+ // Auto-persist compact summary so data survives context compression
899
+ try {
900
+ const s = { url: entry.url, method: entry.method, status: entry.status, ts: entry.timestamp };
901
+ const prev = JSON.parse(localStorage.getItem('__capturedAPIs') || '[]');
902
+ prev.push(s);
903
+ if (prev.length > 500) prev.splice(0, prev.length - 500);
904
+ localStorage.setItem('__capturedAPIs', JSON.stringify(prev));
905
+ } catch(e) {}
906
+ return res;
907
+ });
908
+ };
909
+ console.log('[PlaywrightFetch] Fetch interceptor injected');
910
+ })();
911
+ `;
912
+ if (options?.persistent) await this.evaluateOnNewDocumentInPage(script);
913
+ else await this.evaluateInPage(script);
914
+ }
915
+ async getXHRRequests() {
916
+ try {
917
+ const result = await this.evaluateInPage(() => {
918
+ return window.__xhrRequests ?? [];
919
+ });
920
+ return this.isUnknownArray(result) ? result : [];
921
+ } catch (err) {
922
+ logger.warn(`[PW] Failed to get XHR requests: ${err instanceof Error ? err.message : String(err)}`);
923
+ return [];
924
+ }
925
+ }
926
+ async getFetchRequests() {
927
+ try {
928
+ const result = await this.evaluateInPage(() => {
929
+ return window.__fetchRequests ?? [];
930
+ });
931
+ return this.isUnknownArray(result) ? result : [];
932
+ } catch (err) {
933
+ logger.warn(`[PW] Failed to get fetch requests: ${err instanceof Error ? err.message : String(err)}`);
934
+ return [];
935
+ }
936
+ }
937
+ async clearInjectedBuffers() {
938
+ try {
939
+ const result = await this.evaluateInPage(() => {
940
+ const bridgeWindow = window;
941
+ const xhrRequests = bridgeWindow.__xhrRequests;
942
+ const fetchRequests = bridgeWindow.__fetchRequests;
943
+ const xhrCleared = Array.isArray(xhrRequests) ? xhrRequests.length : 0;
944
+ const fetchCleared = Array.isArray(fetchRequests) ? fetchRequests.length : 0;
945
+ if (Array.isArray(xhrRequests)) xhrRequests.length = 0;
946
+ if (Array.isArray(fetchRequests)) fetchRequests.length = 0;
947
+ return {
948
+ xhrCleared,
949
+ fetchCleared
950
+ };
951
+ });
952
+ return this.isClearedBuffersResult(result) ? result : {
953
+ xhrCleared: 0,
954
+ fetchCleared: 0
955
+ };
956
+ } catch (err) {
957
+ logger.warn(`[PW] Failed to clear injected buffers: ${err instanceof Error ? err.message : String(err)}`);
958
+ return {
959
+ xhrCleared: 0,
960
+ fetchCleared: 0
961
+ };
962
+ }
963
+ }
964
+ async resetInjectedInterceptors() {
965
+ try {
966
+ const result = await this.evaluateInPage(() => {
967
+ const bridgeWindow = window;
968
+ let xhrReset = false;
969
+ let fetchReset = false;
970
+ if (bridgeWindow.__pwOriginalXMLHttpRequest) {
971
+ bridgeWindow.XMLHttpRequest = bridgeWindow.__pwOriginalXMLHttpRequest;
972
+ xhrReset = true;
973
+ }
974
+ if (bridgeWindow.__pwOriginalFetch) {
975
+ bridgeWindow.fetch = bridgeWindow.__pwOriginalFetch;
976
+ fetchReset = true;
977
+ }
978
+ if (Array.isArray(bridgeWindow.__xhrRequests)) bridgeWindow.__xhrRequests.length = 0;
979
+ if (Array.isArray(bridgeWindow.__fetchRequests)) bridgeWindow.__fetchRequests.length = 0;
980
+ bridgeWindow.__xhrInterceptorInjected = false;
981
+ bridgeWindow.__fetchInterceptorInjected = false;
982
+ return {
983
+ xhrReset,
984
+ fetchReset
985
+ };
986
+ });
987
+ return this.isResetInterceptorsResult(result) ? result : {
988
+ xhrReset: false,
989
+ fetchReset: false
990
+ };
991
+ } catch (err) {
992
+ logger.warn(`[PW] Failed to reset interceptors: ${err instanceof Error ? err.message : String(err)}`);
993
+ return {
994
+ xhrReset: false,
995
+ fetchReset: false
996
+ };
997
+ }
998
+ }
999
+ async getAllJavaScriptResponses() {
1000
+ return Array.from(this.responses.values()).filter((r) => r.mimeType.includes("javascript"));
1001
+ }
1002
+ };
1003
+ //#endregion
1004
+ //#region src/modules/monitor/FetchInterceptor.ts
1005
+ var FetchInterceptor = class {
1006
+ rules = /* @__PURE__ */ new Map();
1007
+ enabled = false;
1008
+ eventHandler = null;
1009
+ compiledPatterns = /* @__PURE__ */ new Map();
1010
+ constructor(cdpSession) {
1011
+ this.cdpSession = cdpSession;
1012
+ }
1013
+ /**
1014
+ * Enable Fetch domain interception with the given rules.
1015
+ * If already enabled, merges new rules with existing ones.
1016
+ */
1017
+ async enable(ruleInputs) {
1018
+ const newRules = [];
1019
+ for (const input of ruleInputs) {
1020
+ const rule = this.createRule(input);
1021
+ this.rules.set(rule.id, rule);
1022
+ this.compiledPatterns.set(rule.id, this.compilePattern(rule));
1023
+ newRules.push(rule);
1024
+ }
1025
+ await this.applyRules();
1026
+ if (!this.eventHandler) {
1027
+ this.eventHandler = (params) => {
1028
+ this.handleRequestPaused(params);
1029
+ };
1030
+ this.cdpSession.on("Fetch.requestPaused", this.eventHandler);
1031
+ }
1032
+ this.enabled = true;
1033
+ logger.info(`FetchInterceptor enabled with ${this.rules.size} rule(s)`);
1034
+ return newRules;
1035
+ }
1036
+ /**
1037
+ * Disable all interception, remove all rules, detach event handler.
1038
+ */
1039
+ async disable() {
1040
+ const count = this.rules.size;
1041
+ if (this.eventHandler) {
1042
+ try {
1043
+ this.cdpSession.off("Fetch.requestPaused", this.eventHandler);
1044
+ } catch {}
1045
+ this.eventHandler = null;
1046
+ }
1047
+ try {
1048
+ await this.cdpSession.send("Fetch.disable");
1049
+ } catch (error) {
1050
+ logger.warn("Fetch.disable failed:", error);
1051
+ }
1052
+ this.rules.clear();
1053
+ this.compiledPatterns.clear();
1054
+ this.enabled = false;
1055
+ logger.info(`FetchInterceptor disabled, removed ${count} rule(s)`);
1056
+ return { removedRules: count };
1057
+ }
1058
+ /**
1059
+ * Remove a specific rule by ID. If no rules remain, disables Fetch domain.
1060
+ */
1061
+ async removeRule(ruleId) {
1062
+ const removed = this.rules.delete(ruleId);
1063
+ this.compiledPatterns.delete(ruleId);
1064
+ if (removed) if (this.rules.size === 0) await this.disable();
1065
+ else await this.applyRules();
1066
+ return removed;
1067
+ }
1068
+ /**
1069
+ * List all active rules with hit statistics.
1070
+ */
1071
+ listRules() {
1072
+ const rules = Array.from(this.rules.values());
1073
+ return {
1074
+ enabled: this.enabled,
1075
+ rules,
1076
+ totalHits: rules.reduce((sum, r) => sum + r.hitCount, 0)
1077
+ };
1078
+ }
1079
+ isEnabled() {
1080
+ return this.enabled;
1081
+ }
1082
+ createRule(input) {
1083
+ const headers = [];
1084
+ if (input.responseHeaders) for (const [name, value] of Object.entries(input.responseHeaders)) headers.push({
1085
+ name,
1086
+ value
1087
+ });
1088
+ return {
1089
+ id: randomUUID().slice(0, 8),
1090
+ urlPattern: input.urlPattern,
1091
+ urlPatternType: input.urlPatternType ?? "glob",
1092
+ stage: input.stage ?? "Response",
1093
+ responseCode: input.responseCode ?? 200,
1094
+ responseHeaders: headers,
1095
+ responseBody: input.responseBody ?? "",
1096
+ hitCount: 0,
1097
+ createdAt: Date.now()
1098
+ };
1099
+ }
1100
+ compilePattern(rule) {
1101
+ if (rule.urlPatternType === "regex") try {
1102
+ return new RegExp(rule.urlPattern, "i");
1103
+ } catch {
1104
+ return new RegExp(rule.urlPattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i");
1105
+ }
1106
+ const escaped = rule.urlPattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "⟨GLOBSTAR⟩").replace(/\*/g, "[^/]*").replace(/⟨GLOBSTAR⟩/g, ".*");
1107
+ return new RegExp(escaped, "i");
1108
+ }
1109
+ async applyRules() {
1110
+ const patterns = [];
1111
+ for (const rule of this.rules.values()) patterns.push({
1112
+ urlPattern: rule.urlPatternType === "glob" ? rule.urlPattern : "*",
1113
+ requestStage: rule.stage
1114
+ });
1115
+ if (patterns.length === 0) return;
1116
+ try {
1117
+ try {
1118
+ await this.cdpSession.send("Fetch.disable");
1119
+ } catch {}
1120
+ await this.cdpSession.send("Fetch.enable", {
1121
+ patterns: patterns.length > 0 ? patterns : [{
1122
+ urlPattern: "*",
1123
+ requestStage: "Response"
1124
+ }],
1125
+ handleAuthRequests: false
1126
+ });
1127
+ } catch (error) {
1128
+ logger.error("Failed to apply Fetch interception rules:", error);
1129
+ throw error;
1130
+ }
1131
+ }
1132
+ async handleRequestPaused(params) {
1133
+ const requestUrl = params.request.url;
1134
+ for (const [ruleId, rule] of this.rules) {
1135
+ const pattern = this.compiledPatterns.get(ruleId);
1136
+ if (!pattern) continue;
1137
+ if (pattern.test(requestUrl)) {
1138
+ rule.hitCount++;
1139
+ logger.info(`[FetchInterceptor] Rule "${rule.urlPattern}" matched: ${requestUrl}`);
1140
+ try {
1141
+ const headers = [...rule.responseHeaders];
1142
+ if (!headers.some((h) => h.name.toLowerCase() === "content-type")) {
1143
+ const body = rule.responseBody;
1144
+ if (body.startsWith("{") || body.startsWith("[")) headers.push({
1145
+ name: "Content-Type",
1146
+ value: "application/json"
1147
+ });
1148
+ else headers.push({
1149
+ name: "Content-Type",
1150
+ value: "text/plain"
1151
+ });
1152
+ }
1153
+ if (!headers.some((h) => h.name.toLowerCase() === "access-control-allow-origin")) headers.push({
1154
+ name: "Access-Control-Allow-Origin",
1155
+ value: "*"
1156
+ });
1157
+ await this.cdpSession.send("Fetch.fulfillRequest", {
1158
+ requestId: params.requestId,
1159
+ responseCode: rule.responseCode,
1160
+ responseHeaders: headers,
1161
+ body: Buffer.from(rule.responseBody, "utf-8").toString("base64")
1162
+ });
1163
+ return;
1164
+ } catch (error) {
1165
+ logger.error(`[FetchInterceptor] fulfillRequest failed for ${requestUrl}:`, error);
1166
+ }
1167
+ }
1168
+ }
1169
+ try {
1170
+ if (params.responseStatusCode !== void 0) await this.cdpSession.send("Fetch.continueResponse", { requestId: params.requestId });
1171
+ else await this.cdpSession.send("Fetch.continueRequest", { requestId: params.requestId });
1172
+ } catch (error) {
1173
+ logger.warn(`[FetchInterceptor] continue failed for ${requestUrl}:`, error);
1174
+ }
1175
+ }
1176
+ };
1177
+ //#endregion
1178
+ //#region src/modules/monitor/ConsoleMonitor.impl.core.logs.ts
1179
+ function asLogsCoreContext(ctx) {
1180
+ return ctx;
1181
+ }
1182
+ function getLogsCore(ctx, filter) {
1183
+ const coreCtx = asLogsCoreContext(ctx);
1184
+ if (coreCtx.contextSwitchPending) return [];
1185
+ let logs = coreCtx.messages;
1186
+ if (filter?.type) logs = logs.filter((msg) => msg.type === filter.type);
1187
+ const since = filter?.since;
1188
+ if (since !== void 0) logs = logs.filter((msg) => msg.timestamp >= since);
1189
+ if (filter?.limit) logs = logs.slice(-filter.limit);
1190
+ logger.debug(`getLogs: ${logs.length} messages`);
1191
+ return logs;
1192
+ }
1193
+ function clearLogsCore(ctx) {
1194
+ const coreCtx = asLogsCoreContext(ctx);
1195
+ coreCtx.messages = [];
1196
+ logger.info("Console logs cleared");
1197
+ }
1198
+ function getStatsCore(ctx) {
1199
+ const coreCtx = asLogsCoreContext(ctx);
1200
+ if (coreCtx.contextSwitchPending) return {
1201
+ totalMessages: 0,
1202
+ byType: {}
1203
+ };
1204
+ const byType = {};
1205
+ for (const msg of coreCtx.messages) byType[msg.type] = (byType[msg.type] || 0) + 1;
1206
+ return {
1207
+ totalMessages: coreCtx.messages.length,
1208
+ byType
1209
+ };
1210
+ }
1211
+ function getExceptionsCore(ctx, filter) {
1212
+ const coreCtx = asLogsCoreContext(ctx);
1213
+ if (coreCtx.contextSwitchPending) return [];
1214
+ let exceptions = coreCtx.exceptions;
1215
+ if (filter?.url) exceptions = exceptions.filter((ex) => ex.url?.includes(filter.url));
1216
+ const since = filter?.since;
1217
+ if (since !== void 0) exceptions = exceptions.filter((ex) => ex.timestamp >= since);
1218
+ if (filter?.limit) exceptions = exceptions.slice(-filter.limit);
1219
+ return exceptions;
1220
+ }
1221
+ function clearExceptionsCore(ctx) {
1222
+ const coreCtx = asLogsCoreContext(ctx);
1223
+ coreCtx.exceptions = [];
1224
+ logger.info("Exceptions cleared");
1225
+ }
1226
+ //#endregion
1227
+ //#region src/modules/monitor/ConsoleMonitor.impl.core.network.ts
1228
+ function asNetworkCoreContext(ctx) {
1229
+ return ctx;
1230
+ }
1231
+ function hasStaleContext(ctx) {
1232
+ return ctx.contextSwitchPending === true;
1233
+ }
1234
+ function isNetworkEnabledCore(ctx) {
1235
+ const coreCtx = asNetworkCoreContext(ctx);
1236
+ if (hasStaleContext(coreCtx)) return false;
1237
+ return (coreCtx.networkMonitor?.isEnabled() ?? false) || (coreCtx.playwrightNetworkMonitor?.isEnabled() ?? false);
1238
+ }
1239
+ function getNetworkStatusCore(ctx) {
1240
+ const coreCtx = asNetworkCoreContext(ctx);
1241
+ if (hasStaleContext(coreCtx)) return {
1242
+ enabled: false,
1243
+ requestCount: 0,
1244
+ responseCount: 0,
1245
+ listenerCount: 0,
1246
+ cdpSessionActive: false
1247
+ };
1248
+ if (coreCtx.playwrightNetworkMonitor) return coreCtx.playwrightNetworkMonitor.getStatus();
1249
+ if (!coreCtx.networkMonitor) return {
1250
+ enabled: false,
1251
+ requestCount: 0,
1252
+ responseCount: 0,
1253
+ listenerCount: 0,
1254
+ cdpSessionActive: coreCtx.cdpSession !== null
1255
+ };
1256
+ return coreCtx.networkMonitor.getStatus();
1257
+ }
1258
+ function getNetworkRequestsCore(ctx, filter) {
1259
+ const coreCtx = asNetworkCoreContext(ctx);
1260
+ if (hasStaleContext(coreCtx)) return [];
1261
+ if (coreCtx.playwrightNetworkMonitor) return coreCtx.playwrightNetworkMonitor.getRequests(filter);
1262
+ return coreCtx.networkMonitor?.getRequests(filter) ?? [];
1263
+ }
1264
+ function getNetworkResponsesCore(ctx, filter) {
1265
+ const coreCtx = asNetworkCoreContext(ctx);
1266
+ if (hasStaleContext(coreCtx)) return [];
1267
+ if (coreCtx.playwrightNetworkMonitor) return coreCtx.playwrightNetworkMonitor.getResponses(filter);
1268
+ return coreCtx.networkMonitor?.getResponses(filter) ?? [];
1269
+ }
1270
+ function getNetworkActivityCore(ctx, requestId) {
1271
+ const coreCtx = asNetworkCoreContext(ctx);
1272
+ if (hasStaleContext(coreCtx)) return {};
1273
+ if (coreCtx.playwrightNetworkMonitor) return coreCtx.playwrightNetworkMonitor.getActivity(requestId);
1274
+ return coreCtx.networkMonitor?.getActivity(requestId) ?? {};
1275
+ }
1276
+ async function getResponseBodyCore(ctx, requestId) {
1277
+ const coreCtx = asNetworkCoreContext(ctx);
1278
+ if (hasStaleContext(coreCtx)) return null;
1279
+ if (coreCtx.playwrightNetworkMonitor) return coreCtx.playwrightNetworkMonitor.getResponseBody(requestId);
1280
+ if (!coreCtx.networkMonitor) {
1281
+ logger.error("Network monitoring is not enabled. Call enable() with enableNetwork: true first.");
1282
+ return null;
1283
+ }
1284
+ return coreCtx.networkMonitor.getResponseBody(requestId);
1285
+ }
1286
+ async function getAllJavaScriptResponsesCore(ctx) {
1287
+ const coreCtx = asNetworkCoreContext(ctx);
1288
+ if (hasStaleContext(coreCtx)) return [];
1289
+ if (coreCtx.playwrightNetworkMonitor) return coreCtx.playwrightNetworkMonitor.getAllJavaScriptResponses();
1290
+ if (!coreCtx.networkMonitor) return [];
1291
+ return coreCtx.networkMonitor.getAllJavaScriptResponses();
1292
+ }
1293
+ function clearNetworkRecordsCore(ctx) {
1294
+ const coreCtx = asNetworkCoreContext(ctx);
1295
+ coreCtx.networkMonitor?.clearRecords();
1296
+ coreCtx.playwrightNetworkMonitor?.clearRecords();
1297
+ }
1298
+ async function clearInjectedBuffersCore(ctx) {
1299
+ const coreCtx = asNetworkCoreContext(ctx);
1300
+ if (coreCtx.playwrightNetworkMonitor) return {
1301
+ ...await coreCtx.playwrightNetworkMonitor.clearInjectedBuffers(),
1302
+ dynamicScriptsCleared: 0
1303
+ };
1304
+ const networkResult = coreCtx.networkMonitor ? await coreCtx.networkMonitor.clearInjectedBuffers() : {
1305
+ xhrCleared: 0,
1306
+ fetchCleared: 0
1307
+ };
1308
+ const dynamicResult = await coreCtx.clearDynamicScriptBuffer();
1309
+ return {
1310
+ ...networkResult,
1311
+ ...dynamicResult
1312
+ };
1313
+ }
1314
+ async function resetInjectedInterceptorsCore(ctx) {
1315
+ const coreCtx = asNetworkCoreContext(ctx);
1316
+ if (coreCtx.playwrightNetworkMonitor) return {
1317
+ ...await coreCtx.playwrightNetworkMonitor.resetInjectedInterceptors(),
1318
+ scriptMonitorReset: false
1319
+ };
1320
+ const networkResult = coreCtx.networkMonitor ? await coreCtx.networkMonitor.resetInjectedInterceptors() : {
1321
+ xhrReset: false,
1322
+ fetchReset: false
1323
+ };
1324
+ const scriptResult = await coreCtx.resetDynamicScriptMonitoring();
1325
+ return {
1326
+ ...networkResult,
1327
+ ...scriptResult
1328
+ };
1329
+ }
1330
+ function getNetworkStatsCore(ctx) {
1331
+ const coreCtx = asNetworkCoreContext(ctx);
1332
+ if (hasStaleContext(coreCtx)) return {
1333
+ totalRequests: 0,
1334
+ totalResponses: 0,
1335
+ byMethod: {},
1336
+ byStatus: {},
1337
+ byType: {}
1338
+ };
1339
+ if (coreCtx.playwrightNetworkMonitor) return coreCtx.playwrightNetworkMonitor.getStats();
1340
+ return coreCtx.networkMonitor?.getStats() ?? {
1341
+ totalRequests: 0,
1342
+ totalResponses: 0,
1343
+ byMethod: {},
1344
+ byStatus: {},
1345
+ byType: {}
1346
+ };
1347
+ }
1348
+ async function injectXHRInterceptorCore(ctx, options) {
1349
+ const coreCtx = asNetworkCoreContext(ctx);
1350
+ if (hasStaleContext(coreCtx)) throw new PrerequisiteError("Network monitoring is not enabled. Call enable() with enableNetwork: true first.");
1351
+ if (coreCtx.playwrightNetworkMonitor) return coreCtx.playwrightNetworkMonitor.injectXHRInterceptor(options);
1352
+ if (!coreCtx.networkMonitor) throw new PrerequisiteError("Network monitoring is not enabled. Call enable() with enableNetwork: true first.");
1353
+ return coreCtx.networkMonitor.injectXHRInterceptor(options);
1354
+ }
1355
+ async function injectFetchInterceptorCore(ctx, options) {
1356
+ const coreCtx = asNetworkCoreContext(ctx);
1357
+ if (hasStaleContext(coreCtx)) throw new PrerequisiteError("Network monitoring is not enabled. Call enable() with enableNetwork: true first.");
1358
+ if (coreCtx.playwrightNetworkMonitor) return coreCtx.playwrightNetworkMonitor.injectFetchInterceptor(options);
1359
+ if (!coreCtx.networkMonitor) throw new PrerequisiteError("Network monitoring is not enabled. Call enable() with enableNetwork: true first.");
1360
+ return coreCtx.networkMonitor.injectFetchInterceptor(options);
1361
+ }
1362
+ async function getXHRRequestsCore(ctx) {
1363
+ const coreCtx = asNetworkCoreContext(ctx);
1364
+ if (hasStaleContext(coreCtx)) return [];
1365
+ if (coreCtx.playwrightNetworkMonitor) return coreCtx.playwrightNetworkMonitor.getXHRRequests();
1366
+ if (!coreCtx.networkMonitor) return [];
1367
+ return coreCtx.networkMonitor.getXHRRequests();
1368
+ }
1369
+ async function getFetchRequestsCore(ctx) {
1370
+ const coreCtx = asNetworkCoreContext(ctx);
1371
+ if (hasStaleContext(coreCtx)) return [];
1372
+ if (coreCtx.playwrightNetworkMonitor) return coreCtx.playwrightNetworkMonitor.getFetchRequests();
1373
+ if (!coreCtx.networkMonitor) return [];
1374
+ return coreCtx.networkMonitor.getFetchRequests();
1375
+ }
1376
+ //#endregion
1377
+ //#region src/modules/monitor/ConsoleMonitor.impl.core.object-cache.ts
1378
+ async function inspectObjectCore(ctx, objectId) {
1379
+ const context = ctx;
1380
+ await context.ensureSession();
1381
+ if (!context.cdpSession) throw new Error("CDP session not available after reconnect attempt");
1382
+ if (context.objectCache.has(objectId)) {
1383
+ const cached = context.objectCache.get(objectId);
1384
+ if (cached !== void 0) return cached;
1385
+ }
1386
+ try {
1387
+ const result = await context.cdpSession.send("Runtime.getProperties", {
1388
+ objectId,
1389
+ ownProperties: true,
1390
+ accessorPropertiesOnly: false,
1391
+ generatePreview: true
1392
+ });
1393
+ const properties = {};
1394
+ for (const prop of result.result) {
1395
+ if (!prop.value) continue;
1396
+ const valueObj = prop.value;
1397
+ properties[prop.name] = {
1398
+ value: context.extractValue(valueObj),
1399
+ type: valueObj.type,
1400
+ objectId: valueObj.objectId,
1401
+ description: valueObj.description
1402
+ };
1403
+ }
1404
+ if (!context.objectCache.has(objectId)) while (context.objectCache.size >= context.MAX_OBJECT_CACHE_SIZE) {
1405
+ const oldestKey = context.objectCache.keys().next().value;
1406
+ if (oldestKey === void 0) break;
1407
+ context.objectCache.delete(oldestKey);
1408
+ }
1409
+ context.objectCache.set(objectId, properties);
1410
+ logger.info(`Object inspected: ${objectId}`, { propertyCount: Object.keys(properties).length });
1411
+ return properties;
1412
+ } catch (error) {
1413
+ logger.error("Failed to inspect object:", error);
1414
+ throw error;
1415
+ }
1416
+ }
1417
+ function clearObjectCacheCore(ctx) {
1418
+ ctx.objectCache.clear();
1419
+ logger.info("Object cache cleared");
1420
+ }
1421
+ //#endregion
1422
+ //#region src/modules/monitor/ConsoleMonitor.impl.core.dynamic.ts
1423
+ function asDynamicCoreContext(ctx) {
1424
+ return ctx;
1425
+ }
1426
+ async function enableDynamicScriptMonitoringCore(ctx, options) {
1427
+ const coreCtx = asDynamicCoreContext(ctx);
1428
+ await coreCtx.ensureSession();
1429
+ if (!coreCtx.cdpSession) throw new PrerequisiteError("CDP session not available after reconnect attempt");
1430
+ const monitorCode = `
1431
+ (function() {
1432
+ if (window.__dynamicScriptMonitorInstalled) {
1433
+ console.log('[ScriptMonitor] Already installed');
1434
+ return;
1435
+ }
1436
+ window.__dynamicScriptMonitorInstalled = true;
1437
+
1438
+ const maxRecords = ${coreCtx.MAX_INJECTED_DYNAMIC_SCRIPTS};
1439
+ if (!window.__dynamicScripts) {
1440
+ window.__dynamicScripts = [];
1441
+ }
1442
+ const dynamicScripts = window.__dynamicScripts;
1443
+ const state = window.__dynamicScriptMonitorState || {};
1444
+ if (!state.originalCreateElement) state.originalCreateElement = document.createElement;
1445
+ if (!state.originalEval) state.originalEval = window.eval;
1446
+ if (!state.originalFunction) state.originalFunction = window.Function;
1447
+ window.__dynamicScriptMonitorState = state;
1448
+
1449
+ const observer = new MutationObserver((mutations) => {
1450
+ mutations.forEach((mutation) => {
1451
+ mutation.addedNodes.forEach((node) => {
1452
+ if (node.nodeName === 'SCRIPT') {
1453
+ const script = node;
1454
+ const info = {
1455
+ type: 'dynamic',
1456
+ src: script.src || '(inline)',
1457
+ content: script.src ? null : script.textContent,
1458
+ timestamp: Date.now(),
1459
+ async: script.async,
1460
+ defer: script.defer,
1461
+ };
1462
+
1463
+ dynamicScripts.push(info);
1464
+ if (dynamicScripts.length > maxRecords) {
1465
+ dynamicScripts.splice(0, dynamicScripts.length - maxRecords);
1466
+ }
1467
+ console.log('[ScriptMonitor] Dynamic script added:', info);
1468
+ }
1469
+ });
1470
+ });
1471
+ });
1472
+
1473
+ observer.observe(document.documentElement, {
1474
+ childList: true,
1475
+ subtree: true,
1476
+ });
1477
+ state.observer = observer;
1478
+
1479
+ const originalCreateElement = state.originalCreateElement;
1480
+ document.createElement = function(tagName) {
1481
+ const element = originalCreateElement.call(document, tagName);
1482
+
1483
+ if (tagName.toLowerCase() === 'script') {
1484
+ console.log('[ScriptMonitor] Script element created via createElement');
1485
+
1486
+ const originalSetAttribute = element.setAttribute;
1487
+ element.setAttribute = function(name, value) {
1488
+ if (name === 'src') {
1489
+ console.log('[ScriptMonitor] Script src set to:', value);
1490
+ }
1491
+ return originalSetAttribute.call(element, name, value);
1492
+ };
1493
+ }
1494
+
1495
+ return element;
1496
+ };
1497
+
1498
+ const originalEval = state.originalEval;
1499
+ window.eval = function(code) {
1500
+ console.log('[ScriptMonitor] eval() called with code:',
1501
+ typeof code === 'string' ? code.substring(0, 100) + '...' : code);
1502
+ return originalEval.call(window, code);
1503
+ };
1504
+
1505
+ const originalFunction = state.originalFunction;
1506
+ window.Function = function(...args) {
1507
+ console.log('[ScriptMonitor] Function() constructor called with args:', args);
1508
+ return originalFunction.apply(this, args);
1509
+ };
1510
+
1511
+ window.__getDynamicScripts = function() {
1512
+ return dynamicScripts;
1513
+ };
1514
+
1515
+ console.log('[ScriptMonitor] Dynamic script monitoring enabled');
1516
+ })();
1517
+ `;
1518
+ if (options?.persistent) {
1519
+ await coreCtx.cdpSession.send("Page.addScriptToEvaluateOnNewDocument", { source: monitorCode });
1520
+ logger.info("Dynamic script monitoring enabled (persistent)");
1521
+ } else {
1522
+ await coreCtx.cdpSession.send("Runtime.evaluate", { expression: monitorCode });
1523
+ logger.info("Dynamic script monitoring enabled");
1524
+ }
1525
+ }
1526
+ async function clearDynamicScriptBufferCore(ctx) {
1527
+ const coreCtx = asDynamicCoreContext(ctx);
1528
+ if (!coreCtx.cdpSession) return { dynamicScriptsCleared: 0 };
1529
+ try {
1530
+ const value = (await coreCtx.cdpSession.send("Runtime.evaluate", {
1531
+ expression: `
1532
+ (() => {
1533
+ const store = Array.isArray(window.__dynamicScripts)
1534
+ ? window.__dynamicScripts
1535
+ : (typeof window.__getDynamicScripts === 'function'
1536
+ ? window.__getDynamicScripts()
1537
+ : null);
1538
+ const dynamicScriptsCleared = Array.isArray(store) ? store.length : 0;
1539
+ if (Array.isArray(store)) {
1540
+ store.length = 0;
1541
+ }
1542
+ return { dynamicScriptsCleared };
1543
+ })()
1544
+ `,
1545
+ returnByValue: true
1546
+ })).result?.value;
1547
+ if (typeof value === "object" && value !== null && "dynamicScriptsCleared" in value && typeof value.dynamicScriptsCleared === "number") return value;
1548
+ return { dynamicScriptsCleared: 0 };
1549
+ } catch (error) {
1550
+ logger.error("Failed to clear dynamic script buffer:", error);
1551
+ return { dynamicScriptsCleared: 0 };
1552
+ }
1553
+ }
1554
+ async function resetDynamicScriptMonitoringCore(ctx) {
1555
+ const coreCtx = asDynamicCoreContext(ctx);
1556
+ if (!coreCtx.cdpSession) return { scriptMonitorReset: false };
1557
+ try {
1558
+ const value = (await coreCtx.cdpSession.send("Runtime.evaluate", {
1559
+ expression: `
1560
+ (() => {
1561
+ const state = window.__dynamicScriptMonitorState;
1562
+ let scriptMonitorReset = false;
1563
+
1564
+ try {
1565
+ if (state && state.observer && typeof state.observer.disconnect === 'function') {
1566
+ state.observer.disconnect();
1567
+ state.observer = null;
1568
+ scriptMonitorReset = true;
1569
+ }
1570
+ } catch (_) {}
1571
+
1572
+ try {
1573
+ if (state && state.originalCreateElement) {
1574
+ document.createElement = state.originalCreateElement;
1575
+ scriptMonitorReset = true;
1576
+ }
1577
+ } catch (_) {}
1578
+
1579
+ try {
1580
+ if (state && state.originalEval) {
1581
+ window.eval = state.originalEval;
1582
+ scriptMonitorReset = true;
1583
+ }
1584
+ } catch (_) {}
1585
+
1586
+ try {
1587
+ if (state && state.originalFunction) {
1588
+ window.Function = state.originalFunction;
1589
+ scriptMonitorReset = true;
1590
+ }
1591
+ } catch (_) {}
1592
+
1593
+ if (Array.isArray(window.__dynamicScripts)) {
1594
+ window.__dynamicScripts.length = 0;
1595
+ }
1596
+ delete window.__getDynamicScripts;
1597
+ window.__dynamicScriptMonitorInstalled = false;
1598
+
1599
+ return { scriptMonitorReset };
1600
+ })()
1601
+ `,
1602
+ returnByValue: true
1603
+ })).result?.value;
1604
+ if (typeof value === "object" && value !== null && "scriptMonitorReset" in value && typeof value.scriptMonitorReset === "boolean") return value;
1605
+ return { scriptMonitorReset: false };
1606
+ } catch (error) {
1607
+ logger.error("Failed to reset dynamic script monitoring:", error);
1608
+ return { scriptMonitorReset: false };
1609
+ }
1610
+ }
1611
+ async function getDynamicScriptsCore(ctx) {
1612
+ const coreCtx = asDynamicCoreContext(ctx);
1613
+ if (!coreCtx.cdpSession) throw new PrerequisiteError("CDP session not initialized");
1614
+ try {
1615
+ const value = (await coreCtx.cdpSession.send("Runtime.evaluate", {
1616
+ expression: "window.__getDynamicScripts ? window.__getDynamicScripts() : []",
1617
+ returnByValue: true
1618
+ })).result?.value;
1619
+ return Array.isArray(value) ? value : [];
1620
+ } catch (error) {
1621
+ logger.error("Failed to get dynamic scripts:", error);
1622
+ return [];
1623
+ }
1624
+ }
1625
+ async function injectFunctionTracerCore(ctx, functionName, options) {
1626
+ const coreCtx = asDynamicCoreContext(ctx);
1627
+ if (!coreCtx.cdpSession) throw new PrerequisiteError("CDP session not initialized");
1628
+ const tracerCode = `
1629
+ (function() {
1630
+ const originalFunc = window.${functionName};
1631
+ if (typeof originalFunc !== 'function') {
1632
+ console.error('[Tracer] ${functionName} is not a function');
1633
+ return;
1634
+ }
1635
+
1636
+ window.${functionName} = new Proxy(originalFunc, {
1637
+ apply: function(target, thisArg, args) {
1638
+ console.log('[Tracer] ${functionName} called with args:', args);
1639
+ const startTime = performance.now();
1640
+
1641
+ try {
1642
+ const result = target.apply(thisArg, args);
1643
+ const endTime = performance.now();
1644
+ console.log('[Tracer] ${functionName} returned:', result, 'Time:', (endTime - startTime).toFixed(2), 'ms');
1645
+ return result;
1646
+ } catch (error) {
1647
+ console.error('[Tracer] ${functionName} threw error:', error);
1648
+ throw error;
1649
+ }
1650
+ }
1651
+ });
1652
+
1653
+ console.log('[Tracer] ${functionName} is now being traced');
1654
+ })();
1655
+ `;
1656
+ if (options?.persistent) {
1657
+ await coreCtx.cdpSession.send("Page.addScriptToEvaluateOnNewDocument", { source: tracerCode });
1658
+ logger.info(`Function tracer injected for: ${functionName} (persistent)`);
1659
+ } else {
1660
+ await coreCtx.cdpSession.send("Runtime.evaluate", { expression: tracerCode });
1661
+ logger.info(`Function tracer injected for: ${functionName}`);
1662
+ }
1663
+ }
1664
+ async function injectPropertyWatcherCore(ctx, objectPath, propertyName, options) {
1665
+ const coreCtx = asDynamicCoreContext(ctx);
1666
+ if (!coreCtx.cdpSession) throw new PrerequisiteError("CDP session not initialized");
1667
+ const watcherCode = `
1668
+ (function() {
1669
+ const obj = ${objectPath};
1670
+ if (!obj) {
1671
+ console.error('[Watcher] Object not found: ${objectPath}');
1672
+ return;
1673
+ }
1674
+
1675
+ let value = obj.${propertyName};
1676
+
1677
+ Object.defineProperty(obj, '${propertyName}', {
1678
+ get: function() {
1679
+ console.log('[Watcher] ${objectPath}.${propertyName} accessed, value:', value);
1680
+ return value;
1681
+ },
1682
+ set: function(newValue) {
1683
+ console.log('[Watcher] ${objectPath}.${propertyName} changed from', value, 'to', newValue);
1684
+ value = newValue;
1685
+ },
1686
+ enumerable: true,
1687
+ configurable: true
1688
+ });
1689
+
1690
+ console.log('[Watcher] Property watcher installed for ${objectPath}.${propertyName}');
1691
+ })();
1692
+ `;
1693
+ if (options?.persistent) {
1694
+ await coreCtx.cdpSession.send("Page.addScriptToEvaluateOnNewDocument", { source: watcherCode });
1695
+ logger.info(`Property watcher injected for: ${objectPath}.${propertyName} (persistent)`);
1696
+ } else {
1697
+ await coreCtx.cdpSession.send("Runtime.evaluate", { expression: watcherCode });
1698
+ logger.info(`Property watcher injected for: ${objectPath}.${propertyName}`);
1699
+ }
1700
+ }
1701
+ //#endregion
1702
+ //#region src/modules/monitor/ConsoleMonitor.impl.core.session.ts
1703
+ function asSessionCtx(ctx) {
1704
+ return ctx;
1705
+ }
1706
+ async function doEnableCdpCore(ctx, session, managed, options) {
1707
+ const state = asSessionCtx(ctx);
1708
+ state.cdpSession = session;
1709
+ state.usingManagedTargetSession = managed;
1710
+ state.lastEnableOptions = { ...options };
1711
+ state.cdpSession.on("disconnected", () => {
1712
+ logger.warn("ConsoleMonitor CDP session disconnected");
1713
+ state.cdpSession = null;
1714
+ state.networkMonitor = null;
1715
+ state.usingManagedTargetSession = false;
1716
+ });
1717
+ await cdpSendWithTimeout(state.cdpSession, "Runtime.enable", {}, 5e3);
1718
+ await cdpSendWithTimeout(state.cdpSession, "Console.enable", {}, 5e3);
1719
+ state.cdpSession.on("Runtime.consoleAPICalled", (params) => {
1720
+ const stackTrace = params.stackTrace?.callFrames?.map((frame) => ({
1721
+ functionName: frame.functionName || "(anonymous)",
1722
+ url: frame.url,
1723
+ lineNumber: frame.lineNumber,
1724
+ columnNumber: frame.columnNumber
1725
+ })) || [];
1726
+ const message = {
1727
+ type: params.type,
1728
+ text: params.args.map((arg) => state.formatRemoteObject(arg)).join(" "),
1729
+ args: params.args.map((arg) => state.extractValue(arg)),
1730
+ timestamp: params.timestamp,
1731
+ stackTrace,
1732
+ url: stackTrace[0]?.url,
1733
+ lineNumber: stackTrace[0]?.lineNumber,
1734
+ columnNumber: stackTrace[0]?.columnNumber
1735
+ };
1736
+ state.messages.push(message);
1737
+ if (state.messages.length > state.MAX_MESSAGES) state.messages = state.messages.slice(-Math.floor(state.MAX_MESSAGES / 2));
1738
+ logger.debug(`Console ${params.type}: ${message.text}`);
1739
+ });
1740
+ state.cdpSession.on("Console.messageAdded", (params) => {
1741
+ const msg = params.message;
1742
+ const message = {
1743
+ type: msg.level || "log",
1744
+ text: msg.text,
1745
+ timestamp: Date.now(),
1746
+ url: msg.url,
1747
+ lineNumber: msg.line,
1748
+ columnNumber: msg.column
1749
+ };
1750
+ state.messages.push(message);
1751
+ if (state.messages.length > state.MAX_MESSAGES) state.messages = state.messages.slice(-Math.floor(state.MAX_MESSAGES / 2));
1752
+ });
1753
+ if (options?.enableExceptions !== false) state.cdpSession.on("Runtime.exceptionThrown", (params) => {
1754
+ const exception = params.exceptionDetails;
1755
+ const stackTrace = exception.stackTrace?.callFrames?.map((frame) => ({
1756
+ functionName: frame.functionName || "(anonymous)",
1757
+ url: frame.url,
1758
+ lineNumber: frame.lineNumber,
1759
+ columnNumber: frame.columnNumber
1760
+ })) || [];
1761
+ const exceptionInfo = {
1762
+ text: exception.exception?.description || exception.text,
1763
+ exceptionId: exception.exceptionId,
1764
+ timestamp: Date.now(),
1765
+ stackTrace,
1766
+ url: exception.url,
1767
+ lineNumber: exception.lineNumber,
1768
+ columnNumber: exception.columnNumber,
1769
+ scriptId: exception.scriptId
1770
+ };
1771
+ state.exceptions.push(exceptionInfo);
1772
+ if (state.exceptions.length > state.MAX_EXCEPTIONS) state.exceptions = state.exceptions.slice(-Math.floor(state.MAX_EXCEPTIONS / 2));
1773
+ logger.error(`Exception thrown: ${exceptionInfo.text}`, {
1774
+ url: exceptionInfo.url,
1775
+ line: exceptionInfo.lineNumber
1776
+ });
1777
+ });
1778
+ if (options?.enableNetwork) {
1779
+ state.networkMonitor = new NetworkMonitor(state.cdpSession);
1780
+ await state.networkMonitor.enable();
1781
+ }
1782
+ logger.info("ConsoleMonitor enabled", {
1783
+ network: options?.enableNetwork || false,
1784
+ exceptions: options?.enableExceptions !== false
1785
+ });
1786
+ }
1787
+ async function enablePlaywrightCore(ctx, options) {
1788
+ const state = asSessionCtx(ctx);
1789
+ if (state.playwrightConsoleHandler) {
1790
+ if (options?.enableNetwork && !state.playwrightNetworkMonitor) {
1791
+ state.playwrightNetworkMonitor = new PlaywrightNetworkMonitor(state.playwrightPage);
1792
+ await state.playwrightNetworkMonitor.enable();
1793
+ logger.info("Network monitoring added to existing ConsoleMonitor Playwright session");
1794
+ }
1795
+ return;
1796
+ }
1797
+ const page = state.playwrightPage;
1798
+ state.playwrightConsoleHandler = (msg) => {
1799
+ const message = {
1800
+ type: msg.type() || "log",
1801
+ text: msg.text(),
1802
+ timestamp: Date.now()
1803
+ };
1804
+ state.messages.push(message);
1805
+ if (state.messages.length > state.MAX_MESSAGES) state.messages = state.messages.slice(-Math.floor(state.MAX_MESSAGES / 2));
1806
+ };
1807
+ page.on("console", state.playwrightConsoleHandler);
1808
+ if (options?.enableExceptions !== false) {
1809
+ state.playwrightErrorHandler = (error) => {
1810
+ const exceptionInfo = {
1811
+ text: error.message,
1812
+ exceptionId: Date.now(),
1813
+ timestamp: Date.now()
1814
+ };
1815
+ state.exceptions.push(exceptionInfo);
1816
+ if (state.exceptions.length > state.MAX_EXCEPTIONS) state.exceptions = state.exceptions.slice(-Math.floor(state.MAX_EXCEPTIONS / 2));
1817
+ };
1818
+ page.on("pageerror", state.playwrightErrorHandler);
1819
+ }
1820
+ if (options?.enableNetwork) {
1821
+ state.playwrightNetworkMonitor = new PlaywrightNetworkMonitor(state.playwrightPage);
1822
+ await state.playwrightNetworkMonitor.enable();
1823
+ }
1824
+ logger.info("ConsoleMonitor enabled (Playwright/camoufox mode)", { network: options?.enableNetwork || false });
1825
+ }
1826
+ async function disableCore(ctx) {
1827
+ const state = asSessionCtx(ctx);
1828
+ if (state.playwrightPage) {
1829
+ const page = state.playwrightPage;
1830
+ if (state.playwrightConsoleHandler) {
1831
+ try {
1832
+ page.off("console", state.playwrightConsoleHandler);
1833
+ } catch {}
1834
+ state.playwrightConsoleHandler = null;
1835
+ }
1836
+ if (state.playwrightErrorHandler) {
1837
+ try {
1838
+ page.off("pageerror", state.playwrightErrorHandler);
1839
+ } catch {}
1840
+ state.playwrightErrorHandler = null;
1841
+ }
1842
+ }
1843
+ if (state.playwrightNetworkMonitor) {
1844
+ await state.playwrightNetworkMonitor.disable();
1845
+ state.playwrightNetworkMonitor = null;
1846
+ }
1847
+ if (state.cdpSession) {
1848
+ if (state.networkMonitor) {
1849
+ await state.networkMonitor.disable();
1850
+ state.networkMonitor = null;
1851
+ }
1852
+ try {
1853
+ await state.cdpSession.send("Console.disable");
1854
+ } catch (error) {
1855
+ logger.warn("Failed to disable Console domain:", error);
1856
+ }
1857
+ try {
1858
+ await state.cdpSession.send("Runtime.disable");
1859
+ } catch (error) {
1860
+ logger.warn("Failed to disable Runtime domain:", error);
1861
+ }
1862
+ if (!state.usingManagedTargetSession) try {
1863
+ await state.cdpSession.detach();
1864
+ } catch (error) {
1865
+ logger.warn("Failed to detach ConsoleMonitor CDP session:", error);
1866
+ }
1867
+ else logger.debug("ConsoleMonitor released managed target session without detaching target");
1868
+ state.cdpSession = null;
1869
+ state.usingManagedTargetSession = false;
1870
+ logger.info("ConsoleMonitor disabled");
1871
+ }
1872
+ }
1873
+ async function cdpSendWithTimeout(session, method, params, timeoutMs = 3e4) {
1874
+ return Promise.race([session.send(method, params), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error(`CDP ${method} timed out after ${timeoutMs}ms`)), timeoutMs))]);
1875
+ }
1876
+ //#endregion
1877
+ //#region src/modules/monitor/ConsoleMonitor.impl.core.class.ts
1878
+ var ConsoleMonitor = class {
1879
+ cdpSession = null;
1880
+ networkMonitor = null;
1881
+ fetchInterceptor = null;
1882
+ playwrightNetworkMonitor = null;
1883
+ playwrightPage = null;
1884
+ usingManagedTargetSession = false;
1885
+ contextSwitchPending = false;
1886
+ playwrightConsoleHandler = null;
1887
+ playwrightErrorHandler = null;
1888
+ messages = [];
1889
+ MAX_MESSAGES = 1e3;
1890
+ exceptions = [];
1891
+ MAX_EXCEPTIONS = 500;
1892
+ MAX_INJECTED_DYNAMIC_SCRIPTS = 500;
1893
+ MAX_OBJECT_CACHE_SIZE = 1e3;
1894
+ objectCache = /* @__PURE__ */ new Map();
1895
+ initPromise;
1896
+ lastEnableOptions = {};
1897
+ constructor(collector) {
1898
+ this.collector = collector;
1899
+ this.touchSplitMembersForTypeCheck();
1900
+ }
1901
+ touchSplitMembersForTypeCheck() {
1902
+ this.MAX_INJECTED_DYNAMIC_SCRIPTS;
1903
+ this.MAX_OBJECT_CACHE_SIZE;
1904
+ this.clearDynamicScriptBuffer;
1905
+ this.resetDynamicScriptMonitoring;
1906
+ this.usingManagedTargetSession;
1907
+ this.playwrightErrorHandler;
1908
+ this.messages;
1909
+ this.MAX_MESSAGES;
1910
+ this.exceptions;
1911
+ this.MAX_EXCEPTIONS;
1912
+ this.formatRemoteObject;
1913
+ this.extractValue;
1914
+ }
1915
+ setPlaywrightPage(page) {
1916
+ this.playwrightPage = page;
1917
+ this.playwrightNetworkMonitor?.setPage(page);
1918
+ }
1919
+ clearPlaywrightPage() {
1920
+ this.playwrightPage = null;
1921
+ this.contextSwitchPending = false;
1922
+ this.playwrightConsoleHandler = null;
1923
+ this.playwrightErrorHandler = null;
1924
+ this.playwrightNetworkMonitor?.setPage(null);
1925
+ this.playwrightNetworkMonitor = null;
1926
+ }
1927
+ getManagedTargetSession() {
1928
+ return this.collector.getAttachedTargetSession?.() ?? null;
1929
+ }
1930
+ async createCdpSession() {
1931
+ const managedSession = this.getManagedTargetSession();
1932
+ if (managedSession) return {
1933
+ session: managedSession,
1934
+ managed: true
1935
+ };
1936
+ const page = await this.collector.getActivePage();
1937
+ return {
1938
+ session: await Promise.race([page.createCDPSession(), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("cdp_session_timeout")), 500))]),
1939
+ managed: false
1940
+ };
1941
+ }
1942
+ markContextChanged() {
1943
+ if (!this.cdpSession && !this.playwrightPage && !this.networkMonitor && !this.playwrightNetworkMonitor && !this.fetchInterceptor) return;
1944
+ this.contextSwitchPending = true;
1945
+ this.clearLogs();
1946
+ this.clearExceptions();
1947
+ this.clearNetworkRecords();
1948
+ this.clearObjectCache();
1949
+ logger.info("ConsoleMonitor marked stale after active context switch");
1950
+ }
1951
+ async enable(options) {
1952
+ if (this.contextSwitchPending) await this.disable();
1953
+ if (this.initPromise) {
1954
+ await this.initPromise;
1955
+ await this.applyPostEnableOptions(options);
1956
+ return;
1957
+ }
1958
+ this.initPromise = this.doEnable(options);
1959
+ try {
1960
+ await this.initPromise;
1961
+ } finally {
1962
+ this.initPromise = void 0;
1963
+ }
1964
+ }
1965
+ async doEnable(options) {
1966
+ if (this.playwrightPage) {
1967
+ this.lastEnableOptions = { ...options };
1968
+ return enablePlaywrightCore(this, options);
1969
+ }
1970
+ if (this.cdpSession) {
1971
+ if (options?.enableNetwork && !this.networkMonitor) {
1972
+ this.networkMonitor = new NetworkMonitor(this.cdpSession);
1973
+ await this.networkMonitor.enable();
1974
+ logger.info("Network monitoring added to existing ConsoleMonitor session");
1975
+ }
1976
+ return;
1977
+ }
1978
+ const { session, managed } = await this.createCdpSession();
1979
+ await doEnableCdpCore(this, session, managed, options);
1980
+ }
1981
+ async applyPostEnableOptions(options) {
1982
+ if (!options?.enableNetwork) return;
1983
+ this.lastEnableOptions = {
1984
+ ...this.lastEnableOptions,
1985
+ ...options
1986
+ };
1987
+ if (this.playwrightPage && this.playwrightConsoleHandler && !this.playwrightNetworkMonitor) {
1988
+ await enablePlaywrightCore(this, options);
1989
+ return;
1990
+ }
1991
+ if (this.cdpSession && !this.networkMonitor) {
1992
+ this.networkMonitor = new NetworkMonitor(this.cdpSession);
1993
+ await this.networkMonitor.enable();
1994
+ logger.info("Network monitoring added to existing ConsoleMonitor session");
1995
+ }
1996
+ }
1997
+ async disable() {
1998
+ try {
1999
+ if (this.cdpSession && this.fetchInterceptor) {
2000
+ await this.fetchInterceptor.disable();
2001
+ this.fetchInterceptor = null;
2002
+ }
2003
+ await disableCore(this);
2004
+ } finally {
2005
+ this.fetchInterceptor = null;
2006
+ this.initPromise = void 0;
2007
+ this.contextSwitchPending = false;
2008
+ this.objectCache.clear();
2009
+ }
2010
+ }
2011
+ async ensureSession() {
2012
+ if (this.contextSwitchPending) {
2013
+ logger.info("ConsoleMonitor context switched, rebinding on demand...");
2014
+ const rebindOptions = { ...this.lastEnableOptions };
2015
+ await this.disable();
2016
+ await this.enable(rebindOptions);
2017
+ return;
2018
+ }
2019
+ if (!this.cdpSession && !this.playwrightPage) {
2020
+ logger.info("ConsoleMonitor CDP session lost, reinitializing...");
2021
+ await this.enable(this.lastEnableOptions);
2022
+ return;
2023
+ }
2024
+ if (this.cdpSession) try {
2025
+ await Promise.race([this.cdpSession.send("Runtime.evaluate", {
2026
+ expression: "1",
2027
+ returnByValue: true
2028
+ }), new Promise((_, reject) => setTimeout(() => reject(/* @__PURE__ */ new Error("session_unreachable")), 3e3))]);
2029
+ return;
2030
+ } catch {
2031
+ logger.warn("ConsoleMonitor CDP session unresponsive (zombie), reinitializing...");
2032
+ this.cdpSession = null;
2033
+ this.networkMonitor = null;
2034
+ this.fetchInterceptor = null;
2035
+ this.usingManagedTargetSession = false;
2036
+ await this.enable(this.lastEnableOptions);
2037
+ }
2038
+ }
2039
+ isSessionActive() {
2040
+ return !this.contextSwitchPending && (this.cdpSession !== null || this.playwrightPage !== null);
2041
+ }
2042
+ getLogs(filter) {
2043
+ return getLogsCore(this, filter);
2044
+ }
2045
+ async execute(expression) {
2046
+ await this.ensureSession();
2047
+ try {
2048
+ const result = await cdpSendWithTimeout(this.cdpSession, "Runtime.evaluate", {
2049
+ expression,
2050
+ returnByValue: true
2051
+ });
2052
+ if (result.exceptionDetails) {
2053
+ logger.error("Console execute error:", result.exceptionDetails);
2054
+ throw new Error(result.exceptionDetails.text);
2055
+ }
2056
+ logger.info("Console expression executed");
2057
+ return result.result.value;
2058
+ } catch (error) {
2059
+ logger.error("Console execute failed:", error);
2060
+ throw error;
2061
+ }
2062
+ }
2063
+ clearLogs() {
2064
+ clearLogsCore(this);
2065
+ }
2066
+ getStats() {
2067
+ return getStatsCore(this);
2068
+ }
2069
+ async close() {
2070
+ try {
2071
+ await this.disable();
2072
+ } finally {
2073
+ this.initPromise = void 0;
2074
+ this.objectCache.clear();
2075
+ }
2076
+ }
2077
+ isNetworkEnabled() {
2078
+ return isNetworkEnabledCore(this);
2079
+ }
2080
+ getNetworkStatus() {
2081
+ return getNetworkStatusCore(this);
2082
+ }
2083
+ getNetworkRequests(filter) {
2084
+ return getNetworkRequestsCore(this, filter);
2085
+ }
2086
+ getNetworkResponses(filter) {
2087
+ return getNetworkResponsesCore(this, filter);
2088
+ }
2089
+ getNetworkActivity(requestId) {
2090
+ return getNetworkActivityCore(this, requestId);
2091
+ }
2092
+ async getResponseBody(requestId) {
2093
+ return getResponseBodyCore(this, requestId);
2094
+ }
2095
+ async getAllJavaScriptResponses() {
2096
+ return getAllJavaScriptResponsesCore(this);
2097
+ }
2098
+ clearNetworkRecords() {
2099
+ clearNetworkRecordsCore(this);
2100
+ }
2101
+ async clearInjectedBuffers() {
2102
+ return clearInjectedBuffersCore(this);
2103
+ }
2104
+ async resetInjectedInterceptors() {
2105
+ return resetInjectedInterceptorsCore(this);
2106
+ }
2107
+ getNetworkStats() {
2108
+ return getNetworkStatsCore(this);
2109
+ }
2110
+ async injectXHRInterceptor(options) {
2111
+ return injectXHRInterceptorCore(this, options);
2112
+ }
2113
+ async injectFetchInterceptor(options) {
2114
+ return injectFetchInterceptorCore(this, options);
2115
+ }
2116
+ async getXHRRequests() {
2117
+ return getXHRRequestsCore(this);
2118
+ }
2119
+ async getFetchRequests() {
2120
+ return getFetchRequestsCore(this);
2121
+ }
2122
+ getExceptions(filter) {
2123
+ return getExceptionsCore(this, filter);
2124
+ }
2125
+ clearExceptions() {
2126
+ clearExceptionsCore(this);
2127
+ }
2128
+ async inspectObject(objectId) {
2129
+ return inspectObjectCore(this, objectId);
2130
+ }
2131
+ clearObjectCache() {
2132
+ clearObjectCacheCore(this);
2133
+ }
2134
+ async enableDynamicScriptMonitoring(options) {
2135
+ return enableDynamicScriptMonitoringCore(this, options);
2136
+ }
2137
+ async clearDynamicScriptBuffer() {
2138
+ return clearDynamicScriptBufferCore(this);
2139
+ }
2140
+ async resetDynamicScriptMonitoring() {
2141
+ return resetDynamicScriptMonitoringCore(this);
2142
+ }
2143
+ async getDynamicScripts() {
2144
+ return getDynamicScriptsCore(this);
2145
+ }
2146
+ async injectFunctionTracer(functionName, options) {
2147
+ return injectFunctionTracerCore(this, functionName, options);
2148
+ }
2149
+ async injectPropertyWatcher(objectPath, propertyName, options) {
2150
+ return injectPropertyWatcherCore(this, objectPath, propertyName, options);
2151
+ }
2152
+ async enableFetchIntercept(rules) {
2153
+ await this.ensureSession();
2154
+ if (!this.cdpSession) throw new Error("No CDP session available for Fetch interception");
2155
+ if (!this.fetchInterceptor) this.fetchInterceptor = new FetchInterceptor(this.cdpSession);
2156
+ return this.fetchInterceptor.enable(rules);
2157
+ }
2158
+ async disableFetchIntercept() {
2159
+ if (!this.fetchInterceptor) return { removedRules: 0 };
2160
+ const result = await this.fetchInterceptor.disable();
2161
+ this.fetchInterceptor = null;
2162
+ return result;
2163
+ }
2164
+ async removeFetchInterceptRule(ruleId) {
2165
+ if (!this.fetchInterceptor) return false;
2166
+ const removed = await this.fetchInterceptor.removeRule(ruleId);
2167
+ if (!this.fetchInterceptor.isEnabled()) this.fetchInterceptor = null;
2168
+ return removed;
2169
+ }
2170
+ getFetchInterceptStatus() {
2171
+ if (!this.fetchInterceptor) return {
2172
+ enabled: false,
2173
+ rules: [],
2174
+ totalHits: 0
2175
+ };
2176
+ return this.fetchInterceptor.listRules();
2177
+ }
2178
+ formatRemoteObject(obj) {
2179
+ if (obj.value !== void 0) return String(obj.value);
2180
+ if (obj.description) return obj.description;
2181
+ if (obj.type === "undefined") return "undefined";
2182
+ if (obj.type === "object" && obj.subtype === "null") return "null";
2183
+ return `[${obj.type}]`;
2184
+ }
2185
+ extractValue(obj) {
2186
+ if (obj.value !== void 0) return obj.value;
2187
+ if (obj.type === "undefined") return;
2188
+ if (obj.type === "object" && obj.subtype === "null") return null;
2189
+ if (obj.objectId) return {
2190
+ __objectId: obj.objectId,
2191
+ __type: obj.type,
2192
+ __description: obj.description
2193
+ };
2194
+ return obj.description || `[${obj.type}]`;
2195
+ }
2196
+ };
2197
+ //#endregion
2198
+ //#region src/modules/monitor/ConsoleMonitor.ts
2199
+ var ConsoleMonitor_exports = /* @__PURE__ */ __exportAll({ ConsoleMonitor: () => ConsoleMonitor });
2200
+ //#endregion
2201
+ export { ConsoleMonitor_exports as t };