@jshookmcp/jshook 0.2.8 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/README.md +36 -5
  2. package/README.zh.md +36 -5
  3. package/dist/{AntiCheatDetector-S8VRj-dD.mjs → AntiCheatDetector-CqGDXmfc.mjs} +160 -54
  4. package/dist/{CodeInjector-4Z3ngPoX.mjs → CodeInjector-BdjRfNx7.mjs} +5 -5
  5. package/dist/ConsoleMonitor-DykL3IAw.mjs +2269 -0
  6. package/dist/{DarwinAPI-B8hg_yhz.mjs → DarwinAPI-ETyy0xyo.mjs} +1 -1
  7. package/dist/DetailedDataManager-HT49OrvF.mjs +217 -0
  8. package/dist/EventBus-DFKvADm3.mjs +141 -0
  9. package/dist/EvidenceGraphBridge-318Oi0Lf.mjs +153 -0
  10. package/dist/{ExtensionManager-D5-bO9D8.mjs → ExtensionManager-BDMsY2Dz.mjs} +27 -13
  11. package/dist/{FingerprintManager-BVxFJL2-.mjs → FingerprintManager-BN4UQWnX.mjs} +1 -1
  12. package/dist/{HardwareBreakpoint-DK1yjWkV.mjs → HardwareBreakpoint-Cc2AFq1Y.mjs} +3 -3
  13. package/dist/{HeapAnalyzer-CEbo10xU.mjs → HeapAnalyzer-DruMgsgj.mjs} +21 -21
  14. package/dist/HookGeneratorBuilders.core.generators.storage-CTbB4Lcx.mjs +566 -0
  15. package/dist/InstrumentationSession-DLH0vd-z.mjs +244 -0
  16. package/dist/{MemoryController-DdtnBdD4.mjs → MemoryController-CMtviNW_.mjs} +3 -3
  17. package/dist/{MemoryScanSession-RMixN3bX.mjs → MemoryScanSession-ITgb_NMi.mjs} +81 -78
  18. package/dist/{MemoryScanner-QjK4ld0B.mjs → MemoryScanner-CiL7Z3ey.mjs} +50 -21
  19. package/dist/{NativeMemoryManager.impl-CB6gJ0NM.mjs → NativeMemoryManager.impl-D9Lkovvn.mjs} +20 -56
  20. package/dist/{NativeMemoryManager.utils-BML4q1ry.mjs → NativeMemoryManager.utils-BBlAixF5.mjs} +1 -1
  21. package/dist/{PEAnalyzer-CK0xe0Fs.mjs → PEAnalyzer-DMQ44gen.mjs} +16 -16
  22. package/dist/PageController-BPJNqqBN.mjs +431 -0
  23. package/dist/{PointerChainEngine-Cd73qu5b.mjs → PointerChainEngine-K7wN8Z-w.mjs} +10 -7
  24. package/dist/PrerequisiteError-TuyZIs6n.mjs +20 -0
  25. package/dist/ProcessRegistry-zGg12QbE.mjs +74 -0
  26. package/dist/ResponseBuilder-CJXWmWNw.mjs +143 -0
  27. package/dist/ReverseEvidenceGraph-C02-gXOh.mjs +269 -0
  28. package/dist/ScriptManager-ZuWD-0Jg.mjs +3003 -0
  29. package/dist/{Speedhack-CeF0XmEz.mjs → Speedhack-D-z0umeT.mjs} +2 -2
  30. package/dist/{StructureAnalyzer-D4GkMduU.mjs → StructureAnalyzer-Cav5AVSL.mjs} +9 -6
  31. package/dist/ToolCatalog-5OJdMiF0.mjs +582 -0
  32. package/dist/ToolError-jh9whhMd.mjs +15 -0
  33. package/dist/ToolProbe-DbCFGyrg.mjs +45 -0
  34. package/dist/ToolRegistry-B9krbTtI.mjs +180 -0
  35. package/dist/ToolRouter.policy-BGDAGyeH.mjs +344 -0
  36. package/dist/TraceRecorder-B41Z5XBj.mjs +1286 -0
  37. package/dist/{Win32API-Bc0QnQsN.mjs → Win32API-C2kjj0ze.mjs} +19 -13
  38. package/dist/{Win32Debug-DUHt9XUn.mjs → Win32Debug-CKrGOTpo.mjs} +3 -3
  39. package/dist/WorkflowEngine-DJ6M4opp.mjs +569 -0
  40. package/dist/analysis-BHeJW2Nb.mjs +1234 -0
  41. package/dist/antidebug-BRKeyt27.mjs +1081 -0
  42. package/dist/artifactRetention-CPXkUJXp.mjs +598 -0
  43. package/dist/artifacts-DkfosXH3.mjs +59 -0
  44. package/dist/authorization-schema-DRqyJMSk.mjs +31 -0
  45. package/dist/betterSqlite3-DLSBZodi.mjs +74 -0
  46. package/dist/binary-instrument--V3MAhJ4.mjs +971 -0
  47. package/dist/bind-helpers-ClV34xdn.mjs +42 -0
  48. package/dist/boringssl-inspector-Bo_LOLaS.mjs +180 -0
  49. package/dist/browser-Dx3_S2cG.mjs +4369 -0
  50. package/dist/capabilities-CcHlvWgK.mjs +33 -0
  51. package/dist/concurrency-Drev_Vz9.mjs +41 -0
  52. package/dist/{constants-CCvsN80K.mjs → constants-CDZLOoVv.mjs} +105 -48
  53. package/dist/coordination-DgItD9DL.mjs +259 -0
  54. package/dist/debugger-RS3RSAqs.mjs +1288 -0
  55. package/dist/definitions-BEoYofW5.mjs +47 -0
  56. package/dist/definitions-BRaefg3u.mjs +365 -0
  57. package/dist/definitions-BbkvZkiv.mjs +96 -0
  58. package/dist/definitions-BtWSHJ3o.mjs +17 -0
  59. package/dist/definitions-C1gCHO0i.mjs +43 -0
  60. package/dist/definitions-CDOg_b-l.mjs +138 -0
  61. package/dist/definitions-CVPD9hzZ.mjs +54 -0
  62. package/dist/definitions-Cea8Lgl7.mjs +94 -0
  63. package/dist/definitions-DAgIyjxM.mjs +10 -0
  64. package/dist/definitions-DJA27nsL.mjs +66 -0
  65. package/dist/definitions-DKPFU3LW.mjs +25 -0
  66. package/dist/definitions-DPRpZQ96.mjs +47 -0
  67. package/dist/definitions-DUE5gmdn.mjs +18 -0
  68. package/dist/definitions-DYVjOtxa.mjs +26 -0
  69. package/dist/definitions-DcYLVLCo.mjs +37 -0
  70. package/dist/definitions-Pp5LI2H4.mjs +27 -0
  71. package/dist/definitions-j9KdHVNR.mjs +14 -0
  72. package/dist/definitions-uzkjBwa7.mjs +258 -0
  73. package/dist/definitions-va-AnLuQ.mjs +28 -0
  74. package/dist/encoding-DJeqHmpd.mjs +1079 -0
  75. package/dist/evidence-graph-bridge-DcYizFk2.mjs +136 -0
  76. package/dist/{factory-CibqTNC8.mjs → factory-C90tBff6.mjs} +41 -56
  77. package/dist/flat-target-session-Dgax2Cy3.mjs +29 -0
  78. package/dist/graphql-CoHrhweh.mjs +1197 -0
  79. package/dist/handlers-4jmR0nMs.mjs +898 -0
  80. package/dist/handlers-BAHPxcch.mjs +789 -0
  81. package/dist/handlers-BOs9b907.mjs +2600 -0
  82. package/dist/handlers-BWXEy6ef.mjs +917 -0
  83. package/dist/handlers-Bndn6QvE.mjs +111 -0
  84. package/dist/handlers-BqC4bD4s.mjs +681 -0
  85. package/dist/handlers-BtYq60bM2.mjs +276 -0
  86. package/dist/handlers-BzgcB4iv.mjs +799 -0
  87. package/dist/handlers-CRyRWj2b.mjs +859 -0
  88. package/dist/handlers-CVv2H1uq.mjs +592 -0
  89. package/dist/handlers-Dl5a7JS4.mjs +572 -0
  90. package/dist/handlers-Dx2d7jt7.mjs +2537 -0
  91. package/dist/handlers-Dz9PYsCa.mjs +2805 -0
  92. package/dist/handlers-HujRKC3b.mjs +661 -0
  93. package/dist/handlers.impl-XWXkQfyi.mjs +807 -0
  94. package/dist/hooks-B1B8NRHL.mjs +898 -0
  95. package/dist/index.mjs +491 -259
  96. package/dist/{logger-BmWzC2lM.mjs → logger-Dh_xb7_2.mjs} +14 -6
  97. package/dist/maintenance-PRMkLVRW.mjs +835 -0
  98. package/dist/manifest-67Bok-Si.mjs +58 -0
  99. package/dist/manifest-6lNTMZAB2.mjs +87 -0
  100. package/dist/manifest-B2duEHiH.mjs +90 -0
  101. package/dist/manifest-B6EY9Vm8.mjs +57 -0
  102. package/dist/manifest-B6nKSbyY.mjs +95 -0
  103. package/dist/manifest-BL8AQNPF.mjs +106 -0
  104. package/dist/manifest-BSZvJJmV.mjs +47 -0
  105. package/dist/manifest-BU7qzUyX.mjs +418 -0
  106. package/dist/manifest-Bl62e8WK.mjs +49 -0
  107. package/dist/manifest-Bo5cXjdt.mjs +82 -0
  108. package/dist/manifest-BpS4gtUK.mjs +1347 -0
  109. package/dist/manifest-Bv65_e2W.mjs +101 -0
  110. package/dist/manifest-BytNIF4Z.mjs +117 -0
  111. package/dist/manifest-C-xtsjS3.mjs +81 -0
  112. package/dist/manifest-CDYl7OhA.mjs +66 -0
  113. package/dist/manifest-CRZ3xmkD.mjs +61 -0
  114. package/dist/manifest-CoW6u4Tp.mjs +132 -0
  115. package/dist/manifest-Cq5zN_8A.mjs +50 -0
  116. package/dist/manifest-D7YZM_2e.mjs +194 -0
  117. package/dist/manifest-DE_VrAeQ.mjs +314 -0
  118. package/dist/manifest-DGsXSCpT.mjs +39 -0
  119. package/dist/manifest-DJ2vfEuW.mjs +156 -0
  120. package/dist/manifest-DPXDYhEu.mjs +80 -0
  121. package/dist/manifest-Dd4fQb0a.mjs +322 -0
  122. package/dist/manifest-Deq6opGg.mjs +223 -0
  123. package/dist/manifest-DfJTafJK.mjs +37 -0
  124. package/dist/manifest-DgOdgN_j.mjs +50 -0
  125. package/dist/manifest-DlbMW4v4.mjs +47 -0
  126. package/dist/manifest-DmVfbH0w.mjs +374 -0
  127. package/dist/manifest-Dog6Ddjr.mjs +109 -0
  128. package/dist/manifest-DvgU5FWb.mjs +58 -0
  129. package/dist/manifest-HsfDBs7j.mjs +50 -0
  130. package/dist/manifest-I8oQHvCG.mjs +186 -0
  131. package/dist/manifest-NvH_a-av.mjs +786 -0
  132. package/dist/manifest-cEJU1v0Z.mjs +129 -0
  133. package/dist/manifest-wOl5XLB12.mjs +112 -0
  134. package/dist/modules-tZozf0LQ.mjs +10635 -0
  135. package/dist/mojo-ipc-DXNEXEqb.mjs +640 -0
  136. package/dist/network-CPVvwvFg.mjs +3852 -0
  137. package/dist/{artifacts-BbdOMET5.mjs → outputPaths-um7lCRY3.mjs} +219 -216
  138. package/dist/parse-args-B4cY5Vx5.mjs +39 -0
  139. package/dist/platform-CYeFoTWp.mjs +2161 -0
  140. package/dist/process-BTbgcVc6.mjs +1306 -0
  141. package/dist/proxy-r8YN6nP1.mjs +192 -0
  142. package/dist/registry-Bl8ZQW61.mjs +34 -0
  143. package/dist/response-CWhh2aLo.mjs +34 -0
  144. package/dist/server/plugin-api.mjs +2 -2
  145. package/dist/shared-state-board-BoZnSoj-.mjs +586 -0
  146. package/dist/sourcemap-BIDHUVXy.mjs +934 -0
  147. package/dist/ssrf-policy-Dsqd-DTX.mjs +166 -0
  148. package/dist/streaming-Dal6utPp.mjs +725 -0
  149. package/dist/tool-builder-BHJp32mV.mjs +186 -0
  150. package/dist/transform-DRVgGG90.mjs +1011 -0
  151. package/dist/types-Bx92KJfT.mjs +4 -0
  152. package/dist/wasm-BYx5UOeG.mjs +1044 -0
  153. package/dist/webcrack-Be0_FccV.mjs +747 -0
  154. package/dist/workflow-BpuKEtvn.mjs +725 -0
  155. package/package.json +82 -49
  156. package/dist/ExtensionManager-CPTJhHFg.mjs +0 -2
  157. package/dist/ToolCatalog-Bq4V2sbJ.mjs +0 -67201
  158. package/dist/{CacheAdapters-CzFNpD9a.mjs → CacheAdapters-jJFy20G-.mjs} +0 -0
  159. package/dist/{StealthVerifier-BzBCFiwx.mjs → StealthVerifier-BWmPgQsv.mjs} +0 -0
  160. package/dist/{VersionDetector-CNXcvD46.mjs → VersionDetector-K3V4vGsw.mjs} +0 -0
  161. package/dist/{formatAddress-ChCSIRWT.mjs → formatAddress-nnMvEohD.mjs} +0 -0
  162. package/dist/{types-BBjOqye-.mjs → types-DDBWs9UP.mjs} +1 -1
