Back to Docs/Files, processes, and previews

Files, processes, and previews

Write files, run commands and services, and expose bounded previews with the Sandbox SDK.

Files, processes, and previews

The raw Sandbox SDK separates short commands from long-running processes. Use exec for bounded setup and checks. Use startProcess for a service that must stay alive while you inspect it or open a preview.

A complete service example

This example creates a sandbox, writes a tiny Node server, starts it as a managed process, exposes a private preview, inspects the files, and cleans up.

ts
import { createOpenPondClient } from "openpond-sdk"; const apiKey = process.env.OPENPOND_API_KEY?.trim(); if (!apiKey) throw new Error("OPENPOND_API_KEY is required"); const openpond = createOpenPondClient({ apiKey }); let sandboxId: string | undefined; let processId: string | undefined; try { const sandbox = await openpond.sandboxes.create({ resources: { cpu: 1, memoryGb: 2, diskGb: 8 }, budget: { maxUsd: "0.15" }, quotas: { maxSpendUsd: "0.15", maxDurationSeconds: 900, idleTimeoutSeconds: 300, maxCommands: 20, maxOpenPorts: 1, maxSnapshots: 0, }, }); sandboxId = sandbox.id; await openpond.sandboxes.uploadFile( sandbox.id, "server.mjs", [ "import { createServer } from 'node:http';", "const server = createServer((_request, response) => response.end('ok'));", "server.listen(3000, '0.0.0.0');", ].join("\n"), ); const started = await openpond.sandboxes.startProcess(sandbox.id, { command: "node server.mjs", timeoutSeconds: 600, }); processId = started.process.id; const preview = await openpond.sandboxes.openPort(sandbox.id, { port: 3000, label: "example-service", access: "private", }); const files = await openpond.sandboxes.listFiles(sandbox.id, { recursive: true, maxEntries: 50, }); const source = await openpond.sandboxes.downloadFile( sandbox.id, "server.mjs", ); console.log({ previewUrl: preview.preview.url, processStatus: started.process.status, fileCount: files.files.length, sourceBytes: source.length, }); } finally { if (sandboxId && processId) { await openpond.sandboxes.stopProcess(sandboxId, processId); } if (sandboxId) { await openpond.sandboxes.delete(sandboxId, { async: true }); } }

Wait for your service to listen before relying on its preview. A production integration should poll getProcess and probe the service, with a bounded deadline, before handing the URL to a user.

File operations

Use the typed methods rather than shelling out when the application needs structured results:

  • uploadFile, uploadFileBase64, downloadFile, and downloadFileResponse move content in and out.
  • listFiles, searchFiles, and statFile inspect the workspace.
  • mkdir, moveFile, and deleteFile modify paths explicitly.

Download responses support bounded byte ranges. Prefer them for large artifacts instead of loading an entire file into memory. Treat recursive deletion as destructive and resolve the exact sandbox-relative target first.

Commands and processes

exec returns a structured command with status, exitCode, and output. Check the status or exit code before using the output.

startProcess returns a process ID. Use getProcess for status and incremental output, listProcesses for reconciliation, streamProcessOutput for terminal-style streaming, and stopProcess during teardown.

PTY methods are for interactive terminal sessions. They add terminal state and input handling, so they are not the default for ordinary automation.

Preview safety

Open only ports your application expects and keep maxOpenPorts small. Use access: "private" unless the result is intentionally public. Do not log preview tokens or return them to an unrelated client. Stop the process and delete the sandbox when the preview is no longer needed.

Continue with runtimes, snapshots, and cleanup.