warpo 3.1.1 → 3.1.3

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 (189) hide show
  1. package/asconfig.schema.json +10 -2
  2. package/dist/debug_server/debugPath.d.ts +1 -0
  3. package/dist/debug_server/debugPath.js +10 -0
  4. package/dist/debug_server/debugPath.js.map +1 -0
  5. package/dist/debug_server/debugSession.d.ts +61 -3
  6. package/dist/debug_server/debugSession.js +919 -80
  7. package/dist/debug_server/debugSession.js.map +1 -1
  8. package/dist/debug_server/debugger.d.ts +30 -2
  9. package/dist/debug_server/debuggerWasmModule.d.ts +59 -3
  10. package/dist/debug_server/debuggerWasmModule.js +234 -14
  11. package/dist/debug_server/debuggerWasmModule.js.map +1 -1
  12. package/dist/debug_server/nodeDebugger.d.ts +42 -3
  13. package/dist/debug_server/nodeDebugger.js +648 -59
  14. package/dist/debug_server/nodeDebugger.js.map +1 -1
  15. package/dist/debug_server/tests/debugSession.test.js +1154 -26
  16. package/dist/debug_server/tests/debugSession.test.js.map +1 -1
  17. package/dist/debug_server/tests/launcher.js +1 -0
  18. package/dist/debug_server/tests/launcher.js.map +1 -1
  19. package/dist/debug_server/tests/testModule/debugger_array.d.ts +1 -0
  20. package/dist/debug_server/tests/testModule/debugger_array.js +9 -0
  21. package/dist/debug_server/tests/testModule/debugger_array.js.map +1 -0
  22. package/dist/debug_server/tests/testModule/debugger_array_buffer.d.ts +1 -0
  23. package/dist/debug_server/tests/testModule/debugger_array_buffer.js +12 -0
  24. package/dist/debug_server/tests/testModule/debugger_array_buffer.js.map +1 -0
  25. package/dist/debug_server/tests/testModule/debugger_basic.d.ts +1 -0
  26. package/dist/debug_server/tests/testModule/debugger_basic.js +9 -1
  27. package/dist/debug_server/tests/testModule/debugger_basic.js.map +1 -1
  28. package/dist/debug_server/tests/testModule/debugger_breakpoint_update.d.ts +1 -0
  29. package/dist/debug_server/tests/testModule/debugger_breakpoint_update.js +10 -0
  30. package/dist/debug_server/tests/testModule/debugger_breakpoint_update.js.map +1 -0
  31. package/dist/debug_server/tests/testModule/debugger_callee.d.ts +10 -0
  32. package/dist/debug_server/tests/testModule/debugger_callee.js +106 -0
  33. package/dist/debug_server/tests/testModule/debugger_callee.js.map +1 -0
  34. package/dist/debug_server/tests/testModule/debugger_caller.d.ts +1 -0
  35. package/dist/debug_server/tests/testModule/debugger_caller.js +7 -0
  36. package/dist/debug_server/tests/testModule/debugger_caller.js.map +1 -0
  37. package/dist/debug_server/tests/testModule/debugger_class.d.ts +1 -0
  38. package/dist/debug_server/tests/testModule/debugger_class.js +39 -0
  39. package/dist/debug_server/tests/testModule/debugger_class.js.map +1 -0
  40. package/dist/debug_server/tests/testModule/debugger_class_array.d.ts +1 -0
  41. package/dist/debug_server/tests/testModule/debugger_class_array.js +15 -0
  42. package/dist/debug_server/tests/testModule/debugger_class_array.js.map +1 -0
  43. package/dist/debug_server/tests/testModule/debugger_closure.d.ts +1 -0
  44. package/dist/debug_server/tests/testModule/debugger_closure.js +48 -0
  45. package/dist/debug_server/tests/testModule/debugger_closure.js.map +1 -0
  46. package/dist/debug_server/tests/testModule/debugger_closure_if.d.ts +1 -0
  47. package/dist/debug_server/tests/testModule/debugger_closure_if.js +16 -0
  48. package/dist/debug_server/tests/testModule/debugger_closure_if.js.map +1 -0
  49. package/dist/debug_server/tests/testModule/debugger_generic_function.d.ts +1 -0
  50. package/dist/debug_server/tests/testModule/debugger_generic_function.js +10 -0
  51. package/dist/debug_server/tests/testModule/debugger_generic_function.js.map +1 -0
  52. package/dist/debug_server/tests/testModule/debugger_global.d.ts +1 -0
  53. package/dist/debug_server/tests/testModule/debugger_global.js +11 -0
  54. package/dist/debug_server/tests/testModule/debugger_global.js.map +1 -0
  55. package/dist/debug_server/tests/testModule/debugger_map.d.ts +1 -0
  56. package/dist/debug_server/tests/testModule/debugger_map.js +22 -0
  57. package/dist/debug_server/tests/testModule/debugger_map.js.map +1 -0
  58. package/dist/debug_server/tests/testModule/debugger_member_function.d.ts +1 -0
  59. package/dist/debug_server/tests/testModule/debugger_member_function.js +16 -0
  60. package/dist/debug_server/tests/testModule/debugger_member_function.js.map +1 -0
  61. package/dist/debug_server/tests/testModule/debugger_scopes.d.ts +1 -0
  62. package/dist/debug_server/tests/testModule/debugger_scopes.js +22 -0
  63. package/dist/debug_server/tests/testModule/debugger_scopes.js.map +1 -0
  64. package/dist/debug_server/tests/testModule/debugger_set.d.ts +1 -0
  65. package/dist/debug_server/tests/testModule/debugger_set.js +23 -0
  66. package/dist/debug_server/tests/testModule/debugger_set.js.map +1 -0
  67. package/dist/debug_server/tests/testModule/debugger_static_array.d.ts +1 -0
  68. package/dist/debug_server/tests/testModule/debugger_static_array.js +21 -0
  69. package/dist/debug_server/tests/testModule/debugger_static_array.js.map +1 -0
  70. package/dist/debug_server/tests/testModule/debugger_string.d.ts +1 -0
  71. package/dist/debug_server/tests/testModule/debugger_string.js +16 -0
  72. package/dist/debug_server/tests/testModule/debugger_string.js.map +1 -0
  73. package/dist/debug_server/tests/testModule/debugger_trap.d.ts +1 -0
  74. package/dist/debug_server/tests/testModule/debugger_trap.js +9 -0
  75. package/dist/debug_server/tests/testModule/debugger_trap.js.map +1 -0
  76. package/dist/debug_server/tests/testModule/debugger_tuple.d.ts +1 -0
  77. package/dist/debug_server/tests/testModule/debugger_tuple.js +15 -0
  78. package/dist/debug_server/tests/testModule/debugger_tuple.js.map +1 -0
  79. package/dist/debug_server/tests/testModule/import_failure.d.ts +1 -0
  80. package/dist/debug_server/tests/testModule/import_failure.js +4 -0
  81. package/dist/debug_server/tests/testModule/import_failure.js.map +1 -0
  82. package/dist/debug_server/tests/testModule/unittest_debug.case.js +10 -0
  83. package/dist/debug_server/tests/testModule/unittest_debug.case.js.map +1 -0
  84. package/dist/debug_server/tests/testModule/unittest_debug.d.ts +1 -0
  85. package/dist/debug_server/tests/testModule/unittest_debug.js +6 -0
  86. package/dist/debug_server/tests/testModule/unittest_debug.js.map +1 -0
  87. package/dist/debug_server/wasmEntry.js +32 -12
  88. package/dist/debug_server/wasmEntry.js.map +1 -1
  89. package/dist/dwarf/classDebugInfo.d.ts +45 -0
  90. package/dist/dwarf/classDebugInfo.js +292 -0
  91. package/dist/dwarf/classDebugInfo.js.map +1 -0
  92. package/dist/{heap_analyzer/src → dwarf}/dwarfParser.js +2 -0
  93. package/dist/dwarf/dwarfParser.js.map +1 -0
  94. package/dist/dwarf/functionDebugInfo.d.ts +63 -0
  95. package/dist/dwarf/functionDebugInfo.js +377 -0
  96. package/dist/dwarf/functionDebugInfo.js.map +1 -0
  97. package/dist/dwarf/tests/fixtures/functionDebugInfo.d.ts +3 -0
  98. package/dist/dwarf/tests/fixtures/functionDebugInfo.js +24 -0
  99. package/dist/dwarf/tests/fixtures/functionDebugInfo.js.map +1 -0
  100. package/dist/dwarf/tests/functionDebugInfo.test.d.ts +1 -0
  101. package/dist/dwarf/tests/functionDebugInfo.test.js +102 -0
  102. package/dist/dwarf/tests/functionDebugInfo.test.js.map +1 -0
  103. package/dist/heap_analyzer/cli.js +1 -1
  104. package/dist/heap_analyzer/cli.js.map +1 -1
  105. package/dist/heap_analyzer/src/constants.js +2 -1
  106. package/dist/heap_analyzer/src/constants.js.map +1 -1
  107. package/dist/heap_analyzer/src/debugInfoResolver.d.ts +4 -15
  108. package/dist/heap_analyzer/src/debugInfoResolver.js +20 -231
  109. package/dist/heap_analyzer/src/debugInfoResolver.js.map +1 -1
  110. package/dist/heap_analyzer/src/dominator.js +4 -1
  111. package/dist/heap_analyzer/src/dominator.js.map +1 -1
  112. package/dist/heap_analyzer/src/referenceScanner.js +7 -7
  113. package/dist/heap_analyzer/src/referenceScanner.js.map +1 -1
  114. package/dist/heap_analyzer/src/retainedSize.js +2 -0
  115. package/dist/heap_analyzer/src/retainedSize.js.map +1 -1
  116. package/dist/heap_analyzer/src/snapshot.js +1 -1
  117. package/dist/heap_analyzer/src/snapshot.js.map +1 -1
  118. package/dist/heap_analyzer/src/{tlsf.js → tlsfBlockWalker.js} +4 -3
  119. package/dist/heap_analyzer/src/tlsfBlockWalker.js.map +1 -0
  120. package/dist/heap_analyzer/src/types.d.ts +3 -32
  121. package/dist/heap_analyzer/src/types.js +1 -8
  122. package/dist/heap_analyzer/src/types.js.map +1 -1
  123. package/dist/heap_analyzer/tests/debugInfoResolver.test.js +1 -1
  124. package/dist/heap_analyzer/tests/debugInfoResolver.test.js.map +1 -1
  125. package/dist/heap_analyzer/tests/dwarfParser.test.js +57 -40
  126. package/dist/heap_analyzer/tests/dwarfParser.test.js.map +1 -1
  127. package/dist/heap_analyzer/tests/roots.test.js +1 -1
  128. package/dist/heap_analyzer/tests/roots.test.js.map +1 -1
  129. package/dist/heap_analyzer/tests/snapshot.test.js +4 -4
  130. package/dist/heap_analyzer/tests/testHelper.js +4 -7
  131. package/dist/heap_analyzer/tests/testHelper.js.map +1 -1
  132. package/dist/heap_analyzer/tests/tlsfBlockWalker.test.d.ts +1 -0
  133. package/dist/heap_analyzer/tests/{tlsf.test.js → tlsfBlockWalker.test.js} +2 -2
  134. package/dist/heap_analyzer/tests/tlsfBlockWalker.test.js.map +1 -0
  135. package/dist/heap_analyzer/tests/wasmExecutor.d.ts +2 -2
  136. package/dist/heap_analyzer/tests/wasmExecutor.js +5 -5
  137. package/dist/heap_analyzer/tests/wasmExecutor.js.map +1 -1
  138. package/dist/runtime/objectLayout.d.ts +10 -0
  139. package/dist/runtime/objectLayout.js +13 -0
  140. package/dist/runtime/objectLayout.js.map +1 -0
  141. package/dist/scripts/lib.d.ts +1 -0
  142. package/dist/scripts/lib.js +86 -22
  143. package/dist/scripts/lib.js.map +1 -1
  144. package/dist/test_runner/cli.d.ts +0 -1
  145. package/dist/test_runner/cli.js +37 -19
  146. package/dist/test_runner/cli.js.map +1 -1
  147. package/dist/test_runner/config.d.ts +3 -0
  148. package/dist/test_runner/config.js +8 -0
  149. package/dist/test_runner/config.js.map +1 -0
  150. package/dist/test_runner/core/analyze.js +12 -3
  151. package/dist/test_runner/core/analyze.js.map +1 -1
  152. package/dist/test_runner/core/compile.js +1 -4
  153. package/dist/test_runner/core/compile.js.map +1 -1
  154. package/dist/test_runner/core/compiler.js +2 -0
  155. package/dist/test_runner/core/compiler.js.map +1 -1
  156. package/dist/test_runner/core/execute.js +20 -3
  157. package/dist/test_runner/core/execute.js.map +1 -1
  158. package/dist/test_runner/executionResult.js +10 -8
  159. package/dist/test_runner/executionResult.js.map +1 -1
  160. package/dist/test_runner/generator/table-generator/index.js +4 -2
  161. package/dist/test_runner/generator/table-generator/index.js.map +1 -1
  162. package/dist/test_runner/parser/index.js +6 -5
  163. package/dist/test_runner/parser/index.js.map +1 -1
  164. package/dist/test_runner/parser/singleFileAnalysis.js +7 -4
  165. package/dist/test_runner/parser/singleFileAnalysis.js.map +1 -1
  166. package/dist/test_runner/parser/singleFunctionAnalysis.js +1 -1
  167. package/dist/test_runner/parser/singleFunctionAnalysis.js.map +1 -1
  168. package/dist/test_runner/utils/errorTraceHandler.js +2 -1
  169. package/dist/test_runner/utils/errorTraceHandler.js.map +1 -1
  170. package/dist/test_runner/utils/index.js +9 -2
  171. package/dist/test_runner/utils/index.js.map +1 -1
  172. package/dist/test_runner/utils/interface.js +2 -1
  173. package/dist/test_runner/utils/interface.js.map +1 -1
  174. package/dist/test_runner/utils/pathResolver.js +9 -7
  175. package/dist/test_runner/utils/pathResolver.js.map +1 -1
  176. package/dist/test_runner/utils/wasm.js +16 -8
  177. package/dist/test_runner/utils/wasm.js.map +1 -1
  178. package/dist/trace_visualizer.d.ts +2 -0
  179. package/dist/trace_visualizer.js +18 -0
  180. package/dist/trace_visualizer.js.map +1 -0
  181. package/dist/warpo.js +2 -1
  182. package/dist/warpo.js.map +1 -1
  183. package/package.json +9 -5
  184. package/dist/heap_analyzer/src/dwarfParser.js.map +0 -1
  185. package/dist/heap_analyzer/src/tlsf.js.map +0 -1
  186. package/dist/heap_analyzer/tests/tlsf.test.js.map +0 -1
  187. /package/dist/{heap_analyzer/tests/tlsf.test.d.ts → debug_server/tests/testModule/unittest_debug.case.d.ts} +0 -0
  188. /package/dist/{heap_analyzer/src → dwarf}/dwarfParser.d.ts +0 -0
  189. /package/dist/heap_analyzer/src/{tlsf.d.ts → tlsfBlockWalker.d.ts} +0 -0
