@blaxel/core 0.2.49-preview.112 → 0.2.50-dev.215

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 (87) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/agents/index.js +2 -2
  3. package/dist/cjs/authentication/clientcredentials.js +4 -1
  4. package/dist/cjs/common/internal.js +40 -0
  5. package/dist/cjs/common/settings.js +5 -2
  6. package/dist/cjs/jobs/jobs.js +2 -2
  7. package/dist/cjs/jobs/start.js +32 -1
  8. package/dist/cjs/sandbox/action.js +1 -2
  9. package/dist/cjs/sandbox/codegen/codegen-ws.js +30 -0
  10. package/dist/cjs/sandbox/filesystem/filesystem-ws.js +106 -0
  11. package/dist/cjs/sandbox/network/network-ws.js +12 -0
  12. package/dist/cjs/sandbox/process/process-ws.js +139 -0
  13. package/dist/cjs/sandbox/sandbox.js +67 -10
  14. package/dist/cjs/sandbox/websocket/client.js +269 -0
  15. package/dist/cjs/sandbox/websocket/index.js +17 -0
  16. package/dist/cjs/tools/mcpTool.js +2 -2
  17. package/dist/cjs/types/client/types.gen.d.ts +1 -1
  18. package/dist/cjs/types/common/internal.d.ts +2 -0
  19. package/dist/cjs/types/common/settings.d.ts +1 -0
  20. package/dist/cjs/types/sandbox/codegen/codegen-ws.d.ts +10 -0
  21. package/dist/cjs/types/sandbox/filesystem/filesystem-ws.d.ts +35 -0
  22. package/dist/cjs/types/sandbox/network/network-ws.d.ts +7 -0
  23. package/dist/cjs/types/sandbox/process/process-ws.d.ts +27 -0
  24. package/dist/cjs/types/sandbox/sandbox.d.ts +12 -6
  25. package/dist/cjs/types/sandbox/types.d.ts +3 -0
  26. package/dist/cjs/types/sandbox/websocket/client.d.ts +48 -0
  27. package/dist/cjs/types/sandbox/websocket/index.d.ts +1 -0
  28. package/dist/cjs-browser/.tsbuildinfo +1 -1
  29. package/dist/cjs-browser/agents/index.js +2 -2
  30. package/dist/cjs-browser/authentication/clientcredentials.js +4 -1
  31. package/dist/cjs-browser/common/internal.js +40 -0
  32. package/dist/cjs-browser/common/settings.js +5 -2
  33. package/dist/cjs-browser/jobs/jobs.js +2 -2
  34. package/dist/cjs-browser/jobs/start.js +32 -1
  35. package/dist/cjs-browser/sandbox/action.js +1 -2
  36. package/dist/cjs-browser/sandbox/codegen/codegen-ws.js +30 -0
  37. package/dist/cjs-browser/sandbox/filesystem/filesystem-ws.js +106 -0
  38. package/dist/cjs-browser/sandbox/network/network-ws.js +12 -0
  39. package/dist/cjs-browser/sandbox/process/process-ws.js +139 -0
  40. package/dist/cjs-browser/sandbox/sandbox.js +67 -10
  41. package/dist/cjs-browser/sandbox/websocket/client.js +269 -0
  42. package/dist/cjs-browser/sandbox/websocket/index.js +17 -0
  43. package/dist/cjs-browser/tools/mcpTool.js +2 -2
  44. package/dist/cjs-browser/types/client/types.gen.d.ts +1 -1
  45. package/dist/cjs-browser/types/common/internal.d.ts +2 -0
  46. package/dist/cjs-browser/types/common/settings.d.ts +1 -0
  47. package/dist/cjs-browser/types/sandbox/codegen/codegen-ws.d.ts +10 -0
  48. package/dist/cjs-browser/types/sandbox/filesystem/filesystem-ws.d.ts +35 -0
  49. package/dist/cjs-browser/types/sandbox/network/network-ws.d.ts +7 -0
  50. package/dist/cjs-browser/types/sandbox/process/process-ws.d.ts +27 -0
  51. package/dist/cjs-browser/types/sandbox/sandbox.d.ts +12 -6
  52. package/dist/cjs-browser/types/sandbox/types.d.ts +3 -0
  53. package/dist/cjs-browser/types/sandbox/websocket/client.d.ts +48 -0
  54. package/dist/cjs-browser/types/sandbox/websocket/index.d.ts +1 -0
  55. package/dist/esm/.tsbuildinfo +1 -1
  56. package/dist/esm/agents/index.js +3 -3
  57. package/dist/esm/authentication/clientcredentials.js +4 -1
  58. package/dist/esm/common/internal.js +38 -0
  59. package/dist/esm/common/settings.js +5 -2
  60. package/dist/esm/jobs/jobs.js +3 -3
  61. package/dist/esm/jobs/start.js +32 -1
  62. package/dist/esm/sandbox/action.js +2 -3
  63. package/dist/esm/sandbox/codegen/codegen-ws.js +26 -0
  64. package/dist/esm/sandbox/filesystem/filesystem-ws.js +102 -0
  65. package/dist/esm/sandbox/network/network-ws.js +8 -0
  66. package/dist/esm/sandbox/process/process-ws.js +135 -0
  67. package/dist/esm/sandbox/sandbox.js +67 -10
  68. package/dist/esm/sandbox/websocket/client.js +265 -0
  69. package/dist/esm/sandbox/websocket/index.js +1 -0
  70. package/dist/esm/tools/mcpTool.js +3 -3
  71. package/dist/esm-browser/.tsbuildinfo +1 -1
  72. package/dist/esm-browser/agents/index.js +3 -3
  73. package/dist/esm-browser/authentication/clientcredentials.js +4 -1
  74. package/dist/esm-browser/common/internal.js +38 -0
  75. package/dist/esm-browser/common/settings.js +5 -2
  76. package/dist/esm-browser/jobs/jobs.js +3 -3
  77. package/dist/esm-browser/jobs/start.js +32 -1
  78. package/dist/esm-browser/sandbox/action.js +2 -3
  79. package/dist/esm-browser/sandbox/codegen/codegen-ws.js +26 -0
  80. package/dist/esm-browser/sandbox/filesystem/filesystem-ws.js +102 -0
  81. package/dist/esm-browser/sandbox/network/network-ws.js +8 -0
  82. package/dist/esm-browser/sandbox/process/process-ws.js +135 -0
  83. package/dist/esm-browser/sandbox/sandbox.js +67 -10
  84. package/dist/esm-browser/sandbox/websocket/client.js +265 -0
  85. package/dist/esm-browser/sandbox/websocket/index.js +1 -0
  86. package/dist/esm-browser/tools/mcpTool.js +3 -3
  87. package/package.json +2 -2
