@blaxel/core 0.2.49-dev.211 → 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.
Files changed (53) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/common/settings.js +2 -2
  3. package/dist/cjs/sandbox/codegen/codegen-ws.js +30 -0
  4. package/dist/cjs/sandbox/filesystem/filesystem-ws.js +106 -0
  5. package/dist/cjs/sandbox/network/network-ws.js +12 -0
  6. package/dist/cjs/sandbox/process/process-ws.js +139 -0
  7. package/dist/cjs/sandbox/sandbox.js +67 -10
  8. package/dist/cjs/sandbox/websocket/client.js +275 -0
  9. package/dist/cjs/sandbox/websocket/index.js +17 -0
  10. package/dist/cjs/types/sandbox/codegen/codegen-ws.d.ts +10 -0
  11. package/dist/cjs/types/sandbox/filesystem/filesystem-ws.d.ts +35 -0
  12. package/dist/cjs/types/sandbox/network/network-ws.d.ts +7 -0
  13. package/dist/cjs/types/sandbox/process/process-ws.d.ts +27 -0
  14. package/dist/cjs/types/sandbox/sandbox.d.ts +12 -6
  15. package/dist/cjs/types/sandbox/types.d.ts +3 -0
  16. package/dist/cjs/types/sandbox/websocket/client.d.ts +49 -0
  17. package/dist/cjs/types/sandbox/websocket/index.d.ts +1 -0
  18. package/dist/cjs-browser/.tsbuildinfo +1 -1
  19. package/dist/cjs-browser/common/settings.js +2 -2
  20. package/dist/cjs-browser/sandbox/codegen/codegen-ws.js +30 -0
  21. package/dist/cjs-browser/sandbox/filesystem/filesystem-ws.js +106 -0
  22. package/dist/cjs-browser/sandbox/network/network-ws.js +12 -0
  23. package/dist/cjs-browser/sandbox/process/process-ws.js +139 -0
  24. package/dist/cjs-browser/sandbox/sandbox.js +67 -10
  25. package/dist/cjs-browser/sandbox/websocket/client.js +275 -0
  26. package/dist/cjs-browser/sandbox/websocket/index.js +17 -0
  27. package/dist/cjs-browser/types/sandbox/codegen/codegen-ws.d.ts +10 -0
  28. package/dist/cjs-browser/types/sandbox/filesystem/filesystem-ws.d.ts +35 -0
  29. package/dist/cjs-browser/types/sandbox/network/network-ws.d.ts +7 -0
  30. package/dist/cjs-browser/types/sandbox/process/process-ws.d.ts +27 -0
  31. package/dist/cjs-browser/types/sandbox/sandbox.d.ts +12 -6
  32. package/dist/cjs-browser/types/sandbox/types.d.ts +3 -0
  33. package/dist/cjs-browser/types/sandbox/websocket/client.d.ts +49 -0
  34. package/dist/cjs-browser/types/sandbox/websocket/index.d.ts +1 -0
  35. package/dist/esm/.tsbuildinfo +1 -1
  36. package/dist/esm/common/settings.js +2 -2
  37. package/dist/esm/sandbox/codegen/codegen-ws.js +26 -0
  38. package/dist/esm/sandbox/filesystem/filesystem-ws.js +102 -0
  39. package/dist/esm/sandbox/network/network-ws.js +8 -0
  40. package/dist/esm/sandbox/process/process-ws.js +135 -0
  41. package/dist/esm/sandbox/sandbox.js +67 -10
  42. package/dist/esm/sandbox/websocket/client.js +271 -0
  43. package/dist/esm/sandbox/websocket/index.js +1 -0
  44. package/dist/esm-browser/.tsbuildinfo +1 -1
  45. package/dist/esm-browser/common/settings.js +2 -2
  46. package/dist/esm-browser/sandbox/codegen/codegen-ws.js +26 -0
  47. package/dist/esm-browser/sandbox/filesystem/filesystem-ws.js +102 -0
  48. package/dist/esm-browser/sandbox/network/network-ws.js +8 -0
  49. package/dist/esm-browser/sandbox/process/process-ws.js +135 -0
  50. package/dist/esm-browser/sandbox/sandbox.js +67 -10
  51. package/dist/esm-browser/sandbox/websocket/client.js +271 -0
  52. package/dist/esm-browser/sandbox/websocket/index.js +1 -0
  53. 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;
@@ -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
- this.process = new index_js_4.SandboxProcess(sandbox);
25
- this.fs = new index_js_2.SandboxFileSystem(sandbox, this.process);
26
- this.network = new index_js_3.SandboxNetwork(sandbox);
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
- const instance = new SandboxInstance(data);
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
- return new SandboxInstance(data);
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