@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.
Files changed (2) hide show
  1. package/dist/index.mjs +71 -11
  2. 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
- if (depth === 0) {
306
- segments.push(input.slice(start, i));
307
- if (input[i + 1] === " ") i++;
308
- start = i + 1;
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 - PADDING * 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 + PADDING * 2);
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 !== "eval") return;
536
- evaluateForController(ws, message.id, message.code);
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.1.4",
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.1.3",
27
+ "@unbound-app/debugger-protocol": "0.6.0",
28
28
  "cleye": "^1.3.4",
29
29
  "terminal-kit": "^3.1.2"
30
30
  },