@@ -98,7 +98,7 @@ export default {
9898 const sandbox = getSandbox (env .Sandbox , " my-sandbox" );
9999
100100 // Execute a command
101- const result = await sandbox .exec (" echo" , [ " Hello from the edge!" ] );
101+ const result = await sandbox .exec (" echo ' Hello from the edge!' " );
102102 return new Response (result .stdout );
103103 },
104104};
@@ -108,13 +108,51 @@ export default {
108108
109109### Core Methods
110110
111- #### ` exec(command, args, options?) `
111+ #### Command Execution
112112
113- Execute a command in the sandbox.
113+ ** ` exec(command, options?) ` ** - Enhanced command execution that always returns results
114114
115115``` typescript
116- const result = await sandbox .exec (" npm" , [" install" , " express" ]);
117- console .log (result .stdout );
116+ // Simple execution
117+ const result = await sandbox .exec (" npm install express" );
118+ console .log (result .stdout , result .exitCode );
119+
120+ // With streaming callbacks
121+ const result = await sandbox .exec (" npm run build" , {
122+ stream: true ,
123+ onOutput : (stream , data ) => console .log (` [${stream }] ${data } ` )
124+ });
125+ ```
126+
127+ ** ` execStream(command, options?) ` ** - Dedicated streaming method returning SSE stream
128+
129+ ``` typescript
130+ import { parseSSEStream , type ExecEvent } from ' @cloudflare/sandbox' ;
131+
132+ const stream = await sandbox .execStream (" npm run test" );
133+ for await (const event of parseSSEStream <ExecEvent >(stream )) {
134+ switch (event .type ) {
135+ case ' stdout' :
136+ console .log (` Test output: ${event .data } ` );
137+ break ;
138+ case ' complete' :
139+ console .log (` Tests ${event .exitCode === 0 ? ' passed' : ' failed' } ` );
140+ break ;
141+ }
142+ }
143+ ```
144+
145+ ** ` startProcess(command, options?) ` ** - Start background processes with lifecycle management
146+
147+ ``` typescript
148+ const process = await sandbox .startProcess (" node server.js" );
149+ console .log (` Started process ${process .id } with PID ${process .pid } ` );
150+
151+ // Monitor the process
152+ const logStream = await sandbox .streamProcessLogs (process .id );
153+ for await (const log of parseSSEStream <LogEvent >(logStream )) {
154+ console .log (` Server: ${log .data } ` );
155+ }
118156```
119157
120158#### ` writeFile(path, content, options?) `
@@ -145,16 +183,26 @@ await sandbox.gitCheckout("https://github.com/user/repo", {
145183});
146184```
147185
148- ### File System Methods
186+ #### Process Management
187+
188+ - ` listProcesses() ` - List all running processes
189+ - ` getProcess(id) ` - Get detailed process status
190+ - ` killProcess(id, signal?) ` - Terminate specific processes
191+ - ` killAllProcesses() ` - Kill all processes
192+ - ` streamProcessLogs(id, options?) ` - Stream logs from running processes
193+ - ` getProcessLogs(id) ` - Get accumulated process output
194+
195+ #### File System Methods
149196
150197- ` writeFile(path, content, options?) ` - Write content to a file
151198- ` readFile(path, options?) ` - Read a file from the sandbox
152199- ` mkdir(path, options?) ` - Create a directory
153200- ` deleteFile(path) ` - Delete a file
154201- ` renameFile(oldPath, newPath) ` - Rename a file
155202- ` moveFile(sourcePath, destinationPath) ` - Move a file
203+ - ` gitCheckout(repoUrl, options?) ` - Clone git repositories
156204
157- ### Network Methods
205+ #### Network Methods
158206
159207- ` exposePort(port, options?) ` - Expose a port and get a public URL
160208- ` unexposePort(port) ` - Remove port exposure
@@ -188,8 +236,7 @@ console.log(preview.url); // https://3000-sandbox-id.your-worker.dev
188236
189237The SDK handles:
190238
191- - Production subdomain routing (` 3000-sandbox-id.domain.com ` )
192- - Local development routing (` localhost:8787/preview/3000/sandbox-id ` )
239+ - Subdomain routing (` 3000-sandbox-id.domain.com ` ) for both production and local development
193240- All localhost variants (127.0.0.1, ::1, etc.)
194241- Request forwarding with proper headers
195242
@@ -243,9 +290,9 @@ await sandbox.writeFile(
243290);
244291
245292// Install dependencies and start the server
246- await sandbox .exec (" npm" , [ " init" , " -y" ] );
247- await sandbox .exec (" npm" , [ " install" , " express" ] );
248- await sandbox .exec (" node" , [ " app.js" ] );
293+ await sandbox .exec (" npm init -y" );
294+ await sandbox .exec (" npm install express" );
295+ const server = await sandbox .startProcess (" node app.js" );
249296
250297// Expose it to the internet
251298const preview = await sandbox .exposePort (3000 );
@@ -261,10 +308,10 @@ const sandbox = getSandbox(env.Sandbox, "test-env");
261308await sandbox .gitCheckout (" https://github.com/user/project" );
262309
263310// Run tests
264- const testResult = await sandbox .exec (" npm" , [ " test" ] );
311+ const testResult = await sandbox .exec (" npm test" );
265312
266313// Build the project
267- const buildResult = await sandbox .exec (" npm" , [ " run" , " build" ] );
314+ const buildResult = await sandbox .exec (" npm run build" );
268315
269316return new Response (
270317 JSON .stringify ({
@@ -283,10 +330,10 @@ const sandbox = getSandbox(env.Sandbox, "dev-env");
283330
284331// Set up the project
285332await sandbox .gitCheckout (" https://github.com/user/my-app" );
286- await sandbox .exec (" npm" , [ " install" ] );
333+ await sandbox .exec (" npm install" );
287334
288335// Start dev server
289- await sandbox .exec (" npm" , [ " run" , " dev" ] );
336+ const devServer = await sandbox .startProcess (" npm run dev" );
290337
291338// Expose the dev server
292339const preview = await sandbox .exposePort (3000 , { name: " dev-server" });
@@ -309,7 +356,7 @@ await sandbox.writeFile(
309356 }); `
310357);
311358
312- await sandbox .exec (" bun" , [ " run" , " /server.js" ] );
359+ const server = await sandbox .startProcess (" bun run /server.js" );
313360
314361// Expose the port - returns a public URL
315362const preview = await sandbox .exposePort (8080 );
@@ -330,19 +377,78 @@ The SDK leverages Cloudflare's infrastructure:
330377
331378## 🛠️ Advanced Usage
332379
333- ### Streaming Output
380+ ### AsyncIterable Streaming Support
334381
335- For long-running commands, use streaming:
382+ The SDK provides powerful streaming capabilities with typed AsyncIterable support:
383+
384+ ``` typescript
385+ import { parseSSEStream , type ExecEvent } from ' @cloudflare/sandbox' ;
386+
387+ // Stream command execution
388+ const stream = await sandbox .execStream (' npm run build' );
389+ for await (const event of parseSSEStream <ExecEvent >(stream )) {
390+ switch (event .type ) {
391+ case ' start' :
392+ console .log (` Build started: ${event .command } ` );
393+ break ;
394+ case ' stdout' :
395+ console .log (` Build: ${event .data } ` );
396+ break ;
397+ case ' complete' :
398+ console .log (` Exit code: ${event .exitCode } ` );
399+ break ;
400+ case ' error' :
401+ console .error (` Error: ${event .error } ` );
402+ break ;
403+ }
404+ }
405+ ```
406+
407+ #### Streaming Utilities
408+
409+ The SDK exports utilities for working with Server-Sent Event streams:
410+
411+ - ** ` parseSSEStream<T>(stream) ` ** - Convert ReadableStream to typed AsyncIterable
412+ - ** ` responseToAsyncIterable<T>(response) ` ** - Convert SSE Response to AsyncIterable
413+ - ** ` asyncIterableToSSEStream<T>(iterable) ` ** - Convert AsyncIterable back to SSE stream
414+
415+ #### Advanced Streaming Examples
416+
417+ ** CI/CD Build System:**
418+ ``` typescript
419+ export async function runBuild(env : Env , buildId : string ) {
420+ const sandbox = getSandbox (env .SANDBOX , buildId );
421+ const stream = await sandbox .execStream (' npm run build' );
422+
423+ for await (const event of parseSSEStream <ExecEvent >(stream )) {
424+ switch (event .type ) {
425+ case ' start' :
426+ await env .BUILDS .put (buildId , { status: ' running' });
427+ break ;
428+ case ' complete' :
429+ await env .BUILDS .put (buildId , {
430+ status: event .exitCode === 0 ? ' success' : ' failed' ,
431+ exitCode: event .exitCode
432+ });
433+ break ;
434+ }
435+ }
436+ }
437+ ```
336438
439+ ** System Monitoring:**
337440``` typescript
338- const response = await sandbox .exec (" npm" , [" install" ], { stream: true });
339-
340- // Process the stream
341- const reader = response .body .getReader ();
342- while (true ) {
343- const { done, value } = await reader .read ();
344- if (done ) break ;
345- console .log (new TextDecoder ().decode (value ));
441+ const monitor = await sandbox .startProcess (' tail -f /var/log/system.log' );
442+ const logStream = await sandbox .streamProcessLogs (monitor .id );
443+
444+ for await (const log of parseSSEStream <LogEvent >(logStream )) {
445+ if (log .type === ' stdout' && log .data .includes (' ERROR' )) {
446+ await env .ALERTS .send ({
447+ severity: ' high' ,
448+ message: log .data ,
449+ timestamp: log .timestamp
450+ });
451+ }
346452}
347453```
348454
@@ -354,9 +460,9 @@ Maintain context across commands:
354460const sessionId = crypto .randomUUID ();
355461
356462// Commands in the same session share working directory
357- await sandbox .exec (" cd" , [ " /app" ] , { sessionId });
358- await sandbox .exec (" npm" , [ " install" ] , { sessionId });
359- await sandbox .exec (" npm" , [ " start" ] , { sessionId });
463+ await sandbox .exec (" cd /app" , { sessionId });
464+ await sandbox .exec (" npm install" , { sessionId });
465+ const app = await sandbox .startProcess (" npm start" , { sessionId });
360466```
361467
362468## 🔍 Debugging
@@ -399,17 +505,16 @@ npm run build
399505
400506## 📄 License
401507
402- [ MIT License] ( LICENSE ) - feel free to use this in your projects!
508+ [ MIT License] ( LICENSE )
403509
404510## 🙌 Acknowledgments
405511
406- Built with ❤️ by the Cloudflare team. Special thanks to all early adopters and contributors who are helping shape the future of edge computing .
512+ Built with ❤️ by the Cloudflare team. Special thanks to all early adopters and contributors.
407513
408514---
409515
410516<div align =" center " >
411517 <p >
412- <a href="https://developers.cloudflare.com">Docs</a> •
413518 <a href="https://github.com/cloudflare/sandbox-sdk/issues">Issues</a> •
414519 <a href="https://discord.gg/cloudflaredev">Discord</a> •
415520 <a href="https://twitter.com/CloudflareDev">Twitter</a>
0 commit comments