@sandbox-engine/sdk 0.2.1 → 0.2.2

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,26 @@ 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) {
102
134
  const wsUrl = this.baseUrl.replace(/^http/, "ws") + path;
103
- return new import_ws.default(wsUrl, {
104
- headers: { authorization: `Bearer ${this.apiKey}` }
105
- });
135
+ const authHeader = `Bearer ${this.apiKey}`;
136
+ if (IS_CF_WORKERS) {
137
+ const resp = await fetch(wsUrl, {
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
+ }
148
+ const { default: WS } = await import("ws");
149
+ return new WS(wsUrl, { headers: { authorization: authHeader } });
106
150
  }
107
151
  };
108
152
 
@@ -169,7 +213,7 @@ var Filesystem = class {
169
213
  });
170
214
  }
171
215
  async watch(dirPath, opts) {
172
- const ws = this.client.openWebSocket(`/api/sandboxes/${this.sandboxId}/files/watch`);
216
+ const ws = await this.client.openWebSocket(`/api/sandboxes/${this.sandboxId}/files/watch`);
173
217
  await new Promise((resolve, reject) => {
174
218
  ws.once("open", () => {
175
219
  ws.send(JSON.stringify({ path: dirPath, recursive: opts.recursive ?? false }));
@@ -179,7 +223,7 @@ var Filesystem = class {
179
223
  });
180
224
  ws.on("message", (raw) => {
181
225
  try {
182
- const event = JSON.parse(raw.toString());
226
+ const event = JSON.parse(String(raw));
183
227
  opts.onEvent(event);
184
228
  } catch {
185
229
  }
@@ -195,8 +239,8 @@ var Filesystem = class {
195
239
  };
196
240
 
197
241
  // src/process.ts
198
- var import_node_events = require("events");
199
- var Process = class extends import_node_events.EventEmitter {
242
+ var import_node_events2 = require("events");
243
+ var Process = class extends import_node_events2.EventEmitter {
200
244
  ws;
201
245
  constructor(ws) {
202
246
  super();
@@ -282,8 +326,8 @@ var BackgroundProcess = class {
282
326
  );
283
327
  return res.match;
284
328
  }
285
- streamLogs(opts = {}) {
286
- const ws = this.client.openWebSocket(
329
+ async streamLogs(opts = {}) {
330
+ const ws = await this.client.openWebSocket(
287
331
  `/api/sandboxes/${this.sandboxId}/processes/logs/stream`
288
332
  );
289
333
  ws.on("open", () => {
@@ -344,8 +388,8 @@ var ProcessManager = class {
344
388
  };
345
389
 
346
390
  // src/terminal.ts
347
- var import_node_events2 = require("events");
348
- var Terminal = class extends import_node_events2.EventEmitter {
391
+ var import_node_events3 = require("events");
392
+ var Terminal = class extends import_node_events3.EventEmitter {
349
393
  ws;
350
394
  constructor(ws) {
351
395
  super();
@@ -427,7 +471,7 @@ var Sandbox = class _Sandbox {
427
471
  async exec(cmd, opts = {}) {
428
472
  const { args, cwd, env, timeout, stream } = opts;
429
473
  if (stream) {
430
- const ws = this.client.openWebSocket(`/api/sandboxes/${this.id}/exec/stream`);
474
+ const ws = await this.client.openWebSocket(`/api/sandboxes/${this.id}/exec/stream`);
431
475
  const proc = new Process(ws);
432
476
  await new Promise((resolve, reject) => {
433
477
  ws.once("open", () => {
@@ -454,7 +498,7 @@ var Sandbox = class _Sandbox {
454
498
  });
455
499
  }
456
500
  async terminal() {
457
- const ws = this.client.openWebSocket(`/api/sandboxes/${this.id}/terminal`);
501
+ const ws = await this.client.openWebSocket(`/api/sandboxes/${this.id}/terminal`);
458
502
  await new Promise((resolve, reject) => {
459
503
  ws.once("open", resolve);
460
504
  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,26 @@ 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) {
61
93
  const wsUrl = this.baseUrl.replace(/^http/, "ws") + path;
62
- return new WebSocket(wsUrl, {
63
- headers: { authorization: `Bearer ${this.apiKey}` }
64
- });
94
+ const authHeader = `Bearer ${this.apiKey}`;
95
+ if (IS_CF_WORKERS) {
96
+ const resp = await fetch(wsUrl, {
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
+ }
107
+ const { default: WS } = await import("ws");
108
+ return new WS(wsUrl, { headers: { authorization: authHeader } });
65
109
  }
66
110
  };
67
111
 
@@ -128,7 +172,7 @@ var Filesystem = class {
128
172
  });
129
173
  }
130
174
  async watch(dirPath, opts) {
131
- const ws = this.client.openWebSocket(`/api/sandboxes/${this.sandboxId}/files/watch`);
175
+ const ws = await this.client.openWebSocket(`/api/sandboxes/${this.sandboxId}/files/watch`);
132
176
  await new Promise((resolve, reject) => {
133
177
  ws.once("open", () => {
134
178
  ws.send(JSON.stringify({ path: dirPath, recursive: opts.recursive ?? false }));
@@ -138,7 +182,7 @@ var Filesystem = class {
138
182
  });
139
183
  ws.on("message", (raw) => {
140
184
  try {
141
- const event = JSON.parse(raw.toString());
185
+ const event = JSON.parse(String(raw));
142
186
  opts.onEvent(event);
143
187
  } catch {
144
188
  }
@@ -154,8 +198,8 @@ var Filesystem = class {
154
198
  };
155
199
 
156
200
  // src/process.ts
157
- import { EventEmitter } from "events";
158
- var Process = class extends EventEmitter {
201
+ import { EventEmitter as EventEmitter2 } from "events";
202
+ var Process = class extends EventEmitter2 {
159
203
  ws;
160
204
  constructor(ws) {
161
205
  super();
@@ -241,8 +285,8 @@ var BackgroundProcess = class {
241
285
  );
242
286
  return res.match;
243
287
  }
244
- streamLogs(opts = {}) {
245
- const ws = this.client.openWebSocket(
288
+ async streamLogs(opts = {}) {
289
+ const ws = await this.client.openWebSocket(
246
290
  `/api/sandboxes/${this.sandboxId}/processes/logs/stream`
247
291
  );
248
292
  ws.on("open", () => {
@@ -303,8 +347,8 @@ var ProcessManager = class {
303
347
  };
304
348
 
305
349
  // src/terminal.ts
306
- import { EventEmitter as EventEmitter2 } from "events";
307
- var Terminal = class extends EventEmitter2 {
350
+ import { EventEmitter as EventEmitter3 } from "events";
351
+ var Terminal = class extends EventEmitter3 {
308
352
  ws;
309
353
  constructor(ws) {
310
354
  super();
@@ -386,7 +430,7 @@ var Sandbox = class _Sandbox {
386
430
  async exec(cmd, opts = {}) {
387
431
  const { args, cwd, env, timeout, stream } = opts;
388
432
  if (stream) {
389
- const ws = this.client.openWebSocket(`/api/sandboxes/${this.id}/exec/stream`);
433
+ const ws = await this.client.openWebSocket(`/api/sandboxes/${this.id}/exec/stream`);
390
434
  const proc = new Process(ws);
391
435
  await new Promise((resolve, reject) => {
392
436
  ws.once("open", () => {
@@ -413,7 +457,7 @@ var Sandbox = class _Sandbox {
413
457
  });
414
458
  }
415
459
  async terminal() {
416
- const ws = this.client.openWebSocket(`/api/sandboxes/${this.id}/terminal`);
460
+ const ws = await this.client.openWebSocket(`/api/sandboxes/${this.id}/terminal`);
417
461
  await new Promise((resolve, reject) => {
418
462
  ws.once("open", resolve);
419
463
  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.2",
4
4
  "description": "SDK for creating and managing isolated sandbox environments",
5
5
  "keywords": [
6
6
  "sandbox",