roku-debug 0.20.5 → 0.20.7

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 (214) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/CompileErrorProcessor.d.ts +7 -2
  3. package/dist/CompileErrorProcessor.js +64 -69
  4. package/dist/CompileErrorProcessor.js.map +1 -1
  5. package/dist/DeviceInfo.d.ts +1 -0
  6. package/dist/adapters/DebugProtocolAdapter.d.ts +64 -17
  7. package/dist/adapters/DebugProtocolAdapter.js +264 -157
  8. package/dist/adapters/DebugProtocolAdapter.js.map +1 -1
  9. package/dist/adapters/TelnetAdapter.d.ts +8 -3
  10. package/dist/adapters/TelnetAdapter.js +14 -6
  11. package/dist/adapters/TelnetAdapter.js.map +1 -1
  12. package/dist/adapters/TelnetRequestPipeline.d.ts +34 -0
  13. package/dist/adapters/TelnetRequestPipeline.js +35 -22
  14. package/dist/adapters/TelnetRequestPipeline.js.map +1 -1
  15. package/dist/debugProtocol/Constants.d.ts +171 -81
  16. package/dist/debugProtocol/Constants.js +206 -126
  17. package/dist/debugProtocol/Constants.js.map +1 -1
  18. package/dist/debugProtocol/DebugProtocolClientReplaySession.d.ts +46 -0
  19. package/dist/debugProtocol/DebugProtocolClientReplaySession.js +278 -0
  20. package/dist/debugProtocol/DebugProtocolClientReplaySession.js.map +1 -0
  21. package/dist/debugProtocol/PluginInterface.d.ts +38 -0
  22. package/dist/debugProtocol/PluginInterface.js +86 -0
  23. package/dist/debugProtocol/PluginInterface.js.map +1 -0
  24. package/dist/debugProtocol/ProtocolUtil.d.ts +56 -0
  25. package/dist/debugProtocol/ProtocolUtil.js +164 -0
  26. package/dist/debugProtocol/ProtocolUtil.js.map +1 -0
  27. package/dist/debugProtocol/client/DebugProtocolClient.d.ts +310 -0
  28. package/dist/debugProtocol/client/DebugProtocolClient.js +1079 -0
  29. package/dist/debugProtocol/client/DebugProtocolClient.js.map +1 -0
  30. package/dist/debugProtocol/client/DebugProtocolClientPlugin.d.ts +44 -0
  31. package/dist/debugProtocol/client/DebugProtocolClientPlugin.js +3 -0
  32. package/dist/debugProtocol/client/DebugProtocolClientPlugin.js.map +1 -0
  33. package/dist/debugProtocol/events/ProtocolEvent.d.ts +66 -0
  34. package/dist/debugProtocol/events/ProtocolEvent.js +3 -0
  35. package/dist/debugProtocol/events/ProtocolEvent.js.map +1 -0
  36. package/dist/debugProtocol/events/requests/AddBreakpointsRequest.d.ts +30 -0
  37. package/dist/debugProtocol/events/requests/AddBreakpointsRequest.js +63 -0
  38. package/dist/debugProtocol/events/requests/AddBreakpointsRequest.js.map +1 -0
  39. package/dist/debugProtocol/events/requests/AddConditionalBreakpointsRequest.d.ts +48 -0
  40. package/dist/debugProtocol/events/requests/AddConditionalBreakpointsRequest.js +69 -0
  41. package/dist/debugProtocol/events/requests/AddConditionalBreakpointsRequest.js.map +1 -0
  42. package/dist/debugProtocol/events/requests/ContinueRequest.d.ts +20 -0
  43. package/dist/debugProtocol/events/requests/ContinueRequest.js +40 -0
  44. package/dist/debugProtocol/events/requests/ContinueRequest.js.map +1 -0
  45. package/dist/debugProtocol/events/requests/ExecuteRequest.d.ts +26 -0
  46. package/dist/debugProtocol/events/requests/ExecuteRequest.js +49 -0
  47. package/dist/debugProtocol/events/requests/ExecuteRequest.js.map +1 -0
  48. package/dist/debugProtocol/events/requests/ExitChannelRequest.d.ts +20 -0
  49. package/dist/debugProtocol/events/requests/ExitChannelRequest.js +40 -0
  50. package/dist/debugProtocol/events/requests/ExitChannelRequest.js.map +1 -0
  51. package/dist/debugProtocol/events/requests/HandshakeRequest.d.ts +26 -0
  52. package/dist/debugProtocol/events/requests/HandshakeRequest.js +47 -0
  53. package/dist/debugProtocol/events/requests/HandshakeRequest.js.map +1 -0
  54. package/dist/debugProtocol/events/requests/ListBreakpointsRequest.d.ts +20 -0
  55. package/dist/debugProtocol/events/requests/ListBreakpointsRequest.js +40 -0
  56. package/dist/debugProtocol/events/requests/ListBreakpointsRequest.js.map +1 -0
  57. package/dist/debugProtocol/events/requests/RemoveBreakpointsRequest.d.ts +29 -0
  58. package/dist/debugProtocol/events/requests/RemoveBreakpointsRequest.js +60 -0
  59. package/dist/debugProtocol/events/requests/RemoveBreakpointsRequest.js.map +1 -0
  60. package/dist/debugProtocol/events/requests/StackTraceRequest.d.ts +22 -0
  61. package/dist/debugProtocol/events/requests/StackTraceRequest.js +43 -0
  62. package/dist/debugProtocol/events/requests/StackTraceRequest.js.map +1 -0
  63. package/dist/debugProtocol/events/requests/StepRequest.d.ts +25 -0
  64. package/dist/debugProtocol/events/requests/StepRequest.js +46 -0
  65. package/dist/debugProtocol/events/requests/StepRequest.js.map +1 -0
  66. package/dist/debugProtocol/events/requests/StopRequest.d.ts +20 -0
  67. package/dist/debugProtocol/events/requests/StopRequest.js +39 -0
  68. package/dist/debugProtocol/events/requests/StopRequest.js.map +1 -0
  69. package/dist/debugProtocol/events/requests/ThreadsRequest.d.ts +20 -0
  70. package/dist/debugProtocol/events/requests/ThreadsRequest.js +40 -0
  71. package/dist/debugProtocol/events/requests/ThreadsRequest.js.map +1 -0
  72. package/dist/debugProtocol/events/requests/VariablesRequest.d.ts +59 -0
  73. package/dist/debugProtocol/events/requests/VariablesRequest.js +123 -0
  74. package/dist/debugProtocol/events/requests/VariablesRequest.js.map +1 -0
  75. package/dist/debugProtocol/events/responses/AddBreakpointsResponse.js.map +1 -0
  76. package/dist/debugProtocol/events/responses/AddConditionalBreakpointsResponse.d.ts +3 -0
  77. package/dist/debugProtocol/events/responses/AddConditionalBreakpointsResponse.js +9 -0
  78. package/dist/debugProtocol/events/responses/AddConditionalBreakpointsResponse.js.map +1 -0
  79. package/dist/debugProtocol/events/responses/ExecuteV3Response.d.ts +42 -0
  80. package/dist/debugProtocol/events/responses/ExecuteV3Response.js +94 -0
  81. package/dist/debugProtocol/events/responses/ExecuteV3Response.js.map +1 -0
  82. package/dist/debugProtocol/events/responses/GenericResponse.d.ts +17 -0
  83. package/dist/debugProtocol/events/responses/GenericResponse.js +40 -0
  84. package/dist/debugProtocol/events/responses/GenericResponse.js.map +1 -0
  85. package/dist/debugProtocol/events/responses/GenericV3Response.d.ts +15 -0
  86. package/dist/debugProtocol/events/responses/GenericV3Response.js +38 -0
  87. package/dist/debugProtocol/events/responses/GenericV3Response.js.map +1 -0
  88. package/dist/debugProtocol/events/responses/HandshakeResponse.d.ts +28 -0
  89. package/dist/debugProtocol/events/responses/HandshakeResponse.js +69 -0
  90. package/dist/debugProtocol/events/responses/HandshakeResponse.js.map +1 -0
  91. package/dist/debugProtocol/events/responses/HandshakeV3Response.d.ts +42 -0
  92. package/dist/debugProtocol/events/responses/HandshakeV3Response.js +98 -0
  93. package/dist/debugProtocol/events/responses/HandshakeV3Response.js.map +1 -0
  94. package/dist/debugProtocol/events/responses/ListBreakpointsResponse.d.ts +35 -0
  95. package/dist/debugProtocol/events/responses/ListBreakpointsResponse.js +68 -0
  96. package/dist/debugProtocol/events/responses/ListBreakpointsResponse.js.map +1 -0
  97. package/dist/debugProtocol/events/responses/RemoveBreakpointsResponse.js.map +1 -0
  98. package/dist/debugProtocol/events/responses/StackTraceResponse.d.ts +24 -0
  99. package/dist/debugProtocol/events/responses/StackTraceResponse.js +72 -0
  100. package/dist/debugProtocol/events/responses/StackTraceResponse.js.map +1 -0
  101. package/dist/debugProtocol/events/responses/StackTraceV3Response.d.ts +37 -0
  102. package/dist/debugProtocol/events/responses/StackTraceV3Response.js +67 -0
  103. package/dist/debugProtocol/events/responses/StackTraceV3Response.js.map +1 -0
  104. package/dist/debugProtocol/events/responses/ThreadsResponse.d.ts +54 -0
  105. package/dist/debugProtocol/events/responses/ThreadsResponse.js +80 -0
  106. package/dist/debugProtocol/events/responses/ThreadsResponse.js.map +1 -0
  107. package/dist/debugProtocol/events/responses/VariablesResponse.d.ts +117 -0
  108. package/dist/debugProtocol/events/responses/VariablesResponse.js +335 -0
  109. package/dist/debugProtocol/events/responses/VariablesResponse.js.map +1 -0
  110. package/dist/debugProtocol/events/updates/AllThreadsStoppedUpdate.d.ts +35 -0
  111. package/dist/debugProtocol/events/updates/AllThreadsStoppedUpdate.js +58 -0
  112. package/dist/debugProtocol/events/updates/AllThreadsStoppedUpdate.js.map +1 -0
  113. package/dist/debugProtocol/events/updates/BreakpointErrorUpdate.d.ts +42 -0
  114. package/dist/debugProtocol/events/updates/BreakpointErrorUpdate.js +97 -0
  115. package/dist/debugProtocol/events/updates/BreakpointErrorUpdate.js.map +1 -0
  116. package/dist/debugProtocol/events/updates/BreakpointVerifiedUpdate.d.ts +41 -0
  117. package/dist/debugProtocol/events/updates/BreakpointVerifiedUpdate.js +74 -0
  118. package/dist/debugProtocol/events/updates/BreakpointVerifiedUpdate.js.map +1 -0
  119. package/dist/debugProtocol/events/updates/CompileErrorUpdate.d.ts +60 -0
  120. package/dist/debugProtocol/events/updates/CompileErrorUpdate.js +89 -0
  121. package/dist/debugProtocol/events/updates/CompileErrorUpdate.js.map +1 -0
  122. package/dist/debugProtocol/events/updates/IOPortOpenedUpdate.d.ts +23 -0
  123. package/dist/debugProtocol/events/updates/IOPortOpenedUpdate.js +49 -0
  124. package/dist/debugProtocol/events/updates/IOPortOpenedUpdate.js.map +1 -0
  125. package/dist/debugProtocol/events/updates/ThreadAttachedUpdate.d.ts +26 -0
  126. package/dist/debugProtocol/events/updates/ThreadAttachedUpdate.js +50 -0
  127. package/dist/debugProtocol/events/updates/ThreadAttachedUpdate.js.map +1 -0
  128. package/dist/debugProtocol/server/DebugProtocolServer.d.ts +110 -0
  129. package/dist/debugProtocol/server/DebugProtocolServer.js +306 -0
  130. package/dist/debugProtocol/server/DebugProtocolServer.js.map +1 -0
  131. package/dist/debugProtocol/server/DebugProtocolServerPlugin.d.ts +41 -0
  132. package/dist/debugProtocol/server/DebugProtocolServerPlugin.js +3 -0
  133. package/dist/debugProtocol/server/DebugProtocolServerPlugin.js.map +1 -0
  134. package/dist/debugSession/BrightScriptDebugSession.d.ts +9 -1
  135. package/dist/debugSession/BrightScriptDebugSession.js +178 -89
  136. package/dist/debugSession/BrightScriptDebugSession.js.map +1 -1
  137. package/dist/index.d.ts +2 -3
  138. package/dist/index.js +2 -3
  139. package/dist/index.js.map +1 -1
  140. package/dist/logging.d.ts +1 -0
  141. package/dist/logging.js +4 -2
  142. package/dist/logging.js.map +1 -1
  143. package/dist/managers/ActionQueue.d.ts +7 -1
  144. package/dist/managers/ActionQueue.js +27 -5
  145. package/dist/managers/ActionQueue.js.map +1 -1
  146. package/dist/managers/BreakpointManager.d.ts +82 -27
  147. package/dist/managers/BreakpointManager.js +168 -63
  148. package/dist/managers/BreakpointManager.js.map +1 -1
  149. package/dist/managers/ProjectManager.d.ts +3 -0
  150. package/dist/managers/ProjectManager.js +42 -36
  151. package/dist/managers/ProjectManager.js.map +1 -1
  152. package/dist/util.d.ts +8 -6
  153. package/dist/util.js +36 -19
  154. package/dist/util.js.map +1 -1
  155. package/package.json +15 -6
  156. package/roku-debug-0.20.7.tgz +0 -0
  157. package/dist/debugProtocol/Debugger.d.ts +0 -161
  158. package/dist/debugProtocol/Debugger.js +0 -635
  159. package/dist/debugProtocol/Debugger.js.map +0 -1
  160. package/dist/debugProtocol/responses/AddBreakpointsResponse.js.map +0 -1
  161. package/dist/debugProtocol/responses/BreakpointErrorUpdateResponse.d.ts +0 -32
  162. package/dist/debugProtocol/responses/BreakpointErrorUpdateResponse.js +0 -67
  163. package/dist/debugProtocol/responses/BreakpointErrorUpdateResponse.js.map +0 -1
  164. package/dist/debugProtocol/responses/BreakpointVerifiedUpdateResponse.d.ts +0 -32
  165. package/dist/debugProtocol/responses/BreakpointVerifiedUpdateResponse.js +0 -56
  166. package/dist/debugProtocol/responses/BreakpointVerifiedUpdateResponse.js.map +0 -1
  167. package/dist/debugProtocol/responses/ConnectIOPortResponse.d.ts +0 -10
  168. package/dist/debugProtocol/responses/ConnectIOPortResponse.js +0 -39
  169. package/dist/debugProtocol/responses/ConnectIOPortResponse.js.map +0 -1
  170. package/dist/debugProtocol/responses/ExecuteResponseV3.d.ts +0 -23
  171. package/dist/debugProtocol/responses/ExecuteResponseV3.js +0 -54
  172. package/dist/debugProtocol/responses/ExecuteResponseV3.js.map +0 -1
  173. package/dist/debugProtocol/responses/HandshakeResponse.d.ts +0 -12
  174. package/dist/debugProtocol/responses/HandshakeResponse.js +0 -39
  175. package/dist/debugProtocol/responses/HandshakeResponse.js.map +0 -1
  176. package/dist/debugProtocol/responses/HandshakeResponseV3.d.ts +0 -14
  177. package/dist/debugProtocol/responses/HandshakeResponseV3.js +0 -47
  178. package/dist/debugProtocol/responses/HandshakeResponseV3.js.map +0 -1
  179. package/dist/debugProtocol/responses/ListBreakpointsResponse.d.ts +0 -25
  180. package/dist/debugProtocol/responses/ListBreakpointsResponse.js +0 -65
  181. package/dist/debugProtocol/responses/ListBreakpointsResponse.js.map +0 -1
  182. package/dist/debugProtocol/responses/ProtocolEvent.d.ts +0 -11
  183. package/dist/debugProtocol/responses/ProtocolEvent.js +0 -38
  184. package/dist/debugProtocol/responses/ProtocolEvent.js.map +0 -1
  185. package/dist/debugProtocol/responses/ProtocolEventV3.d.ts +0 -11
  186. package/dist/debugProtocol/responses/ProtocolEventV3.js +0 -42
  187. package/dist/debugProtocol/responses/ProtocolEventV3.js.map +0 -1
  188. package/dist/debugProtocol/responses/RemoveBreakpointsResponse.js.map +0 -1
  189. package/dist/debugProtocol/responses/StackTraceResponse.d.ts +0 -18
  190. package/dist/debugProtocol/responses/StackTraceResponse.js +0 -58
  191. package/dist/debugProtocol/responses/StackTraceResponse.js.map +0 -1
  192. package/dist/debugProtocol/responses/StackTraceResponseV3.d.ts +0 -18
  193. package/dist/debugProtocol/responses/StackTraceResponseV3.js +0 -58
  194. package/dist/debugProtocol/responses/StackTraceResponseV3.js.map +0 -1
  195. package/dist/debugProtocol/responses/ThreadsResponse.d.ts +0 -22
  196. package/dist/debugProtocol/responses/ThreadsResponse.js +0 -63
  197. package/dist/debugProtocol/responses/ThreadsResponse.js.map +0 -1
  198. package/dist/debugProtocol/responses/UndefinedResponse.d.ts +0 -10
  199. package/dist/debugProtocol/responses/UndefinedResponse.js +0 -39
  200. package/dist/debugProtocol/responses/UndefinedResponse.js.map +0 -1
  201. package/dist/debugProtocol/responses/UpdateThreadsResponse.d.ts +0 -25
  202. package/dist/debugProtocol/responses/UpdateThreadsResponse.js +0 -91
  203. package/dist/debugProtocol/responses/UpdateThreadsResponse.js.map +0 -1
  204. package/dist/debugProtocol/responses/VariableResponse.d.ts +0 -27
  205. package/dist/debugProtocol/responses/VariableResponse.js +0 -141
  206. package/dist/debugProtocol/responses/VariableResponse.js.map +0 -1
  207. package/dist/debugProtocol/responses/index.d.ts +0 -11
  208. package/dist/debugProtocol/responses/index.js +0 -24
  209. package/dist/debugProtocol/responses/index.js.map +0 -1
  210. package/roku-debug-0.20.5.tgz +0 -0
  211. /package/dist/debugProtocol/{responses → events/responses}/AddBreakpointsResponse.d.ts +0 -0
  212. /package/dist/debugProtocol/{responses → events/responses}/AddBreakpointsResponse.js +0 -0
  213. /package/dist/debugProtocol/{responses → events/responses}/RemoveBreakpointsResponse.d.ts +0 -0
  214. /package/dist/debugProtocol/{responses → events/responses}/RemoveBreakpointsResponse.js +0 -0