@@ -0,0 +1,265 @@
1
+ import { v4 as uuidv4 } from "uuid";
2
+ import { getWebSocket } from "../../common/node.js";
3
+ import { settings } from "../../common/settings.js";
4
+ export class WebSocketClient {
5
+ ws = null;
6
+ WebSocketClass = null;
7
+ url;
8
+ reconnect;
9
+ reconnectInterval;
10
+ maxReconnectAttempts;
11
+ reconnectAttempts = 0;
12
+ pendingRequests = new Map();
13
+ streamHandlers = new Map();
14
+ isClosing = false;
15
+ connectionPromise = null;
16
+ heartbeatInterval = null;
17
+ reconnectTimeout = null;
18
+ lastPongReceived = Date.now();
19
+ constructor(options) {
20
+ this.url = options.url;
21
+ this.reconnect = options.reconnect ?? true;
22
+ this.reconnectInterval = options.reconnectInterval ?? 5000;
23
+ this.maxReconnectAttempts = options.maxReconnectAttempts ?? 5;
24
+ }
25
+ async connect() {
26
+ if (this.connectionPromise) {
27
+ return this.connectionPromise;
28
+ }
29
+ this.connectionPromise = this.initializeConnection();
30
+ return this.connectionPromise;
31
+ }
32
+ async initializeConnection() {
33
+ return new Promise((resolve, reject) => {
34
+ // Get WebSocket class and connect
35
+ void (async () => {
36
+ try {
37
+ // Get WebSocket class if not already loaded
38
+ if (!this.WebSocketClass) {
39
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
40
+ this.WebSocketClass = await getWebSocket();
41
+ }
42
+ // Convert http/https URL to ws/wss
43
+ let wsUrl = this.url;
44
+ if (wsUrl.startsWith("http://")) {
45
+ wsUrl = wsUrl.replace("http://", "ws://");
46
+ }
47
+ else if (wsUrl.startsWith("https://")) {
48
+ wsUrl = wsUrl.replace("https://", "wss://");
49
+ }
50
+ // Add /ws endpoint if not present
51
+ if (!wsUrl.endsWith("/ws")) {
52
+ wsUrl = `${wsUrl}/ws`;
53
+ }
54
+ wsUrl = `${wsUrl}?token=${settings.token}`;
55
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
56
+ this.ws = new this.WebSocketClass(wsUrl);
57
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
58
+ this.ws.onopen = () => {
59
+ this.reconnectAttempts = 0;
60
+ this.startHeartbeat();
61
+ resolve();
62
+ };
63
+ this.ws.onmessage = (event) => {
64
+ this.handleMessage(event);
65
+ };
66
+ this.ws.onerror = (error) => {
67
+ console.error("WebSocket error:", error);
68
+ reject(new Error("WebSocket connection error"));
69
+ };
70
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
71
+ this.ws.onclose = () => {
72
+ this.stopHeartbeat();
73
+ this.connectionPromise = null;
74
+ if (!this.isClosing && this.reconnect && this.reconnectAttempts < this.maxReconnectAttempts) {
75
+ this.reconnectAttempts++;
76
+ this.reconnectTimeout = setTimeout(() => {
77
+ this.connect().catch(console.error);
78
+ }, this.reconnectInterval);
79
+ // Allow process to exit even if reconnect timeout is pending
80
+ if (this.reconnectTimeout.unref) {
81
+ this.reconnectTimeout.unref();
82
+ }
83
+ }
84
+ else {
85
+ // Reject all pending requests
86
+ this.pendingRequests.forEach(({ reject }) => {
87
+ reject(new Error("WebSocket connection closed"));
88
+ });
89
+ this.pendingRequests.clear();
90
+ }
91
+ };
92
+ // Handle pong messages for heartbeat
93
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
94
+ if (typeof this.ws.on === 'function') {
95
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
96
+ this.ws.on('pong', () => {
97
+ this.lastPongReceived = Date.now();
98
+ });
99
+ }
100
+ }
101
+ catch (error) {
102
+ reject(error instanceof Error ? error : new Error(String(error)));
103
+ }
104
+ })();
105
+ });
106
+ }
107
+ startHeartbeat() {
108
+ // Send ping every 30 seconds
109
+ this.heartbeatInterval = setInterval(() => {
110
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
111
+ if (this.ws && this.WebSocketClass && this.ws.readyState === this.WebSocketClass.OPEN) {
112
+ // Check if we received a pong recently (within 60 seconds)
113
+ if (Date.now() - this.lastPongReceived > 60000) {
114
+ console.warn("WebSocket heartbeat timeout, closing connection");
115
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
116
+ this.ws.close();
117
+ return;
118
+ }
119
+ // Send ping
120
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
121
+ if (typeof this.ws.ping === 'function') {
122
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
123
+ this.ws.ping();
124
+ }
125
+ }
126
+ }, 30000);
127
+ // Allow process to exit even if heartbeat interval is active
128
+ if (this.heartbeatInterval.unref) {
129
+ this.heartbeatInterval.unref();
130
+ }
131
+ }
132
+ stopHeartbeat() {
133
+ if (this.heartbeatInterval) {
134
+ clearInterval(this.heartbeatInterval);
135
+ this.heartbeatInterval = null;
136
+ }
137
+ }
138
+ handleMessage(event) {
139
+ try {
140
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
141
+ const response = JSON.parse(String(event.data));
142
+ // Check if this is a streaming response
143
+ if (response.stream) {
144
+ const streamHandler = this.streamHandlers.get(response.id);
145
+ if (streamHandler) {
146
+ // Call the data handler with the response data
147
+ streamHandler.onData(response.data);
148
+ // If stream is done, call end handler and clean up
149
+ if (response.done) {
150
+ streamHandler.onEnd();
151
+ this.streamHandlers.delete(response.id);
152
+ }
153
+ }
154
+ return;
155
+ }
156
+ // Regular request-response handling
157
+ const pending = this.pendingRequests.get(response.id);
158
+ if (pending) {
159
+ this.pendingRequests.delete(response.id);
160
+ if (response.success) {
161
+ pending.resolve(response.data);
162
+ }
163
+ else {
164
+ pending.reject(new Error(response.error || "Unknown error"));
165
+ }
166
+ }
167
+ }
168
+ catch (error) {
169
+ console.error("Failed to parse WebSocket message:", error);
170
+ }
171
+ }
172
+ async send(operation, data = {}) {
173
+ // Ensure we're connected
174
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
175
+ if (!this.ws || !this.WebSocketClass || this.ws.readyState !== this.WebSocketClass.OPEN) {
176
+ await this.connect();
177
+ }
178
+ return new Promise((resolve, reject) => {
179
+ const id = uuidv4();
180
+ const message = {
181
+ id,
182
+ operation,
183
+ data,
184
+ };
185
+ // Store the promise handlers
186
+ this.pendingRequests.set(id, { resolve, reject });
187
+ // Set a timeout for the request (60 seconds)
188
+ setTimeout(() => {
189
+ if (this.pendingRequests.has(id)) {
190
+ this.pendingRequests.delete(id);
191
+ reject(new Error("Request timeout"));
192
+ }
193
+ }, 60000);
194
+ // Send the message
195
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
196
+ if (this.ws && this.WebSocketClass && this.ws.readyState === this.WebSocketClass.OPEN) {
197
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
198
+ this.ws.send(JSON.stringify(message));
199
+ }
200
+ else {
201
+ this.pendingRequests.delete(id);
202
+ reject(new Error("WebSocket not connected"));
203
+ }
204
+ });
205
+ }
206
+ sendStream(operation, data, onData, onEnd) {
207
+ // Ensure we're connected
208
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
209
+ if (!this.ws || !this.WebSocketClass || this.ws.readyState !== this.WebSocketClass.OPEN) {
210
+ throw new Error("WebSocket not connected");
211
+ }
212
+ const id = uuidv4();
213
+ const message = {
214
+ id,
215
+ operation,
216
+ data,
217
+ };
218
+ // Store the stream handlers
219
+ this.streamHandlers.set(id, { onData, onEnd });
220
+ // Send the message
221
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
222
+ this.ws.send(JSON.stringify(message));
223
+ return id;
224
+ }
225
+ cancelStream(id) {
226
+ this.streamHandlers.delete(id);
227
+ }
228
+ close() {
229
+ this.isClosing = true;
230
+ this.reconnect = false;
231
+ this.stopHeartbeat();
232
+ // Clear reconnect timeout if any
233
+ if (this.reconnectTimeout) {
234
+ clearTimeout(this.reconnectTimeout);
235
+ this.reconnectTimeout = null;
236
+ }
237
+ if (this.ws) {
238
+ // In Node.js (ws package), use terminate() to forcefully close the connection
239
+ // This immediately closes the socket without waiting for the close handshake
240
+ // In browser, terminate() doesn't exist, so we fall back to close()
241
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
242
+ if (typeof this.ws.terminate === 'function') {
243
+ // Node.js ws package - force immediate close
244
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
245
+ this.ws.terminate();
246
+ }
247
+ else {
248
+ // Browser WebSocket - graceful close
249
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
250
+ this.ws.close();
251
+ }
252
+ this.ws = null;
253
+ }
254
+ // Reject all pending requests
255
+ this.pendingRequests.forEach(({ reject }) => {
256
+ reject(new Error("WebSocket client closed"));
257
+ });
258
+ this.pendingRequests.clear();
259
+ this.connectionPromise = null;
260
+ }
261
+ get isConnected() {
262
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
263
+ return this.ws !== null && this.WebSocketClass !== null && this.ws.readyState === this.WebSocketClass.OPEN;
264
+ }
265
+ }
@@ -0,0 +1 @@
1
+ export * from "./client.js";
@@ -1,6 +1,6 @@
1
1
  import { Client as ModelContextProtocolClient } from "@modelcontextprotocol/sdk/client/index.js";
