@mybase-dev/cli 1.0.10 → 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/mybase.js +64 -15
  2. package/package.json +1 -1
package/dist/mybase.js CHANGED
@@ -109,7 +109,7 @@ var package_default;
109
109
  var init_package = __esm(() => {
110
110
  package_default = {
111
111
  name: "@mybase-dev/cli",
112
- version: "1.0.10",
112
+ version: "1.0.12",
113
113
  description: "The mybase CLI: projects, keys, cron, queues, cache, rate limits, analytics, docs, and agent setup for a self-hosted mybase.",
114
114
  type: "module",
115
115
  repository: {
@@ -1714,6 +1714,42 @@ function publicSandboxIp(ip) {
1714
1714
  }
1715
1715
  var init_public_ip = () => {};
1716
1716
 
1717
+ // ../../packages/shared/src/sandbox.ts
1718
+ function sandboxConfig(raw) {
1719
+ const config = { resources: { ...SANDBOX_RESOURCES }, limits: { ...SANDBOX_LIMITS } };
1720
+ if (!raw)
1721
+ return config;
1722
+ const input = JSON.parse(raw);
1723
+ if (!input || typeof input !== "object" || Array.isArray(input))
1724
+ throw new Error("MYBASE_SANDBOX_CONFIG must be a JSON object");
1725
+ for (const group of Object.keys(input)) {
1726
+ if (group !== "resources" && group !== "limits")
1727
+ throw new Error(`unknown sandbox config group: ${group}`);
1728
+ const values = input[group];
1729
+ if (!values || typeof values !== "object" || Array.isArray(values))
1730
+ throw new Error(`sandbox ${group} must be an object`);
1731
+ const target = config[group];
1732
+ for (const [key, value] of Object.entries(values)) {
1733
+ if (!Object.hasOwn(target, key))
1734
+ throw new Error(`unknown sandbox ${group} setting: ${key}`);
1735
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0 || key !== "cpus" && !Number.isSafeInteger(value))
1736
+ throw new Error(`sandbox ${key} must be a positive ${key === "cpus" ? "number" : "safe integer"}`);
1737
+ target[key] = value;
1738
+ }
1739
+ }
1740
+ return config;
1741
+ }
1742
+ var SANDBOX_RESOURCES, SANDBOX_LIMITS;
1743
+ var init_sandbox = __esm(() => {
1744
+ SANDBOX_RESOURCES = { cpus: 1, memoryMb: 1024, workspaceMb: 128, pids: 256, tmpMb: 256, shmMb: 64 };
1745
+ SANDBOX_LIMITS = {
1746
+ fileBytes: 8 * 1024 * 1024,
1747
+ outputBytes: 64 * 1024,
1748
+ networkStreams: 32,
1749
+ networkIdleMs: 15000
1750
+ };
1751
+ });
1752
+
1717
1753
  // ../../docker/compose.yml
1718
1754
  var compose_default = `# Runs mybase: the control plane (API + dashboard), the shared Postgres server, Garage
1719
1755
  # (S3-compatible storage), Valkey (Redis-compatible cache), and SearXNG (web search). All images are multi-arch (arm64 + amd64).
@@ -1831,6 +1867,7 @@ services:
1831
1867
  LOG_LEVEL: \${LOG_LEVEL:-info}
1832
1868
  MYBASE_SANDBOX_WORKER_URL: \${MYBASE_SANDBOX_WORKER_URL:-}
1833
1869
  MYBASE_SANDBOX_WORKER_KEY: \${MYBASE_SANDBOX_WORKER_KEY:-}
1870
+ MYBASE_SANDBOX_CONFIG: \${MYBASE_SANDBOX_CONFIG:-}
1834
1871
  ports:
1835
1872
  - "\${MYBASE_BIND:-0.0.0.0}:\${MYBASE_PORT:-4000}:4000"
1836
1873
 
@@ -1918,6 +1955,7 @@ services:
1918
1955
  environment:
1919
1956
  MYBASE_SANDBOX_WORKER_KEY: \${MYBASE_SANDBOX_WORKER_KEY:-}
1920
1957
  MYBASE_SANDBOX_DENY_HOSTS: \${MYBASE_SANDBOX_DENY_HOSTS:-}
1958
+ MYBASE_SANDBOX_CONFIG: \${MYBASE_SANDBOX_CONFIG:-}
1921
1959
  MYBASE_SANDBOX_IMAGE: \${MYBASE_SANDBOX_IMAGE:-ghcr.io/landonharter/mybase-sandbox:latest}
1922
1960
  LOG_LEVEL: \${LOG_LEVEL:-info}
1923
1961
  volumes:
@@ -2370,8 +2408,15 @@ function checkSandboxDocker(info, endpoint, platform = process.platform) {
2370
2408
  throw new CliError("sandboxes support Linux amd64 and arm64 hosts only (use a 64-bit OS on a Raspberry Pi)");
2371
2409
  if (!versionAtLeast(info.KernelVersion, "5.6.0"))
2372
2410
  throw new CliError("gVisor requires Linux 5.6 or newer");
2373
- if (info.CgroupVersion !== "2" || !info.MemoryLimit || !info.SwapLimit || !info.CpuCfsQuota || !info.PidsLimit)
2374
- throw new CliError("sandboxes require working cgroup v2 memory, swap, CPU and process controllers. The host kernel/Docker configuration needs those enabled first");
2411
+ const missing = [
2412
+ info.CgroupVersion !== "2" ? "cgroup v2" : null,
2413
+ !info.MemoryLimit ? "memory limits" : null,
2414
+ !info.SwapLimit ? "swap accounting" : null,
2415
+ info.CpuCfsQuota === false ? "CPU quotas" : null,
2416
+ !info.PidsLimit ? "process limits" : null
2417
+ ].filter(Boolean);
2418
+ if (missing.length)
2419
+ throw new CliError(`sandboxes require working cgroup v2 resource controllers; missing: ${missing.join(", ")}. The host kernel/Docker configuration needs those enabled first`);
2375
2420
  }
2376
2421
  function gvisorChecksum(text) {
2377
2422
  const match = /^([a-f0-9]{128})\s+\*?gvisor\.tar\.bz2\s*$/i.exec(text.trim());
@@ -3417,7 +3462,7 @@ async function sandboxWorkerHealth(dir, run = hostRun) {
3417
3462
  return null;
3418
3463
  }
3419
3464
  }
3420
- async function probeRuntime(image, run) {
3465
+ async function probeRuntime(image, run, resources) {
3421
3466
  const name = `mybase-sandbox-probe-${crypto.randomUUID()}`;
3422
3467
  const code = "const timer=setTimeout(()=>process.exit(1),15000);const {chromium}=require('/opt/runtime/node_modules/playwright');chromium.launch({headless:true,chromiumSandbox:false,args:['--disable-dev-shm-usage']}).then(async b=>{await b.close();clearTimeout(timer)}).catch(()=>process.exit(1))";
3423
3468
  try {
@@ -3432,16 +3477,17 @@ async function probeRuntime(image, run) {
3432
3477
  "--read-only",
3433
3478
  "--cap-drop=ALL",
3434
3479
  "--security-opt=no-new-privileges:true",
3435
- "--cpus=1",
3436
- "--memory=1024m",
3437
- "--memory-swap=1024m",
3438
- "--pids-limit=256",
3439
- "--ulimit=nproc=256:256",
3480
+ `--cpus=${resources.cpus}`,
3481
+ `--memory=${resources.memoryMb}m`,
3482
+ `--memory-swap=${resources.memoryMb}m`,
3483
+ `--pids-limit=${resources.pids}`,
3484
+ `--ulimit=nproc=${resources.pids}:${resources.pids}`,
3440
3485
  "--log-driver=none",
3441
3486
  "--tmpfs",
3442
- "/tmp:rw,nosuid,nodev,size=256m,uid=1000,gid=1000,mode=0700",
3487
+ `/tmp:rw,nosuid,nodev,size=${resources.tmpMb}m,uid=1000,gid=1000,mode=0700`,
3443
3488
  "--tmpfs",
3444
- "/workspace:rw,nosuid,nodev,size=128m,uid=1000,gid=1000,mode=0700",
3489
+ `/workspace:rw,nosuid,nodev,size=${resources.workspaceMb}m,uid=1000,gid=1000,mode=0700`,
3490
+ `--shm-size=${resources.shmMb}m`,
3445
3491
  "--entrypoint",
3446
3492
  "node",
3447
3493
  image,
@@ -3464,6 +3510,7 @@ async function prepareSandboxHost(args, options = {}, overrides = {}) {
3464
3510
  throw new CliError(`no mybase server in ${dir}; run mybase server setup --sandboxes first`, 4);
3465
3511
  const text = await file.text();
3466
3512
  const values = parseEnv(text);
3513
+ const config = sandboxConfig(values.MYBASE_SANDBOX_CONFIG);
3467
3514
  const interactive = !jsonMode && process.stdin.isTTY === true && !args.includes("--yes");
3468
3515
  if (!options.confirmed && !args.includes("--yes")) {
3469
3516
  if (!interactive)
@@ -3510,7 +3557,7 @@ async function prepareSandboxHost(args, options = {}, overrides = {}) {
3510
3557
  await pullImage(settings.MYBASE_SANDBOX_IMAGE, io.run, false);
3511
3558
  await pullImage(settings.MYBASE_SANDBOX_WORKER_IMAGE, io.run, false);
3512
3559
  s.message("Verifying Chromium under gVisor with bounded resources");
3513
- await probeRuntime(settings.MYBASE_SANDBOX_IMAGE, io.run);
3560
+ await probeRuntime(settings.MYBASE_SANDBOX_IMAGE, io.run, config.resources);
3514
3561
  await writeFiles(dir, mergeEnv(text, settings), interactive, true);
3515
3562
  const current = { ...values, ...settings };
3516
3563
  const url = localUrl(current);
@@ -3560,6 +3607,7 @@ var WORKER_HEALTH = "fetch('http://127.0.0.1:4010/health',{headers:{Authorizatio
3560
3607
  var init_server_sandbox = __esm(async () => {
3561
3608
  init_dist4();
3562
3609
  init_public_ip();
3610
+ init_sandbox();
3563
3611
  init_src();
3564
3612
  init_output();
3565
3613
  init_server_docker();
@@ -5849,10 +5897,10 @@ await init_service_enable();
5849
5897
  var sandboxUsage = ` sandbox enable <project> [--setup-worker] [--dir <dir>] [--yes]
5850
5898
  Enable isolated compute; --setup-worker configures the local host first
5851
5899
  sandbox disable <project> [--yes] Stop sandboxes and delete their artifacts
5852
- sandbox create <project> --key <key> [--ttl 300] [--idle 120]
5900
+ sandbox create <project> --key <key> [--ttl <seconds>] [--idle <seconds>]
5853
5901
  sandbox list|get|usage <project> [<id>]
5854
5902
  sandbox terminate <project> <id> [--yes]
5855
- sandbox exec <project> <id> --key <key> [--code file.js | --command '["node","script.js"]'] [--timeout 30000]
5903
+ sandbox exec <project> <id> --key <key> [--code file.js | --command '["node","script.js"]'] [--timeout <ms>]
5856
5904
  sandbox runs|artifacts|browser <project> <id>
5857
5905
  sandbox run <project> <id> <execution>
5858
5906
  sandbox cancel <project> <id> <execution> [--yes]
@@ -5860,7 +5908,8 @@ var sandboxUsage = ` sandbox enable <project> [--setup-worker] [--dir <dir>] [-
5860
5908
  sandbox export <project> <id> <workspace-path> [--type image/png]
5861
5909
  sandbox artifact <project> <id> <artifact-id> <local-file>
5862
5910
  Creation/execution return promptly. Poll get/run. Cancelling execution terminates sandbox.
5863
- Browser credentials expire after 30s; authenticated CDP connection lasts at most 60s.`;
5911
+ No default lifetime, idle expiry, or execution timeout. Set optional deadlines as needed.
5912
+ Browser credentials expire after 30s; authenticated CDP connections have no fixed lifetime.`;
5864
5913
  async function sandbox(sub, args) {
5865
5914
  const known = ["enable", "disable", "create", "list", "get", "usage", "terminate", "exec", "runs", "run", "cancel", "upload", "download", "export", "artifacts", "artifact", "browser"];
5866
5915
  if (!known.includes(sub))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mybase-dev/cli",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "The mybase CLI: projects, keys, cron, queues, cache, rate limits, analytics, docs, and agent setup for a self-hosted mybase.",
5
5
  "type": "module",
6
6
  "repository": {