@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.
- package/dist/mybase.js +64 -15
- 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.
|
|
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
|
-
|
|
2374
|
-
|
|
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
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
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
|
-
|
|
3487
|
+
`/tmp:rw,nosuid,nodev,size=${resources.tmpMb}m,uid=1000,gid=1000,mode=0700`,
|
|
3443
3488
|
"--tmpfs",
|
|
3444
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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