2
2
  import { env } from "../common/env.js";
3
- import { getForcedUrl, getGlobalUniqueHash } from "../common/internal.js";
3
+ import { generateInternalUrl, getForcedUrl } from "../common/internal.js";
4
4
  import { logger } from "../common/logger.js";
5
5
  import { settings } from "../common/settings.js";
6
6
  import { authenticate } from "../index.js";
@@ -51,8 +51,8 @@ export class McpTool {
51
51
  return new URL(`${settings.runUrl}/${settings.workspace}/${this.pluralType}/${this.name}`);
52
52
  }
53
53
  get internalUrl() {
54
- const hash = getGlobalUniqueHash(settings.workspace, this.type, this.name);
55
- return new URL(`${settings.runInternalProtocol}://bl-${settings.env}-${hash}.${settings.runInternalHostname}`);
54
+ const url = generateInternalUrl(settings.workspace, this.type, this.name, settings.env, settings.runInternalProtocol, settings.runInternalHostname, settings.blCloud, settings.workspaceId);
55
+ return new URL(url);
56
56
  }
57
57
  get forcedUrl() {
58
58
  return getForcedUrl(this.type, this.name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blaxel/core",
3
- "version": "0.2.49-preview.112",
3
+ "version": "0.2.50-dev.215",
4
4
  "description": "Blaxel Core SDK for TypeScript",
5
5
  "license": "MIT",
6
6
  "author": "Blaxel, INC (https://blaxel.ai)",
@@ -74,7 +74,7 @@
74
74
  "vite": "^5.2.0",
75
75
  "vitest": "^1.5.0"
76
76
  },
77
- "commit": "d50dddc5a1963abd22bad3b294e9f6096c3e8287",
77
+ "commit": "833c34cbba3735060a62bdd3594fa917160f3d3c",
78
78
  "scripts": {
79
79
  "lint": "eslint src/",
80
80
  "dev": "tsc --watch",