@aerol-ai/aerolvm-sdk 0.1.2 → 0.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.
@@ -442,6 +442,35 @@ async function decodeError(response) {
442
442
  }
443
443
  const STREAM_PREFIX_STDOUT = 0x01;
444
444
  const STREAM_PREFIX_STDERR = 0x02;
445
+ // Pull whatever diagnostic detail the runtime gave us off a WebSocket "error"
446
+ // event. Node 22's native WebSocket fires an ErrorEvent with `.error` /
447
+ // `.message`; browsers' base WebSocket fires a bare Event. Returns "" when
448
+ // nothing useful is there so callers can fall back to a generic label.
449
+ function describeWSError(event) {
450
+ if (!event || typeof event !== "object")
451
+ return "";
452
+ const e = event;
453
+ if (e.error instanceof Error && e.error.message)
454
+ return e.error.message;
455
+ if (typeof e.error === "string" && e.error !== "")
456
+ return e.error;
457
+ if (typeof e.message === "string" && e.message !== "")
458
+ return e.message;
459
+ return "";
460
+ }
461
+ function describeWSClose(event) {
462
+ if (!event || typeof event !== "object")
463
+ return "";
464
+ const e = event;
465
+ const parts = [];
466
+ if (typeof e.code === "number")
467
+ parts.push(`code=${e.code}`);
468
+ if (typeof e.reason === "string" && e.reason !== "")
469
+ parts.push(`reason=${JSON.stringify(e.reason)}`);
470
+ if (typeof e.wasClean === "boolean")
471
+ parts.push(`wasClean=${e.wasClean}`);
472
+ return parts.join(" ");
473
+ }
445
474
  function openExecStream(baseURL, patToken, sandboxID, options) {
446
475
  const wsURL = baseURL.replace(/^http/, "ws") + `/v1/sandboxes/${encodeURIComponent(sandboxID)}/toolbox/process/exec/stream`;
447
476
  const WS = globalThis.WebSocket;
@@ -453,6 +482,10 @@ function openExecStream(baseURL, patToken, sandboxID, options) {
453
482
  // `sandbox.bearer, <token>`.
454
483
  const ws = new WS(wsURL, ["sandbox.bearer", patToken]);
455
484
  ws.binaryType = "arraybuffer";
485
+ // Captured by the "error" listener and consumed by "close" so we report the
486
+ // root cause (e.g. "Unexpected server response: 502") rather than the
487
+ // generic "stream closed before exit" that would otherwise win the race.
488
+ let lastErrorDetail = "";
456
489
  let exitResolve;
457
490
  let exitReject;
458
491
  const done = new Promise((resolve, reject) => {
@@ -513,11 +546,19 @@ function openExecStream(baseURL, patToken, sandboxID, options) {
513
546
  options.onStderr?.(payload);
514
547
  }
515
548
  });
516
- ws.addEventListener("close", () => {
517
- failWith("stream closed before exit");
549
+ ws.addEventListener("close", (event) => {
550
+ const closeDetail = describeWSClose(event);
551
+ const parts = [lastErrorDetail, closeDetail].filter((s) => s !== "");
552
+ const suffix = parts.length > 0 ? ` (${parts.join("; ")})` : "";
553
+ failWith(`stream closed before exit${suffix}`);
518
554
  });
519
- ws.addEventListener("error", () => {
520
- failWith("websocket error");
555
+ ws.addEventListener("error", (event) => {
556
+ const detail = describeWSError(event);
557
+ if (detail !== "") {
558
+ lastErrorDetail = detail;
559
+ }
560
+ options.onError?.(detail !== "" ? detail : "websocket error");
561
+ failWith(detail !== "" ? `websocket error: ${detail}` : "websocket error");
521
562
  });
522
563
  const sendBinary = (data) => {
523
564
  const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
@@ -552,6 +593,7 @@ function openSessionAttach(baseURL, patToken, sandboxID, sessionID, options) {
552
593
  exitReject = reject;
553
594
  });
554
595
  let settled = false;
596
+ let lastErrorDetail = "";
555
597
  const finishWith = (info) => {
556
598
  if (settled)
557
599
  return;
@@ -602,13 +644,21 @@ function openSessionAttach(baseURL, patToken, sandboxID, sessionID, options) {
602
644
  options.onStderr?.(payload);
603
645
  }
604
646
  });
605
- ws.addEventListener("close", () => {
647
+ ws.addEventListener("close", (event) => {
606
648
  if (!settled) {
607
- failWith("session stream closed before exit");
649
+ const closeDetail = describeWSClose(event);
650
+ const parts = [lastErrorDetail, closeDetail].filter((s) => s !== "");
651
+ const suffix = parts.length > 0 ? ` (${parts.join("; ")})` : "";
652
+ failWith(`session stream closed before exit${suffix}`);
608
653
  }
609
654
  });
610
- ws.addEventListener("error", () => {
611
- failWith("websocket error");
655
+ ws.addEventListener("error", (event) => {
656
+ const detail = describeWSError(event);
657
+ if (detail !== "") {
658
+ lastErrorDetail = detail;
659
+ }
660
+ options.onError?.(detail !== "" ? detail : "websocket error");
661
+ failWith(detail !== "" ? `websocket error: ${detail}` : "websocket error");
612
662
  });
613
663
  const sendBinary = (data) => {
614
664
  const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aerol-ai/aerolvm-sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",