−25%

en Windows con pago anual, hasta el 31/10. Ver planes

EQVPS
Empezar

SDK de TypeScript para sandboxes en 5 minutos: de npm i @eqvps/sdk a la primera ejecución

Instala @eqvps/sdk, arranca una sandbox Firecracker desde Node.js, Deno o Bun, ejecuta en ella código Python, Node y shell, mueve archivos y sigue un trabajo largo en directo. Seis pasos con cada línea de código.

Esta guía pone en marcha una sandbox desde JavaScript o TypeScript. Arrancarás una microVM Firecracker aislada, ejecutarás código en tres lenguajes, moverás archivos y seguirás la salida de un trabajo largo. Cada paso es un fragmento corto.

Necesitas Node.js 18+ (o Deno, o Bun) y una cuenta de EQVPS.

1. Consigue un token

El SDK se autentica con un token de cuenta normal. Conectar tu cuenta muestra cómo obtenerlo desde el panel, la API o el servidor MCP.

export EQVPS_API_KEY="your-token"

Una cuenta nueva sin saldo recibe 1 $ de crédito para sandboxes la primera vez que crea una. Eso cubre esta guía muchas veces.

2. Instala el SDK

npm i @eqvps/sdk

Los ejemplos usan módulos ES y await de nivel superior. Guárdalos como archivos .mjs, o como .ts y ejecútalos con npx tsx.

3. Arranca una sandbox y ejecuta código

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);
});

La salida es el id de la sandbox (sb_ y 24 caracteres más) y luego 0 3.12.x. Sandbox.with borra la sandbox cuando el callback termina, también si lanza una excepción.

El lenguaje por defecto es Python. Los otros dos están a una opción de distancia:

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);
});

Un script que falla no lanza nada. Comprueba r.ok, que es true cuando exit_code es 0 y el comando no agotó su tiempo.

4. Comandos de shell y paquetes

exec acepta una cadena de shell o un array argv. La sandbox tiene acceso a Internet, así que las instalaciones con npm y pip funcionan:

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);
});

Una llamada síncrona dura como máximo 55 segundos. Lo que dure más va a una tarea en segundo plano (paso 6).

5. Archivos

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 acepta una cadena o un Uint8Array. download devuelve un Uint8Array y downloadText una cadena. Cada transferencia está limitada a 5 MB.

6. Trabajos largos con salida en directo

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
});

La tarea vuelve de inmediato y no tiene el límite de 55 segundos. wait consulta cada 2 segundos por defecto (pollIntervalMs lo cambia). task.kill() la detiene; sb.task(id) se vuelve a conectar desde otro proceso.

Errores

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;
}

El SDK reintenta por sí solo los 429 y 503, hasta tres veces, cuando el servidor envía Retry-After. El 429 más común aparece al ejecutar más de dos comandos a la vez en una cuenta. Todas las clases están en la referencia del SDK.

Coste de esta guía

Cada ejemplo vivió unos segundos y se facturó con el mínimo de 60 segundos: 0,00055 $ en small, 0,0011 $ en standard. El trabajo del paso 6 corrió unos 100 segundos en standard, unos 0,002 $. Todo junto queda muy por debajo de un centavo. La lista completa de precios está en límites y facturación de sandboxes.

Siguientes pasos

Preguntas frecuentes

¿Qué entornos soporta @eqvps/sdk?

Node.js 18 o posterior, Deno y Bun. No tiene dependencias y usa el fetch integrado, así que también funciona en un navegador, pero no pongas el token de tu cuenta en código de front-end.

¿Puede la sandbox ejecutar Python si mi aplicación está en TypeScript?

Sí. El lenguaje de tu aplicación y el del código de la sandbox son independientes. run acepta language python, node o bash, y exec ejecuta cualquier comando de shell.

¿Cómo me aseguro de que la sandbox se borra?

Usa Sandbox.with(options, fn), que borra la sandbox cuando fn termina o lanza una excepción. Con TypeScript 5.2 o posterior también puedes escribir await using sb = await Sandbox.create().

¿Qué devuelve run cuando el código falla?

Un ExecResult con un exit_code distinto de cero y el error en stderr. No lanza nada. Las excepciones son solo para errores de la API, como un token no válido o un saldo vacío.

Comentarios

Aún no hay comentarios. Sé el primero.

Deja un comentario

Los comentarios se moderan antes de aparecer.