@sandbox-engine/sdk 0.2.1 → 0.2.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/index.d.mts CHANGED
@@ -1,6 +1,20 @@
1
- import WebSocket from 'ws';
2
1
  import { EventEmitter } from 'node:events';
3
2
 
3
+ interface WsLike {
4
+ on(event: 'message', handler: (data: unknown) => void): void;
5
+ on(event: 'error', handler: (err: Error) => void): void;
6
+ on(event: 'close', handler: () => void): void;
7
+ on(event: 'open', handler: () => void): void;
8
+ once(event: 'message', handler: (data: unknown) => void): void;
9
+ once(event: 'error', handler: (err: Error) => void): void;
10
+ once(event: 'open', handler: () => void): void;
11
+ send(data: string): void;
12
+ close(): void;
13
+ readyState: number;
14
+ readonly OPEN: number;
15
+ readonly CONNECTING: number;
16
+ }
17
+
4
18
  declare class HttpClient {
5
19
  private readonly baseUrl;
6
20
  private readonly apiKey;
@@ -9,7 +23,7 @@ declare class HttpClient {
9
23
  get<T>(path: string, query?: Record<string, string>): Promise<T>;
10
24
  post<T>(path: string, body?: unknown, timeoutMs?: number): Promise<T>;
11
25
  delete<T = void>(path: string, query?: Record<string, string>): Promise<T>;
12
- openWebSocket(path: string): WebSocket;
26
+ openWebSocket(path: string): Promise<WsLike>;
13
27
  }
14
28
 
15
29
  interface SandboxOptions {
@@ -174,7 +188,7 @@ declare class Filesystem {
174
188
 
175
189
  declare class Process extends EventEmitter {
176
190
  private ws;
177
- constructor(ws: WebSocket);
191
+ constructor(ws: WsLike);
178
192
  kill(): void;
179
193
  wait(): Promise<ExecResult>;
180
194
  }
@@ -198,9 +212,9 @@ declare class BackgroundProcess {
198
212
  }>;
199
213
  waitForPort(port: number, opts?: WaitForPortOptions): Promise<void>;
200
214
  waitForLog(pattern: string | RegExp, opts?: WaitForLogOptions): Promise<string>;
201
- streamLogs(opts?: StreamLogsOptions): {
215
+ streamLogs(opts?: StreamLogsOptions): Promise<{
202
216
  close: () => void;
203
- };
217
+ }>;
204
218
  }
205
219
  declare class ProcessManager {
206
220
  private readonly sandboxId;
@@ -215,7 +229,7 @@ declare class ProcessManager {
215
229
 
216
230
  declare class Terminal extends EventEmitter {
217
231
  private ws;
218
- constructor(ws: WebSocket);
232
+ constructor(ws: WsLike);
219
233
  write(data: string): void;
220
234
  resize(cols: number, rows: number): void;
221
235
  close(): void;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,20 @@
1
- import WebSocket from 'ws';
2
1
  import { EventEmitter } from 'node:events';
3
2
 
3
+ interface WsLike {
4
+ on(event: 'message', handler: (data: unknown) => void): void;
5
+ on(event: 'error', handler: (err: Error) => void): void;
6
+ on(event: 'close', handler: () => void): void;
7
+ on(event: 'open', handler: () => void): void;
8
+ once(event: 'message', handler: (data: unknown) => void): void;
9
+ once(event: 'error', handler: (err: Error) => void): void;
10
+ once(event: 'open', handler: () => void): void;
11
+ send(data: string): void;
12
+ close(): void;
13
+ readyState: number;
14
+ readonly OPEN: number;
15
+ readonly CONNECTING: number;
16
+ }
17
+
4
18
  declare class HttpClient {
5
19
  private readonly baseUrl;
6
20
  private readonly apiKey;
@@ -9,7 +23,7 @@ declare class HttpClient {
9
23
  get<T>(path: string, query?: Record<string, string>): Promise<T>;
10
24
  post<T>(path: string, body?: unknown, timeoutMs?: number): Promise<T>;
11
25
  delete<T = void>(path: string, query?: Record<string, string>): Promise<T>;
12
- openWebSocket(path: string): WebSocket;
26
+ openWebSocket(path: string): Promise<WsLike>;
13
27
  }
14
28
 
15
29
  interface SandboxOptions {
@@ -174,7 +188,7 @@ declare class Filesystem {
174
188
 
175
189
  declare class Process extends EventEmitter {
176
190
  private ws;
177
- constructor(ws: WebSocket);
191
+ constructor(ws: WsLike);
178
192
  kill(): void;
179
193
  wait(): Promise<ExecResult>;
180
194
  }
@@ -198,9 +212,9 @@ declare class BackgroundProcess {
198
212
  }>;
199
213
  waitForPort(port: number, opts?: WaitForPortOptions): Promise<void>;
200
214
  waitForLog(pattern: string | RegExp, opts?: WaitForLogOptions): Promise<string>;
201
- streamLogs(opts?: StreamLogsOptions): {
215
+ streamLogs(opts?: StreamLogsOptions): Promise<{
202
216
  close: () => void;
203
- };
217
+ }>;
204
218
  }
205
219
  declare class ProcessManager {
206
220
  private readonly sandboxId;
@@ -215,7 +229,7 @@ declare class ProcessManager {
215
229
 
216
230
  declare class Terminal extends EventEmitter {
217
231
  private ws;
218
- constructor(ws: WebSocket);
232
+ constructor(ws: WsLike);
219
233
  write(data: string): void;
220
234
  resize(cols: number, rows: number): void;
221
235
  close(): void;
package/dist/index.js CHANGED
@@ -39,8 +39,37 @@ __export(index_exports, {
39
39
  });
40
40
  module.exports = __toCommonJS(index_exports);
41
41
 
42
+ // src/ws-compat.ts
43
+ var import_node_events = require("events");
44
+ var WsEmitterAdapter = class extends import_node_events.EventEmitter {
45
+ constructor(ws) {
46
+ super();
47
+ this.ws = ws;
48
+ ws.accept?.();
49
+ ws.addEventListener("message", (e) => {
50
+ const raw = e.data;
51
+ this.emit("message", typeof raw === "string" ? raw : String(raw));
52
+ });
53
+ ws.addEventListener("error", (e) => this.emit("error", e));
54
+ ws.addEventListener("close", () => this.emit("close"));
55
+ ws.addEventListener("open", () => this.emit("open"));
56
+ }
57
+ ws;
58
+ OPEN = 1;
59
+ CONNECTING = 0;
60
+ get readyState() {
61
+ return this.ws.readyState;
62
+ }
63
+ send(data) {
64
+ this.ws.send(data);
65
+ }
66
+ close() {
67
+ this.ws.close();
68
+ }
69
+ };
70
+ var IS_CF_WORKERS = typeof globalThis.WebSocketPair !== "undefined";
71
+
42
72
  // src/client.ts
43
- var import_ws = __toESM(require("ws"));
44
73
  var HttpClient = class {
45
74
  constructor(baseUrl, apiKey) {
46
75
  this.baseUrl = baseUrl;
@@ -98,11 +127,27 @@ var HttpClient = class {
98
127
  if (!text) return void 0;
99
128
  return JSON.parse(text);
100
129
  }
101
- openWebSocket(path) {
130
+ // ── WebSocket ───────────────────────────────────────────────────────────────
131
+ // CF Workers: uses fetch() with Upgrade header (supports Authorization).
132
+ // Node.js: uses the ws package (installed as an optional dependency).
133
+ async openWebSocket(path) {
134
+ const authHeader = `Bearer ${this.apiKey}`;
135
+ if (IS_CF_WORKERS) {
136
+ const httpUrl = this.baseUrl + path;
137
+ const resp = await fetch(httpUrl, {
138
+ headers: {
139
+ Upgrade: "websocket",
140
+ Connection: "Upgrade",
141
+ Authorization: authHeader
142
+ }
143
+ });
144
+ const cfWs = resp.webSocket;
145
+ if (!cfWs) throw new Error("WebSocket upgrade failed \u2014 server did not accept");
146
+ return new WsEmitterAdapter(cfWs);
147
+ }
102
148
  const wsUrl = this.baseUrl.replace(/^http/, "ws") + path;
103
- return new import_ws.default(wsUrl, {
104
- headers: { authorization: `Bearer ${this.apiKey}` }
105
- });
149
+ const { default: WS } = await import("ws");
150
+ return new WS(wsUrl, { headers: { authorization: authHeader } });
106
151
  }
107
152
  };
108
153
 
@@ -169,7 +214,7 @@ var Filesystem = class {
169
214
  });
170
215
  }
171
216
  async watch(dirPath, opts) {
172
- const ws = this.client.openWebSocket(`/api/sandboxes/${this.sandboxId}/files/watch`);
217
+ const ws = await this.client.openWebSocket(`/api/sandboxes/${this.sandboxId}/files/watch`);
173
218
  await new Promise((resolve, reject) => {
174
219
  ws.once("open", () => {
175
220
  ws.send(JSON.stringify({ path: dirPath, recursive: opts.recursive ?? false }));
@@ -179,7 +224,7 @@ var Filesystem = class {
179
224
  });
180
225
  ws.on("message", (raw) => {
181
226
  try {
182
- const event = JSON.parse(raw.toString());
227
+ const event = JSON.parse(String(raw));
183
228
  opts.onEvent(event);
184
229
  } catch {
185
230
  }
@@ -195,8 +240,8 @@ var Filesystem = class {
195
240
  };
196
241
 
197
242
  // src/process.ts
198
- var import_node_events = require("events");
199
- var Process = class extends import_node_events.EventEmitter {
243
+ var import_node_events2 = require("events");
244
+ var Process = class extends import_node_events2.EventEmitter {
200
245
  ws;
201
246
  constructor(ws) {
202
247
  super();
@@ -282,8 +327,8 @@ var BackgroundProcess = class {
282
327
  );
283
328
  return res.match;
284
329
  }
285
- streamLogs(opts = {}) {
286
- const ws = this.client.openWebSocket(
330
+ async streamLogs(opts = {}) {
331
+ const ws = await this.client.openWebSocket(
287
332
  `/api/sandboxes/${this.sandboxId}/processes/logs/stream`
288
333
  );
289
334
  ws.on("open", () => {
@@ -344,8 +389,8 @@ var ProcessManager = class {
344
389
  };
345
390
 
346
391
  // src/terminal.ts
347
- var import_node_events2 = require("events");
348
- var Terminal = class extends import_node_events2.EventEmitter {
392
+ var import_node_events3 = require("events");
393
+ var Terminal = class extends import_node_events3.EventEmitter {
349
394
  ws;
350
395
  constructor(ws) {
351
396
  super();
@@ -427,7 +472,7 @@ var Sandbox = class _Sandbox {
427
472
  async exec(cmd, opts = {}) {
428
473
  const { args, cwd, env, timeout, stream } = opts;
429
474
  if (stream) {
430
- const ws = this.client.openWebSocket(`/api/sandboxes/${this.id}/exec/stream`);
475
+ const ws = await this.client.openWebSocket(`/api/sandboxes/${this.id}/exec/stream`);
431
476
  const proc = new Process(ws);
432
477
  await new Promise((resolve, reject) => {
433
478
  ws.once("open", () => {
@@ -454,7 +499,7 @@ var Sandbox = class _Sandbox {
454
499
  });
455
500
  }
456
501
  async terminal() {
457
- const ws = this.client.openWebSocket(`/api/sandboxes/${this.id}/terminal`);
502
+ const ws = await this.client.openWebSocket(`/api/sandboxes/${this.id}/terminal`);
458
503
  await new Promise((resolve, reject) => {
459
504
  ws.once("open", resolve);
460
505
  ws.once("error", reject);
package/dist/index.mjs CHANGED
@@ -1,5 +1,34 @@
1
+ // src/ws-compat.ts
2
+ import { EventEmitter } from "events";
3
+ var WsEmitterAdapter = class extends EventEmitter {
4
+ constructor(ws) {
5
+ super();
6
+ this.ws = ws;
7
+ ws.accept?.();
8
+ ws.addEventListener("message", (e) => {
9
+ const raw = e.data;
10
+ this.emit("message", typeof raw === "string" ? raw : String(raw));
11
+ });
12
+ ws.addEventListener("error", (e) => this.emit("error", e));
13
+ ws.addEventListener("close", () => this.emit("close"));
14
+ ws.addEventListener("open", () => this.emit("open"));
15
+ }
16
+ ws;
17
+ OPEN = 1;
18
+ CONNECTING = 0;
19
+ get readyState() {
20
+ return this.ws.readyState;
21
+ }
22
+ send(data) {
23
+ this.ws.send(data);
24
+ }
25
+ close() {
26
+ this.ws.close();
27
+ }
28
+ };
29
+ var IS_CF_WORKERS = typeof globalThis.WebSocketPair !== "undefined";
30
+
1
31
  // src/client.ts
2
- import WebSocket from "ws";
3
32
  var HttpClient = class {
4
33
  constructor(baseUrl, apiKey) {
5
34
  this.baseUrl = baseUrl;
@@ -57,11 +86,27 @@ var HttpClient = class {
57
86
  if (!text) return void 0;
58
87
  return JSON.parse(text);
59
88
  }
60
- openWebSocket(path) {
89
+ // ── WebSocket ───────────────────────────────────────────────────────────────
90
+ // CF Workers: uses fetch() with Upgrade header (supports Authorization).
91
+ // Node.js: uses the ws package (installed as an optional dependency).
92
+ async openWebSocket(path) {
93
+ const authHeader = `Bearer ${this.apiKey}`;
94
+ if (IS_CF_WORKERS) {
95
+ const httpUrl = this.baseUrl + path;
96
+ const resp = await fetch(httpUrl, {
97
+ headers: {
98
+ Upgrade: "websocket",
99
+ Connection: "Upgrade",
100
+ Authorization: authHeader
101
+ }
102
+ });
103
+ const cfWs = resp.webSocket;
104
+ if (!cfWs) throw new Error("WebSocket upgrade failed \u2014 server did not accept");
105
+ return new WsEmitterAdapter(cfWs);
106
+ }
61
107
  const wsUrl = this.baseUrl.replace(/^http/, "ws") + path;
62
- return new WebSocket(wsUrl, {
63
- headers: { authorization: `Bearer ${this.apiKey}` }
64
- });
108
+ const { default: WS } = await import("ws");
109
+ return new WS(wsUrl, { headers: { authorization: authHeader } });
65
110
  }
66
111
  };
67
112
 
@@ -128,7 +173,7 @@ var Filesystem = class {
128
173
  });
129
174
  }
130
175
  async watch(dirPath, opts) {
131
- const ws = this.client.openWebSocket(`/api/sandboxes/${this.sandboxId}/files/watch`);
176
+ const ws = await this.client.openWebSocket(`/api/sandboxes/${this.sandboxId}/files/watch`);
132
177
  await new Promise((resolve, reject) => {
133
178
  ws.once("open", () => {
134
179
  ws.send(JSON.stringify({ path: dirPath, recursive: opts.recursive ?? false }));
@@ -138,7 +183,7 @@ var Filesystem = class {
138
183
  });
139
184
  ws.on("message", (raw) => {
140
185
  try {
141
- const event = JSON.parse(raw.toString());
186
+ const event = JSON.parse(String(raw));
142
187
  opts.onEvent(event);
143
188
  } catch {
144
189
  }
@@ -154,8 +199,8 @@ var Filesystem = class {
154
199
  };
155
200
 
156
201
  // src/process.ts
157
- import { EventEmitter } from "events";
158
- var Process = class extends EventEmitter {
202
+ import { EventEmitter as EventEmitter2 } from "events";
203
+ var Process = class extends EventEmitter2 {
159
204
  ws;
160
205
  constructor(ws) {
161
206
  super();
@@ -241,8 +286,8 @@ var BackgroundProcess = class {
241
286
  );
242
287
  return res.match;
243
288
  }
244
- streamLogs(opts = {}) {
245
- const ws = this.client.openWebSocket(
289
+ async streamLogs(opts = {}) {
290
+ const ws = await this.client.openWebSocket(
246
291
  `/api/sandboxes/${this.sandboxId}/processes/logs/stream`
247
292
  );
248
293
  ws.on("open", () => {
@@ -303,8 +348,8 @@ var ProcessManager = class {
303
348
  };
304
349
 
305
350
  // src/terminal.ts
306
- import { EventEmitter as EventEmitter2 } from "events";
307
- var Terminal = class extends EventEmitter2 {
351
+ import { EventEmitter as EventEmitter3 } from "events";
352
+ var Terminal = class extends EventEmitter3 {
308
353
  ws;
309
354
  constructor(ws) {
310
355
  super();
@@ -386,7 +431,7 @@ var Sandbox = class _Sandbox {
386
431
  async exec(cmd, opts = {}) {
387
432
  const { args, cwd, env, timeout, stream } = opts;
388
433
  if (stream) {
389
- const ws = this.client.openWebSocket(`/api/sandboxes/${this.id}/exec/stream`);
434
+ const ws = await this.client.openWebSocket(`/api/sandboxes/${this.id}/exec/stream`);
390
435
  const proc = new Process(ws);
391
436
  await new Promise((resolve, reject) => {
392
437
  ws.once("open", () => {
@@ -413,7 +458,7 @@ var Sandbox = class _Sandbox {
413
458
  });
414
459
  }
415
460
  async terminal() {
416
- const ws = this.client.openWebSocket(`/api/sandboxes/${this.id}/terminal`);
461
+ const ws = await this.client.openWebSocket(`/api/sandboxes/${this.id}/terminal`);
417
462
  await new Promise((resolve, reject) => {
418
463
  ws.once("open", resolve);
419
464
  ws.once("error", reject);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sandbox-engine/sdk",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "SDK for creating and managing isolated sandbox environments",
5
5
  "keywords": [
6
6
  "sandbox",