@aerol-ai/aerolvm-sdk 0.1.1 → 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.
- package/dist/MicroVM.d.ts +1 -0
- package/dist/MicroVM.js +3 -0
- package/dist/internal/client.d.ts +1 -0
- package/dist/internal/client.js +61 -9
- package/package.json +3 -1
package/dist/MicroVM.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export declare class MicroVM {
|
|
|
19
19
|
destroy(id: string): Promise<void>;
|
|
20
20
|
resize(id: string, options: ResizeOptions): Promise<Sandbox>;
|
|
21
21
|
updateLifecycle(id: string, lifecycle: Lifecycle): Promise<Sandbox>;
|
|
22
|
+
reconcile(): Promise<void>;
|
|
22
23
|
health(): Promise<HealthStatus>;
|
|
23
24
|
mounts(sandboxID: string): Promise<MountSpecRedacted[]>;
|
|
24
25
|
execStream(sandboxID: string, options: ExecStreamOptions): ExecStreamHandle;
|
package/dist/MicroVM.js
CHANGED
|
@@ -33,6 +33,7 @@ export declare class APIClient {
|
|
|
33
33
|
downloadFile(id: string, targetPath: string): Promise<Uint8Array>;
|
|
34
34
|
exposePort(id: string, port: number): Promise<string>;
|
|
35
35
|
unexposePort(id: string, port: number): Promise<void>;
|
|
36
|
+
reconcile(): Promise<void>;
|
|
36
37
|
health(): Promise<HealthStatus>;
|
|
37
38
|
mounts(id: string): Promise<MountSpecRedacted[]>;
|
|
38
39
|
private wrap;
|
package/dist/internal/client.js
CHANGED
|
@@ -99,6 +99,9 @@ export class APIClient {
|
|
|
99
99
|
async unexposePort(id, port) {
|
|
100
100
|
await this.doJSON("DELETE", `/v1/sandboxes/${id}/ports/${port}`);
|
|
101
101
|
}
|
|
102
|
+
async reconcile() {
|
|
103
|
+
await this.doJSON("POST", "/v1/admin/reconcile");
|
|
104
|
+
}
|
|
102
105
|
async health() {
|
|
103
106
|
const response = await this.doJSON("GET", "/health");
|
|
104
107
|
return fromApiHealthStatus(response);
|
|
@@ -439,6 +442,35 @@ async function decodeError(response) {
|
|
|
439
442
|
}
|
|
440
443
|
const STREAM_PREFIX_STDOUT = 0x01;
|
|
441
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
|
+
}
|
|
442
474
|
function openExecStream(baseURL, patToken, sandboxID, options) {
|
|
443
475
|
const wsURL = baseURL.replace(/^http/, "ws") + `/v1/sandboxes/${encodeURIComponent(sandboxID)}/toolbox/process/exec/stream`;
|
|
444
476
|
const WS = globalThis.WebSocket;
|
|
@@ -450,6 +482,10 @@ function openExecStream(baseURL, patToken, sandboxID, options) {
|
|
|
450
482
|
// `sandbox.bearer, <token>`.
|
|
451
483
|
const ws = new WS(wsURL, ["sandbox.bearer", patToken]);
|
|
452
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 = "";
|
|
453
489
|
let exitResolve;
|
|
454
490
|
let exitReject;
|
|
455
491
|
const done = new Promise((resolve, reject) => {
|
|
@@ -510,11 +546,19 @@ function openExecStream(baseURL, patToken, sandboxID, options) {
|
|
|
510
546
|
options.onStderr?.(payload);
|
|
511
547
|
}
|
|
512
548
|
});
|
|
513
|
-
ws.addEventListener("close", () => {
|
|
514
|
-
|
|
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}`);
|
|
515
554
|
});
|
|
516
|
-
ws.addEventListener("error", () => {
|
|
517
|
-
|
|
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");
|
|
518
562
|
});
|
|
519
563
|
const sendBinary = (data) => {
|
|
520
564
|
const bytes = typeof data === "string" ? new TextEncoder().encode(data) : data;
|
|
@@ -530,7 +574,6 @@ function openExecStream(baseURL, patToken, sandboxID, options) {
|
|
|
530
574
|
},
|
|
531
575
|
close() {
|
|
532
576
|
ws.send(JSON.stringify({ type: "close" }));
|
|
533
|
-
ws.close();
|
|
534
577
|
},
|
|
535
578
|
done,
|
|
536
579
|
};
|
|
@@ -550,6 +593,7 @@ function openSessionAttach(baseURL, patToken, sandboxID, sessionID, options) {
|
|
|
550
593
|
exitReject = reject;
|
|
551
594
|
});
|
|
552
595
|
let settled = false;
|
|
596
|
+
let lastErrorDetail = "";
|
|
553
597
|
const finishWith = (info) => {
|
|
554
598
|
if (settled)
|
|
555
599
|
return;
|
|
@@ -600,13 +644,21 @@ function openSessionAttach(baseURL, patToken, sandboxID, sessionID, options) {
|
|
|
600
644
|
options.onStderr?.(payload);
|
|
601
645
|
}
|
|
602
646
|
});
|
|
603
|
-
ws.addEventListener("close", () => {
|
|
647
|
+
ws.addEventListener("close", (event) => {
|
|
604
648
|
if (!settled) {
|
|
605
|
-
|
|
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}`);
|
|
606
653
|
}
|
|
607
654
|
});
|
|
608
|
-
ws.addEventListener("error", () => {
|
|
609
|
-
|
|
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");
|
|
610
662
|
});
|
|
611
663
|
const sendBinary = (data) => {
|
|
612
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.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
"build": "tsc -p tsconfig.json",
|
|
16
16
|
"example:create": "npm run build && node dist/examples/createSandbox.js",
|
|
17
17
|
"example:create:src": "npx tsx src/examples/createSandbox.ts",
|
|
18
|
+
"example:delete": "npm run build && node dist/examples/deleteSandbox.js",
|
|
19
|
+
"example:delete:src": "npx tsx src/examples/deleteSandbox.ts",
|
|
18
20
|
"test": "tsc -p tsconfig.test.json --outDir dist-test && node --test dist-test/*.test.js"
|
|
19
21
|
},
|
|
20
22
|
"devDependencies": {
|