@blaxel/core 0.2.49-dev.210 → 0.2.49-dev.212
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/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/common/settings.js +2 -2
- package/dist/cjs/sandbox/codegen/codegen-ws.js +30 -0
- package/dist/cjs/sandbox/filesystem/filesystem-ws.js +106 -0
- package/dist/cjs/sandbox/filesystem/filesystem.js +4 -15
- package/dist/cjs/sandbox/network/network-ws.js +12 -0
- package/dist/cjs/sandbox/process/process-ws.js +139 -0
- package/dist/cjs/sandbox/sandbox.js +67 -10
- package/dist/cjs/sandbox/websocket/client.js +275 -0
- package/dist/cjs/sandbox/websocket/index.js +17 -0
- package/dist/cjs/types/sandbox/codegen/codegen-ws.d.ts +10 -0
- package/dist/cjs/types/sandbox/filesystem/filesystem-ws.d.ts +35 -0
- package/dist/cjs/types/sandbox/network/network-ws.d.ts +7 -0
- package/dist/cjs/types/sandbox/process/process-ws.d.ts +27 -0
- package/dist/cjs/types/sandbox/sandbox.d.ts +12 -6
- package/dist/cjs/types/sandbox/types.d.ts +3 -0
- package/dist/cjs/types/sandbox/websocket/client.d.ts +49 -0
- package/dist/cjs/types/sandbox/websocket/index.d.ts +1 -0
- package/dist/cjs-browser/.tsbuildinfo +1 -1
- package/dist/cjs-browser/common/settings.js +2 -2
- package/dist/cjs-browser/sandbox/codegen/codegen-ws.js +30 -0
- package/dist/cjs-browser/sandbox/filesystem/filesystem-ws.js +106 -0
- package/dist/cjs-browser/sandbox/filesystem/filesystem.js +4 -15
- package/dist/cjs-browser/sandbox/network/network-ws.js +12 -0
- package/dist/cjs-browser/sandbox/process/process-ws.js +139 -0
- package/dist/cjs-browser/sandbox/sandbox.js +67 -10
- package/dist/cjs-browser/sandbox/websocket/client.js +275 -0
- package/dist/cjs-browser/sandbox/websocket/index.js +17 -0
- package/dist/cjs-browser/types/sandbox/codegen/codegen-ws.d.ts +10 -0
- package/dist/cjs-browser/types/sandbox/filesystem/filesystem-ws.d.ts +35 -0
- package/dist/cjs-browser/types/sandbox/network/network-ws.d.ts +7 -0
- package/dist/cjs-browser/types/sandbox/process/process-ws.d.ts +27 -0
- package/dist/cjs-browser/types/sandbox/sandbox.d.ts +12 -6
- package/dist/cjs-browser/types/sandbox/types.d.ts +3 -0
- package/dist/cjs-browser/types/sandbox/websocket/client.d.ts +49 -0
- package/dist/cjs-browser/types/sandbox/websocket/index.d.ts +1 -0
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/common/settings.js +2 -2
- package/dist/esm/sandbox/codegen/codegen-ws.js +26 -0
- package/dist/esm/sandbox/filesystem/filesystem-ws.js +102 -0
- package/dist/esm/sandbox/filesystem/filesystem.js +4 -15
- package/dist/esm/sandbox/network/network-ws.js +8 -0
- package/dist/esm/sandbox/process/process-ws.js +135 -0
- package/dist/esm/sandbox/sandbox.js +67 -10
- package/dist/esm/sandbox/websocket/client.js +271 -0
- package/dist/esm/sandbox/websocket/index.js +1 -0
- package/dist/esm-browser/.tsbuildinfo +1 -1
- package/dist/esm-browser/common/settings.js +2 -2
- package/dist/esm-browser/sandbox/codegen/codegen-ws.js +26 -0
- package/dist/esm-browser/sandbox/filesystem/filesystem-ws.js +102 -0
- package/dist/esm-browser/sandbox/filesystem/filesystem.js +4 -15
- package/dist/esm-browser/sandbox/network/network-ws.js +8 -0
- package/dist/esm-browser/sandbox/process/process-ws.js +135 -0
- package/dist/esm-browser/sandbox/sandbox.js +67 -10
- package/dist/esm-browser/sandbox/websocket/client.js +271 -0
- package/dist/esm-browser/sandbox/websocket/index.js +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SandboxCodegenWebSocket = void 0;
|
|
4
|
+
const action_js_1 = require("../action.js");
|
|
5
|
+
class SandboxCodegenWebSocket extends action_js_1.SandboxAction {
|
|
6
|
+
wsClient;
|
|
7
|
+
constructor(sandbox, wsClient) {
|
|
8
|
+
super(sandbox);
|
|
9
|
+
this.wsClient = wsClient;
|
|
10
|
+
}
|
|
11
|
+
async fastapply(path, codeEdit, model) {
|
|
12
|
+
const data = await this.wsClient.send("codegen:fastapply", {
|
|
13
|
+
path,
|
|
14
|
+
codeEdit,
|
|
15
|
+
model,
|
|
16
|
+
});
|
|
17
|
+
return data;
|
|
18
|
+
}
|
|
19
|
+
async reranking(path, query, scoreThreshold, tokenLimit, filePattern) {
|
|
20
|
+
const data = await this.wsClient.send("codegen:reranking", {
|
|
21
|
+
path,
|
|
22
|
+
query,
|
|
23
|
+
scoreThreshold,
|
|
24
|
+
tokenLimit,
|
|
25
|
+
filePattern,
|
|
26
|
+
});
|
|
27
|
+
return data;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.SandboxCodegenWebSocket = SandboxCodegenWebSocket;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SandboxFileSystemWebSocket = void 0;
|
|
4
|
+
const action_js_1 = require("../action.js");
|
|
5
|
+
const filesystem_js_1 = require("./filesystem.js");
|
|
6
|
+
class SandboxFileSystemWebSocket extends action_js_1.SandboxAction {
|
|
7
|
+
process;
|
|
8
|
+
wsClient;
|
|
9
|
+
httpClient;
|
|
10
|
+
constructor(sandbox, process, wsClient) {
|
|
11
|
+
super(sandbox);
|
|
12
|
+
this.process = process;
|
|
13
|
+
this.wsClient = wsClient;
|
|
14
|
+
// Create HTTP client for fallback operations
|
|
15
|
+
this.httpClient = new filesystem_js_1.SandboxFileSystem(sandbox, process);
|
|
16
|
+
}
|
|
17
|
+
async mkdir(path, permissions = "0755") {
|
|
18
|
+
path = this.formatPath(path);
|
|
19
|
+
const data = await this.wsClient.send("filesystem:create", {
|
|
20
|
+
path,
|
|
21
|
+
isDirectory: true,
|
|
22
|
+
permissions,
|
|
23
|
+
});
|
|
24
|
+
return data;
|
|
25
|
+
}
|
|
26
|
+
async write(path, content) {
|
|
27
|
+
path = this.formatPath(path);
|
|
28
|
+
const data = await this.wsClient.send("filesystem:create", {
|
|
29
|
+
path,
|
|
30
|
+
content,
|
|
31
|
+
isDirectory: false,
|
|
32
|
+
});
|
|
33
|
+
return data;
|
|
34
|
+
}
|
|
35
|
+
async writeBinary(path, content) {
|
|
36
|
+
return this.httpClient.writeBinary(path, content);
|
|
37
|
+
}
|
|
38
|
+
async writeTree(files, destinationPath = null) {
|
|
39
|
+
const path = this.formatPath(destinationPath ?? "");
|
|
40
|
+
const filesMap = files.reduce((acc, file) => {
|
|
41
|
+
acc[file.path] = file.content;
|
|
42
|
+
return acc;
|
|
43
|
+
}, {});
|
|
44
|
+
const data = await this.wsClient.send("filesystem:tree:create", {
|
|
45
|
+
path,
|
|
46
|
+
files: filesMap,
|
|
47
|
+
});
|
|
48
|
+
return data;
|
|
49
|
+
}
|
|
50
|
+
async read(path) {
|
|
51
|
+
path = this.formatPath(path);
|
|
52
|
+
const data = await this.wsClient.send("filesystem:get", { path });
|
|
53
|
+
return data.content;
|
|
54
|
+
}
|
|
55
|
+
async readBinary(path) {
|
|
56
|
+
// Binary downloads are better suited for HTTP
|
|
57
|
+
// Fall back to HTTP client for binary operations
|
|
58
|
+
return this.httpClient.readBinary(path);
|
|
59
|
+
}
|
|
60
|
+
async download(src, destinationPath, options = {}) {
|
|
61
|
+
// File downloads are better suited for HTTP
|
|
62
|
+
// Fall back to HTTP client
|
|
63
|
+
return this.httpClient.download(src, destinationPath, options);
|
|
64
|
+
}
|
|
65
|
+
async rm(path, recursive = false) {
|
|
66
|
+
path = this.formatPath(path);
|
|
67
|
+
const data = await this.wsClient.send("filesystem:delete", {
|
|
68
|
+
path,
|
|
69
|
+
recursive,
|
|
70
|
+
});
|
|
71
|
+
return data;
|
|
72
|
+
}
|
|
73
|
+
async ls(path) {
|
|
74
|
+
path = this.formatPath(path);
|
|
75
|
+
const data = await this.wsClient.send("filesystem:get", { path });
|
|
76
|
+
return data;
|
|
77
|
+
}
|
|
78
|
+
async cp(source, destination, { maxWait = 180000 } = {}) {
|
|
79
|
+
// Copy operation is typically done via process execution
|
|
80
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
81
|
+
let process = await this.process.exec({
|
|
82
|
+
command: `cp -r ${source} ${destination}`,
|
|
83
|
+
});
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument
|
|
85
|
+
process = await this.process.wait(process.pid, { maxWait, interval: 100 });
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
87
|
+
if (process.status === "failed") {
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
89
|
+
throw new Error(`Could not copy ${source} to ${destination} cause: ${process.logs}`);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
message: "Files copied",
|
|
93
|
+
source,
|
|
94
|
+
destination,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
watch(path, callback, options) {
|
|
98
|
+
// File watching uses HTTP streaming which is already optimized
|
|
99
|
+
// Fall back to HTTP client
|
|
100
|
+
return this.httpClient.watch(path, callback, options);
|
|
101
|
+
}
|
|
102
|
+
formatPath(path) {
|
|
103
|
+
return path;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.SandboxFileSystemWebSocket = SandboxFileSystemWebSocket;
|
|
@@ -8,7 +8,7 @@ const index_js_1 = require("../client/index.js");
|
|
|
8
8
|
// Multipart upload constants
|
|
9
9
|
const MULTIPART_THRESHOLD = 5 * 1024 * 1024; // 5MB
|
|
10
10
|
const CHUNK_SIZE = 5 * 1024 * 1024; // 5MB per part
|
|
11
|
-
const MAX_PARALLEL_UPLOADS =
|
|
11
|
+
const MAX_PARALLEL_UPLOADS = 20; // Number of parallel part uploads
|
|
12
12
|
class SandboxFileSystem extends action_js_1.SandboxAction {
|
|
13
13
|
process;
|
|
14
14
|
constructor(sandbox, process) {
|
|
@@ -304,7 +304,6 @@ class SandboxFileSystem extends action_js_1.SandboxAction {
|
|
|
304
304
|
// Multipart upload helper methods
|
|
305
305
|
async initiateMultipartUpload(path, permissions = "0644") {
|
|
306
306
|
path = this.formatPath(path);
|
|
307
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
|
|
308
307
|
const { data } = await (0, index_js_1.postFilesystemMultipartInitiateByPath)({
|
|
309
308
|
path: { path },
|
|
310
309
|
body: { permissions },
|
|
@@ -315,7 +314,6 @@ class SandboxFileSystem extends action_js_1.SandboxAction {
|
|
|
315
314
|
return data;
|
|
316
315
|
}
|
|
317
316
|
async uploadPart(uploadId, partNumber, fileBlob) {
|
|
318
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
|
|
319
317
|
const { data } = await (0, index_js_1.putFilesystemMultipartByUploadIdPart)({
|
|
320
318
|
path: { uploadId },
|
|
321
319
|
query: { partNumber },
|
|
@@ -327,7 +325,6 @@ class SandboxFileSystem extends action_js_1.SandboxAction {
|
|
|
327
325
|
return data;
|
|
328
326
|
}
|
|
329
327
|
async completeMultipartUpload(uploadId, parts) {
|
|
330
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
|
|
331
328
|
const { data } = await (0, index_js_1.postFilesystemMultipartByUploadIdComplete)({
|
|
332
329
|
path: { uploadId },
|
|
333
330
|
body: { parts },
|
|
@@ -338,19 +335,17 @@ class SandboxFileSystem extends action_js_1.SandboxAction {
|
|
|
338
335
|
return data;
|
|
339
336
|
}
|
|
340
337
|
async abortMultipartUpload(uploadId) {
|
|
341
|
-
|
|
342
|
-
await (0, index_js_1.deleteFilesystemMultipartByUploadIdAbort)({
|
|
338
|
+
const { data } = await (0, index_js_1.deleteFilesystemMultipartByUploadIdAbort)({
|
|
343
339
|
path: { uploadId },
|
|
344
340
|
baseUrl: this.url,
|
|
345
341
|
client: this.client,
|
|
346
342
|
throwOnError: true,
|
|
347
343
|
});
|
|
344
|
+
return data;
|
|
348
345
|
}
|
|
349
346
|
async uploadWithMultipart(path, blob, permissions = "0644") {
|
|
350
347
|
// Initiate multipart upload
|
|
351
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
352
348
|
const initResponse = await this.initiateMultipartUpload(path, permissions);
|
|
353
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
354
349
|
const uploadId = initResponse.uploadId;
|
|
355
350
|
if (!uploadId) {
|
|
356
351
|
throw new Error("Failed to get upload ID from initiate response");
|
|
@@ -367,26 +362,20 @@ class SandboxFileSystem extends action_js_1.SandboxAction {
|
|
|
367
362
|
const start = (partNumber - 1) * CHUNK_SIZE;
|
|
368
363
|
const end = Math.min(start + CHUNK_SIZE, size);
|
|
369
364
|
const chunk = blob.slice(start, end);
|
|
370
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
371
365
|
batch.push(this.uploadPart(uploadId, partNumber, chunk));
|
|
372
366
|
}
|
|
373
367
|
// Wait for batch to complete
|
|
374
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
375
368
|
const batchResults = await Promise.all(batch);
|
|
376
|
-
|
|
377
|
-
parts.push(...batchResults.map((r) => ({ partNumber: r.partNumber, etag: r.etag })));
|
|
369
|
+
parts.push(...batchResults);
|
|
378
370
|
}
|
|
379
371
|
// Sort parts by partNumber to ensure correct order
|
|
380
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
381
372
|
parts.sort((a, b) => (a.partNumber ?? 0) - (b.partNumber ?? 0));
|
|
382
373
|
// Complete the upload
|
|
383
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
384
374
|
return await this.completeMultipartUpload(uploadId, parts);
|
|
385
375
|
}
|
|
386
376
|
catch (error) {
|
|
387
377
|
// Abort the upload on failure
|
|
388
378
|
try {
|
|
389
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
390
379
|
await this.abortMultipartUpload(uploadId);
|
|
391
380
|
}
|
|
392
381
|
catch (abortError) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SandboxNetworkWebSocket = void 0;
|
|
4
|
+
const action_js_1 = require("../action.js");
|
|
5
|
+
class SandboxNetworkWebSocket extends action_js_1.SandboxAction {
|
|
6
|
+
wsClient;
|
|
7
|
+
constructor(sandbox, wsClient) {
|
|
8
|
+
super(sandbox);
|
|
9
|
+
this.wsClient = wsClient;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.SandboxNetworkWebSocket = SandboxNetworkWebSocket;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SandboxProcessWebSocket = void 0;
|
|
4
|
+
const action_js_1 = require("../action.js");
|
|
5
|
+
const process_js_1 = require("./process.js");
|
|
6
|
+
class SandboxProcessWebSocket extends action_js_1.SandboxAction {
|
|
7
|
+
wsClient;
|
|
8
|
+
httpClient;
|
|
9
|
+
constructor(sandbox, wsClient) {
|
|
10
|
+
super(sandbox);
|
|
11
|
+
this.wsClient = wsClient;
|
|
12
|
+
// Create HTTP client for fallback operations
|
|
13
|
+
this.httpClient = new process_js_1.SandboxProcess(sandbox);
|
|
14
|
+
}
|
|
15
|
+
streamLogs(identifier, options) {
|
|
16
|
+
const streamId = this.wsClient.sendStream("process:logs:stream:start", { identifier }, (data) => {
|
|
17
|
+
// Handle streaming log data
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
19
|
+
if (data && data.log) {
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
21
|
+
const log = String(data.log);
|
|
22
|
+
// Parse log format: "stdout:" or "stderr:" prefix
|
|
23
|
+
if (log.startsWith('stdout:')) {
|
|
24
|
+
const stdout = log.slice(7);
|
|
25
|
+
options.onStdout?.(stdout);
|
|
26
|
+
options.onLog?.(stdout);
|
|
27
|
+
}
|
|
28
|
+
else if (log.startsWith('stderr:')) {
|
|
29
|
+
const stderr = log.slice(7);
|
|
30
|
+
options.onStderr?.(stderr);
|
|
31
|
+
options.onLog?.(stderr);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
options.onLog?.(log);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}, () => {
|
|
38
|
+
// Stream ended
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
close: () => this.wsClient.cancelStream(streamId),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async exec(process) {
|
|
45
|
+
let onLog;
|
|
46
|
+
if ('onLog' in process && process.onLog) {
|
|
47
|
+
onLog = process.onLog;
|
|
48
|
+
delete process.onLog;
|
|
49
|
+
}
|
|
50
|
+
// Store original wait_for_completion setting
|
|
51
|
+
const shouldWaitForCompletion = process.waitForCompletion;
|
|
52
|
+
// Always start process without wait_for_completion to avoid server-side blocking
|
|
53
|
+
if (shouldWaitForCompletion && onLog) {
|
|
54
|
+
process.waitForCompletion = false;
|
|
55
|
+
}
|
|
56
|
+
const data = await this.wsClient.send("process:execute", process);
|
|
57
|
+
let result = data;
|
|
58
|
+
// Handle wait_for_completion with parallel log streaming
|
|
59
|
+
if (shouldWaitForCompletion && onLog) {
|
|
60
|
+
const streamControl = this.streamLogs(result.pid, { onLog });
|
|
61
|
+
try {
|
|
62
|
+
// Wait for process completion
|
|
63
|
+
result = await this.wait(result.pid, { interval: 500, maxWait: 1000 * 60 * 60 });
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
// Clean up log streaming
|
|
67
|
+
if (streamControl) {
|
|
68
|
+
streamControl.close();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
// For non-blocking execution, set up log streaming immediately if requested
|
|
74
|
+
if (onLog) {
|
|
75
|
+
const streamControl = this.streamLogs(result.pid, { onLog });
|
|
76
|
+
return {
|
|
77
|
+
...result,
|
|
78
|
+
close() {
|
|
79
|
+
if (streamControl) {
|
|
80
|
+
streamControl.close();
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return { ...result, close: () => { } };
|
|
87
|
+
}
|
|
88
|
+
async wait(identifier, { maxWait = 60000, interval = 1000 } = {}) {
|
|
89
|
+
const startTime = Date.now();
|
|
90
|
+
let status = "running";
|
|
91
|
+
let data = await this.get(identifier);
|
|
92
|
+
while (status === "running") {
|
|
93
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
94
|
+
try {
|
|
95
|
+
data = await this.get(identifier);
|
|
96
|
+
status = data.status ?? "running";
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
if (Date.now() - startTime > maxWait) {
|
|
102
|
+
throw new Error("Process did not finish in time");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return data;
|
|
106
|
+
}
|
|
107
|
+
async get(identifier) {
|
|
108
|
+
const data = await this.wsClient.send("process:get", { identifier });
|
|
109
|
+
return data;
|
|
110
|
+
}
|
|
111
|
+
async list() {
|
|
112
|
+
const data = await this.wsClient.send("process:list", {});
|
|
113
|
+
return data;
|
|
114
|
+
}
|
|
115
|
+
async stop(identifier) {
|
|
116
|
+
const data = await this.wsClient.send("process:stop", { identifier });
|
|
117
|
+
return data;
|
|
118
|
+
}
|
|
119
|
+
async kill(identifier) {
|
|
120
|
+
const data = await this.wsClient.send("process:kill", { identifier });
|
|
121
|
+
return data;
|
|
122
|
+
}
|
|
123
|
+
async logs(identifier, type = "all") {
|
|
124
|
+
const data = await this.wsClient.send("process:logs", {
|
|
125
|
+
identifier,
|
|
126
|
+
});
|
|
127
|
+
if (type === "all") {
|
|
128
|
+
return data.logs || "";
|
|
129
|
+
}
|
|
130
|
+
else if (type === "stdout") {
|
|
131
|
+
return data.stdout || "";
|
|
132
|
+
}
|
|
133
|
+
else if (type === "stderr") {
|
|
134
|
+
return data.stderr || "";
|
|
135
|
+
}
|
|
136
|
+
throw new Error("Unsupported log type");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.SandboxProcessWebSocket = SandboxProcessWebSocket;
|
|
@@ -5,11 +5,16 @@ const uuid_1 = require("uuid");
|
|
|
5
5
|
const index_js_1 = require("../client/index.js");
|
|
6
6
|
const logger_js_1 = require("../common/logger.js");
|
|
7
7
|
const index_js_2 = require("./filesystem/index.js");
|
|
8
|
+
const filesystem_ws_js_1 = require("./filesystem/filesystem-ws.js");
|
|
8
9
|
const index_js_3 = require("./network/index.js");
|
|
10
|
+
const network_ws_js_1 = require("./network/network-ws.js");
|
|
9
11
|
const preview_js_1 = require("./preview.js");
|
|
10
12
|
const index_js_4 = require("./process/index.js");
|
|
13
|
+
const process_ws_js_1 = require("./process/process-ws.js");
|
|
11
14
|
const index_js_5 = require("./codegen/index.js");
|
|
15
|
+
const codegen_ws_js_1 = require("./codegen/codegen-ws.js");
|
|
12
16
|
const session_js_1 = require("./session.js");
|
|
17
|
+
const index_js_6 = require("./websocket/index.js");
|
|
13
18
|
const types_js_1 = require("./types.js");
|
|
14
19
|
class SandboxInstance {
|
|
15
20
|
sandbox;
|
|
@@ -19,14 +24,32 @@ class SandboxInstance {
|
|
|
19
24
|
previews;
|
|
20
25
|
sessions;
|
|
21
26
|
codegen;
|
|
27
|
+
wsClient;
|
|
22
28
|
constructor(sandbox) {
|
|
23
29
|
this.sandbox = sandbox;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
// If connection type is websocket, initialize WebSocket client and use WebSocket transport layers
|
|
31
|
+
if (sandbox.connectionType === "websocket") {
|
|
32
|
+
const url = sandbox.forceUrl || sandbox.metadata?.url || "";
|
|
33
|
+
this.wsClient = new index_js_6.WebSocketClient({
|
|
34
|
+
url,
|
|
35
|
+
headers: sandbox.headers,
|
|
36
|
+
});
|
|
37
|
+
// Initialize WebSocket-based action handlers
|
|
38
|
+
this.process = new process_ws_js_1.SandboxProcessWebSocket(sandbox, this.wsClient);
|
|
39
|
+
this.fs = new filesystem_ws_js_1.SandboxFileSystemWebSocket(sandbox, this.process, this.wsClient);
|
|
40
|
+
this.network = new network_ws_js_1.SandboxNetworkWebSocket(sandbox, this.wsClient);
|
|
41
|
+
this.codegen = new codegen_ws_js_1.SandboxCodegenWebSocket(sandbox, this.wsClient);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Default to HTTP-based action handlers
|
|
45
|
+
this.process = new index_js_4.SandboxProcess(sandbox);
|
|
46
|
+
this.fs = new index_js_2.SandboxFileSystem(sandbox, this.process);
|
|
47
|
+
this.network = new index_js_3.SandboxNetwork(sandbox);
|
|
48
|
+
this.codegen = new index_js_5.SandboxCodegen(sandbox);
|
|
49
|
+
}
|
|
50
|
+
// These are always HTTP-based
|
|
27
51
|
this.previews = new preview_js_1.SandboxPreviews(sandbox);
|
|
28
52
|
this.sessions = new session_js_1.SandboxSessions(sandbox);
|
|
29
|
-
this.codegen = new index_js_5.SandboxCodegen(sandbox);
|
|
30
53
|
}
|
|
31
54
|
get metadata() {
|
|
32
55
|
return this.sandbox.metadata;
|
|
@@ -45,10 +68,17 @@ class SandboxInstance {
|
|
|
45
68
|
logger_js_1.logger.warn("⚠️ Warning: sandbox.wait() is deprecated. You don't need to wait for the sandbox to be deployed anymore.");
|
|
46
69
|
return this;
|
|
47
70
|
}
|
|
71
|
+
closeConnection() {
|
|
72
|
+
if (this.wsClient) {
|
|
73
|
+
this.wsClient.close();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
48
76
|
static async create(sandbox, { safe = true } = {}) {
|
|
49
77
|
const defaultName = `sandbox-${(0, uuid_1.v4)().replace(/-/g, '').substring(0, 8)}`;
|
|
50
78
|
const defaultImage = `blaxel/base-image:latest`;
|
|
51
79
|
const defaultMemory = 4096;
|
|
80
|
+
// Store connection type if provided
|
|
81
|
+
let connectionType;
|
|
52
82
|
// Handle SandboxCreateConfiguration or simple dict with name/image/memory/ports/envs/volumes keys
|
|
53
83
|
if (!sandbox ||
|
|
54
84
|
'name' in sandbox ||
|
|
@@ -58,7 +88,8 @@ class SandboxInstance {
|
|
|
58
88
|
'envs' in sandbox ||
|
|
59
89
|
'volumes' in sandbox ||
|
|
60
90
|
'lifecycle' in sandbox ||
|
|
61
|
-
'snapshotEnabled' in sandbox
|
|
91
|
+
'snapshotEnabled' in sandbox ||
|
|
92
|
+
'connectionType' in sandbox) {
|
|
62
93
|
if (!sandbox)
|
|
63
94
|
sandbox = {};
|
|
64
95
|
if (!sandbox.name)
|
|
@@ -67,6 +98,7 @@ class SandboxInstance {
|
|
|
67
98
|
sandbox.image = defaultImage;
|
|
68
99
|
if (!sandbox.memory)
|
|
69
100
|
sandbox.memory = defaultMemory;
|
|
101
|
+
connectionType = sandbox.connectionType;
|
|
70
102
|
const ports = (0, types_js_1.normalizePorts)(sandbox.ports);
|
|
71
103
|
const envs = (0, types_js_1.normalizeEnvs)(sandbox.envs);
|
|
72
104
|
const volumes = (0, types_js_1.normalizeVolumes)(sandbox.volumes);
|
|
@@ -115,7 +147,16 @@ class SandboxInstance {
|
|
|
115
147
|
body: sandbox,
|
|
116
148
|
throwOnError: true,
|
|
117
149
|
});
|
|
118
|
-
|
|
150
|
+
// Add connection type to configuration
|
|
151
|
+
const config = {
|
|
152
|
+
...data,
|
|
153
|
+
connectionType: connectionType || "http",
|
|
154
|
+
};
|
|
155
|
+
const instance = new SandboxInstance(config);
|
|
156
|
+
// Connect WebSocket if needed
|
|
157
|
+
if (connectionType === "websocket" && instance.wsClient) {
|
|
158
|
+
await instance.wsClient.connect();
|
|
159
|
+
}
|
|
119
160
|
// TODO remove this part once we have a better way to handle this
|
|
120
161
|
if (safe) {
|
|
121
162
|
try {
|
|
@@ -125,20 +166,34 @@ class SandboxInstance {
|
|
|
125
166
|
}
|
|
126
167
|
return instance;
|
|
127
168
|
}
|
|
128
|
-
static async get(sandboxName) {
|
|
169
|
+
static async get(sandboxName, connectionType) {
|
|
129
170
|
const { data } = await (0, index_js_1.getSandbox)({
|
|
130
171
|
path: {
|
|
131
172
|
sandboxName,
|
|
132
173
|
},
|
|
133
174
|
throwOnError: true,
|
|
134
175
|
});
|
|
135
|
-
|
|
176
|
+
// Add connection type to configuration
|
|
177
|
+
const config = {
|
|
178
|
+
...data,
|
|
179
|
+
connectionType: connectionType || "http",
|
|
180
|
+
};
|
|
181
|
+
const instance = new SandboxInstance(config);
|
|
182
|
+
// Connect WebSocket if needed
|
|
183
|
+
if (connectionType === "websocket" && instance.wsClient) {
|
|
184
|
+
await instance.wsClient.connect();
|
|
185
|
+
}
|
|
186
|
+
return instance;
|
|
136
187
|
}
|
|
137
188
|
static async list() {
|
|
138
189
|
const { data } = await (0, index_js_1.listSandboxes)({ throwOnError: true });
|
|
139
190
|
return data.map((sandbox) => new SandboxInstance(sandbox));
|
|
140
191
|
}
|
|
141
|
-
static async delete(sandboxName) {
|
|
192
|
+
static async delete(sandboxName, instance) {
|
|
193
|
+
// Close WebSocket connection if instance is provided
|
|
194
|
+
if (instance && instance.wsClient) {
|
|
195
|
+
instance.closeConnection();
|
|
196
|
+
}
|
|
142
197
|
const { data } = await (0, index_js_1.deleteSandbox)({
|
|
143
198
|
path: {
|
|
144
199
|
sandboxName,
|
|
@@ -168,8 +223,10 @@ class SandboxInstance {
|
|
|
168
223
|
if (!name) {
|
|
169
224
|
throw new Error("Sandbox name is required");
|
|
170
225
|
}
|
|
226
|
+
// Get connection type if specified
|
|
227
|
+
const connectionType = 'connectionType' in sandbox ? sandbox.connectionType : undefined;
|
|
171
228
|
// Get the existing sandbox to check its status
|
|
172
|
-
const sandboxInstance = await SandboxInstance.get(name);
|
|
229
|
+
const sandboxInstance = await SandboxInstance.get(name, connectionType);
|
|
173
230
|
// If the sandbox is TERMINATED, treat it as not existing
|
|
174
231
|
if (sandboxInstance.status === "TERMINATED") {
|
|
175
232
|
// Create a new sandbox - backend will handle cleanup of the terminated one
|