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.
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, anddownloadFileResponsemove content in and out.listFiles,searchFiles, andstatFileinspect the workspace.mkdir,moveFile, anddeleteFilemodify 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.