@@ -0,0 +1,1286 @@
1
+ import { n as __require } from "./chunk-CjcI7cDX.mjs";
2
+ import { i as resolveArtifactPath } from "./artifacts-DkfosXH3.mjs";
3
+ import { t as formatBetterSqlite3Error } from "./betterSqlite3-DLSBZodi.mjs";
4
+ import { randomUUID } from "node:crypto";
5
+ import { writeFile } from "node:fs/promises";
6
+ //#region src/modules/trace/TraceRecorder.internal.ts
7
+ const CDP_EVENTS_BY_DOMAIN = {
8
+ Debugger: [
9
+ "Debugger.paused",
10
+ "Debugger.resumed",
11
+ "Debugger.scriptParsed"
12
+ ],
13
+ Runtime: ["Runtime.consoleAPICalled", "Runtime.exceptionThrown"],
14
+ Network: [
15
+ "Network.requestWillBeSent",
16
+ "Network.requestServedFromCache",
17
+ "Network.responseReceived",
18
+ "Network.dataReceived",
19
+ "Network.loadingFinished",
20
+ "Network.loadingFailed",
21
+ "Network.eventSourceMessageReceived",
22
+ "Network.webSocketCreated",
23
+ "Network.webSocketWillSendHandshakeRequest",
24
+ "Network.webSocketHandshakeResponseReceived",
25
+ "Network.webSocketFrameReceived",
26
+ "Network.webSocketFrameSent",
27
+ "Network.webSocketFrameError",
28
+ "Network.webSocketClosed"
29
+ ],
30
+ Page: ["Page.navigatedWithinDocument", "Page.loadEventFired"]
31
+ };
32
+ const DEFAULT_CDP_DOMAINS = [
33
+ "Debugger",
34
+ "Runtime",
35
+ "Network",
36
+ "Page"
37
+ ];
38
+ const DEFAULT_NETWORK_CAPTURE = {
39
+ recordResponseBodies: true,
40
+ streamResponseChunks: true,
41
+ maxBodyBytes: 10 * 1024 * 1024,
42
+ inlineBodyBytes: 256 * 1024
43
+ };
44
+ const MAX_INLINE_EVENT_FIELD_BYTES = 16 * 1024;
45
+ const isObjectRecord = (value) => typeof value === "object" && value !== null;
46
+ const asString = (value) => typeof value === "string" ? value : null;
47
+ const asFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
48
+ const toCdpMilliseconds = (value) => {
49
+ const num = asFiniteNumber(value);
50
+ if (num === null) return null;
51
+ return num > 0xe8d4a51000 ? num : num * 1e3;
52
+ };
53
+ const isResponseBodyPayload = (value) => isObjectRecord(value) && typeof value.body === "string" && typeof value.base64Encoded === "boolean";
54
+ const extractEventTiming = (params) => {
55
+ const receivedAt = Date.now();
56
+ if (!isObjectRecord(params)) return {
57
+ timestamp: receivedAt,
58
+ wallTime: receivedAt,
59
+ monotonicTime: null
60
+ };
61
+ const wallTime = toCdpMilliseconds(params["wallTime"]);
62
+ const monotonicTime = toCdpMilliseconds(params["timestamp"]);
63
+ return {
64
+ timestamp: wallTime ?? receivedAt,
65
+ wallTime: wallTime ?? receivedAt,
66
+ monotonicTime
67
+ };
68
+ };
69
+ const extractRequestId = (params) => {
70
+ if (!isObjectRecord(params)) return null;
71
+ return typeof params["requestId"] === "string" ? params["requestId"] : null;
72
+ };
73
+ const extractScriptLocation = (eventName, params) => {
74
+ let scriptId = null;
75
+ let lineNumber = null;
76
+ if (!isObjectRecord(params)) return {
77
+ scriptId,
78
+ lineNumber
79
+ };
80
+ if ("scriptId" in params) scriptId = String(params["scriptId"]);
81
+ if ("lineNumber" in params) lineNumber = Number(params["lineNumber"]) || null;
82
+ if (eventName === "Debugger.paused" && Array.isArray(params["callFrames"])) {
83
+ const frame = params["callFrames"][0];
84
+ if (frame) {
85
+ const location = frame["location"];
86
+ if (location) {
87
+ scriptId = String(location["scriptId"] ?? scriptId);
88
+ lineNumber = Number(location["lineNumber"] ?? lineNumber) || null;
89
+ }
90
+ }
91
+ }
92
+ return {
93
+ scriptId,
94
+ lineNumber
95
+ };
96
+ };
97
+ const sanitizeTracePayload = (eventName, params) => {
98
+ if (!isObjectRecord(params)) return params ?? {};
99
+ const cloned = { ...params };
100
+ if (eventName === "Network.dataReceived" && typeof cloned["data"] === "string") {
101
+ const chunk = cloned["data"];
102
+ cloned["hasChunkData"] = true;
103
+ cloned["chunkDataBytes"] = Buffer.byteLength(chunk, "utf8");
104
+ cloned["data"] = "[captured in network_chunks]";
105
+ }
106
+ if (eventName === "Network.eventSourceMessageReceived" && typeof cloned["data"] === "string" && Buffer.byteLength(cloned["data"], "utf8") > MAX_INLINE_EVENT_FIELD_BYTES) {
107
+ cloned["data"] = `${cloned["data"].slice(0, MAX_INLINE_EVENT_FIELD_BYTES)}...[truncated]`;
108
+ cloned["truncatedData"] = true;
109
+ }
110
+ if ((eventName === "Network.webSocketFrameReceived" || eventName === "Network.webSocketFrameSent") && isObjectRecord(cloned["response"]) && typeof cloned["response"]["payloadData"] === "string") {
111
+ const response = { ...cloned["response"] };
112
+ const payload = response["payloadData"];
113
+ if (Buffer.byteLength(payload, "utf8") > MAX_INLINE_EVENT_FIELD_BYTES) {
114
+ response["payloadData"] = `${payload.slice(0, MAX_INLINE_EVENT_FIELD_BYTES)}...[truncated]`;
115
+ response["truncatedPayloadData"] = true;
116
+ cloned["response"] = response;
117
+ }
118
+ }
119
+ return cloned;
120
+ };
121
+ const extractRemoteAddress = (response) => {
122
+ const ip = asString(response["remoteIPAddress"]);
123
+ const port = asFiniteNumber(response["remotePort"]);
124
+ if (!ip) return null;
125
+ return port !== null ? `${ip}:${port}` : ip;
126
+ };
127
+ const createNetworkTraceResource = (requestId) => ({
128
+ requestId,
129
+ url: null,
130
+ method: null,
131
+ resourceType: null,
132
+ requestHeaders: "{}",
133
+ requestPostData: null,
134
+ status: null,
135
+ statusText: null,
136
+ responseHeaders: "{}",
137
+ mimeType: null,
138
+ protocol: null,
139
+ remoteAddress: null,
140
+ fromDiskCache: false,
141
+ fromServiceWorker: false,
142
+ startedWallTime: null,
143
+ responseWallTime: null,
144
+ finishedWallTime: null,
145
+ startedMonotonicTime: null,
146
+ responseMonotonicTime: null,
147
+ finishedMonotonicTime: null,
148
+ encodedDataLength: null,
149
+ receivedDataLength: 0,
150
+ receivedEncodedDataLength: 0,
151
+ chunkCount: 0,
152
+ streamingEnabled: false,
153
+ streamingSupported: null,
154
+ streamingError: null,
155
+ bodyCaptureState: "none",
156
+ bodyInline: null,
157
+ bodyArtifactPath: null,
158
+ bodyBase64Encoded: false,
159
+ bodySize: null,
160
+ bodyTruncated: false,
161
+ bodyError: null,
162
+ failed: false,
163
+ errorText: null
164
+ });
165
+ //#endregion
166
+ //#region src/modules/trace/TraceRecorder.network.ts
167
+ var TraceNetworkCapture = class {
168
+ resources = /* @__PURE__ */ new Map();
169
+ options = { ...DEFAULT_NETWORK_CAPTURE };
170
+ counts = {
171
+ networkRequestCount: 0,
172
+ networkChunkCount: 0,
173
+ networkBodyCount: 0
174
+ };
175
+ constructor(deps) {
176
+ this.deps = deps;
177
+ }
178
+ configure(options) {
179
+ this.resources.clear();
180
+ this.counts = {
181
+ networkRequestCount: 0,
182
+ networkChunkCount: 0,
183
+ networkBodyCount: 0
184
+ };
185
+ this.options = {
186
+ ...DEFAULT_NETWORK_CAPTURE,
187
+ ...options
188
+ };
189
+ return this.getOptions();
190
+ }
191
+ clear() {
192
+ this.resources.clear();
193
+ this.counts = {
194
+ networkRequestCount: 0,
195
+ networkChunkCount: 0,
196
+ networkBodyCount: 0
197
+ };
198
+ }
199
+ getOptions() {
200
+ return { ...this.options };
201
+ }
202
+ getCounts() {
203
+ return { ...this.counts };
204
+ }
205
+ handleEvent(eventName, params, timing) {
206
+ const requestId = extractRequestId(params);
207
+ if (!requestId) return;
208
+ switch (eventName) {
209
+ case "Network.requestWillBeSent":
210
+ this.handleRequestWillBeSent(requestId, params, timing);
211
+ return;
212
+ case "Network.requestServedFromCache":
213
+ this.handleRequestServedFromCache(requestId);
214
+ return;
215
+ case "Network.responseReceived":
216
+ this.handleResponseReceived(requestId, params, timing);
217
+ return;
218
+ case "Network.dataReceived":
219
+ this.handleDataReceived(requestId, params, timing);
220
+ return;
221
+ case "Network.loadingFinished":
222
+ this.handleLoadingFinished(requestId, params, timing);
223
+ return;
224
+ case "Network.loadingFailed":
225
+ this.handleLoadingFailed(requestId, params, timing);
226
+ return;
227
+ default: return;
228
+ }
229
+ }
230
+ handleRequestWillBeSent(requestId, params, timing) {
231
+ const resource = this.getOrCreateResource(requestId);
232
+ const request = isObjectRecord(params) && isObjectRecord(params["request"]) ? params["request"] : null;
233
+ resource.url = request ? asString(request["url"]) : resource.url;
234
+ resource.method = request ? asString(request["method"]) : resource.method;
235
+ resource.resourceType = isObjectRecord(params) && typeof params["type"] === "string" ? params["type"] : resource.resourceType;
236
+ resource.requestHeaders = request ? JSON.stringify(request["headers"] ?? {}) : resource.requestHeaders;
237
+ resource.requestPostData = request ? asString(request["postData"]) : resource.requestPostData;
238
+ resource.startedWallTime = timing.wallTime ?? resource.startedWallTime ?? timing.timestamp;
239
+ resource.startedMonotonicTime = timing.monotonicTime ?? resource.startedMonotonicTime;
240
+ this.syncResource(resource);
241
+ }
242
+ handleRequestServedFromCache(requestId) {
243
+ const resource = this.getOrCreateResource(requestId);
244
+ resource.fromDiskCache = true;
245
+ this.syncResource(resource);
246
+ }
247
+ handleResponseReceived(requestId, params, timing) {
248
+ const resource = this.getOrCreateResource(requestId);
249
+ const response = isObjectRecord(params) && isObjectRecord(params["response"]) ? params["response"] : null;
250
+ resource.url = response ? asString(response["url"]) ?? resource.url : resource.url;
251
+ resource.status = response ? asFiniteNumber(response["status"]) : resource.status;
252
+ resource.statusText = response ? asString(response["statusText"]) : resource.statusText;
253
+ resource.responseHeaders = response ? JSON.stringify(response["headers"] ?? {}) : resource.responseHeaders;
254
+ resource.mimeType = response ? asString(response["mimeType"]) : resource.mimeType;
255
+ resource.protocol = response ? asString(response["protocol"]) : resource.protocol;
256
+ resource.remoteAddress = response ? extractRemoteAddress(response) : resource.remoteAddress;
257
+ resource.fromDiskCache = response ? Boolean(response["fromDiskCache"]) : resource.fromDiskCache;
258
+ resource.fromServiceWorker = response ? Boolean(response["fromServiceWorker"]) : resource.fromServiceWorker;
259
+ resource.responseWallTime = timing.wallTime ?? resource.responseWallTime ?? timing.timestamp;
260
+ resource.responseMonotonicTime = timing.monotonicTime ?? resource.responseMonotonicTime;
261
+ this.syncResource(resource);
262
+ if (this.options.streamResponseChunks && resource.streamingSupported === null) this.deps.trackOperation(this.enableStreamingForRequest(requestId));
263
+ }
264
+ handleDataReceived(requestId, params, timing) {
265
+ const resource = this.getOrCreateResource(requestId);
266
+ const payload = isObjectRecord(params) ? params : null;
267
+ const dataLength = payload ? asFiniteNumber(payload["dataLength"]) ?? 0 : 0;
268
+ const encodedDataLength = payload ? asFiniteNumber(payload["encodedDataLength"]) ?? 0 : 0;
269
+ const rawChunk = payload ? asString(payload["data"]) : null;
270
+ resource.receivedDataLength += dataLength;
271
+ resource.receivedEncodedDataLength += encodedDataLength;
272
+ resource.chunkCount += 1;
273
+ const allowChunkData = resource.receivedDataLength <= this.options.maxBodyBytes;
274
+ const chunk = {
275
+ requestId,
276
+ sequence: resource.chunkCount,
277
+ timestamp: timing.timestamp,
278
+ monotonicTime: timing.monotonicTime,
279
+ dataLength,
280
+ encodedDataLength,
281
+ chunkData: allowChunkData ? rawChunk : null,
282
+ chunkIsBase64: rawChunk !== null
283
+ };
284
+ try {
285
+ this.deps.getDb()?.insertNetworkChunk(chunk);
286
+ this.counts.networkChunkCount++;
287
+ } catch {}
288
+ this.syncResource(resource);
289
+ }
290
+ handleLoadingFinished(requestId, params, timing) {
291
+ const resource = this.getOrCreateResource(requestId);
292
+ resource.finishedWallTime = timing.wallTime ?? timing.timestamp;
293
+ resource.finishedMonotonicTime = timing.monotonicTime ?? resource.finishedMonotonicTime;
294
+ if (isObjectRecord(params)) resource.encodedDataLength = asFiniteNumber(params["encodedDataLength"]) ?? resource.encodedDataLength;
295
+ this.syncResource(resource);
296
+ if (this.options.recordResponseBodies) this.deps.trackOperation(this.captureResponseBody(requestId));
297
+ }
298
+ handleLoadingFailed(requestId, params, timing) {
299
+ const resource = this.getOrCreateResource(requestId);
300
+ resource.finishedWallTime = timing.wallTime ?? timing.timestamp;
301
+ resource.finishedMonotonicTime = timing.monotonicTime ?? resource.finishedMonotonicTime;
302
+ resource.failed = true;
303
+ resource.errorText = isObjectRecord(params) ? asString(params["errorText"]) : null;
304
+ this.syncResource(resource);
305
+ }
306
+ async enableStreamingForRequest(requestId) {
307
+ const cdpSession = this.deps.getCdpSession();
308
+ const db = this.deps.getDb();
309
+ if (!cdpSession || !db || !this.options.streamResponseChunks) return;
310
+ const resource = this.resources.get(requestId);
311
+ if (!resource || resource.streamingSupported !== null) return;
312
+ try {
313
+ const result = await cdpSession.send("Network.streamResourceContent", { requestId });
314
+ resource.streamingEnabled = true;
315
+ resource.streamingSupported = true;
316
+ resource.streamingError = null;
317
+ if (isObjectRecord(result)) {
318
+ const bufferedData = asString(result["bufferedData"]);
319
+ if (bufferedData) {
320
+ const dataLength = Buffer.from(bufferedData, "base64").length;
321
+ const bufferedChunk = {
322
+ requestId,
323
+ sequence: resource.chunkCount + 1,
324
+ timestamp: Date.now(),
325
+ monotonicTime: resource.responseMonotonicTime,
326
+ dataLength,
327
+ encodedDataLength: dataLength,
328
+ chunkData: resource.receivedDataLength + dataLength <= this.options.maxBodyBytes ? bufferedData : null,
329
+ chunkIsBase64: true
330
+ };
331
+ resource.chunkCount += 1;
332
+ resource.receivedDataLength += dataLength;
333
+ resource.receivedEncodedDataLength += dataLength;
334
+ db.insertNetworkChunk(bufferedChunk);
335
+ this.counts.networkChunkCount++;
336
+ }
337
+ }
338
+ } catch (error) {
339
+ resource.streamingEnabled = false;
340
+ resource.streamingSupported = false;
341
+ resource.streamingError = error instanceof Error ? error.message : String(error);
342
+ } finally {
343
+ this.syncResource(resource);
344
+ }
345
+ }
346
+ async captureResponseBody(requestId) {
347
+ const cdpSession = this.deps.getCdpSession();
348
+ if (!cdpSession || !this.deps.getDb() || !this.options.recordResponseBodies) return;
349
+ const resource = this.resources.get(requestId);
350
+ if (!resource) return;
351
+ try {
352
+ const rawResult = await cdpSession.send("Network.getResponseBody", { requestId });
353
+ if (!isResponseBodyPayload(rawResult)) return;
354
+ resource.bodyBase64Encoded = rawResult.base64Encoded;
355
+ resource.bodySize = rawResult.base64Encoded ? Buffer.from(rawResult.body, "base64").length : Buffer.byteLength(rawResult.body, "utf8");
356
+ resource.bodyTruncated = resource.bodySize > this.options.maxBodyBytes;
357
+ if (resource.bodyTruncated) {
358
+ resource.bodyCaptureState = "truncated";
359
+ resource.bodyInline = rawResult.body.slice(0, this.options.inlineBodyBytes);
360
+ resource.bodyArtifactPath = null;
361
+ resource.bodyError = `Body exceeded configured maxBodyBytes (${this.options.maxBodyBytes})`;
362
+ } else if (resource.bodySize <= this.options.inlineBodyBytes) {
363
+ resource.bodyCaptureState = "inline";
364
+ resource.bodyInline = rawResult.body;
365
+ resource.bodyArtifactPath = null;
366
+ resource.bodyError = null;
367
+ } else {
368
+ const ext = rawResult.base64Encoded ? "b64" : "txt";
369
+ const { absolutePath } = await resolveArtifactPath({
370
+ category: "traces",
371
+ toolName: "trace_body",
372
+ target: requestId.slice(0, 32),
373
+ ext
374
+ });
375
+ await writeFile(absolutePath, rawResult.body, "utf8");
376
+ resource.bodyCaptureState = "artifact";
377
+ resource.bodyInline = null;
378
+ resource.bodyArtifactPath = absolutePath;
379
+ resource.bodyError = null;
380
+ }
381
+ this.counts.networkBodyCount++;
382
+ } catch (error) {
383
+ resource.bodyCaptureState = resource.bodyCaptureState === "none" ? "error" : resource.bodyCaptureState;
384
+ resource.bodyError = error instanceof Error ? error.message : String(error);
385
+ } finally {
386
+ this.syncResource(resource);
387
+ }
388
+ }
389
+ getOrCreateResource(requestId) {
390
+ const existing = this.resources.get(requestId);
391
+ if (existing) return existing;
392
+ const created = createNetworkTraceResource(requestId);
393
+ this.resources.set(requestId, created);
394
+ this.counts.networkRequestCount++;
395
+ return created;
396
+ }
397
+ syncResource(resource) {
398
+ try {
399
+ this.deps.getDb()?.upsertNetworkResource(resource);
400
+ } catch {}
401
+ }
402
+ };
403
+ //#endregion
404
+ //#region src/modules/trace/TraceDB.internal.ts
405
+ function initializeTraceSchema(db) {
406
+ db.exec(`
407
+ CREATE TABLE IF NOT EXISTS events (
408
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
409
+ timestamp REAL NOT NULL,
410
+ category TEXT NOT NULL,
411
+ event_type TEXT NOT NULL,
412
+ data TEXT NOT NULL DEFAULT '{}',
413
+ script_id TEXT,
414
+ line_number INTEGER,
415
+ wall_time REAL,
416
+ monotonic_time REAL,
417
+ request_id TEXT,
418
+ sequence INTEGER
419
+ );
420
+ CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
421
+ CREATE INDEX IF NOT EXISTS idx_events_category_type ON events(category, event_type);
422
+ CREATE INDEX IF NOT EXISTS idx_events_script_id ON events(script_id);
423
+ CREATE INDEX IF NOT EXISTS idx_events_request_id ON events(request_id);
424
+
425
+ CREATE TABLE IF NOT EXISTS memory_deltas (
426
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
427
+ timestamp REAL NOT NULL,
428
+ address TEXT NOT NULL,
429
+ old_value TEXT NOT NULL,
430
+ new_value TEXT NOT NULL,
431
+ size INTEGER NOT NULL,
432
+ value_type TEXT NOT NULL
433
+ );
434
+ CREATE INDEX IF NOT EXISTS idx_memory_timestamp ON memory_deltas(timestamp);
435
+ CREATE INDEX IF NOT EXISTS idx_memory_address ON memory_deltas(address);
436
+
437
+ CREATE TABLE IF NOT EXISTS heap_snapshots (
438
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
439
+ timestamp REAL NOT NULL,
440
+ snapshot_data BLOB,
441
+ summary TEXT NOT NULL DEFAULT '{}'
442
+ );
443
+
444
+ CREATE TABLE IF NOT EXISTS metadata (
445
+ key TEXT PRIMARY KEY,
446
+ value TEXT NOT NULL
447
+ );
448
+
449
+ CREATE TABLE IF NOT EXISTS network_resources (
450
+ request_id TEXT PRIMARY KEY,
451
+ url TEXT,
452
+ method TEXT,
453
+ resource_type TEXT,
454
+ request_headers TEXT NOT NULL DEFAULT '{}',
455
+ request_post_data TEXT,
456
+ status INTEGER,
457
+ status_text TEXT,
458
+ response_headers TEXT NOT NULL DEFAULT '{}',
459
+ mime_type TEXT,
460
+ protocol TEXT,
461
+ remote_address TEXT,
462
+ from_disk_cache INTEGER NOT NULL DEFAULT 0,
463
+ from_service_worker INTEGER NOT NULL DEFAULT 0,
464
+ started_wall_time REAL,
465
+ response_wall_time REAL,
466
+ finished_wall_time REAL,
467
+ started_monotonic_time REAL,
468
+ response_monotonic_time REAL,
469
+ finished_monotonic_time REAL,
470
+ encoded_data_length INTEGER,
471
+ received_data_length INTEGER NOT NULL DEFAULT 0,
472
+ received_encoded_data_length INTEGER NOT NULL DEFAULT 0,
473
+ chunk_count INTEGER NOT NULL DEFAULT 0,
474
+ streaming_enabled INTEGER NOT NULL DEFAULT 0,
475
+ streaming_supported INTEGER,
476
+ streaming_error TEXT,
477
+ body_capture_state TEXT NOT NULL DEFAULT 'none',
478
+ body_inline TEXT,
479
+ body_artifact_path TEXT,
480
+ body_base64_encoded INTEGER NOT NULL DEFAULT 0,
481
+ body_size INTEGER,
482
+ body_truncated INTEGER NOT NULL DEFAULT 0,
483
+ body_error TEXT,
484
+ failed INTEGER NOT NULL DEFAULT 0,
485
+ error_text TEXT
486
+ );
487
+ CREATE INDEX IF NOT EXISTS idx_network_resources_started_wall_time
488
+ ON network_resources(started_wall_time);
489
+
490
+ CREATE TABLE IF NOT EXISTS network_chunks (
491
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
492
+ request_id TEXT NOT NULL,
493
+ sequence INTEGER NOT NULL,
494
+ timestamp REAL NOT NULL,
495
+ monotonic_time REAL,
496
+ data_length INTEGER NOT NULL,
497
+ encoded_data_length INTEGER NOT NULL,
498
+ chunk_data TEXT,
499
+ chunk_is_base64 INTEGER NOT NULL DEFAULT 0
500
+ );
501
+ CREATE INDEX IF NOT EXISTS idx_network_chunks_request_sequence
502
+ ON network_chunks(request_id, sequence);
503
+ CREATE INDEX IF NOT EXISTS idx_network_chunks_timestamp
504
+ ON network_chunks(timestamp);
505
+ `);
506
+ ensureColumn(db, "events", "wall_time", "REAL");
507
+ ensureColumn(db, "events", "monotonic_time", "REAL");
508
+ ensureColumn(db, "events", "request_id", "TEXT");
509
+ ensureColumn(db, "events", "sequence", "INTEGER");
510
+ }
511
+ function prepareTraceStatements(db) {
512
+ return {
513
+ insertEventStmt: db.prepare(`
514
+ INSERT INTO events (
515
+ timestamp,
516
+ category,
517
+ event_type,
518
+ data,
519
+ script_id,
520
+ line_number,
521
+ wall_time,
522
+ monotonic_time,
523
+ request_id,
524
+ sequence
525
+ )
526
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
527
+ `),
528
+ insertDeltaStmt: db.prepare(`
529
+ INSERT INTO memory_deltas (timestamp, address, old_value, new_value, size, value_type)
530
+ VALUES (?, ?, ?, ?, ?, ?)
531
+ `),
532
+ insertSnapshotStmt: db.prepare(`
533
+ INSERT INTO heap_snapshots (timestamp, snapshot_data, summary)
534
+ VALUES (?, ?, ?)
535
+ `),
536
+ upsertMetadataStmt: db.prepare(`
537
+ INSERT INTO metadata (key, value) VALUES (?, ?)
538
+ ON CONFLICT(key) DO UPDATE SET value = excluded.value
539
+ `),
540
+ upsertNetworkResourceStmt: db.prepare(`
541
+ INSERT INTO network_resources (
542
+ request_id,
543
+ url,
544
+ method,
545
+ resource_type,
546
+ request_headers,
547
+ request_post_data,
548
+ status,
549
+ status_text,
550
+ response_headers,
551
+ mime_type,
552
+ protocol,
553
+ remote_address,
554
+ from_disk_cache,
555
+ from_service_worker,
556
+ started_wall_time,
557
+ response_wall_time,
558
+ finished_wall_time,
559
+ started_monotonic_time,
560
+ response_monotonic_time,
561
+ finished_monotonic_time,
562
+ encoded_data_length,
563
+ received_data_length,
564
+ received_encoded_data_length,
565
+ chunk_count,
566
+ streaming_enabled,
567
+ streaming_supported,
568
+ streaming_error,
569
+ body_capture_state,
570
+ body_inline,
571
+ body_artifact_path,
572
+ body_base64_encoded,
573
+ body_size,
574
+ body_truncated,
575
+ body_error,
576
+ failed,
577
+ error_text
578
+ )
579
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
580
+ ON CONFLICT(request_id) DO UPDATE SET
581
+ url = excluded.url,
582
+ method = excluded.method,
583
+ resource_type = excluded.resource_type,
584
+ request_headers = excluded.request_headers,
585
+ request_post_data = excluded.request_post_data,
586
+ status = excluded.status,
587
+ status_text = excluded.status_text,
588
+ response_headers = excluded.response_headers,
589
+ mime_type = excluded.mime_type,
590
+ protocol = excluded.protocol,
591
+ remote_address = excluded.remote_address,
592
+ from_disk_cache = excluded.from_disk_cache,
593
+ from_service_worker = excluded.from_service_worker,
594
+ started_wall_time = excluded.started_wall_time,
595
+ response_wall_time = excluded.response_wall_time,
596
+ finished_wall_time = excluded.finished_wall_time,
597
+ started_monotonic_time = excluded.started_monotonic_time,
598
+ response_monotonic_time = excluded.response_monotonic_time,
599
+ finished_monotonic_time = excluded.finished_monotonic_time,
600
+ encoded_data_length = excluded.encoded_data_length,
601
+ received_data_length = excluded.received_data_length,
602
+ received_encoded_data_length = excluded.received_encoded_data_length,
603
+ chunk_count = excluded.chunk_count,
604
+ streaming_enabled = excluded.streaming_enabled,
605
+ streaming_supported = excluded.streaming_supported,
606
+ streaming_error = excluded.streaming_error,
607
+ body_capture_state = excluded.body_capture_state,
608
+ body_inline = excluded.body_inline,
609
+ body_artifact_path = excluded.body_artifact_path,
610
+ body_base64_encoded = excluded.body_base64_encoded,
611
+ body_size = excluded.body_size,
612
+ body_truncated = excluded.body_truncated,
613
+ body_error = excluded.body_error,
614
+ failed = excluded.failed,
615
+ error_text = excluded.error_text
616
+ `),
617
+ insertNetworkChunkStmt: db.prepare(`
618
+ INSERT INTO network_chunks (
619
+ request_id,
620
+ sequence,
621
+ timestamp,
622
+ monotonic_time,
623
+ data_length,
624
+ encoded_data_length,
625
+ chunk_data,
626
+ chunk_is_base64
627
+ )
628
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
629
+ `)
630
+ };
631
+ }
632
+ function mapEventRow(row) {
633
+ return {
634
+ id: row["id"],
635
+ timestamp: row["timestamp"],
636
+ category: row["category"],
637
+ eventType: row["event_type"],
638
+ data: row["data"],
639
+ scriptId: row["script_id"] ?? null,
640
+ lineNumber: row["line_number"] ?? null,
641
+ wallTime: row["wall_time"] ?? null,
642
+ monotonicTime: row["monotonic_time"] ?? null,
643
+ requestId: row["request_id"] ?? null,
644
+ sequence: row["sequence"] ?? null
645
+ };
646
+ }
647
+ function mapNetworkChunkRow(row, fromSqliteBoolean) {
648
+ return {
649
+ id: row["id"],
650
+ requestId: row["request_id"],
651
+ sequence: row["sequence"],
652
+ timestamp: row["timestamp"],
653
+ monotonicTime: row["monotonic_time"] ?? null,
654
+ dataLength: row["data_length"],
655
+ encodedDataLength: row["encoded_data_length"],
656
+ chunkData: row["chunk_data"] ?? null,
657
+ chunkIsBase64: fromSqliteBoolean(row["chunk_is_base64"])
658
+ };
659
+ }
660
+ function mapNetworkResourceRow(row, fromSqliteBoolean) {
661
+ return {
662
+ requestId: row["request_id"],
663
+ url: row["url"] ?? null,
664
+ method: row["method"] ?? null,
665
+ resourceType: row["resource_type"] ?? null,
666
+ requestHeaders: row["request_headers"] ?? "{}",
667
+ requestPostData: row["request_post_data"] ?? null,
668
+ status: row["status"] ?? null,
669
+ statusText: row["status_text"] ?? null,
670
+ responseHeaders: row["response_headers"] ?? "{}",
671
+ mimeType: row["mime_type"] ?? null,
672
+ protocol: row["protocol"] ?? null,
673
+ remoteAddress: row["remote_address"] ?? null,
674
+ fromDiskCache: fromSqliteBoolean(row["from_disk_cache"]),
675
+ fromServiceWorker: fromSqliteBoolean(row["from_service_worker"]),
676
+ startedWallTime: row["started_wall_time"] ?? null,
677
+ responseWallTime: row["response_wall_time"] ?? null,
678
+ finishedWallTime: row["finished_wall_time"] ?? null,
679
+ startedMonotonicTime: row["started_monotonic_time"] ?? null,
680
+ responseMonotonicTime: row["response_monotonic_time"] ?? null,
681
+ finishedMonotonicTime: row["finished_monotonic_time"] ?? null,
682
+ encodedDataLength: row["encoded_data_length"] ?? null,
683
+ receivedDataLength: row["received_data_length"] ?? 0,
684
+ receivedEncodedDataLength: row["received_encoded_data_length"] ?? 0,
685
+ chunkCount: row["chunk_count"] ?? 0,
686
+ streamingEnabled: fromSqliteBoolean(row["streaming_enabled"]),
687
+ streamingSupported: row["streaming_supported"] === null || row["streaming_supported"] === void 0 ? null : fromSqliteBoolean(row["streaming_supported"]),
688
+ streamingError: row["streaming_error"] ?? null,
689
+ bodyCaptureState: row["body_capture_state"] ?? "none",
690
+ bodyInline: row["body_inline"] ?? null,
691
+ bodyArtifactPath: row["body_artifact_path"] ?? null,
692
+ bodyBase64Encoded: fromSqliteBoolean(row["body_base64_encoded"]),
693
+ bodySize: row["body_size"] ?? null,
694
+ bodyTruncated: fromSqliteBoolean(row["body_truncated"]),
695
+ bodyError: row["body_error"] ?? null,
696
+ failed: fromSqliteBoolean(row["failed"]),
697
+ errorText: row["error_text"] ?? null
698
+ };
699
+ }
700
+ function ensureColumn(db, tableName, columnName, definition) {
701
+ if (db.prepare(`PRAGMA table_info(${tableName})`).all().some((column) => column.name === columnName)) return;
702
+ db.exec(`ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${definition}`);
703
+ }
704
+ //#endregion
705
+ //#region src/modules/trace/TraceDB.ts
706
+ let Database;
707
+ try {
708
+ Database = __require("better-sqlite3");
709
+ } catch {}
710
+ /** Write-modify SQL keywords rejected by the safety filter. */
711
+ const WRITE_SQL_PATTERN = /\b(INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|ATTACH|DETACH|REPLACE|PRAGMA)\b/i;
712
+ var TraceDB = class {
713
+ db;
714
+ batchSize;
715
+ eventBuffer = [];
716
+ memoryBuffer = [];
717
+ networkChunkBuffer = [];
718
+ closed = false;
719
+ insertEventStmt;
720
+ insertDeltaStmt;
721
+ insertSnapshotStmt;
722
+ upsertMetadataStmt;
723
+ upsertNetworkResourceStmt;
724
+ insertNetworkChunkStmt;
725
+ constructor(options) {
726
+ this.options = options;
727
+ if (!Database) throw new Error(formatBetterSqlite3Error(/* @__PURE__ */ new Error("Cannot find package 'better-sqlite3'")));
728
+ try {
729
+ this.db = new Database(options.dbPath);
730
+ } catch (error) {
731
+ throw new Error(formatBetterSqlite3Error(error), { cause: error });
732
+ }
733
+ this.batchSize = options.batchSize ?? 200;
734
+ this.db.pragma("journal_mode = WAL");
735
+ this.db.pragma("synchronous = NORMAL");
736
+ initializeTraceSchema(this.db);
737
+ const statements = prepareTraceStatements(this.db);
738
+ this.insertEventStmt = statements.insertEventStmt;
739
+ this.insertDeltaStmt = statements.insertDeltaStmt;
740
+ this.insertSnapshotStmt = statements.insertSnapshotStmt;
741
+ this.upsertMetadataStmt = statements.upsertMetadataStmt;
742
+ this.upsertNetworkResourceStmt = statements.upsertNetworkResourceStmt;
743
+ this.insertNetworkChunkStmt = statements.insertNetworkChunkStmt;
744
+ }
745
+ /** Database file path. */
746
+ get dbPath() {
747
+ return this.options.dbPath;
748
+ }
749
+ insertEvent(event) {
750
+ this.ensureOpen();
751
+ this.eventBuffer.push(event);
752
+ if (this.eventBuffer.length >= this.batchSize) this.flush();
753
+ }
754
+ insertMemoryDelta(delta) {
755
+ this.ensureOpen();
756
+ this.memoryBuffer.push(delta);
757
+ if (this.memoryBuffer.length >= this.batchSize) this.flush();
758
+ }
759
+ insertNetworkChunk(chunk) {
760
+ this.ensureOpen();
761
+ this.networkChunkBuffer.push(chunk);
762
+ if (this.networkChunkBuffer.length >= this.batchSize) this.flush();
763
+ }
764
+ upsertNetworkResource(resource) {
765
+ this.ensureOpen();
766
+ this.upsertNetworkResourceStmt.run(resource.requestId, resource.url, resource.method, resource.resourceType, resource.requestHeaders, resource.requestPostData, resource.status, resource.statusText, resource.responseHeaders, resource.mimeType, resource.protocol, resource.remoteAddress, resource.fromDiskCache ? 1 : 0, resource.fromServiceWorker ? 1 : 0, resource.startedWallTime, resource.responseWallTime, resource.finishedWallTime, resource.startedMonotonicTime, resource.responseMonotonicTime, resource.finishedMonotonicTime, resource.encodedDataLength, resource.receivedDataLength, resource.receivedEncodedDataLength, resource.chunkCount, resource.streamingEnabled ? 1 : 0, resource.streamingSupported === null ? null : resource.streamingSupported ? 1 : 0, resource.streamingError, resource.bodyCaptureState, resource.bodyInline, resource.bodyArtifactPath, resource.bodyBase64Encoded ? 1 : 0, resource.bodySize, resource.bodyTruncated ? 1 : 0, resource.bodyError, resource.failed ? 1 : 0, resource.errorText);
767
+ }
768
+ insertHeapSnapshot(snapshot) {
769
+ this.ensureOpen();
770
+ this.insertSnapshotStmt.run(snapshot.timestamp, snapshot.snapshotData, snapshot.summary);
771
+ }
772
+ setMetadata(key, value) {
773
+ this.ensureOpen();
774
+ this.upsertMetadataStmt.run(key, value);
775
+ }
776
+ flush() {
777
+ if (this.closed) return;
778
+ this.db.transaction(() => {
779
+ for (const event of this.eventBuffer) this.insertEventStmt.run(event.timestamp, event.category, event.eventType, event.data, event.scriptId, event.lineNumber, event.wallTime ?? null, event.monotonicTime ?? null, event.requestId ?? null, event.sequence ?? null);
780
+ for (const delta of this.memoryBuffer) this.insertDeltaStmt.run(delta.timestamp, delta.address, delta.oldValue, delta.newValue, delta.size, delta.valueType);
781
+ for (const chunk of this.networkChunkBuffer) this.insertNetworkChunkStmt.run(chunk.requestId, chunk.sequence, chunk.timestamp, chunk.monotonicTime, chunk.dataLength, chunk.encodedDataLength, chunk.chunkData, chunk.chunkIsBase64 ? 1 : 0);
782
+ })();
783
+ this.eventBuffer = [];
784
+ this.memoryBuffer = [];
785
+ this.networkChunkBuffer = [];
786
+ }
787
+ query(sql) {
788
+ this.ensureOpen();
789
+ if (WRITE_SQL_PATTERN.test(sql)) throw new Error(`Write operations are not allowed in trace queries. Rejected SQL: ${sql.slice(0, 100)}`);
790
+ const stmt = this.db.prepare(sql);
791
+ const rows = stmt.all();
792
+ if (rows.length === 0) return {
793
+ columns: stmt.columns().map((column) => column.name),
794
+ rows: [],
795
+ rowCount: 0
796
+ };
797
+ const columns = Object.keys(rows[0]);
798
+ return {
799
+ columns,
800
+ rows: rows.map((row) => columns.map((column) => row[column])),
801
+ rowCount: rows.length
802
+ };
803
+ }
804
+ getEventsByTimeRange(start, end) {
805
+ this.ensureOpen();
806
+ this.flush();
807
+ return this.db.prepare(`
808
+ SELECT
809
+ id,
810
+ timestamp,
811
+ category,
812
+ event_type,
813
+ data,
814
+ script_id,
815
+ line_number,
816
+ wall_time,
817
+ monotonic_time,
818
+ request_id,
819
+ sequence
820
+ FROM events
821
+ WHERE timestamp >= ? AND timestamp <= ?
822
+ ORDER BY timestamp ASC, sequence ASC, id ASC
823
+ `).all(start, end).map(mapEventRow);
824
+ }
825
+ getEventsByRequestId(requestId) {
826
+ this.ensureOpen();
827
+ this.flush();
828
+ return this.db.prepare(`
829
+ SELECT
830
+ id,
831
+ timestamp,
832
+ category,
833
+ event_type,
834
+ data,
835
+ script_id,
836
+ line_number,
837
+ wall_time,
838
+ monotonic_time,
839
+ request_id,
840
+ sequence
841
+ FROM events
842
+ WHERE request_id = ?
843
+ ORDER BY COALESCE(monotonic_time, timestamp) ASC, sequence ASC, id ASC
844
+ `).all(requestId).map(mapEventRow);
845
+ }
846
+ getNetworkResource(requestId) {
847
+ this.ensureOpen();
848
+ this.flush();
849
+ const row = this.db.prepare(`
850
+ SELECT *
851
+ FROM network_resources
852
+ WHERE request_id = ?
853
+ LIMIT 1
854
+ `).get(requestId);
855
+ return row ? mapNetworkResourceRow(row, this.fromSqliteBoolean) : null;
856
+ }
857
+ getNetworkChunks(requestId, limit) {
858
+ this.ensureOpen();
859
+ this.flush();
860
+ const sql = `
861
+ SELECT
862
+ id,
863
+ request_id,
864
+ sequence,
865
+ timestamp,
866
+ monotonic_time,
867
+ data_length,
868
+ encoded_data_length,
869
+ chunk_data,
870
+ chunk_is_base64
871
+ FROM network_chunks
872
+ WHERE request_id = ?
873
+ ORDER BY sequence ASC
874
+ ${typeof limit === "number" ? "LIMIT ?" : ""}
875
+ `;
876
+ const stmt = this.db.prepare(sql);
877
+ return (typeof limit === "number" ? stmt.all(requestId, limit) : stmt.all(requestId)).map((row) => mapNetworkChunkRow(row, this.fromSqliteBoolean));
878
+ }
879
+ getMemoryDeltasByAddress(address) {
880
+ this.ensureOpen();
881
+ this.flush();
882
+ return this.db.prepare(`
883
+ SELECT id, timestamp, address, old_value, new_value, size, value_type
884
+ FROM memory_deltas
885
+ WHERE address = ?
886
+ ORDER BY timestamp ASC
887
+ `).all(address).map((row) => ({
888
+ id: row["id"],
889
+ timestamp: row["timestamp"],
890
+ address: row["address"],
891
+ oldValue: row["old_value"],
892
+ newValue: row["new_value"],
893
+ size: row["size"],
894
+ valueType: row["value_type"]
895
+ }));
896
+ }
897
+ getHeapSnapshots() {
898
+ this.ensureOpen();
899
+ return this.db.prepare(`
900
+ SELECT id, timestamp, snapshot_data, summary
901
+ FROM heap_snapshots
902
+ ORDER BY timestamp ASC
903
+ `).all().map((row) => ({
904
+ id: row["id"],
905
+ timestamp: row["timestamp"],
906
+ snapshotData: row["snapshot_data"],
907
+ summary: row["summary"]
908
+ }));
909
+ }
910
+ getMetadata() {
911
+ this.ensureOpen();
912
+ const rows = this.db.prepare("SELECT key, value FROM metadata").all();
913
+ const result = {};
914
+ for (const row of rows) result[row.key] = row.value;
915
+ return result;
916
+ }
917
+ close() {
918
+ if (this.closed) return;
919
+ this.flush();
920
+ this.db.close();
921
+ this.closed = true;
922
+ }
923
+ get isClosed() {
924
+ return this.closed;
925
+ }
926
+ fromSqliteBoolean(value) {
927
+ return value === 1 || value === true;
928
+ }
929
+ ensureOpen() {
930
+ if (this.closed) throw new Error("TraceDB is closed");
931
+ }
932
+ };
933
+ //#endregion
934
+ //#region src/modules/trace/TraceRecorder.ts
935
+ /**
936
+ * TraceRecorder — Event capture engine for time-travel debugging.
937
+ *
938
+ * Subscribes to EventBus and CDP events and persists them into TraceDB.
939
+ */
940
+ var TraceRecorder = class {
941
+ db = null;
942
+ state = "idle";
943
+ session = null;
944
+ eventBusUnsub = null;
945
+ cdpListeners = /* @__PURE__ */ new Map();
946
+ enabledCdpDomains = /* @__PURE__ */ new Set();
947
+ cdpSession = null;
948
+ eventCount = 0;
949
+ memoryDeltaCount = 0;
950
+ heapSnapshotCount = 0;
951
+ eventSequence = 0;
952
+ pendingOperations = /* @__PURE__ */ new Set();
953
+ networkCapture = new TraceNetworkCapture({
954
+ getDb: () => this.db,
955
+ getCdpSession: () => this.cdpSession,
956
+ trackOperation: (operation) => this.trackOperation(operation)
957
+ });
958
+ /**
959
+ * Start recording events into a new trace database.
960
+ *
961
+ * @param eventBus The server EventBus to subscribe to
962
+ * @param cdpSession Optional CDP session for browser event recording
963
+ * @param options Recording configuration
964
+ * @returns The recording session details
965
+ */
966
+ async start(eventBus, cdpSession, options) {
967
+ if (this.state === "recording") throw new Error("Recording already in progress");
968
+ const sessionId = randomUUID();
969
+ const { absolutePath } = await resolveArtifactPath({
970
+ category: "traces",
971
+ toolName: "trace_recorder",
972
+ target: sessionId.slice(0, 8),
973
+ ext: "db"
974
+ });
975
+ const selectedDomains = cdpSession ? (options?.cdpDomains ?? DEFAULT_CDP_DOMAINS).filter((domain) => CDP_EVENTS_BY_DOMAIN[domain]) : [];
976
+ this.db = new TraceDB({ dbPath: absolutePath });
977
+ this.eventCount = 0;
978
+ this.memoryDeltaCount = 0;
979
+ this.heapSnapshotCount = 0;
980
+ this.eventSequence = 0;
981
+ this.pendingOperations.clear();
982
+ this.cdpListeners.clear();
983
+ this.enabledCdpDomains.clear();
984
+ this.cdpSession = cdpSession;
985
+ try {
986
+ const networkOptions = this.networkCapture.configure(options?.network);
987
+ if (cdpSession) for (const domain of selectedDomains) {
988
+ await cdpSession.send(`${domain}.enable`);
989
+ this.enabledCdpDomains.add(domain);
990
+ }
991
+ const startedAt = Date.now();
992
+ this.db.setMetadata("sessionId", sessionId);
993
+ this.db.setMetadata("platform", process.platform);
994
+ this.db.setMetadata("startedAt", String(startedAt));
995
+ this.db.setMetadata("nodeVersion", process.version);
996
+ this.db.setMetadata("network.recordResponseBodies", String(networkOptions.recordResponseBodies));
997
+ this.db.setMetadata("network.streamResponseChunks", String(networkOptions.streamResponseChunks));
998
+ this.db.setMetadata("network.maxBodyBytes", String(networkOptions.maxBodyBytes));
999
+ this.db.setMetadata("network.inlineBodyBytes", String(networkOptions.inlineBodyBytes));
1000
+ this.eventBusUnsub = eventBus.onAny((wrapped) => {
1001
+ if (this.state !== "recording") return;
1002
+ try {
1003
+ const now = Date.now();
1004
+ this.db?.insertEvent({
1005
+ timestamp: now,
1006
+ wallTime: now,
1007
+ monotonicTime: null,
1008
+ category: this.mapEventCategory(String(wrapped.event)),
1009
+ eventType: String(wrapped.event),
1010
+ data: JSON.stringify(wrapped.payload ?? {}),
1011
+ scriptId: null,
1012
+ lineNumber: null,
1013
+ requestId: null,
1014
+ sequence: this.nextSequence()
1015
+ });
1016
+ this.eventCount++;
1017
+ } catch {}
1018
+ });
1019
+ if (cdpSession) for (const domain of selectedDomains) {
1020
+ const events = CDP_EVENTS_BY_DOMAIN[domain] ?? [];
1021
+ for (const eventName of events) {
1022
+ const handler = (params) => {
1023
+ if (this.state !== "recording" || !this.db) return;
1024
+ try {
1025
+ const timing = extractEventTiming(params);
1026
+ const requestId = extractRequestId(params);
1027
+ const { scriptId, lineNumber } = extractScriptLocation(eventName, params);
1028
+ const data = JSON.stringify(sanitizeTracePayload(eventName, params));
1029
+ this.db.insertEvent({
1030
+ timestamp: timing.timestamp,
1031
+ wallTime: timing.wallTime,
1032
+ monotonicTime: timing.monotonicTime,
1033
+ category: domain.toLowerCase(),
1034
+ eventType: eventName,
1035
+ data,
1036
+ scriptId,
1037
+ lineNumber,
1038
+ requestId,
1039
+ sequence: this.nextSequence()
1040
+ });
1041
+ this.eventCount++;
1042
+ if (domain === "Network") this.networkCapture.handleEvent(eventName, params, timing);
1043
+ } catch {}
1044
+ };
1045
+ cdpSession.on(eventName, handler);
1046
+ this.cdpListeners.set(eventName, handler);
1047
+ }
1048
+ }
1049
+ this.session = {
1050
+ sessionId,
1051
+ dbPath: absolutePath,
1052
+ startedAt,
1053
+ eventCount: 0,
1054
+ memoryDeltaCount: 0,
1055
+ heapSnapshotCount: 0,
1056
+ ...this.networkCapture.getCounts()
1057
+ };
1058
+ this.state = "recording";
1059
+ return { ...this.session };
1060
+ } catch (error) {
1061
+ await this.cleanupFailedStart();
1062
+ throw error;
1063
+ }
1064
+ }
1065
+ /**
1066
+ * Record a memory write delta.
1067
+ * Silently ignored if not currently recording.
1068
+ */
1069
+ recordMemoryDelta(delta) {
1070
+ if (this.state !== "recording" || !this.db) return;
1071
+ try {
1072
+ this.db.insertMemoryDelta(delta);
1073
+ this.memoryDeltaCount++;
1074
+ } catch {}
1075
+ }
1076
+ /**
1077
+ * Capture a heap snapshot via CDP HeapProfiler.
1078
+ * Requires an active CDP session and recording in progress.
1079
+ */
1080
+ async captureActiveHeapSnapshot() {
1081
+ if (!this.cdpSession) throw new Error("Cannot capture heap snapshot: no active CDP session");
1082
+ return await this.captureHeapSnapshot(this.cdpSession);
1083
+ }
1084
+ async captureHeapSnapshot(cdpSession) {
1085
+ if (this.state !== "recording" || !this.db) throw new Error("Cannot capture heap snapshot: not recording");
1086
+ const chunks = [];
1087
+ let chunkListenerAttached = false;
1088
+ const chunkHandler = (params) => {
1089
+ if (typeof params === "object" && params !== null) {
1090
+ const chunk = params["chunk"];
1091
+ if (typeof chunk === "string") chunks.push(chunk);
1092
+ }
1093
+ };
1094
+ try {
1095
+ await cdpSession.send("HeapProfiler.enable");
1096
+ cdpSession.on("HeapProfiler.addHeapSnapshotChunk", chunkHandler);
1097
+ chunkListenerAttached = true;
1098
+ await cdpSession.send("HeapProfiler.takeHeapSnapshot", { reportProgress: false });
1099
+ const snapshotStr = chunks.join("");
1100
+ const snapshotBuffer = Buffer.from(snapshotStr, "utf-8");
1101
+ const summary = this.extractHeapSummary(snapshotStr);
1102
+ this.db.insertHeapSnapshot({
1103
+ timestamp: Date.now(),
1104
+ snapshotData: snapshotBuffer,
1105
+ summary: JSON.stringify(summary)
1106
+ });
1107
+ this.heapSnapshotCount++;
1108
+ return snapshotBuffer.byteLength;
1109
+ } finally {
1110
+ if (chunkListenerAttached) cdpSession.off("HeapProfiler.addHeapSnapshotChunk", chunkHandler);
1111
+ await cdpSession.send("HeapProfiler.disable").catch(() => {});
1112
+ }
1113
+ }
1114
+ /**
1115
+ * Stop recording and finalize the trace database.
1116
+ * @returns Final session summary with event counts
1117
+ */
1118
+ async stop() {
1119
+ if (this.state !== "recording") throw new Error("GRACEFUL: Cannot stop: not currently recording");
1120
+ if (this.eventBusUnsub) {
1121
+ this.eventBusUnsub();
1122
+ this.eventBusUnsub = null;
1123
+ }
1124
+ if (this.cdpSession) for (const [event, handler] of this.cdpListeners) this.cdpSession.off(event, handler);
1125
+ this.cdpListeners.clear();
1126
+ await this.waitForPendingOperations();
1127
+ let cleanupErrors;
1128
+ if (this.cdpSession) {
1129
+ if (this.enabledCdpDomains.size > 0) {
1130
+ const enabledDomains = Array.from(this.enabledCdpDomains);
1131
+ cleanupErrors = (await Promise.allSettled(enabledDomains.map((domain) => this.cdpSession.send(`${domain}.disable`)))).flatMap((result, index) => result.status === "rejected" ? [`${enabledDomains[index]}.disable failed: ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`] : []);
1132
+ }
1133
+ this.enabledCdpDomains.clear();
1134
+ this.cdpSession = null;
1135
+ }
1136
+ if (this.db) {
1137
+ const stoppedAt = Date.now();
1138
+ const networkCounts = this.networkCapture.getCounts();
1139
+ this.db.setMetadata("stoppedAt", String(stoppedAt));
1140
+ this.db.setMetadata("eventCount", String(this.eventCount));
1141
+ this.db.setMetadata("memoryDeltaCount", String(this.memoryDeltaCount));
1142
+ this.db.setMetadata("heapSnapshotCount", String(this.heapSnapshotCount));
1143
+ this.db.setMetadata("networkRequestCount", String(networkCounts.networkRequestCount));
1144
+ this.db.setMetadata("networkChunkCount", String(networkCounts.networkChunkCount));
1145
+ this.db.setMetadata("networkBodyCount", String(networkCounts.networkBodyCount));
1146
+ this.db.close();
1147
+ if (this.session) {
1148
+ this.session.stoppedAt = stoppedAt;
1149
+ this.session.eventCount = this.eventCount;
1150
+ this.session.memoryDeltaCount = this.memoryDeltaCount;
1151
+ this.session.heapSnapshotCount = this.heapSnapshotCount;
1152
+ this.session.networkRequestCount = networkCounts.networkRequestCount;
1153
+ this.session.networkChunkCount = networkCounts.networkChunkCount;
1154
+ this.session.networkBodyCount = networkCounts.networkBodyCount;
1155
+ if (cleanupErrors && cleanupErrors.length > 0) this.session.cleanupErrors = cleanupErrors;
1156
+ else delete this.session.cleanupErrors;
1157
+ }
1158
+ }
1159
+ this.state = "stopped";
1160
+ const finalSession = this.session ? { ...this.session } : this.createEmptySession();
1161
+ this.db = null;
1162
+ this.networkCapture.clear();
1163
+ return finalSession;
1164
+ }
1165
+ /** Get the current recording state. */
1166
+ getState() {
1167
+ return this.state;
1168
+ }
1169
+ /** Get the current session details (null if not recording). */
1170
+ getSession() {
1171
+ return this.session ? { ...this.session } : null;
1172
+ }
1173
+ /** Get the active TraceDB instance (null if not recording). */
1174
+ getDB() {
1175
+ return this.db;
1176
+ }
1177
+ trackOperation(operation) {
1178
+ this.pendingOperations.add(operation);
1179
+ operation.finally(() => {
1180
+ this.pendingOperations.delete(operation);
1181
+ });
1182
+ }
1183
+ async waitForPendingOperations() {
1184
+ while (this.pendingOperations.size > 0) await Promise.allSettled(Array.from(this.pendingOperations));
1185
+ }
1186
+ async cleanupFailedStart() {
1187
+ if (this.eventBusUnsub) {
1188
+ this.eventBusUnsub();
1189
+ this.eventBusUnsub = null;
1190
+ }
1191
+ if (this.cdpSession) for (const [event, handler] of this.cdpListeners) this.cdpSession.off(event, handler);
1192
+ this.cdpListeners.clear();
1193
+ if (this.cdpSession && this.enabledCdpDomains.size > 0) await Promise.allSettled(Array.from(this.enabledCdpDomains).map((domain) => this.cdpSession.send(`${domain}.disable`)));
1194
+ this.enabledCdpDomains.clear();
1195
+ this.cdpSession = null;
1196
+ if (this.db) {
1197
+ try {
1198
+ this.db.close();
1199
+ } catch {}
1200
+ this.db = null;
1201
+ }
1202
+ this.session = null;
1203
+ this.state = "idle";
1204
+ this.eventCount = 0;
1205
+ this.memoryDeltaCount = 0;
1206
+ this.heapSnapshotCount = 0;
1207
+ this.eventSequence = 0;
1208
+ this.pendingOperations.clear();
1209
+ this.networkCapture.clear();
1210
+ }
1211
+ nextSequence() {
1212
+ this.eventSequence += 1;
1213
+ return this.eventSequence;
1214
+ }
1215
+ /**
1216
+ * Map an EventBus event name to a trace category.
1217
+ * E.g., 'tool:called' → 'tool', 'debugger:breakpoint_hit' → 'debugger'
1218
+ */
1219
+ mapEventCategory(event) {
1220
+ const colonIdx = event.indexOf(":");
1221
+ return colonIdx > 0 ? event.substring(0, colonIdx) : "other";
1222
+ }
1223
+ /**
1224
+ * Extract a lightweight summary from a V8 heap snapshot.
1225
+ * Only parses the minimal structure needed for diffing.
1226
+ */
1227
+ extractHeapSummary(snapshotStr) {
1228
+ try {
1229
+ const snapshot = JSON.parse(snapshotStr);
1230
+ const snapshotInfo = snapshot["snapshot"];
1231
+ if (!snapshotInfo) return {
1232
+ totalSize: 0,
1233
+ nodeCount: 0,
1234
+ objectCounts: {}
1235
+ };
1236
+ const meta = snapshotInfo["meta"];
1237
+ const nodeCount = snapshotInfo["node_count"] ?? 0;
1238
+ const nodeFields = meta?.["node_fields"];
1239
+ const nodeTypes = meta?.["node_types"];
1240
+ const nodes = snapshot["nodes"];
1241
+ const objectCounts = {};
1242
+ let totalSize = 0;
1243
+ if (nodeFields && nodes && nodeTypes) {
1244
+ const fieldCount = nodeFields.length;
1245
+ const typeIndex = nodeFields.indexOf("type");
1246
+ const nameIndex = nodeFields.indexOf("name");
1247
+ const selfSizeIndex = nodeFields.indexOf("self_size");
1248
+ const strings = snapshot["strings"] ?? [];
1249
+ for (let i = 0; i < nodes.length; i += fieldCount) {
1250
+ const selfSize = selfSizeIndex >= 0 ? nodes[i + selfSizeIndex] ?? 0 : 0;
1251
+ totalSize += selfSize;
1252
+ if (nameIndex >= 0) {
1253
+ const name = strings[nodes[i + nameIndex] ?? 0] ?? `type_${nodes[i + (typeIndex >= 0 ? typeIndex : 0)]}`;
1254
+ if (name) objectCounts[name] = (objectCounts[name] ?? 0) + 1;
1255
+ }
1256
+ }
1257
+ }
1258
+ return {
1259
+ totalSize,
1260
+ nodeCount,
1261
+ objectCounts
1262
+ };
1263
+ } catch {
1264
+ return {
1265
+ totalSize: 0,
1266
+ nodeCount: 0,
1267
+ objectCounts: {}
1268
+ };
1269
+ }
1270
+ }
1271
+ createEmptySession() {
1272
+ return {
1273
+ sessionId: "",
1274
+ dbPath: "",
1275
+ startedAt: 0,
1276
+ eventCount: 0,
1277
+ memoryDeltaCount: 0,
1278
+ heapSnapshotCount: 0,
1279
+ networkRequestCount: 0,
1280
+ networkChunkCount: 0,
1281
+ networkBodyCount: 0
1282
+ };
1283
+ }
1284
+ };
1285
+ //#endregion
1286
+ export { TraceRecorder, TraceDB as t };