@unbound-app/debugger 0.1.4 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.mjs +71 -11
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -29,6 +29,7 @@ const state$2 = {
|
|
|
29
29
|
controllers: /* @__PURE__ */ new Set()
|
|
30
30
|
};
|
|
31
31
|
const pending = /* @__PURE__ */ new Map();
|
|
32
|
+
const pendingPushes = /* @__PURE__ */ new Map();
|
|
32
33
|
const logListeners = /* @__PURE__ */ new Set();
|
|
33
34
|
const deviceListeners = /* @__PURE__ */ new Set();
|
|
34
35
|
const evalListeners = /* @__PURE__ */ new Set();
|
|
@@ -36,6 +37,7 @@ const resultListeners = /* @__PURE__ */ new Set();
|
|
|
36
37
|
const controllerListeners = /* @__PURE__ */ new Set();
|
|
37
38
|
/** How long to wait for a device to answer an eval before failing it. */
|
|
38
39
|
const EVAL_TIMEOUT_MS = 1e4;
|
|
40
|
+
const PLUGIN_PUSH_TIMEOUT_MS = 6e4;
|
|
39
41
|
/**
|
|
40
42
|
* @description Registers the connected device, rejecting a second one so eval routing stays
|
|
41
43
|
* unambiguous.
|
|
@@ -66,6 +68,16 @@ function detachDevice(socket) {
|
|
|
66
68
|
});
|
|
67
69
|
pending.delete(id);
|
|
68
70
|
}
|
|
71
|
+
for (const [id, entry] of pendingPushes) {
|
|
72
|
+
clearTimeout(entry.timer);
|
|
73
|
+
entry.deliver({
|
|
74
|
+
type: "plugin-push-result",
|
|
75
|
+
id,
|
|
76
|
+
ok: false,
|
|
77
|
+
error: "Device disconnected before the reload completed."
|
|
78
|
+
});
|
|
79
|
+
pendingPushes.delete(id);
|
|
80
|
+
}
|
|
69
81
|
broadcastDeviceStatus(false);
|
|
70
82
|
}
|
|
71
83
|
/** @description Adds a controller and immediately reports current device presence to it. */
|
|
@@ -86,6 +98,11 @@ function detachController(socket) {
|
|
|
86
98
|
clearTimeout(entry.timer);
|
|
87
99
|
pending.delete(id);
|
|
88
100
|
}
|
|
101
|
+
for (const [id, entry] of pendingPushes) {
|
|
102
|
+
if (entry.origin !== socket) continue;
|
|
103
|
+
clearTimeout(entry.timer);
|
|
104
|
+
pendingPushes.delete(id);
|
|
105
|
+
}
|
|
89
106
|
controllerDelivery.delete(socket);
|
|
90
107
|
for (const listener of controllerListeners) listener(false, state$2.controllers.size);
|
|
91
108
|
}
|
|
@@ -105,6 +122,40 @@ function evaluateForController(socket, id, code) {
|
|
|
105
122
|
});
|
|
106
123
|
}
|
|
107
124
|
/**
|
|
125
|
+
* @description Forwards a controller's {@link PluginPushRequest} to the device and delivers the
|
|
126
|
+
* id-correlated {@link PluginPushResult} back over that same controller's socket. Replies with an
|
|
127
|
+
* error frame instead if no device is connected or it doesn't answer within {@link PLUGIN_PUSH_TIMEOUT_MS}.
|
|
128
|
+
* @param socket The controller that issued the push.
|
|
129
|
+
* @param request The push to forward verbatim; its `id` correlates the result.
|
|
130
|
+
*/
|
|
131
|
+
function pushPluginForController(socket, request) {
|
|
132
|
+
const deliver = (result) => socket.send(JSON.stringify(result));
|
|
133
|
+
if (!state$2.device) {
|
|
134
|
+
deliver({
|
|
135
|
+
type: "plugin-push-result",
|
|
136
|
+
id: request.id,
|
|
137
|
+
ok: false,
|
|
138
|
+
error: "No device is connected to the debugger."
|
|
139
|
+
});
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const timer = setTimeout(() => {
|
|
143
|
+
pendingPushes.delete(request.id);
|
|
144
|
+
deliver({
|
|
145
|
+
type: "plugin-push-result",
|
|
146
|
+
id: request.id,
|
|
147
|
+
ok: false,
|
|
148
|
+
error: `Plugin push timed out after ${PLUGIN_PUSH_TIMEOUT_MS}ms.`
|
|
149
|
+
});
|
|
150
|
+
}, PLUGIN_PUSH_TIMEOUT_MS);
|
|
151
|
+
pendingPushes.set(request.id, {
|
|
152
|
+
deliver,
|
|
153
|
+
timer,
|
|
154
|
+
origin: socket
|
|
155
|
+
});
|
|
156
|
+
state$2.device.send(JSON.stringify(request));
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
108
159
|
* @description Runs code on the device on behalf of an in-process caller (the terminal REPL),
|
|
109
160
|
* resolving with the device's answer. Rejects if no device is connected or it doesn't answer within
|
|
110
161
|
* {@link EVAL_TIMEOUT_MS}.
|
|
@@ -159,6 +210,14 @@ function handleDeviceMessage$1(message) {
|
|
|
159
210
|
entry.deliver(message);
|
|
160
211
|
return;
|
|
161
212
|
}
|
|
213
|
+
if (message.type === "plugin-push-result") {
|
|
214
|
+
const entry = pendingPushes.get(message.id);
|
|
215
|
+
if (!entry) return;
|
|
216
|
+
clearTimeout(entry.timer);
|
|
217
|
+
pendingPushes.delete(message.id);
|
|
218
|
+
entry.deliver(message);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
162
221
|
if (message.type === "log") {
|
|
163
222
|
for (const socket of state$2.controllers) socket.send(JSON.stringify(message));
|
|
164
223
|
for (const listener of logListeners) listener(message);
|
|
@@ -301,13 +360,11 @@ function splitTopLevel(input) {
|
|
|
301
360
|
case ")":
|
|
302
361
|
depth--;
|
|
303
362
|
break;
|
|
304
|
-
case ",":
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
break;
|
|
363
|
+
case ",": if (depth === 0) {
|
|
364
|
+
segments.push(input.slice(start, i));
|
|
365
|
+
if (input[i + 1] === " ") i++;
|
|
366
|
+
start = i + 1;
|
|
367
|
+
}
|
|
311
368
|
}
|
|
312
369
|
}
|
|
313
370
|
if (depth !== 0 || inString) return null;
|
|
@@ -352,7 +409,7 @@ function printBanner(deviceAddress, mcpAddress) {
|
|
|
352
409
|
value: mcpAddress
|
|
353
410
|
}];
|
|
354
411
|
const longest = Math.max(18, ...lines.map((l) => rowText(l).length));
|
|
355
|
-
const available = terminalWidth() - 2 -
|
|
412
|
+
const available = terminalWidth() - 2 - 4;
|
|
356
413
|
const inner = Math.min(longest, MAX_WIDTH, available);
|
|
357
414
|
if (inner < MIN_BOX_WIDTH || inner < longest) {
|
|
358
415
|
printFallback(title, lines);
|
|
@@ -366,7 +423,7 @@ function rowText(line) {
|
|
|
366
423
|
}
|
|
367
424
|
function printBox(title, lines, inner) {
|
|
368
425
|
const pad = " ".repeat(PADDING);
|
|
369
|
-
const horizontal = "─".repeat(inner +
|
|
426
|
+
const horizontal = "─".repeat(inner + 4);
|
|
370
427
|
rgb(PINK, `╭${horizontal}╮\n`);
|
|
371
428
|
rgb(PINK, `│${pad}`);
|
|
372
429
|
boldRgb(PINK, center(title, inner));
|
|
@@ -532,8 +589,11 @@ function handleDeviceMessage(raw) {
|
|
|
532
589
|
}
|
|
533
590
|
function handleControllerMessage(ws, raw) {
|
|
534
591
|
const message = parseMessage(raw);
|
|
535
|
-
if (message?.type
|
|
536
|
-
|
|
592
|
+
if (message?.type === "eval") {
|
|
593
|
+
evaluateForController(ws, message.id, message.code);
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
if (message?.type === "plugin-push") pushPluginForController(ws, message);
|
|
537
597
|
}
|
|
538
598
|
function getLocalAddress() {
|
|
539
599
|
const interfaces = os.networkInterfaces();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unbound-app/debugger",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "A REPL debugger for @unbound-app/client runtime instances.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mario P.",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"build": "tsdown"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@unbound-app/debugger-protocol": "0.
|
|
27
|
+
"@unbound-app/debugger-protocol": "0.6.0",
|
|
28
28
|
"cleye": "^1.3.4",
|
|
29
29
|
"terminal-kit": "^3.1.2"
|
|
30
30
|
},
|