kiro-mobile-bridge 1.0.8 → 1.0.11

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.
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import http from 'http';
5
5
  import { WebSocket } from 'ws';
6
+ import { CDP_CALL_TIMEOUT, HTTP_TIMEOUT } from '../utils/constants.js';
6
7
 
7
8
  /**
8
9
  * Fetch JSON from a CDP endpoint
@@ -14,7 +15,7 @@ export function fetchCDPTargets(port, path = '/json/list') {
14
15
  return new Promise((resolve, reject) => {
15
16
  const url = `http://127.0.0.1:${port}${path}`;
16
17
 
17
- const req = http.get(url, { timeout: 2000 }, (res) => {
18
+ const req = http.get(url, { timeout: HTTP_TIMEOUT }, (res) => {
18
19
  let data = '';
19
20
  res.on('data', chunk => data += chunk);
20
21
  res.on('end', () => {
@@ -34,6 +35,22 @@ export function fetchCDPTargets(port, path = '/json/list') {
34
35
  });
35
36
  }
36
37
 
38
+ /**
39
+ * @typedef {Object} PendingCall
40
+ * @property {Function} resolve - Promise resolve function
41
+ * @property {Function} reject - Promise reject function
42
+ * @property {NodeJS.Timeout} timeoutId - Timeout handle for cleanup
43
+ */
44
+
45
+ /**
46
+ * @typedef {Object} CDPConnection
47
+ * @property {WebSocket} ws - WebSocket connection
48
+ * @property {Array} contexts - Execution contexts
49
+ * @property {number|null} rootContextId - Root context ID
50
+ * @property {Function} call - Make a CDP call
51
+ * @property {Function} close - Close the connection
52
+ */
53
+
37
54
  /**
38
55
  * Create a CDP connection to a target
39
56
  * @param {string} wsUrl - WebSocket debugger URL
@@ -43,11 +60,27 @@ export function connectToCDP(wsUrl) {
43
60
  return new Promise((resolve, reject) => {
44
61
  const ws = new WebSocket(wsUrl);
45
62
  let idCounter = 1;
63
+ /** @type {Map<number, PendingCall>} */
46
64
  const pendingCalls = new Map();
47
65
  const contexts = [];
48
66
  let rootContextId = null;
49
67
  let isConnected = false;
50
68
 
69
+ /**
70
+ * Clear all pending calls and their timeouts
71
+ * @param {Error} error - Error to reject pending calls with
72
+ */
73
+ function clearAllPendingCalls(error) {
74
+ for (const [id, pending] of pendingCalls) {
75
+ // Clear the timeout to prevent memory leak
76
+ if (pending.timeoutId) {
77
+ clearTimeout(pending.timeoutId);
78
+ }
79
+ pending.reject(error);
80
+ }
81
+ pendingCalls.clear();
82
+ }
83
+
51
84
  ws.on('message', (rawMsg) => {
52
85
  try {
53
86
  const msg = JSON.parse(rawMsg.toString());
@@ -75,12 +108,19 @@ export function connectToCDP(wsUrl) {
75
108
  }
76
109
 
77
110
  if (msg.id !== undefined && pendingCalls.has(msg.id)) {
78
- const { resolve: res, reject: rej } = pendingCalls.get(msg.id);
111
+ const pending = pendingCalls.get(msg.id);
112
+
113
+ // Clear the timeout since we got a response
114
+ if (pending.timeoutId) {
115
+ clearTimeout(pending.timeoutId);
116
+ }
117
+
79
118
  pendingCalls.delete(msg.id);
119
+
80
120
  if (msg.error) {
81
- rej(new Error(`CDP Error: ${msg.error.message} (code: ${msg.error.code})`));
121
+ pending.reject(new Error(`CDP Error: ${msg.error.message} (code: ${msg.error.code})`));
82
122
  } else {
83
- res(msg.result);
123
+ pending.resolve(msg.result);
84
124
  }
85
125
  }
86
126
  } catch (e) {
@@ -97,6 +137,12 @@ export function connectToCDP(wsUrl) {
97
137
  contexts,
98
138
  get rootContextId() { return rootContextId; },
99
139
 
140
+ /**
141
+ * Make a CDP call
142
+ * @param {string} method - CDP method name
143
+ * @param {object} params - Method parameters
144
+ * @returns {Promise<any>} - Call result
145
+ */
100
146
  call(method, params = {}) {
101
147
  return new Promise((res, rej) => {
102
148
  if (!isConnected) {
@@ -105,24 +151,35 @@ export function connectToCDP(wsUrl) {
105
151
  }
106
152
 
107
153
  const id = idCounter++;
108
- pendingCalls.set(id, { resolve: res, reject: rej });
109
- ws.send(JSON.stringify({ id, method, params }));
110
154
 
111
- setTimeout(() => {
155
+ // Set up timeout with cleanup
156
+ const timeoutId = setTimeout(() => {
112
157
  if (pendingCalls.has(id)) {
113
158
  pendingCalls.delete(id);
114
159
  rej(new Error(`CDP call timeout: ${method}`));
115
160
  }
116
- }, 10000);
161
+ }, CDP_CALL_TIMEOUT);
162
+
163
+ // Store pending call with timeout reference for cleanup
164
+ pendingCalls.set(id, { resolve: res, reject: rej, timeoutId });
165
+
166
+ try {
167
+ ws.send(JSON.stringify({ id, method, params }));
168
+ } catch (sendError) {
169
+ // Clean up on send failure
170
+ clearTimeout(timeoutId);
171
+ pendingCalls.delete(id);
172
+ rej(new Error(`Failed to send CDP call: ${sendError.message}`));
173
+ }
117
174
  });
118
175
  },
119
176
 
177
+ /**
178
+ * Close the CDP connection
179
+ */
120
180
  close() {
121
181
  isConnected = false;
122
- for (const [, { reject }] of pendingCalls) {
123
- reject(new Error('CDP connection closed'));
124
- }
125
- pendingCalls.clear();
182
+ clearAllPendingCalls(new Error('CDP connection closed'));
126
183
  ws.terminate();
127
184
  }
128
185
  };
@@ -147,10 +204,7 @@ export function connectToCDP(wsUrl) {
147
204
  ws.on('close', () => {
148
205
  console.log('[CDP] Connection closed');
149
206
  isConnected = false;
150
- for (const [, { reject }] of pendingCalls) {
151
- reject(new Error('CDP connection closed'));
152
- }
153
- pendingCalls.clear();
207
+ clearAllPendingCalls(new Error('CDP connection closed'));
154
208
  });
155
209
  });
156
210
  }