@boxlite-ai/boxlite 0.1.0

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/README.md ADDED
@@ -0,0 +1,434 @@
1
+ # BoxLite Node.js/TypeScript SDK
2
+
3
+ Embeddable VM runtime for secure, isolated code execution environments.
4
+
5
+ **Think "SQLite for sandboxing"** - a lightweight library embedded directly in your application without requiring a daemon or root privileges.
6
+
7
+ [![npm version](https://badge.fury.io/js/%40boxlite%2Fcore.svg)](https://badge.fury.io/js/boxlite)
8
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
9
+
10
+ ## Features
11
+
12
+ - **Hardware-level VM isolation** (KVM on Linux, Hypervisor.framework on macOS)
13
+ - **OCI container support** - Use any Docker/OCI image
14
+ - **Async-first API** - Built on native async Rust + napi-rs
15
+ - **Multiple specialized boxes**:
16
+ - `SimpleBox` - Basic command execution
17
+ - `CodeBox` - Python code sandbox
18
+ - `BrowserBox` - Browser automation (Puppeteer/Playwright)
19
+ - `ComputerBox` - Desktop automation (14 automation functions)
20
+ - `InteractiveBox` - PTY terminal sessions
21
+ - **Zero daemon** - No background processes required
22
+ - **Cross-platform** - macOS ARM64, Linux x86_64/ARM64
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ npm install boxlite
28
+ ```
29
+
30
+ **Requirements:**
31
+ - Node.js 18 or later
32
+ - Platform with hardware virtualization:
33
+ - macOS: Apple Silicon (macOS 12+)
34
+ - Linux: x86_64 or ARM64 with KVM (`/dev/kvm` accessible)
35
+
36
+ **Not supported:** macOS Intel, Windows (use WSL2 with Linux requirements)
37
+
38
+ ## Quick Start
39
+
40
+ ### JavaScript
41
+
42
+ ```javascript
43
+ const { SimpleBox } = require('boxlite');
44
+
45
+ async function main() {
46
+ const box = new SimpleBox({ image: 'alpine:latest' });
47
+
48
+ try {
49
+ const result = await box.exec('echo', 'Hello from BoxLite!');
50
+ console.log(result.stdout); // Hello from BoxLite!
51
+ } finally {
52
+ await box.stop();
53
+ }
54
+ }
55
+
56
+ main();
57
+ ```
58
+
59
+ ### TypeScript
60
+
61
+ ```typescript
62
+ import { SimpleBox } from 'boxlite';
63
+
64
+ async function main() {
65
+ const box = new SimpleBox({ image: 'alpine:latest' });
66
+
67
+ try {
68
+ const result = await box.exec('echo', 'Hello from BoxLite!');
69
+ console.log(result.stdout);
70
+ } finally {
71
+ await box.stop();
72
+ }
73
+ }
74
+
75
+ main();
76
+ ```
77
+
78
+ ### TypeScript 5.2+ (Async Disposal)
79
+
80
+ ```typescript
81
+ import { SimpleBox } from 'boxlite';
82
+
83
+ async function main() {
84
+ await using box = new SimpleBox({ image: 'alpine:latest' });
85
+ const result = await box.exec('echo', 'Hello!');
86
+ console.log(result.stdout);
87
+ // Box automatically stopped when leaving scope
88
+ }
89
+
90
+ main();
91
+ ```
92
+
93
+ ## API Reference
94
+
95
+ ### SimpleBox
96
+
97
+ Basic container for command execution.
98
+
99
+ ```typescript
100
+ import { SimpleBox } from 'boxlite';
101
+
102
+ const box = new SimpleBox({
103
+ image: 'python:slim',
104
+ memoryMib: 512, // Memory limit in MiB
105
+ cpus: 2, // Number of CPU cores
106
+ name: 'my-box', // Optional name
107
+ autoRemove: true, // Auto-remove on stop (default: true)
108
+ workingDir: '/app',
109
+ env: { FOO: 'bar' },
110
+ volumes: [
111
+ { hostPath: '/tmp/data', guestPath: '/data', readOnly: false }
112
+ ],
113
+ ports: [
114
+ { hostPort: 8080, guestPort: 80 }
115
+ ]
116
+ });
117
+
118
+ // Execute command
119
+ const result = await box.exec('ls', '-la', '/');
120
+ console.log(result.exitCode, result.stdout, result.stderr);
121
+
122
+ // Get box info
123
+ console.log(box.id); // ULID
124
+ console.log(box.name); // Optional name
125
+ console.log(box.info()); // Metadata
126
+
127
+ // Cleanup
128
+ await box.stop();
129
+ ```
130
+
131
+ ### CodeBox
132
+
133
+ Python code execution sandbox.
134
+
135
+ ```typescript
136
+ import { CodeBox } from 'boxlite';
137
+
138
+ const codebox = new CodeBox({
139
+ image: 'python:slim', // default
140
+ memoryMib: 512,
141
+ cpus: 1
142
+ });
143
+
144
+ try {
145
+ // Run Python code
146
+ const result = await codebox.run(`
147
+ import math
148
+ print(f"Pi is approximately {math.pi}")
149
+ `);
150
+ console.log(result); // Pi is approximately 3.141592653589793
151
+
152
+ // Install packages
153
+ await codebox.installPackage('requests');
154
+ await codebox.installPackages('numpy', 'pandas');
155
+
156
+ // Use installed packages
157
+ const result2 = await codebox.run(`
158
+ import requests
159
+ response = requests.get('https://api.github.com/zen')
160
+ print(response.text)
161
+ `);
162
+ console.log(result2);
163
+ } finally {
164
+ await codebox.stop();
165
+ }
166
+ ```
167
+
168
+ ### BrowserBox
169
+
170
+ Browser automation with remote debugging.
171
+
172
+ ```typescript
173
+ import { BrowserBox } from 'boxlite';
174
+
175
+ const browser = new BrowserBox({
176
+ browser: 'chromium', // 'chromium', 'firefox', or 'webkit'
177
+ memoryMib: 2048,
178
+ cpus: 2
179
+ });
180
+
181
+ try {
182
+ await browser.start();
183
+
184
+ // Get CDP endpoint
185
+ const endpoint = browser.endpoint();
186
+ console.log(endpoint); // http://localhost:9222
187
+
188
+ // Connect with Puppeteer
189
+ const puppeteer = require('puppeteer-core');
190
+ const browserInstance = await puppeteer.connect({ browserURL: endpoint });
191
+
192
+ const page = await browserInstance.newPage();
193
+ await page.goto('https://example.com');
194
+ const title = await page.title();
195
+ console.log(title);
196
+
197
+ await page.close();
198
+ } finally {
199
+ await browser.stop();
200
+ }
201
+ ```
202
+
203
+ ### ComputerBox
204
+
205
+ Desktop automation with web access.
206
+
207
+ ```typescript
208
+ import { ComputerBox } from 'boxlite';
209
+
210
+ const desktop = new ComputerBox({
211
+ cpus: 2,
212
+ memoryMib: 2048,
213
+ guiHttpPort: 3000, // default
214
+ guiHttpsPort: 3001 // default (self-signed cert)
215
+ });
216
+
217
+ try {
218
+ // Wait for desktop to be ready
219
+ await desktop.waitUntilReady(60);
220
+
221
+ // Mouse automation
222
+ await desktop.mouseMove(100, 200);
223
+ await desktop.leftClick();
224
+ await desktop.doubleClick();
225
+ await desktop.rightClick();
226
+ await desktop.leftClickDrag(100, 100, 200, 200);
227
+
228
+ const [x, y] = await desktop.cursorPosition();
229
+ console.log(`Cursor at: ${x}, ${y}`);
230
+
231
+ // Keyboard automation
232
+ await desktop.type('Hello, World!');
233
+ await desktop.key('Return');
234
+ await desktop.key('ctrl+c');
235
+
236
+ // Screenshot
237
+ const screenshot = await desktop.screenshot();
238
+ console.log(`${screenshot.width}x${screenshot.height} ${screenshot.format}`);
239
+ // screenshot.data contains base64-encoded PNG
240
+
241
+ // Scroll
242
+ await desktop.scroll(500, 300, 'down', 5);
243
+
244
+ // Get screen size
245
+ const [width, height] = await desktop.getScreenSize();
246
+ console.log(`Screen: ${width}x${height}`);
247
+
248
+ // Access desktop via browser:
249
+ // HTTP: http://localhost:3000
250
+ // HTTPS: https://localhost:3001 (self-signed certificate)
251
+ } finally {
252
+ await desktop.stop();
253
+ }
254
+ ```
255
+
256
+ ### InteractiveBox
257
+
258
+ Interactive terminal sessions with PTY.
259
+
260
+ ```typescript
261
+ import { InteractiveBox } from 'boxlite';
262
+
263
+ const box = new InteractiveBox({
264
+ image: 'alpine:latest',
265
+ shell: '/bin/sh',
266
+ tty: true, // Auto-detected if undefined
267
+ memoryMib: 512,
268
+ cpus: 1
269
+ });
270
+
271
+ try {
272
+ await box.start();
273
+ await box.wait(); // Blocks until shell exits
274
+ } finally {
275
+ await box.stop();
276
+ }
277
+ ```
278
+
279
+ ## Examples
280
+
281
+ See [../../examples/node/](../../examples/node/) directory for complete examples:
282
+
283
+ ```bash
284
+ # If installed via npm
285
+ npm install boxlite
286
+ node simplebox.js
287
+
288
+ # If working from source
289
+ cd ../../sdks/node
290
+ npm install && npm run build
291
+ npm link
292
+ cd ../../examples/node
293
+ npm link boxlite
294
+ node simplebox.js
295
+ ```
296
+
297
+ ## Error Handling
298
+
299
+ ```typescript
300
+ import { SimpleBox, ExecError, TimeoutError, ParseError } from 'boxlite';
301
+
302
+ try {
303
+ const box = new SimpleBox({ image: 'alpine:latest' });
304
+ await box.exec('false'); // Exit code 1
305
+ } catch (err) {
306
+ if (err instanceof ExecError) {
307
+ console.error(`Command failed: ${err.command}`);
308
+ console.error(`Exit code: ${err.exitCode}`);
309
+ console.error(`Stderr: ${err.stderr}`);
310
+ }
311
+ }
312
+ ```
313
+
314
+ ## Building from Source
315
+
316
+ ```bash
317
+ # Clone repository
318
+ git clone https://github.com/boxlite-labs/boxlite.git
319
+ cd boxlite/sdks/node
320
+
321
+ # Initialize submodules (critical!)
322
+ git submodule update --init --recursive
323
+
324
+ # Install dependencies
325
+ npm install
326
+
327
+ # Build (Rust + TypeScript)
328
+ npm run build
329
+
330
+ # Link to examples
331
+ npm link
332
+ cd ../../examples/node
333
+ npm link boxlite
334
+
335
+ # Run examples
336
+ node simplebox.js
337
+ ```
338
+
339
+ ## TypeScript Support
340
+
341
+ Full TypeScript support included:
342
+
343
+ ```typescript
344
+ import {
345
+ SimpleBox, CodeBox, BrowserBox, ComputerBox, InteractiveBox,
346
+ type SimpleBoxOptions,
347
+ type CodeBoxOptions,
348
+ type BrowserBoxOptions,
349
+ type ComputerBoxOptions,
350
+ type InteractiveBoxOptions,
351
+ type ExecResult,
352
+ type Screenshot,
353
+ type BrowserType
354
+ } from 'boxlite';
355
+ ```
356
+
357
+ ## Platform Requirements
358
+
359
+ ### macOS
360
+ - Apple Silicon (ARM64)
361
+ - macOS 12+ (Monterey or later)
362
+ - Hypervisor.framework (built-in)
363
+
364
+ ### Linux
365
+ - x86_64 or ARM64
366
+ - KVM enabled (`/dev/kvm` accessible)
367
+ - User in `kvm` group:
368
+ ```bash
369
+ sudo usermod -aG kvm $USER
370
+ # Logout/login required
371
+ ```
372
+
373
+ ## Architecture
374
+
375
+ The SDK uses a dual-layer architecture:
376
+
377
+ 1. **Layer 1 (Rust)**: napi-rs bindings to native BoxLite runtime
378
+ - Direct mapping to Rust `boxlite` crate
379
+ - Async operations via `env.spawn()` (non-blocking)
380
+ - Stream handling via async iterators
381
+
382
+ 2. **Layer 2 (TypeScript)**: Convenience wrappers
383
+ - Specialized box classes (CodeBox, BrowserBox, etc.)
384
+ - Error class hierarchy
385
+ - Output collection helpers
386
+ - TypeScript type definitions
387
+
388
+ ## Performance
389
+
390
+ - Startup time: < 100ms
391
+ - Overhead vs Python SDK: < 5%
392
+ - Concurrent boxes: Limited by system resources
393
+ - Memory footprint: ~50-100MB per box (depends on image)
394
+
395
+ ## Troubleshooting
396
+
397
+ **"BoxLite native extension not found"**
398
+ - Run `npm run build` to compile Rust bindings
399
+
400
+ **"Image not found"**
401
+ - BoxLite auto-pulls OCI images on first use
402
+ - Ensure internet connectivity
403
+
404
+ **"Permission denied" (Linux)**
405
+ - Check KVM access: `ls -l /dev/kvm`
406
+ - Add user to kvm group: `sudo usermod -aG kvm $USER`
407
+
408
+ **"Unsupported engine"**
409
+ - Only Apple Silicon Macs supported (not Intel)
410
+ - Windows users: Use WSL2 with Linux requirements
411
+
412
+ ## Contributing
413
+
414
+ See [../../CONTRIBUTING.md](../../CONTRIBUTING.md) for development guidelines.
415
+
416
+ ## License
417
+
418
+ Apache 2.0 - See [../../LICENSE](../../LICENSE)
419
+
420
+ ## Related Projects
421
+
422
+ - [Python SDK](../python/) - Python bindings (stable, v0.4.4)
423
+ - [C SDK](../c/) - C FFI bindings (early stage)
424
+ - [Core Runtime](../../boxlite/) - Rust runtime implementation
425
+
426
+ ## Support
427
+
428
+ - **Issues**: [GitHub Issues](https://github.com/boxlite-labs/boxlite/issues)
429
+ - **Documentation**: [docs/](../../docs/)
430
+ - **Examples**: [examples/](./examples/)
431
+
432
+ ---
433
+
434
+ **Made with ❤️ by BoxLite Labs**
@@ -0,0 +1,145 @@
1
+ /**
2
+ * BrowserBox - Secure browser with remote debugging.
3
+ *
4
+ * Provides a minimal, elegant API for running isolated browsers that can be
5
+ * controlled from outside using standard tools like Puppeteer or Playwright.
6
+ */
7
+ import { SimpleBox, type SimpleBoxOptions } from './simplebox';
8
+ /**
9
+ * Browser type supported by BrowserBox.
10
+ */
11
+ export type BrowserType = 'chromium' | 'firefox' | 'webkit';
12
+ /**
13
+ * Options for creating a BrowserBox.
14
+ */
15
+ export interface BrowserBoxOptions extends Omit<SimpleBoxOptions, 'image' | 'cpus' | 'memoryMib'> {
16
+ /** Browser type (default: 'chromium') */
17
+ browser?: BrowserType;
18
+ /** Memory in MiB (default: 2048) */
19
+ memoryMib?: number;
20
+ /** Number of CPU cores (default: 2) */
21
+ cpus?: number;
22
+ }
23
+ /**
24
+ * Secure browser environment with remote debugging.
25
+ *
26
+ * Auto-starts a browser with Chrome DevTools Protocol enabled.
27
+ * Connect from outside using Puppeteer, Playwright, Selenium, or DevTools.
28
+ *
29
+ * ## Usage
30
+ *
31
+ * ```typescript
32
+ * const browser = new BrowserBox();
33
+ * try {
34
+ * await browser.start(); // Manually start browser
35
+ * console.log(`Connect to: ${browser.endpoint()}`);
36
+ * // Use Puppeteer/Playwright from your host to connect
37
+ * await new Promise(resolve => setTimeout(resolve, 60000));
38
+ * } finally {
39
+ * await browser.stop();
40
+ * }
41
+ * ```
42
+ *
43
+ * ## Example with custom options
44
+ *
45
+ * ```typescript
46
+ * const browser = new BrowserBox({
47
+ * browser: 'firefox',
48
+ * memoryMib: 4096,
49
+ * cpus: 4
50
+ * });
51
+ * try {
52
+ * await browser.start();
53
+ * const endpoint = browser.endpoint();
54
+ * // Connect using Playwright or Puppeteer
55
+ * } finally {
56
+ * await browser.stop();
57
+ * }
58
+ * ```
59
+ */
60
+ export declare class BrowserBox extends SimpleBox {
61
+ private static readonly DEFAULT_IMAGE;
62
+ private static readonly PORTS;
63
+ private readonly _browser;
64
+ private readonly _port;
65
+ /**
66
+ * Create a new BrowserBox.
67
+ *
68
+ * @param options - BrowserBox configuration options
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * const browser = new BrowserBox({
73
+ * browser: 'chromium',
74
+ * memoryMib: 2048,
75
+ * cpus: 2
76
+ * });
77
+ * ```
78
+ */
79
+ constructor(options?: BrowserBoxOptions);
80
+ /**
81
+ * Start the browser with remote debugging enabled.
82
+ *
83
+ * Call this method after creating the BrowserBox to start the browser process.
84
+ * Waits for the browser to be ready before returning.
85
+ *
86
+ * @param timeout - Maximum time to wait for browser to start in seconds (default: 30)
87
+ * @throws {TimeoutError} If browser doesn't start within timeout
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * const browser = new BrowserBox();
92
+ * try {
93
+ * await browser.start();
94
+ * console.log(`Connect to: ${browser.endpoint()}`);
95
+ * } finally {
96
+ * await browser.stop();
97
+ * }
98
+ * ```
99
+ */
100
+ start(timeout?: number): Promise<void>;
101
+ /**
102
+ * Wait for the browser process to be running.
103
+ *
104
+ * @param processPattern - Pattern to match browser process name
105
+ * @param timeout - Maximum wait time in seconds
106
+ * @throws {TimeoutError} If browser doesn't start within timeout
107
+ */
108
+ private waitForBrowser;
109
+ /**
110
+ * Get the connection endpoint for remote debugging.
111
+ *
112
+ * Returns the HTTP endpoint URL for Chrome DevTools Protocol.
113
+ * Use this with Puppeteer, Playwright, or Selenium to connect to the browser.
114
+ *
115
+ * @returns HTTP endpoint URL (e.g., 'http://localhost:9222')
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * const browser = new BrowserBox();
120
+ * try {
121
+ * await browser.start();
122
+ * const url = browser.endpoint();
123
+ *
124
+ * // Use with Puppeteer:
125
+ * // const browserWSEndpoint = await fetch(`${url}/json/version`)
126
+ * // .then(r => r.json())
127
+ * // .then(d => d.webSocketDebuggerUrl);
128
+ * // const browser = await puppeteer.connect({ browserWSEndpoint });
129
+ *
130
+ * // Use with Playwright:
131
+ * // const browser = await chromium.connectOverCDP(url);
132
+ * } finally {
133
+ * await browser.stop();
134
+ * }
135
+ * ```
136
+ */
137
+ endpoint(): string;
138
+ /**
139
+ * Override async disposal to start browser automatically.
140
+ *
141
+ * @internal
142
+ */
143
+ [Symbol.asyncDispose](): Promise<void>;
144
+ }
145
+ //# sourceMappingURL=browserbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browserbox.d.ts","sourceRoot":"","sources":["../lib/browserbox.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAI/D;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE5D;;GAEG;AACH,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,gBAAgB,EAAE,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC;IAC/F,yCAAyC;IACzC,OAAO,CAAC,EAAE,WAAW,CAAC;IAEtB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,uCAAuC;IACvC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,UAAW,SAAQ,SAAS;IACvC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAgD;IAErF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAI3B;IAEF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B;;;;;;;;;;;;;OAaG;gBACS,OAAO,GAAE,iBAAsB;IAmB3C;;;;;;;;;;;;;;;;;;;OAmBG;IACG,KAAK,CAAC,OAAO,GAAE,MAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAkChD;;;;;;OAMG;YACW,cAAc;IAuB5B;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,QAAQ,IAAI,MAAM;IAIlB;;;;OAIG;IACG,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7C"}