이 가이드는 JavaScript나 TypeScript에서 샌드박스를 실행합니다. 격리된 Firecracker microVM을 띄우고, 세 가지 언어로 코드를 실행하고, 파일을 주고받고, 긴 작업의 출력을 따라갑니다. 각 단계는 짧은 코드 조각입니다.
Node.js 18+(또는 Deno, Bun)와 EQVPS 계정이 필요합니다.
1. 토큰 받기
SDK는 일반 계정 토큰으로 인증합니다. 대시보드, API, MCP 서버에서 토큰을 받는 방법은 계정 연결에 있습니다.
export EQVPS_API_KEY="your-token"
잔액이 없는 새 계정은 처음 샌드박스를 만들 때 1달러의 샌드박스 크레딧을 받습니다. 이 가이드를 여러 번 돌려도 충분한 금액입니다.
2. SDK 설치
npm i @eqvps/sdk
예제는 ES 모듈과 최상위 await를 사용합니다. .mjs 파일로 저장하거나, .ts로 저장한 뒤 npx tsx로 실행하세요.
3. 샌드박스를 띄우고 코드 실행
import { Sandbox } from "@eqvps/sdk";
await Sandbox.with({ tariff: "small" }, async (sb) => {
console.log(sb.id);
const r = await sb.run("import platform; print(platform.python_version())");
console.log(r.exit_code, r.stdout);
});
출력은 샌드박스 id(sb_와 24자), 그다음 0 3.12.x입니다. Sandbox.with는 콜백이 끝나면, 예외를 던진 경우에도 샌드박스를 삭제합니다.
기본 언어는 Python입니다. 나머지 둘은 옵션 하나면 됩니다.
await Sandbox.with({}, async (sb) => {
const js = await sb.run("console.log(process.version)", { language: "node" });
const sh = await sb.run("uname -r && nproc", { language: "bash" });
console.log(js.stdout, sh.stdout);
});
실패한 스크립트는 예외를 던지지 않습니다. r.ok를 확인하세요. exit_code가 0이고 타임아웃에 걸리지 않았으면 true입니다.
4. 셸 명령과 패키지
exec는 셸 문자열이나 argv 배열을 받습니다. 샌드박스는 인터넷에 접속할 수 있으므로 npm과 pip 설치도 됩니다.
await Sandbox.with({ tariff: "small" }, async (sb) => {
await sb.exec("mkdir -p /root/app && cd /root/app && npm init -y && npm i lodash", { timeout: 55 });
const r = await sb.exec(["node", "-e", "console.log(require('/root/app/node_modules/lodash').VERSION)"]);
console.log(r.stdout);
});
동기 호출은 최대 55초입니다. 그보다 오래 걸리면 백그라운드 작업으로 보냅니다(6단계).
5. 파일
await Sandbox.with({}, async (sb) => {
await sb.upload("/root/input.json", JSON.stringify({ values: [3, 5, 8] }));
await sb.run("import json; d = json.load(open('/root/input.json')); open('/root/out.txt', 'w').write(str(sum(d['values'])))");
console.log(await sb.downloadText("/root/out.txt")); // 16
});
upload는 문자열이나 Uint8Array를 받습니다. download는 Uint8Array를, downloadText는 문자열을 반환합니다. 한 번 전송할 수 있는 크기는 5 MB까지입니다.
6. 실시간 출력이 있는 긴 작업
await Sandbox.with({ tariff: "standard" }, async (sb) => {
const task = await sb.exec("for i in 1 2 3 4 5; do echo step $i; sleep 20; done", { background: true });
const res = await task.wait({ onOutput: (out) => process.stdout.write(out) });
console.log(res.state, res.exit_code); // done 0
});
작업은 바로 반환되며 55초 제한이 없습니다. wait는 기본적으로 2초마다 확인합니다(pollIntervalMs로 변경 가능). task.kill()로 멈추고, sb.task(id)로 다른 프로세스에서 다시 연결할 수 있습니다.
오류
import { Sandbox, InsufficientBalanceError, RateLimitError } from "@eqvps/sdk";
try {
await Sandbox.with({}, async (sb) => console.log((await sb.run("print(1)")).stdout));
} catch (e) {
if (e instanceof InsufficientBalanceError) console.log("Top up the balance");
else if (e instanceof RateLimitError) console.log("Busy, retry in", e.retryAfter);
else throw e;
}
서버가 Retry-After를 보내면 SDK가 429와 503을 최대 3번까지 스스로 재시도합니다. 가장 흔한 429는 한 계정에서 명령을 세 개 이상 동시에 실행할 때 생깁니다. 모든 클래스는 SDK 레퍼런스에 있습니다.
이 가이드의 비용
각 예제는 몇 초만 존재했고 최소 60초로 과금되었습니다. small에서 0.00055달러, standard에서 0.0011달러입니다. 6단계의 작업은 standard에서 약 100초 동안 돌아 약 0.002달러가 들었습니다. 전부 합쳐도 1센트에 한참 못 미칩니다. 전체 요금표는 샌드박스 한도와 과금에 있습니다.
다음 단계
- 같은 내용을 Python으로: 5분 만에 시작하는 샌드박스 Python SDK
- 모델을 연결해 자기 코드를 직접 실행하게 하기: 샌드박스에서 첫 에이전트 작업
- 요금제와 1달러 체험: 샌드박스 페이지
댓글
아직 댓글이 없습니다. 첫 번째가 되세요.