UNPKG

@acurast/cli

Version:

A cli to interact with the Acurast Cloud.

122 lines 5.34 kB
import { parseByteSize, MIN_EXECUTION_DURATION_MS } from '@acurast/sdk/chain'; import { buildVpsJob, VPS_IMAGE_PRESETS, } from '@acurast/vps'; import { CLI_NETWORKS } from '../config.js'; import { parse as parseDuration } from './parse-duration.js'; export const DEFAULT_VPS_IMAGE = 'ubuntu'; export const DEFAULT_VPS_DURATION = '24h'; export const DEFAULT_VPS_NETWORK = 'canary'; // From the app-tunnel/cargo example config. export const DEFAULT_VPS_MAX_COST_PER_EXECUTION = 48686320000; export const VPS_IMAGE_NAMES = Object.keys(VPS_IMAGE_PRESETS); /** * Domain suffix the tunnel relay serves per network (mirrors the pinned * tunnel bundle's `NETWORKS` table). Devnet rides on the canary relays. */ const VPS_DOMAIN_SUFFIX = { mainnet: 'acu.run', canary: 'canary.acu.run', devnet: 'canary.acu.run', }; export const VPS_ENV_MAPPING = { image: 'VPS_IMAGE', minMemory: 'VPS_MIN_MEMORY', minStorage: 'VPS_MIN_STORAGE', minComputeScore: 'VPS_MIN_COMPUTE_SCORE', minCpuMultiScore: 'VPS_MIN_CPU_MULTI_SCORE', authorizedSshKey: 'VPS_AUTHORIZED_SSH_KEY', duration: 'VPS_DURATION', callbackUrl: 'VPS_CALLBACK_URL', httpPort: 'VPS_HTTP_PORT', network: 'VPS_NETWORK', maxCostPerExecution: 'VPS_MAX_COST_PER_EXECUTION', }; /** * Merge CLI flags with `VPS_*` environment variables (flags win). `.env` is * already loaded via `dotenv/config` in `src/config.ts`. */ export const resolveVpsOptions = (flags, env = process.env) => { const resolved = { ...flags }; for (const [key, envKey] of Object.entries(VPS_ENV_MAPPING)) { if (resolved[key] === undefined && env[envKey]) { resolved[key] = env[envKey]; } } return resolved; }; const parsePositiveInt = (value, flag) => { const parsed = Number(value); if (!Number.isInteger(parsed) || parsed <= 0) { throw new Error(`Invalid --${flag}: "${value}" (expected a positive integer)`); } return parsed; }; const parseHttpPort = (value) => { const port = parsePositiveInt(value, 'http-port'); // Ports below 1024 can't be bound inside the proot sandbox. if (port < 1024 || port > 65535) { throw new Error(`Invalid --http-port: "${value}" (expected 1024-65535)`); } return port; }; export const buildVpsConfig = (options) => { const imageName = (options.image ?? DEFAULT_VPS_IMAGE); if (!VPS_IMAGE_PRESETS[imageName]) { throw new Error(`Unknown image "${imageName}". Available: ${VPS_IMAGE_NAMES.join(', ')}`); } const network = (options.network ?? DEFAULT_VPS_NETWORK); if (!CLI_NETWORKS.includes(network)) { throw new Error(`Unsupported network "${network}". Supported: ${CLI_NETWORKS.join(', ')}`); } const duration = options.duration ?? DEFAULT_VPS_DURATION; const durationMs = parseDuration(duration) ?? 0; if (!Number.isFinite(durationMs) || durationMs <= 0) { throw new Error(`Invalid duration "${duration}" (expected e.g. 1h, 24h, 2d)`); } if (durationMs < MIN_EXECUTION_DURATION_MS) { throw new Error(`Duration "${duration}" is too short: deployments must run for at least 1 minute`); } if (!options.authorizedSshKey) { throw new Error('An SSH public key is required (--authorized-ssh-key or VPS_AUTHORIZED_SSH_KEY): the VPS only accepts key-based SSH auth.'); } // The tunnel bundle only knows mainnet/canary relays; devnet rides on canary. const tunnelNetwork = network === 'devnet' ? 'canary' : network; const plan = buildVpsJob({ sshKey: options.authorizedSshKey, image: imageName, network: tunnelNetwork, // The SDK defaults to a 3-minute lead, which the CLI validator flags as // risky (< 5 minutes). startAt: { msFromNow: 300000 }, maxExecutionTimeInMs: durationMs, reward: options.maxCostPerExecution !== undefined ? parsePositiveInt(options.maxCostPerExecution, 'max-cost-per-execution') : DEFAULT_VPS_MAX_COST_PER_EXECUTION, minMemory: options.minMemory ? Number(parseByteSize(options.minMemory)) : undefined, minStorage: options.minStorage ? Number(parseByteSize(options.minStorage)) : undefined, minCpuScore: options.minComputeScore !== undefined ? parsePositiveInt(options.minComputeScore, 'min-compute-score') : undefined, minCpuMultiScore: options.minCpuMultiScore !== undefined ? parsePositiveInt(options.minCpuMultiScore, 'min-cpu-multi-score') : undefined, callbackUrl: options.callbackUrl, httpPort: options.httpPort !== undefined ? parseHttpPort(options.httpPort) : undefined, }); // clientId is unique per deployment (fresh keypair), so it doubles as a // stable, recognizable project name. const config = { ...plan.config, projectName: `vps-${plan.clientId}`, network, }; const domain = `${plan.clientId}.${VPS_DOMAIN_SUFFIX[network]}`; const sshCommand = `ssh -o ProxyCommand='openssl s_client -quiet -servername ${domain} -connect ${domain}:443' root@${domain}`; return { config, envVars: plan.envVars, clientId: plan.clientId, domain, sshCommand }; }; //# sourceMappingURL=buildVpsConfig.js.map