@@ -0,0 +1,1079 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isProtocolUpdate = exports.isProtocolResponse = exports.isProtocolRequest = exports.DebugProtocolClient = void 0;
4
+ const Net = require("net");
5
+ const debounce = require("debounce");
6
+ const EventEmitter = require("eventemitter3");
7
+ const semver = require("semver");
8
+ const Constants_1 = require("../Constants");
9
+ const logging_1 = require("../../logging");
10
+ const ExecuteV3Response_1 = require("../events/responses/ExecuteV3Response");
11
+ const ListBreakpointsResponse_1 = require("../events/responses/ListBreakpointsResponse");
12
+ const AddBreakpointsResponse_1 = require("../events/responses/AddBreakpointsResponse");
13
+ const RemoveBreakpointsResponse_1 = require("../events/responses/RemoveBreakpointsResponse");
14
+ const util_1 = require("../../util");
15
+ const BreakpointErrorUpdate_1 = require("../events/updates/BreakpointErrorUpdate");
16
+ const ContinueRequest_1 = require("../events/requests/ContinueRequest");
17
+ const StopRequest_1 = require("../events/requests/StopRequest");
18
+ const ExitChannelRequest_1 = require("../events/requests/ExitChannelRequest");
19
+ const StepRequest_1 = require("../events/requests/StepRequest");
20
+ const RemoveBreakpointsRequest_1 = require("../events/requests/RemoveBreakpointsRequest");
21
+ const ListBreakpointsRequest_1 = require("../events/requests/ListBreakpointsRequest");
22
+ const VariablesRequest_1 = require("../events/requests/VariablesRequest");
23
+ const StackTraceRequest_1 = require("../events/requests/StackTraceRequest");
24
+ const ThreadsRequest_1 = require("../events/requests/ThreadsRequest");
25
+ const ExecuteRequest_1 = require("../events/requests/ExecuteRequest");
26
+ const AddBreakpointsRequest_1 = require("../events/requests/AddBreakpointsRequest");
27
+ const AddConditionalBreakpointsRequest_1 = require("../events/requests/AddConditionalBreakpointsRequest");
28
+ const HandshakeResponse_1 = require("../events/responses/HandshakeResponse");
29
+ const HandshakeV3Response_1 = require("../events/responses/HandshakeV3Response");
30
+ const HandshakeRequest_1 = require("../events/requests/HandshakeRequest");
31
+ const GenericV3Response_1 = require("../events/responses/GenericV3Response");
32
+ const AllThreadsStoppedUpdate_1 = require("../events/updates/AllThreadsStoppedUpdate");
33
+ const CompileErrorUpdate_1 = require("../events/updates/CompileErrorUpdate");
34
+ const GenericResponse_1 = require("../events/responses/GenericResponse");
35
+ const ThreadsResponse_1 = require("../events/responses/ThreadsResponse");
36
+ const VariablesResponse_1 = require("../events/responses/VariablesResponse");
37
+ const IOPortOpenedUpdate_1 = require("../events/updates/IOPortOpenedUpdate");
38
+ const ThreadAttachedUpdate_1 = require("../events/updates/ThreadAttachedUpdate");
39
+ const StackTraceV3Response_1 = require("../events/responses/StackTraceV3Response");
40
+ const ActionQueue_1 = require("../../managers/ActionQueue");
41
+ const PluginInterface_1 = require("../PluginInterface");
42
+ const BreakpointVerifiedUpdate_1 = require("../events/updates/BreakpointVerifiedUpdate");
43
+ class DebugProtocolClient {
44
+ constructor(options) {
45
+ this.logger = logging_1.logger.createLogger(`[client]`);
46
+ // The highest tested version of the protocol we support.
47
+ this.supportedVersionRange = '<=3.0.0';
48
+ this.isHandshakeComplete = false;
49
+ this.connectedToIoPort = false;
50
+ /**
51
+ * Debug protocol version 3.0.0 introduced a packet_length to all responses. Prior to that, most responses had no packet length at all.
52
+ * This field indicates whether we should be looking for packet_length or not in the responses we get from the device
53
+ */
54
+ this.watchPacketLength = false;
55
+ /**
56
+ * A collection of plugins that can interact with the client at lifecycle points
57
+ */
58
+ this.plugins = new PluginInterface_1.default();
59
+ this.emitter = new EventEmitter();
60
+ /**
61
+ * Promise that is resolved when the control socket is closed
62
+ */
63
+ this.controlSocketClosed = (0, util_1.defer)();
64
+ /**
65
+ * Resolves when the ioSocket has closed
66
+ */
67
+ this.ioSocketClosed = (0, util_1.defer)();
68
+ /**
69
+ * The buffer where all unhandled data will be stored until successfully consumed
70
+ */
71
+ this.buffer = Buffer.alloc(0);
72
+ /**
73
+ * Is the debugger currently stopped at a line of code in the program
74
+ */
75
+ this.isStopped = false;
76
+ this.requestIdSequence = 1;
77
+ this.activeRequests = new Map();
78
+ /**
79
+ * A queue for processing the incoming buffer, every transmission at a time
80
+ */
81
+ this.bufferQueue = new ActionQueue_1.ActionQueue();
82
+ /**
83
+ * A counter to help give a unique id to each update (mostly just for logging purposes)
84
+ */
85
+ this.updateSequence = 1;
86
+ this.handleUpdateQueue = new ActionQueue_1.ActionQueue();
87
+ this.isDestroyingControlSocket = false;
88
+ this.isDestroyingIOSocket = false;
89
+ this.options = {
90
+ controlPort: 8081,
91
+ host: undefined,
92
+ //override the defaults with the options from parameters
93
+ ...options !== null && options !== void 0 ? options : {}
94
+ };
95
+ //add the internal plugin last, so it's the final plugin to handle the events
96
+ this.addCorePlugin();
97
+ }
98
+ addCorePlugin() {
99
+ this.plugins.add({
100
+ onUpdate: (event) => {
101
+ return this.handleUpdate(event.update);
102
+ }
103
+ }, 999);
104
+ }
105
+ /**
106
+ * Prior to protocol v3.1.0, the Roku device would regularly set the wrong thread as "active",
107
+ * so this flag lets us know if we should use our better-than-nothing workaround
108
+ */
109
+ get enableThreadHoppingWorkaround() {
110
+ return semver.satisfies(this.protocolVersion, '<3.1.0');
111
+ }
112
+ /**
113
+ * Starting in protocol v3.1.0, component libary breakpoints must be added in the format `lib:/<library_name>/<filepath>`, but prior they didn't require this.
114
+ * So this flag tells us which format to support
115
+ */
116
+ get enableComponentLibrarySpecificBreakpoints() {
117
+ return semver.satisfies(this.protocolVersion, '>=3.1.0');
118
+ }
119
+ /**
120
+ * Starting in protocol v3.1.0, breakpoints can support conditional expressions. This flag indicates whether the current sessuion supports that functionality.
121
+ */
122
+ get supportsConditionalBreakpoints() {
123
+ return semver.satisfies(this.protocolVersion, '>=3.1.0');
124
+ }
125
+ get supportsBreakpointRegistrationWhileRunning() {
126
+ return semver.satisfies(this.protocolVersion, '>=3.2.0');
127
+ }
128
+ get supportsBreakpointVerification() {
129
+ return semver.satisfies(this.protocolVersion, '>=3.2.0');
130
+ }
131
+ once(eventName) {
132
+ return new Promise((resolve) => {
133
+ const disconnect = this.on(eventName, (...args) => {
134
+ disconnect();
135
+ resolve(...args);
136
+ });
137
+ });
138
+ }
139
+ // public on(eventname: 'rendezvous', handler: (output: RendezvousHistory) => void);
140
+ // public on(eventName: 'runtime-error', handler: (error: BrightScriptRuntimeError) => void);
141
+ on(eventName, handler) {
142
+ this.emitter.on(eventName, handler);
143
+ return () => {
144
+ this.emitter.removeListener(eventName, handler);
145
+ };
146
+ }
147
+ emit(eventName, data) {
148
+ //emit these events on next tick, otherwise they will be processed immediately which could cause issues
149
+ setTimeout(() => {
150
+ //in rare cases, this event is fired after the debugger has closed, so make sure the event emitter still exists
151
+ this.emitter.emit(eventName, data);
152
+ }, 0);
153
+ }
154
+ async establishControlConnection() {
155
+ this.pendingControlConnectionSockets = new Set();
156
+ const connection = await new Promise((resolve) => {
157
+ var _a;
158
+ this.cancelControlConnectInterval = util_1.util.setInterval((cancelInterval) => {
159
+ const socket = new Net.Socket({
160
+ allowHalfOpen: false
161
+ });
162
+ this.pendingControlConnectionSockets.add(socket);
163
+ socket.on('error', (error) => {
164
+ console.debug(Date.now(), 'Encountered an error connecting to the debug protocol socket. Ignoring and will try again soon', error);
165
+ });
166
+ socket.connect({ port: this.options.controlPort, host: this.options.host }, () => {
167
+ cancelInterval();
168
+ this.logger.debug(`Connected to debug protocol control port. Socket ${[...this.pendingControlConnectionSockets].indexOf(socket)} of ${this.pendingControlConnectionSockets.size} was the winner`);
169
+ //clean up all remaining pending sockets
170
+ for (const pendingSocket of this.pendingControlConnectionSockets) {
171
+ pendingSocket.removeAllListeners();
172
+ //cleanup and destroy all other sockets
173
+ if (pendingSocket !== socket) {
174
+ pendingSocket.end();
175
+ pendingSocket === null || pendingSocket === void 0 ? void 0 : pendingSocket.destroy();
176
+ }
177
+ }
178
+ this.pendingControlConnectionSockets.clear();
179
+ resolve(socket);
180
+ });
181
+ }, (_a = this.options.controlConnectInterval) !== null && _a !== void 0 ? _a : 250);
182
+ });
183
+ await this.plugins.emit('onServerConnected', {
184
+ client: this,
185
+ server: connection
186
+ });
187
+ return connection;
188
+ }
189
+ /**
190
+ * Connect to the debug server.
191
+ * @param sendHandshake should the handshake be sent as part of this connect process. If false, `.sendHandshake()` will need to be called before a session can begin
192
+ */
193
+ async connect(sendHandshake = true) {
194
+ this.logger.log('connect', this.options);
195
+ // If there is no error, the server has accepted the request and created a new dedicated control socket
196
+ this.controlSocket = await this.establishControlConnection();
197
+ this.controlSocket.on('data', (data) => {
198
+ this.writeToBufferLog('server-to-client', data);
199
+ this.emit('data', data);
200
+ //queue up processing the new data, chunk by chunk
201
+ void this.bufferQueue.run(async () => {
202
+ this.buffer = Buffer.concat([this.buffer, data]);
203
+ while (this.buffer.length > 0 && await this.process()) {
204
+ //the loop condition is the actual work
205
+ }
206
+ return true;
207
+ });
208
+ });
209
+ this.controlSocket.on('close', () => {
210
+ this.logger.log('Control socket closed');
211
+ this.controlSocketClosed.tryResolve();
212
+ void this.shutdown('app-exit');
213
+ });
214
+ // Don't forget to catch error, for your own sake.
215
+ this.controlSocket.once('error', (error) => {
216
+ var _a, _b;
217
+ //the Roku closed the connection for some unknown reason...
218
+ this.logger.error(`error on control port`, error);
219
+ (_b = (_a = this.controlSocket) === null || _a === void 0 ? void 0 : _a.destroy) === null || _b === void 0 ? void 0 : _b.call(_a);
220
+ void this.shutdown('close');
221
+ });
222
+ if (sendHandshake) {
223
+ await this.sendHandshake();
224
+ }
225
+ return true;
226
+ }
227
+ /**
228
+ * Send the initial handshake request, and wait for the handshake response
229
+ */
230
+ async sendHandshake() {
231
+ return this.processHandshakeRequest(HandshakeRequest_1.HandshakeRequest.fromJson({
232
+ magic: DebugProtocolClient.DEBUGGER_MAGIC
233
+ }));
234
+ }
235
+ async processHandshakeRequest(request) {
236
+ //send the magic, which triggers the debug session
237
+ this.logger.log('Sending magic to server');
238
+ //send the handshake request, and wait for the handshake response from the device
239
+ return this.sendRequest(request);
240
+ }
241
+ /**
242
+ * Write a specific buffer log entry to the logger, which, when file logging is enabled
243
+ * can be extracted and processed through the DebugProtocolClientReplaySession
244
+ */
245
+ writeToBufferLog(type, buffer) {
246
+ let obj = {
247
+ type: type,
248
+ timestamp: new Date().toISOString(),
249
+ buffer: buffer.toJSON()
250
+ };
251
+ if (type === 'io') {
252
+ obj.text = buffer.toString();
253
+ }
254
+ this.logger.log('[[bufferLog]]:', JSON.stringify(obj));
255
+ }
256
+ continue() {
257
+ return this.processContinueRequest(ContinueRequest_1.ContinueRequest.fromJson({
258
+ requestId: this.requestIdSequence++
259
+ }));
260
+ }
261
+ async processContinueRequest(request) {
262
+ if (this.isStopped) {
263
+ this.isStopped = false;
264
+ return this.sendRequest(request);
265
+ }
266
+ }
267
+ pause() {
268
+ return this.processStopRequest(StopRequest_1.StopRequest.fromJson({
269
+ requestId: this.requestIdSequence++
270
+ }));
271
+ }
272
+ async processStopRequest(request) {
273
+ if (this.isStopped === false) {
274
+ return this.sendRequest(request);
275
+ }
276
+ }
277
+ /**
278
+ * Send the "exit channel" command, which will tell the debug session to immediately quit
279
+ */
280
+ async exitChannel() {
281
+ return this.sendRequest(ExitChannelRequest_1.ExitChannelRequest.fromJson({
282
+ requestId: this.requestIdSequence++
283
+ }));
284
+ }
285
+ async stepIn(threadIndex = this.primaryThread) {
286
+ return this.step(Constants_1.StepType.Line, threadIndex);
287
+ }
288
+ async stepOver(threadIndex = this.primaryThread) {
289
+ return this.step(Constants_1.StepType.Over, threadIndex);
290
+ }
291
+ async stepOut(threadIndex = this.primaryThread) {
292
+ return this.step(Constants_1.StepType.Out, threadIndex);
293
+ }
294
+ async step(stepType, threadIndex) {
295
+ return this.processStepRequest(StepRequest_1.StepRequest.fromJson({
296
+ requestId: this.requestIdSequence++,
297
+ stepType: stepType,
298
+ threadIndex: threadIndex
299
+ }));
300
+ }
301
+ async processStepRequest(request) {
302
+ if (this.isStopped) {
303
+ this.isStopped = false;
304
+ let stepResult = await this.sendRequest(request);
305
+ if (stepResult.data.errorCode === Constants_1.ErrorCode.OK) {
306
+ this.isStopped = true;
307
+ //TODO this is not correct. Do we get a new threads event after a step? Perhaps that should be what triggers the event instead of us?
308
+ this.emit('suspend', stepResult);
309
+ }
310
+ else {
311
+ // there is a CANT_CONTINUE error code but we can likely treat all errors like a CANT_CONTINUE
312
+ this.emit('cannot-continue');
313
+ }
314
+ return stepResult;
315
+ }
316
+ else {
317
+ this.logger.log('[processStepRequest] skipped because debugger is not paused');
318
+ }
319
+ }
320
+ async threads() {
321
+ return this.processThreadsRequest(ThreadsRequest_1.ThreadsRequest.fromJson({
322
+ requestId: this.requestIdSequence++
323
+ }));
324
+ }
325
+ async processThreadsRequest(request) {
326
+ if (this.isStopped) {
327
+ let result = await this.sendRequest(request);
328
+ if (result.data.errorCode === Constants_1.ErrorCode.OK) {
329
+ //older versions of the debug protocol had issues with maintaining the active thread, so our workaround is to keep track of it elsewhere
330
+ if (this.enableThreadHoppingWorkaround) {
331
+ //ignore the `isPrimary` flag on threads
332
+ this.logger.debug(`Ignoring the 'isPrimary' flag from threads because protocol version 3.0.0 and lower has a bug`);
333
+ }
334
+ else {
335
+ //trust the debug protocol's `isPrimary` flag on threads
336
+ for (let i = 0; i < result.data.threads.length; i++) {
337
+ let thread = result.data.threads[i];
338
+ if (thread.isPrimary) {
339
+ this.primaryThread = i;
340
+ break;
341
+ }
342
+ }
343
+ }
344
+ }
345
+ return result;
346
+ }
347
+ else {
348
+ this.logger.log('[processThreadsRequest] skipped because not stopped');
349
+ }
350
+ }
351
+ /**
352
+ * Get the stackTrace from the device IF currently stopped
353
+ */
354
+ async getStackTrace(threadIndex = this.primaryThread) {
355
+ return this.processStackTraceRequest(StackTraceRequest_1.StackTraceRequest.fromJson({
356
+ requestId: this.requestIdSequence++,
357
+ threadIndex: threadIndex
358
+ }));
359
+ }
360
+ async processStackTraceRequest(request) {
361
+ var _a, _b;
362
+ if (!this.isStopped) {
363
+ this.logger.log('[getStackTrace] skipped because debugger is not paused');
364
+ }
365
+ else if (((_a = request === null || request === void 0 ? void 0 : request.data) === null || _a === void 0 ? void 0 : _a.threadIndex) > -1) {
366
+ return this.sendRequest(request);
367
+ }
368
+ else {
369
+ this.logger.log(`[getStackTrace] skipped because ${(_b = request === null || request === void 0 ? void 0 : request.data) === null || _b === void 0 ? void 0 : _b.threadIndex} is not valid threadIndex`);
370
+ }
371
+ }
372
+ /**
373
+ * @param variablePathEntries One or more path entries to the variable to be inspected. E.g., m.top.myObj["someKey"] can be accessed with ["m","top","myobj","\"someKey\""].
374
+ *
375
+ * If no path is specified, the variables accessible from the specified stack frame are returned.
376
+ *
377
+ * Starting in protocol v3.1.0, The keys for indexed gets (i.e. obj["key"]) should be wrapped in quotes so they can be handled in a case-sensitive fashion (if applicable on device).
378
+ * All non-quoted keys (i.e. strings without leading and trailing quotes inside them) will be treated as case-insensitive).
379
+ * @param getChildKeys If set, VARIABLES response include the child keys for container types like lists and associative arrays
380
+ * @param stackFrameIndex 0 = first function called, nframes-1 = last function. This indexing does not match the order of the frames returned from the STACKTRACE command
381
+ * @param threadIndex the index (or perhaps ID?) of the thread to get variables for
382
+ */
383
+ async getVariables(variablePathEntries = [], stackFrameIndex = this.stackFrameIndex, threadIndex = this.primaryThread) {
384
+ const response = await this.processVariablesRequest(VariablesRequest_1.VariablesRequest.fromJson({
385
+ requestId: this.requestIdSequence++,
386
+ threadIndex: threadIndex,
387
+ stackFrameIndex: stackFrameIndex,
388
+ getChildKeys: true,
389
+ variablePathEntries: variablePathEntries.map(x => ({
390
+ //remove leading and trailing quotes
391
+ name: x.replace(/^"/, '').replace(/"$/, ''),
392
+ forceCaseInsensitive: !x.startsWith('"') && !x.endsWith('"')
393
+ })),
394
+ //starting in protocol v3.1.0, it supports marking certain path items as case-insensitive (i.e. parts of DottedGet expressions)
395
+ enableForceCaseInsensitivity: semver.satisfies(this.protocolVersion, '>=3.1.0') && variablePathEntries.length > 0
396
+ }));
397
+ //if there was an issue, build a "fake" variables response for several known situationsm or throw nicer errors
398
+ if (util_1.util.hasNonNullishProperty(response === null || response === void 0 ? void 0 : response.data.errorData)) {
399
+ let variable = {
400
+ value: null,
401
+ isContainer: false,
402
+ isConst: false,
403
+ refCount: 0,
404
+ childCount: 0
405
+ };
406
+ const simulatedResponse = VariablesResponse_1.VariablesResponse.fromJson({
407
+ ...response.data,
408
+ variables: [variable]
409
+ });
410
+ let parentVarType;
411
+ let parentVarTypeText;
412
+ const loadParentVarInfo = async (index) => {
413
+ var _a, _b, _c, _d, _e, _f, _g;
414
+ //fetch the variable one level back from the bad one to get its type
415
+ const parentVar = await this.getVariables(variablePathEntries.slice(0, index), stackFrameIndex, threadIndex);
416
+ parentVarType = (_c = (_b = (_a = parentVar === null || parentVar === void 0 ? void 0 : parentVar.data) === null || _a === void 0 ? void 0 : _a.variables) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.type;
417
+ parentVarTypeText = parentVarType;
418
+ //convert `roSGNode; Node` to `roSGNode (Node)`
419
+ if (parentVarType === VariablesResponse_1.VariableType.SubtypedObject) {
420
+ const chunks = (_g = (_f = (_e = (_d = parentVar === null || parentVar === void 0 ? void 0 : parentVar.data) === null || _d === void 0 ? void 0 : _d.variables) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.value) === null || _g === void 0 ? void 0 : _g.toString().split(';').map(x => x.trim());
421
+ parentVarTypeText = `${chunks[0]} (${chunks[1]})`;
422
+ }
423
+ };
424
+ if (!util_1.util.isNullish(response.data.errorData.missingKeyIndex)) {
425
+ const { missingKeyIndex } = response.data.errorData;
426
+ //leftmost var is uninitialized, and we tried to read it
427
+ //ex: variablePathEntries = [`notThere`]
428
+ if (variablePathEntries.length === 1 && missingKeyIndex === 0) {
429
+ variable.name = variablePathEntries[0];
430
+ variable.type = VariablesResponse_1.VariableType.Uninitialized;
431
+ return simulatedResponse;
432
+ }
433
+ //leftmost var was uninitialized, and tried to read a prop on it
434
+ //ex: variablePathEntries = ["notThere", "definitelyNotThere"]
435
+ if (missingKeyIndex === 0 && variablePathEntries.length > 1) {
436
+ throw new Error(`Cannot read '${variablePathEntries[missingKeyIndex + 1]}' on type 'Uninitialized'`);
437
+ }
438
+ if (variablePathEntries.length > 1 && missingKeyIndex > 0) {
439
+ await loadParentVarInfo(missingKeyIndex);
440
+ // prop at the end of Node or AA doesn't exist. Treat like `invalid`.
441
+ // ex: variablePathEntries = ['there', 'notThere']
442
+ if (missingKeyIndex === variablePathEntries.length - 1 &&
443
+ [VariablesResponse_1.VariableType.AssociativeArray, VariablesResponse_1.VariableType.SubtypedObject].includes(parentVarType)) {
444
+ variable.name = variablePathEntries[variablePathEntries.length - 1];
445
+ variable.type = VariablesResponse_1.VariableType.Invalid;
446
+ variable.value = 'Invalid (not defined)';
447
+ return simulatedResponse;
448
+ }
449
+ }
450
+ //prop in the middle is missing, tried reading a prop on it
451
+ // ex: variablePathEntries = ["there", "notThere", "definitelyNotThere"]
452
+ throw new Error(`Cannot read '${variablePathEntries[missingKeyIndex]}'${parentVarType ? ` on type '${parentVarTypeText}'` : ''}`);
453
+ }
454
+ //this flow is when the item at the index exists, but is set to literally `invalid` or is an unknown value
455
+ if (!util_1.util.isNullish(response.data.errorData.invalidPathIndex)) {
456
+ const { invalidPathIndex } = response.data.errorData;
457
+ //leftmost var is literal `invalid`, tried to read it
458
+ if (variablePathEntries.length === 1 && invalidPathIndex === 0) {
459
+ variable.name = variablePathEntries[variablePathEntries.length - 1];
460
+ variable.type = VariablesResponse_1.VariableType.Invalid;
461
+ return simulatedResponse;
462
+ }
463
+ if (variablePathEntries.length > 1 &&
464
+ invalidPathIndex > 0 &&
465
+ //only do this logic if the invalid item is not the last item
466
+ invalidPathIndex < variablePathEntries.length - 1) {
467
+ await loadParentVarInfo(invalidPathIndex + 1);
468
+ //leftmost var is set to literal `invalid`, tried to read prop
469
+ if (invalidPathIndex === 0 && variablePathEntries.length > 1) {
470
+ throw new Error(`Cannot read '${variablePathEntries[invalidPathIndex + 1]}' on type '${parentVarTypeText}'`);
471
+ }
472
+ // prop at the end doesn't exist. Treat like `invalid`.
473
+ // ex: variablePathEntries = ['there', 'notThere']
474
+ if (invalidPathIndex === variablePathEntries.length - 1 &&
475
+ [VariablesResponse_1.VariableType.AssociativeArray, VariablesResponse_1.VariableType.SubtypedObject].includes(parentVarType)) {
476
+ variable.name = variablePathEntries[variablePathEntries.length - 1];
477
+ variable.type = VariablesResponse_1.VariableType.Invalid;
478
+ variable.value = 'Invalid (not defined)';
479
+ return simulatedResponse;
480
+ }
481
+ }
482
+ console.log('Bronley');
483
+ //prop in the middle is missing, tried reading a prop on it
484
+ // ex: variablePathEntries = ["there", "thereButSetToInvalid", "definitelyNotThere"]
485
+ throw new Error(`Cannot read '${variablePathEntries[invalidPathIndex + 1]}'${parentVarType ? ` on type '${parentVarTypeText}'` : ''}`);
486
+ }
487
+ }
488
+ return response;
489
+ }
490
+ async processVariablesRequest(request) {
491
+ if (this.isStopped && request.data.threadIndex > -1) {
492
+ return this.sendRequest(request);
493
+ }
494
+ }
495
+ async executeCommand(sourceCode, stackFrameIndex = this.stackFrameIndex, threadIndex = this.primaryThread) {
496
+ return this.processExecuteRequest(ExecuteRequest_1.ExecuteRequest.fromJson({
497
+ requestId: this.requestIdSequence++,
498
+ threadIndex: threadIndex,
499
+ stackFrameIndex: stackFrameIndex,
500
+ sourceCode: sourceCode
501
+ }));
502
+ }
503
+ async processExecuteRequest(request) {
504
+ if (this.isStopped && request.data.threadIndex > -1) {
505
+ return this.sendRequest(request);
506
+ }
507
+ }
508
+ async addBreakpoints(breakpoints) {
509
+ const { enableComponentLibrarySpecificBreakpoints } = this;
510
+ if ((breakpoints === null || breakpoints === void 0 ? void 0 : breakpoints.length) > 0) {
511
+ const json = {
512
+ requestId: this.requestIdSequence++,
513
+ breakpoints: breakpoints.map(x => {
514
+ let breakpoint = {
515
+ ...x,
516
+ ignoreCount: x.hitCount
517
+ };
518
+ if (enableComponentLibrarySpecificBreakpoints && breakpoint.componentLibraryName) {
519
+ breakpoint.filePath = breakpoint.filePath.replace(/^pkg:\//i, `lib:/${breakpoint.componentLibraryName}/`);
520
+ }
521
+ return breakpoint;
522
+ })
523
+ };
524
+ const useConditionalBreakpoints = (
525
+ //does this protocol version support conditional breakpoints?
526
+ this.supportsConditionalBreakpoints &&
527
+ //is there at least one conditional breakpoint present?
528
+ !!breakpoints.find(x => { var _a; return !!((_a = x === null || x === void 0 ? void 0 : x.conditionalExpression) === null || _a === void 0 ? void 0 : _a.trim()); }));
529
+ let response;
530
+ if (useConditionalBreakpoints) {
531
+ response = await this.sendRequest(AddConditionalBreakpointsRequest_1.AddConditionalBreakpointsRequest.fromJson(json));
532
+ }
533
+ else {
534
+ response = await this.sendRequest(AddBreakpointsRequest_1.AddBreakpointsRequest.fromJson(json));
535
+ }
536
+ //if the device does not support breakpoint verification, then auto-mark all of these as verified
537
+ if (!this.supportsBreakpointVerification) {
538
+ this.emit('breakpoints-verified', {
539
+ breakpoints: response.data.breakpoints
540
+ });
541
+ }
542
+ return response;
543
+ }
544
+ return AddBreakpointsResponse_1.AddBreakpointsResponse.fromBuffer(null);
545
+ }
546
+ async listBreakpoints() {
547
+ return this.processRequest(ListBreakpointsRequest_1.ListBreakpointsRequest.fromJson({
548
+ requestId: this.requestIdSequence++
549
+ }));
550
+ }
551
+ /**
552
+ * Remove breakpoints having the specified IDs
553
+ */
554
+ async removeBreakpoints(breakpointIds) {
555
+ return this.processRemoveBreakpointsRequest(RemoveBreakpointsRequest_1.RemoveBreakpointsRequest.fromJson({
556
+ requestId: this.requestIdSequence++,
557
+ breakpointIds: breakpointIds
558
+ }));
559
+ }
560
+ async processRemoveBreakpointsRequest(request) {
561
+ var _a, _b, _c;
562
+ //throw out null breakpoints
563
+ request.data.breakpointIds = (_b = (_a = request.data.breakpointIds) === null || _a === void 0 ? void 0 : _a.filter(x => typeof x === 'number')) !== null && _b !== void 0 ? _b : [];
564
+ if (((_c = request.data.breakpointIds) === null || _c === void 0 ? void 0 : _c.length) > 0) {
565
+ return this.sendRequest(request);
566
+ }
567
+ return RemoveBreakpointsResponse_1.RemoveBreakpointsResponse.fromJson(null);
568
+ }
569
+ /**
570
+ * Given a request, process it in the proper fashion. This is mostly used for external mocking/testing of
571
+ * this client, but it should force the client to flow in the same fashion as a live debug session
572
+ */
573
+ async processRequest(request) {
574
+ switch (request === null || request === void 0 ? void 0 : request.constructor.name) {
575
+ case ContinueRequest_1.ContinueRequest.name:
576
+ return this.processContinueRequest(request);
577
+ case ExecuteRequest_1.ExecuteRequest.name:
578
+ return this.processExecuteRequest(request);
579
+ case HandshakeRequest_1.HandshakeRequest.name:
580
+ return this.processHandshakeRequest(request);
581
+ case RemoveBreakpointsRequest_1.RemoveBreakpointsRequest.name:
582
+ return this.processRemoveBreakpointsRequest(request);
583
+ case StackTraceRequest_1.StackTraceRequest.name:
584
+ return this.processStackTraceRequest(request);
585
+ case StepRequest_1.StepRequest.name:
586
+ return this.processStepRequest(request);
587
+ case StopRequest_1.StopRequest.name:
588
+ return this.processStopRequest(request);
589
+ case ThreadsRequest_1.ThreadsRequest.name:
590
+ return this.processThreadsRequest(request);
591
+ case VariablesRequest_1.VariablesRequest.name:
592
+ return this.processVariablesRequest(request);
593
+ //for all other request types, there's no custom business logic, so just pipe them through manually
594
+ case AddBreakpointsRequest_1.AddBreakpointsRequest.name:
595
+ case AddConditionalBreakpointsRequest_1.AddConditionalBreakpointsRequest.name:
596
+ case ExitChannelRequest_1.ExitChannelRequest.name:
597
+ case ListBreakpointsRequest_1.ListBreakpointsRequest.name:
598
+ return this.sendRequest(request);
599
+ default:
600
+ this.logger.log('Unknown request type. Sending anyway...', request);
601
+ //unknown request type. try sending it as-is
602
+ return this.sendRequest(request);
603
+ }
604
+ }
605
+ /**
606
+ * Send a request to the roku device, and get a promise that resolves once we have received the response
607
+ */
608
+ async sendRequest(request) {
609
+ request = (await this.plugins.emit('beforeSendRequest', {
610
+ client: this,
611
+ request: request
612
+ })).request;
613
+ this.activeRequests.set(request.data.requestId, request);
614
+ return new Promise((resolve, reject) => {
615
+ let unsubscribe = this.on('response', (response) => {
616
+ if (response.data.requestId === request.data.requestId) {
617
+ unsubscribe();
618
+ this.activeRequests.delete(request.data.requestId);
619
+ resolve(response);
620
+ }
621
+ });
622
+ this.logEvent(request);
623
+ if (this.controlSocket) {
624
+ const buffer = request.toBuffer();
625
+ this.writeToBufferLog('client-to-server', buffer);
626
+ this.controlSocket.write(buffer);
627
+ void this.plugins.emit('afterSendRequest', {
628
+ client: this,
629
+ request: request
630
+ });
631
+ }
632
+ else {
633
+ reject(new Error(`Control socket was closed - Command: ${Constants_1.Command[request.data.command]}`));
634
+ }
635
+ });
636
+ }
637
+ /**
638
+ * Sometimes a request arrives that we don't understand. If that's the case, this function can be used
639
+ * to discard that entire response by discarding `packet_length` number of bytes
640
+ */
641
+ discardNextResponseOrUpdate() {
642
+ const response = GenericV3Response_1.GenericV3Response.fromBuffer(this.buffer);
643
+ if (response.success && response.data.packetLength > 0) {
644
+ this.logger.warn(`Unsupported response or updated encountered. Discarding ${response.data.packetLength} bytes:`, JSON.stringify(this.buffer.slice(0, response.data.packetLength + 1).toJSON().data));
645
+ //we have a valid event. Clear the buffer of this data
646
+ this.buffer = this.buffer.slice(response.data.packetLength);
647
+ }
648
+ }
649
+ logEvent(event) {
650
+ var _a;
651
+ const [, eventName, eventType] = (_a = /(.+?)((?:v\d+_?\d*)?(?:request|response|update))/ig.exec(event === null || event === void 0 ? void 0 : event.constructor.name)) !== null && _a !== void 0 ? _a : [];
652
+ if (isProtocolRequest(event)) {
653
+ this.logger.log(`${eventName} ${event.data.requestId} (${eventType})`, event, `(${event === null || event === void 0 ? void 0 : event.constructor.name})`);
654
+ }
655
+ else if (isProtocolUpdate(event)) {
656
+ this.logger.log(`${eventName} ${this.updateSequence++} (${eventType})`, event, `(${event === null || event === void 0 ? void 0 : event.constructor.name})`);
657
+ }
658
+ else {
659
+ if (event.data.errorCode === Constants_1.ErrorCode.OK) {
660
+ this.logger.log(`${eventName} ${event.data.requestId} (${eventType})`, event, `(${event === null || event === void 0 ? void 0 : event.constructor.name})`);
661
+ }
662
+ else {
663
+ this.logger.log(`[error] ${eventName} ${event.data.requestId} (${eventType})`, event, `(${event === null || event === void 0 ? void 0 : event.constructor.name})`);
664
+ }
665
+ }
666
+ }
667
+ async process() {
668
+ var _a;
669
+ try {
670
+ this.logger.info('[process()]: buffer=', this.buffer.toJSON());
671
+ let { responseOrUpdate } = await this.plugins.emit('provideResponseOrUpdate', {
672
+ client: this,
673
+ activeRequests: this.activeRequests,
674
+ buffer: this.buffer
675
+ });
676
+ if (!responseOrUpdate) {
677
+ responseOrUpdate = await this.getResponseOrUpdate(this.buffer);
678
+ }
679
+ //if the event failed to parse, or the buffer doesn't have enough bytes to satisfy the packetLength, exit here (new data will re-trigger this function)
680
+ if (!responseOrUpdate) {
681
+ this.logger.info('Unable to convert buffer into anything meaningful', this.buffer);
682
+ //if we have packet length, and we have at least that many bytes, throw out this message so we can hopefully recover
683
+ this.discardNextResponseOrUpdate();
684
+ return false;
685
+ }
686
+ if (!responseOrUpdate.success || responseOrUpdate.data.packetLength > this.buffer.length) {
687
+ this.logger.log(`event parse failed. ${(_a = responseOrUpdate === null || responseOrUpdate === void 0 ? void 0 : responseOrUpdate.data) === null || _a === void 0 ? void 0 : _a.packetLength} bytes required, ${this.buffer.length} bytes available`);
688
+ return false;
689
+ }
690
+ //we have a valid event. Remove this data from the buffer
691
+ this.buffer = this.buffer.slice(responseOrUpdate.readOffset);
692
+ if (responseOrUpdate.data.errorCode !== Constants_1.ErrorCode.OK) {
693
+ this.logEvent(responseOrUpdate);
694
+ }
695
+ //we got a result
696
+ if (responseOrUpdate) {
697
+ //emit the corresponding event
698
+ if (isProtocolUpdate(responseOrUpdate)) {
699
+ this.logEvent(responseOrUpdate);
700
+ this.emit('update', responseOrUpdate);
701
+ await this.plugins.emit('onUpdate', {
702
+ client: this,
703
+ update: responseOrUpdate
704
+ });
705
+ }
706
+ else {
707
+ this.logEvent(responseOrUpdate);
708
+ this.emit('response', responseOrUpdate);
709
+ await this.plugins.emit('onResponse', {
710
+ client: this,
711
+ response: responseOrUpdate
712
+ });
713
+ }
714
+ return true;
715
+ }
716
+ }
717
+ catch (e) {
718
+ this.logger.error(`process() failed:`, e);
719
+ }
720
+ }
721
+ /**
722
+ * Given a buffer, try to parse into a specific ProtocolResponse or ProtocolUpdate
723
+ */
724
+ async getResponseOrUpdate(buffer) {
725
+ //if we haven't seen a handshake yet, try to convert the buffer into a handshake
726
+ if (!this.isHandshakeComplete) {
727
+ let handshake;
728
+ //try building the v3 handshake response first
729
+ handshake = HandshakeV3Response_1.HandshakeV3Response.fromBuffer(buffer);
730
+ //we didn't get a v3 handshake. try building an older handshake response
731
+ if (!handshake.success) {
732
+ handshake = HandshakeResponse_1.HandshakeResponse.fromBuffer(buffer);
733
+ }
734
+ if (handshake.success) {
735
+ await this.verifyHandshake(handshake);
736
+ return handshake;
737
+ }
738
+ return;
739
+ }
740
+ let genericResponse = this.watchPacketLength ? GenericV3Response_1.GenericV3Response.fromBuffer(buffer) : GenericResponse_1.GenericResponse.fromBuffer(buffer);
741
+ //if the response has a non-OK error code, we won't receive the expected response type,
742
+ //so return the generic response
743
+ if (genericResponse.success && genericResponse.data.errorCode !== Constants_1.ErrorCode.OK) {
744
+ return genericResponse;
745
+ }
746
+ // a nonzero requestId means this is a response to a request that we sent
747
+ if (genericResponse.data.requestId !== 0) {
748
+ //requestId 0 means this is an update
749
+ const request = this.activeRequests.get(genericResponse.data.requestId);
750
+ if (request) {
751
+ return DebugProtocolClient.getResponse(this.buffer, request.data.command);
752
+ }
753
+ }
754
+ else {
755
+ return this.getUpdate(this.buffer);
756
+ }
757
+ }
758
+ static getResponse(buffer, command) {
759
+ switch (command) {
760
+ case Constants_1.Command.Stop:
761
+ case Constants_1.Command.Continue:
762
+ case Constants_1.Command.Step:
763
+ case Constants_1.Command.ExitChannel:
764
+ return GenericV3Response_1.GenericV3Response.fromBuffer(buffer);
765
+ case Constants_1.Command.Execute:
766
+ return ExecuteV3Response_1.ExecuteV3Response.fromBuffer(buffer);
767
+ case Constants_1.Command.AddBreakpoints:
768
+ case Constants_1.Command.AddConditionalBreakpoints:
769
+ return AddBreakpointsResponse_1.AddBreakpointsResponse.fromBuffer(buffer);
770
+ case Constants_1.Command.ListBreakpoints:
771
+ return ListBreakpointsResponse_1.ListBreakpointsResponse.fromBuffer(buffer);
772
+ case Constants_1.Command.RemoveBreakpoints:
773
+ return RemoveBreakpointsResponse_1.RemoveBreakpointsResponse.fromBuffer(buffer);
774
+ case Constants_1.Command.Variables:
775
+ return VariablesResponse_1.VariablesResponse.fromBuffer(buffer);
776
+ case Constants_1.Command.StackTrace:
777
+ return StackTraceV3Response_1.StackTraceV3Response.fromBuffer(buffer);
778
+ case Constants_1.Command.Threads:
779
+ return ThreadsResponse_1.ThreadsResponse.fromBuffer(buffer);
780
+ default:
781
+ return undefined;
782
+ }
783
+ }
784
+ getUpdate(buffer) {
785
+ var _a, _b, _c, _d;
786
+ //read the update_type from the buffer (save some buffer parsing time by narrowing to the exact update type)
787
+ const updateTypeCode = buffer.readUInt32LE(
788
+ // if the protocol supports packet length, then update_type is bytes 12-16. Otherwise, it's bytes 8-12
789
+ this.watchPacketLength ? 12 : 8);
790
+ const updateType = Constants_1.UpdateTypeCode[updateTypeCode];
791
+ (_a = this.logger) === null || _a === void 0 ? void 0 : _a.log('getUpdate(): update Type:', updateType);
792
+ switch (updateType) {
793
+ case Constants_1.UpdateType.IOPortOpened:
794
+ //TODO handle this
795
+ return IOPortOpenedUpdate_1.IOPortOpenedUpdate.fromBuffer(buffer);
796
+ case Constants_1.UpdateType.AllThreadsStopped:
797
+ return AllThreadsStoppedUpdate_1.AllThreadsStoppedUpdate.fromBuffer(buffer);
798
+ case Constants_1.UpdateType.ThreadAttached:
799
+ return ThreadAttachedUpdate_1.ThreadAttachedUpdate.fromBuffer(buffer);
800
+ case Constants_1.UpdateType.BreakpointError:
801
+ //we do nothing with breakpoint errors at this time.
802
+ return BreakpointErrorUpdate_1.BreakpointErrorUpdate.fromBuffer(buffer);
803
+ case Constants_1.UpdateType.CompileError:
804
+ let compileErrorUpdate = CompileErrorUpdate_1.CompileErrorUpdate.fromBuffer(buffer);
805
+ if (((_b = compileErrorUpdate === null || compileErrorUpdate === void 0 ? void 0 : compileErrorUpdate.data) === null || _b === void 0 ? void 0 : _b.errorMessage) !== '') {
806
+ this.emit('compile-error', compileErrorUpdate);
807
+ }
808
+ return compileErrorUpdate;
809
+ case Constants_1.UpdateType.BreakpointVerified:
810
+ let response = BreakpointVerifiedUpdate_1.BreakpointVerifiedUpdate.fromBuffer(buffer);
811
+ if (((_d = (_c = response === null || response === void 0 ? void 0 : response.data) === null || _c === void 0 ? void 0 : _c.breakpoints) === null || _d === void 0 ? void 0 : _d.length) > 0) {
812
+ this.emit('breakpoints-verified', response.data);
813
+ }
814
+ return response;
815
+ default:
816
+ return undefined;
817
+ }
818
+ }
819
+ /**
820
+ * Handle/process any received updates from the debug protocol
821
+ */
822
+ async handleUpdate(update) {
823
+ return this.handleUpdateQueue.run(async () => {
824
+ update = (await this.plugins.emit('beforeHandleUpdate', {
825
+ client: this,
826
+ update: update
827
+ })).update;
828
+ if (update instanceof AllThreadsStoppedUpdate_1.AllThreadsStoppedUpdate || update instanceof ThreadAttachedUpdate_1.ThreadAttachedUpdate) {
829
+ this.isStopped = true;
830
+ let eventName;
831
+ if (update.data.stopReason === Constants_1.StopReason.RuntimeError) {
832
+ eventName = 'runtime-error';
833
+ }
834
+ else {
835
+ eventName = 'suspend';
836
+ }
837
+ const isValidStopReason = [Constants_1.StopReason.RuntimeError, Constants_1.StopReason.Break, Constants_1.StopReason.StopStatement].includes(update.data.stopReason);
838
+ if (update instanceof AllThreadsStoppedUpdate_1.AllThreadsStoppedUpdate && isValidStopReason) {
839
+ this.primaryThread = update.data.threadIndex;
840
+ this.stackFrameIndex = 0;
841
+ this.emit(eventName, update);
842
+ }
843
+ else if (update instanceof ThreadAttachedUpdate_1.ThreadAttachedUpdate && isValidStopReason) {
844
+ this.primaryThread = update.data.threadIndex;
845
+ this.emit(eventName, update);
846
+ }
847
+ }
848
+ else if ((0, IOPortOpenedUpdate_1.isIOPortOpenedUpdate)(update)) {
849
+ this.connectToIoPort(update);
850
+ }
851
+ return true;
852
+ });
853
+ }
854
+ /**
855
+ * Verify all the handshake data
856
+ */
857
+ async verifyHandshake(response) {
858
+ if (DebugProtocolClient.DEBUGGER_MAGIC === response.data.magic) {
859
+ this.logger.log('Magic is valid.');
860
+ this.protocolVersion = response.data.protocolVersion;
861
+ this.logger.log('Protocol Version:', this.protocolVersion);
862
+ this.watchPacketLength = semver.satisfies(this.protocolVersion, '>=3.0.0');
863
+ this.isHandshakeComplete = true;
864
+ let handshakeVerified = true;
865
+ if (semver.satisfies(this.protocolVersion, this.supportedVersionRange)) {
866
+ this.logger.log('supported');
867
+ this.emit('protocol-version', {
868
+ message: `Protocol Version ${this.protocolVersion} is supported!`,
869
+ errorCode: Constants_1.PROTOCOL_ERROR_CODES.SUPPORTED
870
+ });
871
+ }
872
+ else if (semver.gtr(this.protocolVersion, this.supportedVersionRange)) {
873
+ this.logger.log('roku-debug has not been tested against protocol version', this.protocolVersion);
874
+ this.emit('protocol-version', {
875
+ message: `Protocol Version ${this.protocolVersion} has not been tested and my not work as intended.\nPlease open any issues you have with this version to https://github.com/rokucommunity/roku-debug/issues`,
876
+ errorCode: Constants_1.PROTOCOL_ERROR_CODES.NOT_TESTED
877
+ });
878
+ }
879
+ else {
880
+ this.logger.log('not supported');
881
+ this.emit('protocol-version', {
882
+ message: `Protocol Version ${this.protocolVersion} is not supported.\nIf you believe this is an error please open an issue at https://github.com/rokucommunity/roku-debug/issues`,
883
+ errorCode: Constants_1.PROTOCOL_ERROR_CODES.NOT_SUPPORTED
884
+ });
885
+ await this.shutdown('close');
886
+ handshakeVerified = false;
887
+ }
888
+ this.emit('handshake-verified', handshakeVerified);
889
+ return handshakeVerified;
890
+ }
891
+ else {
892
+ this.logger.log('Closing connection due to bad debugger magic', response.data.magic);
893
+ this.emit('handshake-verified', false);
894
+ await this.shutdown('close');
895
+ return false;
896
+ }
897
+ }
898
+ /**
899
+ * When the debugger emits the IOPortOpenedUpdate, we need to immediately connect to the IO port to start receiving that data
900
+ */
901
+ connectToIoPort(update) {
902
+ if (update.success) {
903
+ // Create a new TCP client.
904
+ this.ioSocket = new Net.Socket({
905
+ allowHalfOpen: false
906
+ });
907
+ // Send a connection request to the server.
908
+ this.logger.log(`Connect to IO Port ${this.options.host}:${update.data.port}`);
909
+ //sometimes the server shuts down before we had a chance to connect, so recover more gracefully
910
+ try {
911
+ this.ioSocket.connect({
912
+ port: update.data.port,
913
+ host: this.options.host
914
+ }, () => {
915
+ // If there is no error, the server has accepted the request
916
+ this.logger.log('TCP connection established with the IO Port.');
917
+ this.connectedToIoPort = true;
918
+ let lastPartialLine = '';
919
+ this.ioSocket.on('data', (buffer) => {
920
+ this.writeToBufferLog('io', buffer);
921
+ let responseText = buffer.toString();
922
+ if (!responseText.endsWith('\n')) {
923
+ // buffer was split, save the partial line
924
+ lastPartialLine += responseText;
925
+ }
926
+ else {
927
+ if (lastPartialLine) {
928
+ // there was leftover lines, join the partial lines back together
929
+ responseText = lastPartialLine + responseText;
930
+ lastPartialLine = '';
931
+ }
932
+ // Emit the completed io string.
933
+ this.emit('io-output', responseText.trim());
934
+ }
935
+ });
936
+ this.ioSocket.on('close', () => {
937
+ this.logger.log('IO socket closed');
938
+ this.ioSocketClosed.tryResolve();
939
+ });
940
+ // Don't forget to catch error, for your own sake.
941
+ this.ioSocket.once('error', (err) => {
942
+ this.ioSocket.end();
943
+ this.logger.error(err);
944
+ });
945
+ });
946
+ return true;
947
+ }
948
+ catch (e) {
949
+ this.logger.error(`Failed to connect to IO socket at ${this.options.host}:${update.data.port}`, e);
950
+ void this.shutdown('app-exit');
951
+ }
952
+ }
953
+ return false;
954
+ }
955
+ /**
956
+ * Destroy this instance, shutting down any sockets or other long-running items and cleaning up.
957
+ * @param immediate if true, all sockets are immediately closed and do not gracefully shut down
958
+ */
959
+ async destroy(immediate = false) {
960
+ await this.shutdown('close', immediate);
961
+ }
962
+ async shutdown(eventName, immediate = false) {
963
+ var _a, _b, _c, _d, _e, _f;
964
+ this.logger.log('Shutting down!');
965
+ (_a = this.cancelControlConnectInterval) === null || _a === void 0 ? void 0 : _a.call(this);
966
+ for (const pendingSocket of this.pendingControlConnectionSockets) {
967
+ pendingSocket.removeAllListeners();
968
+ //cleanup and destroy all other sockets
969
+ if (pendingSocket !== this.controlSocket) {
970
+ pendingSocket.end();
971
+ pendingSocket === null || pendingSocket === void 0 ? void 0 : pendingSocket.destroy();
972
+ }
973
+ }
974
+ let exitChannelTimeout = (_c = (_b = this.options) === null || _b === void 0 ? void 0 : _b.exitChannelTimeout) !== null && _c !== void 0 ? _c : 30000;
975
+ let shutdownTimeMax = (_e = (_d = this.options) === null || _d === void 0 ? void 0 : _d.shutdownTimeout) !== null && _e !== void 0 ? _e : 10000;
976
+ //if immediate is true, this is an instant shutdown force. don't wait for anything
977
+ if (immediate) {
978
+ exitChannelTimeout = 0;
979
+ shutdownTimeMax = 0;
980
+ }
981
+ //tell the device to exit the channel
982
+ try {
983
+ //ask the device to terminate the debug session. We have to wait for this to come back.
984
+ //The device might be running unstoppable code, so this might take a while. Wait for the device to send back
985
+ //the response before we continue with the teardown process
986
+ await Promise.race([
987
+ immediate
988
+ ? Promise.resolve(null)
989
+ : this.exitChannel().finally(() => this.logger.log('exit channel completed')),
990
+ //if the exit channel request took this long to finish, something's terribly wrong
991
+ util_1.util.sleep(exitChannelTimeout)
992
+ ]);
993
+ }
994
+ finally { }
995
+ await Promise.all([
996
+ this.destroyControlSocket(shutdownTimeMax),
997
+ this.destroyIOSocket(shutdownTimeMax, immediate)
998
+ ]);
999
+ this.emit(eventName);
1000
+ (_f = this.emitter) === null || _f === void 0 ? void 0 : _f.removeAllListeners();
1001
+ this.buffer = Buffer.alloc(0);
1002
+ this.bufferQueue.destroy();
1003
+ }
1004
+ async destroyControlSocket(timeout) {
1005
+ if (this.controlSocket && !this.isDestroyingControlSocket) {
1006
+ this.isDestroyingControlSocket = true;
1007
+ //wait for the controlSocket to be closed
1008
+ await Promise.race([
1009
+ this.controlSocketClosed.promise,
1010
+ util_1.util.sleep(timeout)
1011
+ ]);
1012
+ this.logger.log('[destroy] controlSocket is: ', this.controlSocketClosed.isResolved ? 'closed' : 'not closed');
1013
+ //destroy the controlSocket
1014
+ this.controlSocket.removeAllListeners();
1015
+ this.controlSocket.destroy();
1016
+ this.controlSocket = undefined;
1017
+ this.isDestroyingControlSocket = false;
1018
+ }
1019
+ }
1020
+ /**
1021
+ * @param immediate if true, force close immediately instead of waiting for it to settle
1022
+ */
1023
+ async destroyIOSocket(timeout, immediate = false) {
1024
+ var _a, _b, _c, _d;
1025
+ if (this.ioSocket && !this.isDestroyingIOSocket) {
1026
+ this.isDestroyingIOSocket = true;
1027
+ //wait for the ioSocket to be closed
1028
+ await Promise.race([
1029
+ this.ioSocketClosed.promise.then(() => this.logger.log('IO socket closed')),
1030
+ util_1.util.sleep(timeout)
1031
+ ]);
1032
+ //if the io socket is not closed, wait for it to at least settle
1033
+ if (!this.ioSocketClosed.isCompleted && !immediate) {
1034
+ await new Promise((resolve) => {
1035
+ var _a;
1036
+ const callback = debounce(() => {
1037
+ resolve();
1038
+ }, 250);
1039
+ //trigger the current callback once.
1040
+ callback();
1041
+ (_a = this.ioSocket) === null || _a === void 0 ? void 0 : _a.on('drain', callback);
1042
+ });
1043
+ }
1044
+ this.logger.log('[destroy] ioSocket is: ', this.ioSocketClosed.isResolved ? 'closed' : 'not closed');
1045
+ //destroy the ioSocket
1046
+ (_b = (_a = this.ioSocket) === null || _a === void 0 ? void 0 : _a.removeAllListeners) === null || _b === void 0 ? void 0 : _b.call(_a);
1047
+ (_d = (_c = this.ioSocket) === null || _c === void 0 ? void 0 : _c.destroy) === null || _d === void 0 ? void 0 : _d.call(_c);
1048
+ this.ioSocket = undefined;
1049
+ this.isDestroyingIOSocket = false;
1050
+ }
1051
+ }
1052
+ }
1053
+ exports.DebugProtocolClient = DebugProtocolClient;
1054
+ DebugProtocolClient.DEBUGGER_MAGIC = 'bsdebug'; // 64-bit = [b'bsdebug\0' little-endian]
1055
+ /**
1056
+ * Is the event a ProtocolRequest
1057
+ */
1058
+ function isProtocolRequest(event) {
1059
+ var _a, _b;
1060
+ return ((_a = event === null || event === void 0 ? void 0 : event.constructor) === null || _a === void 0 ? void 0 : _a.name.endsWith('Request')) && ((_b = event === null || event === void 0 ? void 0 : event.data) === null || _b === void 0 ? void 0 : _b.requestId) > 0;
1061
+ }
1062
+ exports.isProtocolRequest = isProtocolRequest;
1063
+ /**
1064
+ * Is the event a ProtocolResponse
1065
+ */
1066
+ function isProtocolResponse(event) {
1067
+ var _a, _b;
1068
+ return ((_a = event === null || event === void 0 ? void 0 : event.constructor) === null || _a === void 0 ? void 0 : _a.name.endsWith('Response')) && ((_b = event === null || event === void 0 ? void 0 : event.data) === null || _b === void 0 ? void 0 : _b.requestId) !== 0;
1069
+ }
1070
+ exports.isProtocolResponse = isProtocolResponse;
1071
+ /**
1072
+ * Is the event a ProtocolUpdate update
1073
+ */
1074
+ function isProtocolUpdate(event) {
1075
+ var _a, _b;
1076
+ return ((_a = event === null || event === void 0 ? void 0 : event.constructor) === null || _a === void 0 ? void 0 : _a.name.endsWith('Update')) && ((_b = event === null || event === void 0 ? void 0 : event.data) === null || _b === void 0 ? void 0 : _b.requestId) === 0;
1077
+ }
1078
+ exports.isProtocolUpdate = isProtocolUpdate;
1079
+ //# sourceMappingURL=DebugProtocolClient.js.map