@@ -9,6 +9,8 @@ import { DebuggerWasmModule } from "./debuggerWasmModule.js";
9
9
  const DIRNAME = path.dirname(fileURLToPath(import.meta.url));
10
10
  const DEBUG_SERVER_TRACE_ENABLED = process.env.WARPO_DEBUG_SERVER_TRACE === "1";
11
11
  const DEBUG_SERVER_TRACE_FILE = path.join(process.cwd(), ".warpo-debug-server-trace.log");
12
+ const LINEAR_MEMORY_OBJECT_GROUP = "warpo-linear-memory";
13
+ const NODE_WAITING_FOR_DEBUGGER_DISCONNECT = "Waiting for the debugger to disconnect...";
12
14
  if (DEBUG_SERVER_TRACE_ENABLED) {
13
15
  try {
14
16
  writeFileSync(DEBUG_SERVER_TRACE_FILE, "");
@@ -27,6 +29,25 @@ function trace(message) {
27
29
  }
28
30
  }
29
31
  }
32
+ const READ_WASM_MEMORY_FUNCTION = function (address, byteLength) {
33
+ const buffer = this instanceof ArrayBuffer || (typeof SharedArrayBuffer !== "undefined" && this instanceof SharedArrayBuffer)
34
+ ? this
35
+ : this.buffer;
36
+ if (!(buffer instanceof ArrayBuffer) &&
37
+ !(typeof SharedArrayBuffer !== "undefined" && buffer instanceof SharedArrayBuffer)) {
38
+ return;
39
+ }
40
+ if (address < 0 || byteLength < 0 || address + byteLength > buffer.byteLength) {
41
+ return;
42
+ }
43
+ return Array.from(new Uint8Array(buffer, address, byteLength));
44
+ }.toString();
45
+ const GET_WASM_MEMORY_BUFFER_FUNCTION = function () {
46
+ if (this instanceof ArrayBuffer || (typeof SharedArrayBuffer !== "undefined" && this instanceof SharedArrayBuffer)) {
47
+ return this;
48
+ }
49
+ return this.buffer;
50
+ }.toString();
30
51
  function findFreePort() {
31
52
  return new Promise((resolve, reject) => {
32
53
  const srv = net.createServer();
@@ -51,28 +72,99 @@ export class NodeDebugger {
51
72
  name = "node";
52
73
  onModuleLoad;
53
74
  onPause;
75
+ onRuntimeError;
76
+ onRuntimeExit;
77
+ onLog;
54
78
  child;
55
79
  ws;
56
80
  cdpId = 0;
57
81
  pendingCommandCallbacks = new Map();
82
+ wasmBreakpointIds = new Set();
58
83
  paused = false;
59
84
  wasmFilePath;
85
+ wasmScriptId;
86
+ pausedCallFrames = [];
87
+ wasmMemoryBufferObjectId;
88
+ wasmGlobalsObjectId;
89
+ stderrOutput = "";
90
+ disposed = false;
91
+ runtimeExitPromise;
92
+ log(message) {
93
+ trace(message);
94
+ this.onLog?.(`[${this.name}] ${message}`);
95
+ }
60
96
  async launch(config) {
97
+ this.disposed = false;
61
98
  this.wasmFilePath = config.wasmFilePath;
62
99
  const port = await findFreePort();
63
- this.child = spawn(process.execPath, [
64
- `--inspect=${port}`,
65
- path.join(DIRNAME, "wasmEntry.js"),
66
- config.wasmFilePath,
67
- config.entryFunctionName,
68
- ...config.args.map(String),
69
- ], { stdio: ["pipe", "pipe", "pipe"] });
100
+ this.log(`launch wasmFilePath=${config.wasmFilePath} inspectPort=${port}`);
101
+ const launchArgs = "cwd" in config
102
+ ? [`--inspect-brk=${port}`, config.warpoPath ?? path.join(DIRNAME, "..", "warpo.js"), "test"]
103
+ : [
104
+ `--inspect-brk=${port}`,
105
+ path.join(DIRNAME, "wasmEntry.js"),
106
+ config.wasmFilePath,
107
+ config.entryFunctionName,
108
+ ...config.args.map(String),
109
+ ];
110
+ this.child = spawn(process.execPath, launchArgs, {
111
+ cwd: "cwd" in config ? config.cwd : undefined,
112
+ env: getRuntimeEnv(),
113
+ stdio: ["pipe", "pipe", "pipe"],
114
+ });
115
+ this.log(`runtime child spawned pid=${this.child.pid ?? "unknown"}`);
116
+ this.runtimeExitPromise = new Promise((resolve) => {
117
+ this.child?.once("exit", () => resolve());
118
+ this.child?.once("error", () => resolve());
119
+ });
120
+ this.child.stdout?.on("data", (chunk) => {
121
+ const text = chunk.toString().trim();
122
+ if (text) {
123
+ this.log(`runtime stdout: ${text}`);
124
+ }
125
+ });
126
+ this.child.stderr?.on("data", (chunk) => {
127
+ const stderr = parseRuntimeStderr(chunk.toString());
128
+ this.stderrOutput += stderr.output;
129
+ const text = stderr.output.trim();
130
+ if (text) {
131
+ this.log(`runtime stderr: ${text}`);
132
+ }
133
+ if (stderr.waitingForDebuggerDisconnect) {
134
+ this.log("runtime waiting for debugger disconnect -> close websocket");
135
+ this.ws?.close();
136
+ }
137
+ });
138
+ this.child.on("error", (error) => {
139
+ this.log(`runtime child error: ${error.message}`);
140
+ this.onRuntimeError?.(error.message);
141
+ this.onRuntimeExit?.();
142
+ });
143
+ this.child.on("exit", (code, signal) => {
144
+ this.log(`runtime exit code=${code ?? "null"} signal=${signal ?? "null"}`);
145
+ if (this.disposed) {
146
+ return;
147
+ }
148
+ if (code && code !== 0) {
149
+ this.onRuntimeError?.(this.stderrOutput.trim() || `Debug runtime exited with code ${code}`);
150
+ }
151
+ this.onRuntimeExit?.();
152
+ });
70
153
  const wsUrl = await this.fetchWsUrl(port);
71
- await this.connectCDP(wsUrl);
154
+ this.log(`inspector websocket discovered: ${wsUrl}`);
155
+ await Promise.race([this.connectCDP(wsUrl), this.runtimeExitPromise]);
72
156
  }
73
157
  dispose() {
158
+ this.disposed = true;
74
159
  this.paused = false;
75
160
  this.wasmFilePath = undefined;
161
+ this.wasmScriptId = undefined;
162
+ this.pausedCallFrames = [];
163
+ this.wasmMemoryBufferObjectId = undefined;
164
+ this.wasmGlobalsObjectId = undefined;
165
+ this.stderrOutput = "";
166
+ this.runtimeExitPromise = undefined;
167
+ this.wasmBreakpointIds.clear();
76
168
  this.ws?.close();
77
169
  this.child?.kill();
78
170
  }
@@ -85,28 +177,170 @@ export class NodeDebugger {
85
177
  async resume() {
86
178
  await this.waitForCommand("Debugger.resume");
87
179
  this.paused = false;
180
+ this.pausedCallFrames = [];
181
+ this.wasmMemoryBufferObjectId = undefined;
182
+ this.wasmGlobalsObjectId = undefined;
88
183
  }
89
184
  finishModuleLoad() {
185
+ this.log("finishModuleLoad -> Runtime.runIfWaitingForDebugger");
90
186
  this.sendCommand("Runtime.runIfWaitingForDebugger");
91
187
  }
92
- setWasmBreakpoint(module, bytecodeOffset, callbacks) {
93
- this.sendCommand("Debugger.setBreakpointByUrl", {
94
- url: module.url,
95
- lineNumber: 0,
96
- columnNumber: bytecodeOffset,
97
- }, {
98
- onSuccess: () => {
99
- trace(`setWasmBreakpoint success offset=${bytecodeOffset}`);
188
+ setWasmBreakpoints(module, wasmBytecodeOffsets, callbacks) {
189
+ this.clearWasmBreakpoints({
190
+ onSuccess: () => this.installWasmBreakpoints(module, wasmBytecodeOffsets, 0, callbacks),
191
+ onError: callbacks?.onError,
192
+ });
193
+ }
194
+ installWasmBreakpoints(module, wasmBytecodeOffsets, offsetIndex, callbacks) {
195
+ if (offsetIndex >= wasmBytecodeOffsets.length) {
196
+ callbacks?.onSuccess?.();
197
+ return;
198
+ }
199
+ const wasmBytecodeOffset = wasmBytecodeOffsets[offsetIndex];
200
+ this.setNodeWasmBreakpoint(module, wasmBytecodeOffset, {
201
+ onSuccess: () => this.installWasmBreakpoints(module, wasmBytecodeOffsets, offsetIndex + 1, callbacks),
202
+ onError: () => this.installWasmBreakpoints(module, wasmBytecodeOffsets, offsetIndex + 1, callbacks),
203
+ });
204
+ }
205
+ setNodeWasmBreakpoint(module, wasmBytecodeOffset, callbacks) {
206
+ void (async () => {
207
+ try {
208
+ const location = this.resolveWasmBytecodeOffsetLocation(module, wasmBytecodeOffset);
209
+ this.log(`setWasmBreakpoint offset=${wasmBytecodeOffset} url=${module.url}`);
210
+ const result = await this.waitForCommandResult("Debugger.setBreakpointByUrl", {
211
+ lineNumber: location.lineNumber,
212
+ url: module.url,
213
+ columnNumber: location.columnNumber,
214
+ condition: "",
215
+ });
216
+ const breakpointId = result.breakpointId;
217
+ if (typeof breakpointId !== "string") {
218
+ throw new TypeError("CDP did not return a breakpoint ID");
219
+ }
220
+ this.wasmBreakpointIds.add(breakpointId);
221
+ this.log(`setWasmBreakpoint success offset=${wasmBytecodeOffset}`);
222
+ callbacks?.onSuccess?.();
223
+ }
224
+ catch (error) {
225
+ const commandError = error instanceof Error ? error : new Error(String(error));
226
+ this.log(`setWasmBreakpoint error offset=${wasmBytecodeOffset} message=${commandError.message}`);
227
+ callbacks?.onError?.(commandError);
228
+ }
229
+ })();
230
+ }
231
+ clearWasmBreakpoints(callbacks) {
232
+ const breakpointIds = Array.from(this.wasmBreakpointIds);
233
+ const removeNext = (index) => {
234
+ if (index >= breakpointIds.length) {
235
+ callbacks?.onSuccess?.();
236
+ return;
237
+ }
238
+ const breakpointId = breakpointIds[index];
239
+ this.removeNodeBreakpoint(breakpointId, {
240
+ onSuccess: () => {
241
+ this.wasmBreakpointIds.delete(breakpointId);
242
+ removeNext(index + 1);
243
+ },
244
+ onError: () => {
245
+ removeNext(index + 1);
246
+ },
247
+ });
248
+ };
249
+ removeNext(0);
250
+ }
251
+ removeNodeBreakpoint(breakpointId, callbacks) {
252
+ void (async () => {
253
+ try {
254
+ await this.waitForCommand("Debugger.removeBreakpoint", { breakpointId });
255
+ this.log(`removeWasmBreakpoint success id=${breakpointId}`);
100
256
  callbacks?.onSuccess?.();
101
- },
102
- onError: (error) => {
103
- trace(`setWasmBreakpoint error offset=${bytecodeOffset} message=${error.message}`);
104
- callbacks?.onError?.(error);
105
- },
257
+ }
258
+ catch (error) {
259
+ const commandError = error instanceof Error ? error : new Error(String(error));
260
+ this.log(`removeWasmBreakpoint error id=${breakpointId} message=${commandError.message}`);
261
+ callbacks?.onError?.(commandError);
262
+ }
263
+ })();
264
+ }
265
+ resolveWasmBytecodeOffsetLocation(module, wasmBytecodeOffset) {
266
+ if (!module.url) {
267
+ throw new Error("Wasm script URL is not available");
268
+ }
269
+ return { scriptId: module.scriptId, lineNumber: 0, columnNumber: wasmBytecodeOffset };
270
+ }
271
+ resolveWasmLocationBytecodeOffset(location) {
272
+ if (location.lineNumber !== 0) {
273
+ return undefined;
274
+ }
275
+ return location.columnNumber;
276
+ }
277
+ getPausedWasmFrames() {
278
+ const frames = this.pausedCallFrames.map((callFrame) => this.toPausedWasmFrame(callFrame));
279
+ this.log(`getPausedWasmFrames count=${frames.length}`);
280
+ for (const [index, frame] of frames.entries()) {
281
+ this.log(` wasm frame ${index}: name=${frame.functionName}, offset=${frame.wasmBytecodeOffset ?? "unknown"}`);
282
+ }
283
+ return frames;
284
+ }
285
+ async getPausedWasmFrameVariables(frameIndex) {
286
+ const callFrame = this.pausedCallFrames[frameIndex];
287
+ if (!callFrame) {
288
+ this.log(`getPausedWasmFrameVariables frameIndex=${frameIndex} unavailable`);
289
+ return [];
290
+ }
291
+ const variables = await this.getLocalScopeVariables(callFrame);
292
+ this.log(`getPausedWasmFrameVariables frameIndex=${frameIndex} variables=${variables.length}`);
293
+ return variables;
294
+ }
295
+ async getPausedWasmGlobalVariables() {
296
+ const globalsObjectId = await this.getWasmGlobalsObjectId();
297
+ if (!globalsObjectId) {
298
+ return [];
299
+ }
300
+ const globalsResult = await this.waitForCommandResult("Runtime.getProperties", {
301
+ objectId: globalsObjectId,
302
+ ownProperties: true,
303
+ });
304
+ const globals = Array.isArray(globalsResult.result) ? globalsResult.result.filter(isCDPPropertyDescriptor) : [];
305
+ const values = [];
306
+ for (const [globalIndex, global] of globals.entries()) {
307
+ if (!global.value) {
308
+ continue;
309
+ }
310
+ values.push({
311
+ globalIndex,
312
+ value: await this.readRemoteObjectValue(global.value),
313
+ type: global.value.description ?? global.value.type,
314
+ });
315
+ }
316
+ return values;
317
+ }
318
+ async readWasmMemory(address, byteLength) {
319
+ this.log(`readWasmMemory address=${address} byteLength=${byteLength}`);
320
+ const memoryBufferObjectId = await this.getWasmMemoryBufferObjectId();
321
+ if (!memoryBufferObjectId) {
322
+ this.log("readWasmMemory skipped: memory buffer unavailable");
323
+ return undefined;
324
+ }
325
+ this.log("readWasmMemory -> Runtime.callFunctionOn");
326
+ const result = await this.waitForCommandResult("Runtime.callFunctionOn", {
327
+ objectId: memoryBufferObjectId,
328
+ functionDeclaration: READ_WASM_MEMORY_FUNCTION,
329
+ arguments: [{ value: address }, { value: byteLength }],
330
+ silent: true,
331
+ returnByValue: true,
106
332
  });
333
+ const remoteObject = getRuntimeEvaluateRemoteObject(result);
334
+ if (!Array.isArray(remoteObject?.value) || !remoteObject.value.every((value) => typeof value === "number")) {
335
+ this.log("readWasmMemory failed: runtime returned non-byte-array value");
336
+ return undefined;
337
+ }
338
+ this.log(`readWasmMemory success bytes=${remoteObject.value.length}`);
339
+ return Uint8Array.from(remoteObject.value);
107
340
  }
108
341
  async fetchWsUrl(port) {
109
342
  const deadline = Date.now() + 5000;
343
+ this.log(`waiting for inspector endpoint on port ${port}`);
110
344
  while (Date.now() < deadline) {
111
345
  try {
112
346
  const resp = await fetch(`http://127.0.0.1:${port}/json`);
@@ -115,10 +349,12 @@ export class NodeDebugger {
115
349
  }
116
350
  const [info] = (await resp.json());
117
351
  if (info?.webSocketDebuggerUrl) {
352
+ this.log(`inspector endpoint ready on port ${port}`);
118
353
  return info.webSocketDebuggerUrl;
119
354
  }
120
355
  }
121
- catch {
356
+ catch (error) {
357
+ trace(`inspector endpoint not ready: ${error instanceof Error ? error.message : "unknown error"}`);
122
358
  // The inspector endpoint is not always ready immediately after spawn.
123
359
  }
124
360
  await wait(50);
@@ -133,15 +369,33 @@ export class NodeDebugger {
133
369
  if (callbacks) {
134
370
  this.pendingCommandCallbacks.set(id, callbacks);
135
371
  }
372
+ this.log(`CDP -> ${method} id=${id}`);
136
373
  this.ws.send(JSON.stringify({ id, method, params }));
374
+ return id;
137
375
  }
138
376
  waitForCommand(method, params) {
139
377
  return new Promise((resolve, reject) => {
140
- this.sendCommand(method, params, {
378
+ const id = this.sendCommand(method, params, {
141
379
  onSuccess: () => {
380
+ this.log(`CDP command completed ${method} id=${id}`);
142
381
  resolve();
143
382
  },
144
383
  onError: (error) => {
384
+ this.log(`CDP command failed ${method} id=${id}: ${error.message}`);
385
+ reject(error);
386
+ },
387
+ });
388
+ });
389
+ }
390
+ waitForCommandResult(method, params) {
391
+ return new Promise((resolve, reject) => {
392
+ const id = this.sendCommand(method, params, {
393
+ onSuccess: (result) => {
394
+ this.log(`CDP command completed ${method} id=${id}`);
395
+ resolve(result ?? {});
396
+ },
397
+ onError: (error) => {
398
+ this.log(`CDP command failed ${method} id=${id}: ${error.message}`);
145
399
  reject(error);
146
400
  },
147
401
  });
@@ -154,60 +408,143 @@ export class NodeDebugger {
154
408
  ws.addEventListener("open", () => {
155
409
  void (async () => {
156
410
  try {
157
- trace("ws open -> Debugger.enable");
411
+ this.log("websocket open -> Runtime.enable");
412
+ await this.waitForCommand("Runtime.enable");
413
+ this.log("Runtime.enable complete -> Debugger.enable");
158
414
  await this.waitForCommand("Debugger.enable");
159
- trace("Debugger.enable -> Debugger.setBreakpointsActive");
160
- await this.waitForCommand("Debugger.setBreakpointsActive", { active: true });
161
- trace("Debugger.setBreakpointsActive -> Runtime.runIfWaitingForDebugger");
415
+ this.log("Debugger.enable complete -> Runtime.runIfWaitingForDebugger");
162
416
  await this.waitForCommand("Runtime.runIfWaitingForDebugger");
163
- trace("Runtime.runIfWaitingForDebugger -> launch ready");
417
+ this.log("Runtime.runIfWaitingForDebugger complete -> Debugger.setBreakpointsActive");
418
+ await this.waitForCommand("Debugger.setBreakpointsActive", { active: true });
419
+ this.log("Debugger.setBreakpointsActive complete -> Debugger.setPauseOnExceptions");
420
+ await this.waitForCommand("Debugger.setPauseOnExceptions", { state: "all" });
421
+ this.log("Debugger.setPauseOnExceptions complete -> launch ready");
164
422
  resolve();
165
423
  }
166
424
  catch (error) {
425
+ this.log(`CDP setup failed: ${error instanceof Error ? error.message : "unknown error"}`);
167
426
  reject(error instanceof Error ? error : new Error(String(error)));
168
427
  }
169
428
  })();
170
429
  });
171
430
  ws.addEventListener("error", (e) => {
172
431
  const message = e instanceof Error ? e.message : "WebSocket connection failed";
432
+ this.log(`websocket error: ${message}`);
173
433
  reject(new Error(message));
174
434
  });
435
+ ws.addEventListener("close", (event) => {
436
+ this.log(`websocket close code=${event.code} reason=${event.reason || ""}`);
437
+ });
175
438
  ws.addEventListener("message", (ev) => {
176
439
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
177
440
  const msg = JSON.parse(String(ev.data));
178
- if (typeof msg.id === "number") {
179
- this.handleCommandResponse(msg.id, msg);
180
- return;
181
- }
182
- if (msg.method === "Debugger.paused") {
183
- const reason = this.getPauseReason(msg.params);
184
- this.paused = true;
185
- trace(`Debugger.paused reason=${reason}`);
186
- void Promise.resolve(this.onPause?.({ reason })).catch((error) => {
187
- trace(`pause handler failed: ${error instanceof Error ? error.message : "unknown error"}`);
188
- });
189
- return;
190
- }
191
- if (msg.method === "Debugger.scriptParsed") {
192
- const params = msg.params;
193
- const lang = typeof params?.scriptLanguage === "string" ? params.scriptLanguage : "unknown";
194
- const url = typeof params?.url === "string" ? params.url : "";
195
- trace(`Debugger.scriptParsed language=${lang} url=${url}`);
196
- if (params && lang === "WebAssembly" && typeof params.scriptId === "string") {
197
- trace(`wasm module detected scriptId=${params.scriptId}`);
198
- void this.handleModuleLoad({
199
- scriptId: params.scriptId,
200
- url,
201
- }).catch((error) => {
202
- const message = error instanceof Error ? error.message : "unknown error";
203
- trace(`module load handler failed: ${message}`);
204
- process.stderr.write(`[node-debugger] module load handler failed: ${message}\n`);
205
- });
206
- }
207
- }
441
+ this.handleCdpMessage(msg);
208
442
  });
209
443
  });
210
444
  }
445
+ handleCdpMessage(msg) {
446
+ if (typeof msg.id === "number") {
447
+ this.handleCommandResponse(msg.id, msg);
448
+ return;
449
+ }
450
+ if (msg.method === "Debugger.paused") {
451
+ this.handleDebuggerPaused(msg.params);
452
+ return;
453
+ }
454
+ if (msg.method === "Debugger.scriptParsed") {
455
+ this.handleScriptParsed(msg.params);
456
+ }
457
+ }
458
+ handleDebuggerPaused(params) {
459
+ const reason = this.getPauseReason(params);
460
+ this.pausedCallFrames = this.getPausedWasmCallFrames(params);
461
+ this.wasmMemoryBufferObjectId = undefined;
462
+ this.wasmGlobalsObjectId = undefined;
463
+ if (reason === "Break on start" && !this.wasmScriptId) {
464
+ this.log("Debugger.paused reason=Break on start location=inspect-brk startup");
465
+ void this.resumeInternalStartupPause();
466
+ return;
467
+ }
468
+ if (reason === "other" && this.wasmScriptId) {
469
+ this.log("Debugger.paused reason=other location=wasm pre-entry gate");
470
+ return;
471
+ }
472
+ const isExceptionPause = reason === "exception" || reason === "promiseRejection";
473
+ // CDP can only pause on exceptions for the whole Node process, not for a specific wasm module. We need
474
+ // "all" because the JavaScript wrapper can catch a wasm trap, but that also pauses for unrelated JavaScript
475
+ // exceptions. Treat the top frame belonging to our wasm module as the filter for a debugger-visible trap.
476
+ if (isExceptionPause && !this.isTopFrameWasm(params)) {
477
+ this.log(`Debugger.paused reason=${reason} outside wasm -> resume`);
478
+ void this.resumeIgnoredPause();
479
+ return;
480
+ }
481
+ const isWasmTrap = isExceptionPause;
482
+ if (isWasmTrap) {
483
+ this.paused = true;
484
+ this.log(`Debugger.paused reason=${reason} (wasm trap)`);
485
+ void this.notifyPause("exception");
486
+ return;
487
+ }
488
+ this.paused = true;
489
+ this.log(`Debugger.paused reason=${reason}`);
490
+ void this.notifyPause(reason);
491
+ }
492
+ async notifyPause(reason) {
493
+ try {
494
+ const pausedCallFrame = this.pausedCallFrames[0];
495
+ const wasmBytecodeOffset = pausedCallFrame
496
+ ? this.resolveWasmLocationBytecodeOffset(pausedCallFrame.location)
497
+ : undefined;
498
+ await this.onPause?.({ reason, wasmBytecodeOffset });
499
+ }
500
+ catch (error) {
501
+ this.log(`pause handler failed: ${error instanceof Error ? error.message : "unknown error"}`);
502
+ }
503
+ }
504
+ handleScriptParsed(params) {
505
+ const lang = typeof params?.scriptLanguage === "string" ? params.scriptLanguage : "unknown";
506
+ const url = typeof params?.url === "string" ? params.url : "";
507
+ this.log(`Debugger.scriptParsed language=${lang} url=${url}`);
508
+ if (!params || lang !== "WebAssembly" || typeof params.scriptId !== "string") {
509
+ return;
510
+ }
511
+ if (!this.isExpectedWasmModule(params)) {
512
+ this.log(`ignoring non-target wasm module scriptId=${params.scriptId} url=${url}`);
513
+ return;
514
+ }
515
+ this.wasmScriptId = params.scriptId;
516
+ this.log(`wasm module detected scriptId=${params.scriptId}`);
517
+ void this.handleModuleLoad({
518
+ scriptId: params.scriptId,
519
+ url,
520
+ }).catch((error) => {
521
+ const message = error instanceof Error ? error.message : "unknown error";
522
+ this.log(`module load handler failed: ${message}`);
523
+ process.stderr.write(`Module load handler failed: ${message}\n`);
524
+ });
525
+ }
526
+ isExpectedWasmModule(params) {
527
+ if (!this.wasmFilePath) {
528
+ return false;
529
+ }
530
+ return params.sourceMapURL === `${path.basename(this.wasmFilePath)}.map`;
531
+ }
532
+ async resumeInternalStartupPause() {
533
+ await this.resumeIgnoredPause("inspect-brk startup pause");
534
+ }
535
+ async resumeIgnoredPause(description = "non-wasm exception pause") {
536
+ try {
537
+ await this.waitForCommand("Debugger.resume");
538
+ this.paused = false;
539
+ this.pausedCallFrames = [];
540
+ this.wasmMemoryBufferObjectId = undefined;
541
+ this.wasmGlobalsObjectId = undefined;
542
+ this.log(`${description} resumed`);
543
+ }
544
+ catch (error) {
545
+ this.log(`failed to resume ${description}: ${error instanceof Error ? error.message : "unknown error"}`);
546
+ }
547
+ }
211
548
  handleCommandResponse(id, msg) {
212
549
  const callbacks = this.pendingCommandCallbacks.get(id);
213
550
  if (!callbacks) {
@@ -215,10 +552,12 @@ export class NodeDebugger {
215
552
  }
216
553
  this.pendingCommandCallbacks.delete(id);
217
554
  if (msg.error) {
555
+ this.log(`CDP <- error id=${id} message=${msg.error.message ?? "CDP command failed"}`);
218
556
  callbacks.onError?.(new Error(msg.error.message ?? "CDP command failed"));
219
557
  return;
220
558
  }
221
- callbacks.onSuccess?.();
559
+ this.log(`CDP <- success id=${id}`);
560
+ callbacks.onSuccess?.(msg.result);
222
561
  }
223
562
  getPauseReason(params) {
224
563
  if (Array.isArray(params?.hitBreakpoints) && params.hitBreakpoints.length > 0) {
@@ -229,12 +568,262 @@ export class NodeDebugger {
229
568
  }
230
569
  return "unknown";
231
570
  }
571
+ getPausedWasmCallFrames(params) {
572
+ if (!Array.isArray(params?.callFrames)) {
573
+ return [];
574
+ }
575
+ const callFrames = params.callFrames.filter(isCDPCallFrame);
576
+ if (!this.wasmScriptId) {
577
+ this.log(`getPausedWasmCallFrames skipped ${callFrames.length} non-wasm startup frames before wasm script load`);
578
+ return [];
579
+ }
580
+ const wasmCallFrames = callFrames.filter((callFrame) => callFrame.location.scriptId === this.wasmScriptId);
581
+ this.log(`getPausedWasmCallFrames total=${callFrames.length} wasm=${wasmCallFrames.length}`);
582
+ return wasmCallFrames;
583
+ }
584
+ isTopFrameWasm(params) {
585
+ if (!Array.isArray(params?.callFrames) || !this.wasmScriptId) {
586
+ return false;
587
+ }
588
+ const topCallFrame = params.callFrames.find(isCDPCallFrame);
589
+ return topCallFrame?.location.scriptId === this.wasmScriptId;
590
+ }
591
+ toPausedWasmFrame(callFrame) {
592
+ return {
593
+ functionName: callFrame.functionName,
594
+ wasmBytecodeOffset: this.resolveWasmLocationBytecodeOffset(callFrame.location),
595
+ };
596
+ }
597
+ async getLocalScopeVariables(callFrame) {
598
+ const localScope = callFrame.scopeChain.find((scope) => scope.type === "local") ?? callFrame.scopeChain[0];
599
+ const objectId = localScope?.object.objectId;
600
+ if (!objectId) {
601
+ return [];
602
+ }
603
+ const result = await this.waitForCommandResult("Runtime.getProperties", {
604
+ objectId,
605
+ ownProperties: true,
606
+ });
607
+ const properties = Array.isArray(result.result) ? result.result.filter(isCDPPropertyDescriptor) : [];
608
+ const variables = [];
609
+ for (const property of properties) {
610
+ if (!property.value) {
611
+ continue;
612
+ }
613
+ const localIndex = variables.length;
614
+ variables.push({
615
+ name: `local${localIndex}`,
616
+ value: await this.readRemoteObjectValue(property.value),
617
+ type: property.value.description ?? property.value.type,
618
+ localIndex,
619
+ });
620
+ }
621
+ return variables;
622
+ }
623
+ async getWasmMemoryBufferObjectId() {
624
+ if (this.wasmMemoryBufferObjectId) {
625
+ return this.wasmMemoryBufferObjectId;
626
+ }
627
+ this.log("getWasmMemoryBufferObjectId -> getWasmMemoryObjectId");
628
+ const memoryObjectId = await this.getWasmMemoryObjectId();
629
+ if (!memoryObjectId) {
630
+ this.log("getWasmMemoryBufferObjectId failed: memory object unavailable");
631
+ return undefined;
632
+ }
633
+ this.log("getWasmMemoryBufferObjectId -> Runtime.callFunctionOn buffer");
634
+ const bufferResult = await this.waitForCommandResult("Runtime.callFunctionOn", {
635
+ objectId: memoryObjectId,
636
+ functionDeclaration: GET_WASM_MEMORY_BUFFER_FUNCTION,
637
+ silent: true,
638
+ objectGroup: LINEAR_MEMORY_OBJECT_GROUP,
639
+ });
640
+ const bufferObject = getRuntimeEvaluateRemoteObject(bufferResult);
641
+ this.wasmMemoryBufferObjectId = bufferObject?.objectId;
642
+ this.log(`getWasmMemoryBufferObjectId result=${this.wasmMemoryBufferObjectId ?? "undefined"}`);
643
+ return this.wasmMemoryBufferObjectId;
644
+ }
645
+ async getWasmMemoryObjectId() {
646
+ const moduleScope = this.pausedCallFrames[0]?.scopeChain.find((scope) => scope.type === "module");
647
+ const objectId = moduleScope?.object.objectId;
648
+ if (!objectId) {
649
+ return undefined;
650
+ }
651
+ this.log("getWasmMemoryObjectId -> Runtime.getProperties module scope");
652
+ const result = await this.waitForCommandResult("Runtime.getProperties", {
653
+ objectId,
654
+ ownProperties: false,
655
+ });
656
+ const properties = Array.isArray(result.result) ? result.result.filter(isCDPPropertyDescriptor) : [];
657
+ const memoriesProperty = properties.find((property) => property.name === "memories" && property.value?.objectId);
658
+ if (!memoriesProperty?.value?.objectId) {
659
+ return undefined;
660
+ }
661
+ this.log("getWasmMemoryObjectId -> Runtime.getProperties memories");
662
+ const memoriesResult = await this.waitForCommandResult("Runtime.getProperties", {
663
+ objectId: memoriesProperty.value.objectId,
664
+ ownProperties: false,
665
+ });
666
+ const memories = Array.isArray(memoriesResult.result) ? memoriesResult.result.filter(isCDPPropertyDescriptor) : [];
667
+ const nestedMemory = memories.find((property) => property.value && isWasmMemoryObject(property.value));
668
+ this.log(`getWasmMemoryObjectId result=${nestedMemory?.value?.objectId ?? "undefined"}`);
669
+ return nestedMemory?.value?.objectId;
670
+ }
671
+ async getWasmGlobalsObjectId() {
672
+ if (this.wasmGlobalsObjectId) {
673
+ return this.wasmGlobalsObjectId;
674
+ }
675
+ const moduleScope = this.pausedCallFrames[0]?.scopeChain.find((scope) => scope.type === "module");
676
+ const moduleObjectId = moduleScope?.object.objectId;
677
+ if (!moduleObjectId) {
678
+ return undefined;
679
+ }
680
+ const moduleResult = await this.waitForCommandResult("Runtime.getProperties", {
681
+ objectId: moduleObjectId,
682
+ ownProperties: false,
683
+ });
684
+ const moduleProperties = Array.isArray(moduleResult.result)
685
+ ? moduleResult.result.filter(isCDPPropertyDescriptor)
686
+ : [];
687
+ this.wasmGlobalsObjectId = moduleProperties.find((property) => property.name === "globals")?.value?.objectId;
688
+ return this.wasmGlobalsObjectId;
689
+ }
690
+ async readRemoteObjectValue(value) {
691
+ if (value.subtype !== "wasmvalue" || !value.objectId) {
692
+ return formatRemoteObject(value);
693
+ }
694
+ const result = await this.waitForCommandResult("Runtime.getProperties", {
695
+ objectId: value.objectId,
696
+ ownProperties: true,
697
+ });
698
+ const innerProperties = Array.isArray(result.result) ? result.result.filter(isCDPPropertyDescriptor) : [];
699
+ const valueProperty = innerProperties.find((property) => property.name === "value" || property.name === "0");
700
+ return valueProperty?.value ? formatRemoteObject(valueProperty.value) : formatRemoteObject(value);
701
+ }
232
702
  async handleModuleLoad(runtimeInfo) {
703
+ if (this.hasRuntimeExited()) {
704
+ this.log("skip wasm module load because runtime already exited");
705
+ return;
706
+ }
233
707
  if (!this.wasmFilePath) {
234
708
  throw new Error("wasm file path is not available");
235
709
  }
710
+ this.log(`loading wasm debug metadata from ${this.wasmFilePath}`);
236
711
  const module = await DebuggerWasmModule.load(this.wasmFilePath, runtimeInfo);
712
+ this.log(`wasm debug metadata loaded from ${module.sourceMapFilePath}`);
237
713
  void this.onModuleLoad?.(module);
238
714
  }
715
+ hasRuntimeExited() {
716
+ return this.child !== undefined && (this.child.exitCode !== null || this.child.signalCode !== null);
717
+ }
718
+ }
719
+ function parseRuntimeStderr(text) {
720
+ let waitingForDebuggerDisconnect = false;
721
+ const output = text
722
+ .split(/(?<=\n)/)
723
+ .filter((line) => {
724
+ const trimmed = line.trim();
725
+ if (trimmed === NODE_WAITING_FOR_DEBUGGER_DISCONNECT) {
726
+ waitingForDebuggerDisconnect = true;
727
+ return false;
728
+ }
729
+ return (trimmed !== "" &&
730
+ !trimmed.startsWith("Debugger listening on") &&
731
+ !trimmed.startsWith("For help, see:") &&
732
+ trimmed !== "Debugger attached.");
733
+ })
734
+ .join("");
735
+ return { output, waitingForDebuggerDisconnect };
736
+ }
737
+ function getRuntimeEnv() {
738
+ const env = { ...process.env };
739
+ delete env.VSCODE_INSPECTOR_OPTIONS;
740
+ const nodeOptions = filterAutoAttachNodeOptions(env.NODE_OPTIONS);
741
+ if (nodeOptions) {
742
+ env.NODE_OPTIONS = nodeOptions;
743
+ }
744
+ else {
745
+ delete env.NODE_OPTIONS;
746
+ }
747
+ return env;
748
+ }
749
+ function filterAutoAttachNodeOptions(nodeOptions) {
750
+ if (!nodeOptions) {
751
+ return "";
752
+ }
753
+ const parts = nodeOptions.split(/\s+/).filter(Boolean);
754
+ const filtered = [];
755
+ for (let i = 0; i < parts.length; i++) {
756
+ const part = parts[i];
757
+ const next = parts[i + 1];
758
+ if ((part === "--require" || part === "-r") && next && isVsCodeJsDebugBootloader(next)) {
759
+ i++;
760
+ continue;
761
+ }
762
+ if ((part.startsWith("--require=") || part.startsWith("-r=")) && isVsCodeJsDebugBootloader(part)) {
763
+ continue;
764
+ }
765
+ filtered.push(part);
766
+ }
767
+ return filtered.join(" ");
768
+ }
769
+ function isVsCodeJsDebugBootloader(value) {
770
+ return value.includes("js-debug") || value.includes("vscode-js-debug");
771
+ }
772
+ function isCDPPropertyDescriptor(value) {
773
+ if (!value || typeof value !== "object") {
774
+ return false;
775
+ }
776
+ return typeof value.name === "string";
777
+ }
778
+ function isCDPCallFrame(value) {
779
+ if (typeof value !== "object" || value === null) {
780
+ return false;
781
+ }
782
+ const callFrame = value;
783
+ return (typeof callFrame.callFrameId === "string" &&
784
+ typeof callFrame.functionName === "string" &&
785
+ isCDPLocation(callFrame.location) &&
786
+ Array.isArray(callFrame.scopeChain));
787
+ }
788
+ function isCDPLocation(value) {
789
+ if (typeof value !== "object" || value === null) {
790
+ return false;
791
+ }
792
+ const location = value;
793
+ return (typeof location.scriptId === "string" &&
794
+ typeof location.lineNumber === "number" &&
795
+ typeof location.columnNumber === "number");
796
+ }
797
+ function isWasmMemoryObject(value) {
798
+ return value.objectId !== undefined && value.subtype === "webassemblymemory";
799
+ }
800
+ function getRuntimeEvaluateRemoteObject(result) {
801
+ const remoteObject = result.result;
802
+ if (!remoteObject || typeof remoteObject !== "object") {
803
+ return undefined;
804
+ }
805
+ return remoteObject;
806
+ }
807
+ function formatRemoteObject(value) {
808
+ if (value.unserializableValue !== undefined) {
809
+ return value.unserializableValue;
810
+ }
811
+ const rawValue = value.value;
812
+ if (rawValue !== undefined) {
813
+ if (rawValue === null) {
814
+ return "null";
815
+ }
816
+ if (typeof rawValue === "object") {
817
+ return value.description ?? value.type ?? "<unavailable>";
818
+ }
819
+ if (typeof rawValue === "string") {
820
+ return rawValue;
821
+ }
822
+ if (typeof rawValue === "number" || typeof rawValue === "boolean" || typeof rawValue === "bigint") {
823
+ return rawValue.toString();
824
+ }
825
+ return value.description ?? value.type ?? "<unavailable>";
826
+ }
827
+ return value.description ?? value.type ?? "<unavailable>";
239
828
  }
240
829
  //# sourceMappingURL=nodeDebugger.js.map