@videan/cli 0.1.0 → 0.1.1
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/index.js +2 -2
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -788,13 +788,13 @@ function setApiKey(key) {
|
|
|
788
788
|
config.set("apiKey", key);
|
|
789
789
|
}
|
|
790
790
|
function getDefaultOrg() {
|
|
791
|
-
return fromEnv("ORG") || config.get("defaultOrg");
|
|
791
|
+
return fromEnv("ORG_ID") || fromEnv("ORG") || config.get("defaultOrg");
|
|
792
792
|
}
|
|
793
793
|
function setDefaultOrg(org) {
|
|
794
794
|
config.set("defaultOrg", org);
|
|
795
795
|
}
|
|
796
796
|
function getCurrentApp() {
|
|
797
|
-
return fromEnv("APP") || config.get("currentApp");
|
|
797
|
+
return fromEnv("APP_ID") || fromEnv("APP") || config.get("currentApp");
|
|
798
798
|
}
|
|
799
799
|
function setCurrentApp(appId) {
|
|
800
800
|
config.set("currentApp", appId);
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts", "../src/commands/login.ts", "../../shared/src/constants.ts", "../../shared/src/sizing.ts", "../../shared/src/pricing.ts", "../../sdk/src/client.ts", "../../shared/src/constants.ts", "../../shared/src/sizing.ts", "../../shared/src/pricing.ts", "../../shared/src/visibility.ts", "../src/config.ts", "../src/commands/logout.ts", "../src/commands/init.ts", "../src/commands/deploy.ts", "../src/util.ts", "../src/commands/logs.ts", "../src/commands/metrics.ts", "../src/commands/rollback.ts", "../src/commands/secrets.ts", "../src/commands/apps.ts", "../src/commands/status.ts", "../src/commands/keys.ts", "../src/commands/orgs.ts", "../src/commands/storage.ts", "../src/commands/email.ts", "../src/commands/jobs.ts", "../src/commands/usage.ts"],
|
|
4
|
-
"sourcesContent": ["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { logoutCommand } from \"./commands/logout.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { deployCommand } from \"./commands/deploy.js\";\nimport { logsCommand } from \"./commands/logs.js\";\nimport { metricsCommand } from \"./commands/metrics.js\";\nimport { rollbackCommand } from \"./commands/rollback.js\";\nimport { secretsCommand } from \"./commands/secrets.js\";\nimport { appsCommand } from \"./commands/apps.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { keysCommand } from \"./commands/keys.js\";\nimport { orgsCommand } from \"./commands/orgs.js\";\nimport { storageCommand } from \"./commands/storage.js\";\nimport { emailCommand } from \"./commands/email.js\";\nimport { jobsCommand } from \"./commands/jobs.js\";\nimport { usageCommand } from \"./commands/usage.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"videan\")\n .description(\"Videan CLI \u2014 deploy apps in seconds\")\n .version(\"0.1.0\");\n\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(initCommand);\nprogram.addCommand(deployCommand);\nprogram.addCommand(logsCommand);\nprogram.addCommand(metricsCommand);\nprogram.addCommand(rollbackCommand);\nprogram.addCommand(secretsCommand);\nprogram.addCommand(appsCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(keysCommand);\nprogram.addCommand(orgsCommand);\nprogram.addCommand(storageCommand);\nprogram.addCommand(emailCommand);\nprogram.addCommand(jobsCommand);\nprogram.addCommand(usageCommand);\n\n/**\n * Commander does not await an async action's rejection, so anything a command\n * throws lands as an unhandled rejection and node prints a stack trace with\n * `triggerUncaughtException` at the top of it. That is what a user saw for a\n * connection reset. `parseAsync` gives the rejection somewhere to go; the\n * handler is the backstop for a throw outside a command's own promise.\n */\nfunction die(e: any): never {\n console.error(`Error: ${e?.message || e}`);\n // Only when asked: the message is the actionable part, and a stack trace on\n // every network blip trains people to ignore CLI output.\n if (process.env.VIDEAN_DEBUG && e?.stack) console.error(e.stack);\n process.exit(1);\n}\n\nprocess.on(\"unhandledRejection\", die);\n\nprogram.parseAsync().catch(die);\n", "import { Command } from \"commander\";\nimport inquirer from \"inquirer\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport os from \"node:os\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { DEFAULT_API_URL } from \"@cloud/shared\";\nimport { setApiKey, setDefaultOrg, getBaseUrl, setBaseUrl } from \"../config.js\";\n\nexport const loginCommand = new Command(\"login\")\n .description(\"Log in to Cloud\")\n .option(\"-e, --email <email>\", \"Email (skips the prompt)\")\n .option(\"-p, --password <password>\", \"Password (skips the prompt; prefer VIDEAN_PASSWORD)\")\n .option(\"-o, --org <id>\", \"Organization to scope the key to (skips the picker)\")\n .option(\"--api-url <url>\", \"API base URL to use and remember (default: the public API)\")\n .action(async (opts) => {\n // Anything not supplied has to be prompted for, and prompting needs a\n // terminal. Without this the command hung on a closed stdin and then died\n // inside readline with `ERR_USE_AFTER_CLOSE` -- an agent driving the CLI, the\n // platform's whole intended caller, could not log in and could not tell why.\n const password = opts.password || process.env.VIDEAN_PASSWORD || process.env.CLOUD_PASSWORD;\n if ((!opts.email || !password) && !process.stdin.isTTY) {\n console.error(\n chalk.red(\n \"login needs a terminal to prompt. Non-interactively, pass --email and --password \" +\n \"(or VIDEAN_PASSWORD), or skip login entirely by setting VIDEAN_API_KEY.\",\n ),\n );\n process.exit(1);\n }\n\n const prompts = [\n ...(opts.email ? [] : [{ type: \"input\", name: \"email\", message: \"Email:\" }]),\n ...(password ? [] : [{ type: \"password\", name: \"password\", message: \"Password:\" }]),\n ];\n const answers = {\n email: opts.email,\n password,\n ...(prompts.length ? await inquirer.prompt(prompts) : {}),\n };\n\n // Same base as the SDK uses, so a custom baseUrl works for both. Saved\n // before the request, so that a wrong --api-url can be corrected by another\n // login rather than by editing the config file by hand.\n if (opts.apiUrl) setBaseUrl(opts.apiUrl.replace(/\\/$/, \"\"));\n const baseUrl = (getBaseUrl() || DEFAULT_API_URL).replace(/\\/$/, \"\");\n const spinner = ora(\"Logging in...\").start();\n\n let token: string;\n try {\n const response = await fetch(`${baseUrl}/auth/login`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email: answers.email, password: answers.password }),\n });\n\n if (!response.ok) {\n // Only 401 means the credentials are wrong. Everything else is the CLI\n // talking to the wrong place, and blaming the password for it sends the\n // user off resetting a password that was never the problem -- a stale\n // saved `baseUrl` pointing at a host that no longer serves /v1 reported\n // \"check your credentials\" for a plain 404.\n if (response.status === 401) {\n spinner.fail(\"Login failed. Check your credentials.\");\n } else {\n spinner.fail(`Login failed: ${response.status} from ${baseUrl}/auth/login`);\n console.error(\n chalk.gray(\" Wrong API URL? Re-run with --api-url <url>, or `videan logout` to reset.\"),\n );\n }\n process.exit(1);\n }\n\n const data = (await response.json()) as { data: { token: string } };\n token = data.data.token;\n } catch (e: any) {\n spinner.fail(`Login failed: could not reach ${baseUrl} (${e?.message || e})`);\n process.exit(1);\n }\n\n // The login JWT expires in days. Trade it for an API key so the CLI keeps\n // working, and so a stolen config file can be revoked without a password\n // change. Requires an org, since keys are scoped to one.\n const session = new CloudClient({ apiKey: token, baseUrl });\n\n let orgId: string | undefined;\n try {\n const orgs = await session.orgs.list();\n if (opts.org) {\n // Named explicitly, so verify it rather than trusting it: scoping a key\n // to an org the user is not a member of produces a key that fails on\n // every call, at some later point, with no hint as to why.\n const match = orgs.find((o) => o.id === opts.org || o.name === opts.org);\n if (!match) {\n spinner.fail(`No organization ${opts.org} for this account.`);\n process.exit(1);\n }\n orgId = match.id;\n } else if (orgs.length > 1 && !process.stdin.isTTY) {\n spinner.fail(\n `Several organizations (${orgs.map((o) => o.id).join(\", \")}). Pass --org <id>.`,\n );\n process.exit(1);\n } else if (orgs.length > 1) {\n spinner.stop();\n const pick = await inquirer.prompt([\n {\n type: \"list\",\n name: \"orgId\",\n message: \"Organization:\",\n choices: orgs.map((o) => ({ name: `${o.name} (${o.id})`, value: o.id })),\n },\n ]);\n orgId = pick.orgId;\n spinner.start(\"Creating CLI key...\");\n } else {\n // One org, or none yet -- the caller below handles the empty case.\n orgId = orgs[0]?.id;\n }\n } catch (e: any) {\n spinner.fail(`Logged in, but could not list organizations: ${e?.message}`);\n process.exit(1);\n }\n\n if (!orgId) {\n // Nothing to scope a key to yet; the session token still works for the\n // one call needed to create an org.\n setApiKey(token);\n spinner.warn(\n chalk.yellow(\"Logged in, but you have no organization yet. Run `videan orgs create <name>`.\"),\n );\n return;\n }\n\n try {\n const key = await session.apiKeys.create({\n name: `cli@${os.hostname()}`,\n orgId,\n });\n setApiKey(key.key);\n setDefaultOrg(orgId);\n spinner.succeed(chalk.green(\"Logged in.\"));\n console.log(chalk.gray(` Org: ${orgId}`));\n console.log(chalk.gray(` Key: ${key.keyPrefix}\u2026 (revoke with \\`videan keys revoke ${key.id}\\`)`));\n } catch (e: any) {\n // Fall back to the session token rather than leaving the user logged out.\n setApiKey(token);\n setDefaultOrg(orgId);\n spinner.warn(\n chalk.yellow(`Logged in with a temporary session (key creation failed: ${e?.message}).`),\n );\n }\n });\n", "export const DEFAULT_PORT = 3000;\n\nexport const SUPPORTED_RUNTIMES = [\n \"node-20\",\n \"node-22\",\n \"python-3.11\",\n \"python-3.12\",\n \"bun-1\",\n \"deno-2\",\n] as const;\n\nexport type SupportedRuntime = (typeof SUPPORTED_RUNTIMES)[number];\n\nexport const DEPLOYMENT_STATUSES = [\n \"building\",\n \"deploying\",\n \"running\",\n \"failed\",\n // A task that was live and then died on its own -- OOM, panic, ECS\n // replacement. The reconcile pass sets it, so anything enumerating statuses\n // has to know about it.\n \"crashed\",\n \"stopped\",\n] as const;\n\nexport const ENVIRONMENTS = [\"preview\", \"production\"] as const;\n\nexport const ROLES = [\"admin\", \"member\"] as const;\n\nexport const DEFAULT_API_URL = \"https://api.videan.xyz/v1\";\n\n/** The zone every app's hostname hangs off. */\nexport const APP_DOMAIN = process.env.CLOUD_APP_DOMAIN || \"videan.xyz\";\n\n/**\n * The public URL of an app, from its slug.\n *\n * One definition, because it was previously written out by hand in three places\n * and one of them omitted the scheme -- so a deployment's `url` came back as a\n * bare `slug.videan.xyz` that no terminal, browser or `fetch` would follow,\n * while the app resource reported the same app as `https://slug.videan.xyz`.\n * HTTP redirects to HTTPS anyway, so the scheme is not optional in practice.\n */\nexport function appUrl(slug: string): string {\n return `https://${slug}.${APP_DOMAIN}`;\n}\n\n/**\n * Prefix for a single deployment's own hostname.\n *\n * Every deployment is reachable before it is promoted, which is what lets an\n * agent verify its own work without production riding on the answer. The label is\n * a hash of the deployment id rather than the id itself: nanoid's alphabet\n * contains `_` and uppercase, neither of which is legal in a DNS label, and\n * lowercasing or substituting would map two distinct deployments onto one\n * hostname -- serving whichever the router looked up first.\n *\n * The prefix keeps the namespace from colliding with app slugs: `*.videan.xyz`\n * is one flat namespace, and an app legitimately slugged the same as some\n * deployment's hash would otherwise steal its traffic.\n */\nexport const PREVIEW_LABEL_PREFIX = \"d-\";\n\nexport function previewUrl(label: string): string {\n return `https://${PREVIEW_LABEL_PREFIX}${label}.${APP_DOMAIN}`;\n}\n\n/** True for a hostname label that belongs to the preview namespace. */\nexport function isPreviewLabel(label: string): boolean {\n return label.startsWith(PREVIEW_LABEL_PREFIX);\n}\n\nexport const CONFIG_FILE_NAME = \"cloud.yaml\";\n\nexport const IGNORE_FILE_NAME = \".cloudignore\";\n\nexport const MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024; // 50MB\n\nexport const MAX_FILES_PER_PUSH = 10_000;\n", "/**\n * Fargate task sizing.\n *\n * Every app used to run at 256 CPU / 512 MB, hardcoded in `ecs-app.ts`. That is\n * below the working set of a stock Next.js server, so those apps were killed by\n * the OOM killer -- which surfaces as a container that exits without a message,\n * indistinguishable from a crash in the app's own code. Sizing is therefore not\n * a tuning knob; at the old default some runtimes could not work at all.\n *\n * Fargate accepts only specific (cpu, memory) pairs and rejects everything else\n * at RegisterTaskDefinition time. Validating here rather than there means the\n * caller is told which values are legal instead of reading an AWS error, and the\n * CLI can reject a bad `--memory` before a build starts.\n */\n\nimport type { Runtime } from \"./detect.js\";\n\n/**\n * Legal memory values (MiB) for each CPU unit, from the Fargate task-size table.\n *\n * Expressed as a range plus a step rather than a literal list because the larger\n * tiers have hundreds of legal values; a list would be unreadable and would drift.\n */\nconst FARGATE_SIZES: Record<number, { min: number; max: number; step: number }> = {\n 256: { min: 512, max: 2048, step: 512 },\n 512: { min: 1024, max: 4096, step: 1024 },\n 1024: { min: 2048, max: 8192, step: 1024 },\n 2048: { min: 4096, max: 16384, step: 1024 },\n 4096: { min: 8192, max: 30720, step: 1024 },\n 8192: { min: 16384, max: 61440, step: 4096 },\n 16384: { min: 32768, max: 122880, step: 8192 },\n};\n\nexport const FARGATE_CPUS = Object.keys(FARGATE_SIZES)\n .map(Number)\n .sort((a, b) => a - b);\n\n/**\n * 256 CPU is a special case: its legal memory values are 512, 1024 and 2048 --\n * it skips 1536, so the uniform step above would admit a value Fargate rejects.\n */\nconst CPU_256_MEMORY = [512, 1024, 2048];\n\nexport interface SizeValidation {\n ok: boolean;\n /** Why the pair is illegal, naming the legal alternatives. */\n error?: string;\n /** The legal memory values for the given CPU, for building an error message. */\n allowed?: number[];\n}\n\nfunction legalMemory(cpu: number): number[] {\n if (cpu === 256) return CPU_256_MEMORY;\n const spec = FARGATE_SIZES[cpu];\n if (!spec) return [];\n const values: number[] = [];\n for (let m = spec.min; m <= spec.max; m += spec.step) values.push(m);\n return values;\n}\n\n/**\n * Checks a (cpu, memory) pair against the Fargate table.\n *\n * Deliberately strict rather than snapping to the nearest legal value: silently\n * giving an app 2 GB when its owner asked for 1.5 GB means the bill and the\n * behaviour do not match what was requested, and a size that is quietly changed\n * is a size nobody can reason about when the app OOMs anyway.\n */\nexport function validateSize(cpu: number, memory: number): SizeValidation {\n if (!FARGATE_SIZES[cpu]) {\n return {\n ok: false,\n error: `cpu must be one of ${FARGATE_CPUS.join(\", \")} (got ${cpu})`,\n };\n }\n const allowed = legalMemory(cpu);\n if (!allowed.includes(memory)) {\n // Long lists are unhelpful in an error message; show the shape instead.\n const shown =\n allowed.length <= 6\n ? allowed.join(\", \")\n : `${allowed[0]}\u2013${allowed[allowed.length - 1]} in steps of ${allowed[1] - allowed[0]}`;\n return {\n ok: false,\n error: `memory ${memory} is not valid for cpu ${cpu}; allowed: ${shown}`,\n allowed,\n };\n }\n return { ok: true };\n}\n\nexport interface TaskSize {\n cpu: number;\n memory: number;\n}\n\n/**\n * The size an app gets when nobody chose one.\n *\n * Picked per runtime because the failure is runtime-specific: `next start` holds\n * a compiled server plus its module graph and does not fit in 512 MB, while a\n * Go binary is comfortable in it. Defaulting everything to the larger size would\n * quadruple the bill for the runtimes that do not need it; defaulting everything\n * to the smaller one is the bug this replaces.\n */\nexport function defaultSizeFor(runtime: Runtime): TaskSize {\n switch (runtime) {\n case \"nextjs\":\n return { cpu: 512, memory: 1024 };\n case \"nodejs\":\n case \"python\":\n // Comfortable for a framework plus dependencies, and the smallest legal\n // pair above the old default.\n return { cpu: 256, memory: 1024 };\n case \"go\":\n return { cpu: 256, memory: 512 };\n case \"custom\":\n // Unknown contents, so assume it is doing something real.\n return { cpu: 512, memory: 1024 };\n }\n}\n\n/**\n * How many tasks a size change or a scale-out may run at once.\n *\n * A bound exists because `instances` is caller-supplied and reaches RunTask\n * directly: a typo of 100 would launch a hundred Fargate tasks and bill for them\n * before anyone noticed. RunTask itself caps a single call at 10.\n */\nexport const MAX_INSTANCES = 10;\n", "/**\n * What a plan allows and what usage costs.\n *\n * Kept here rather than in the control API because three consumers need the same\n * numbers and must not disagree about them: the API enforces the limits, the\n * usage collector prices the metrics it records, and the CLI prints a bill. A\n * rate duplicated in two of those places is a bill that does not match the\n * invoice.\n *\n * Two things this deliberately is *not*:\n *\n * - **A payment integration.** Nothing here charges anyone. It computes what an\n * org owes; collecting it needs a payment processor and a human to accept its\n * terms, the same way SES production access does.\n * - **The authority on AWS cost.** These are the platform's *prices*. The real\n * cost of a Fargate task is in Cost Explorer, and the two will not match --\n * that difference is the margin, and pretending otherwise would make every\n * price change look like a metering bug.\n */\n\n/**\n * Metrics recorded in `usage_records`.\n *\n * `vcpu_seconds` and `gb_seconds` are what Fargate actually charges for, so they\n * are what a compute line is priced from; `task_seconds` is recorded alongside\n * them because it is the number a human recognises (\"this ran for 20 hours\") and\n * cannot be recovered from the other two without knowing the task size.\n *\n * `storage_mb`, not bytes: `usage_records.quantity` is an `integer`, and bytes\n * overflows int32 at 2.1 GB -- silently, wrapping negative, which would read as a\n * credit.\n */\nexport type UsageMetric =\n | \"task_seconds\"\n | \"vcpu_seconds\"\n | \"gb_seconds\"\n | \"requests\"\n | \"build_seconds\"\n | \"storage_mb\"\n | \"emails_sent\"\n | \"db_days\";\n\nexport const USAGE_METRICS: UsageMetric[] = [\n \"task_seconds\",\n \"vcpu_seconds\",\n \"gb_seconds\",\n \"requests\",\n \"build_seconds\",\n \"storage_mb\",\n \"emails_sent\",\n \"db_days\",\n];\n\n/**\n * Metrics that are a level rather than a total.\n *\n * A day's `storage_mb` row is the last sample taken that day, not a sum of\n * samples -- summing a level double-counts every byte for every time it was\n * observed. Billing a level means averaging the samples across the period, which\n * is why the two kinds cannot be aggregated by the same code path.\n */\nexport const GAUGE_METRICS: UsageMetric[] = [\"storage_mb\"];\n\nexport function isGauge(metric: string): boolean {\n return (GAUGE_METRICS as string[]).includes(metric);\n}\n\n/**\n * Price per unit, in cents. Fractional on purpose: a request costs a fifth of a\n * millionth of a cent and rounding each one to a cent would bill $10,000 for a\n * million requests.\n *\n * `task_seconds` is priced at zero because compute is already billed through\n * `vcpu_seconds` and `gb_seconds`. It is in the table rather than absent from it\n * so that a new metric added without a price is a visible zero here instead of an\n * `undefined` multiplied into `NaN` further down.\n */\nexport const RATES: Record<UsageMetric, number> = {\n task_seconds: 0,\n // Fargate on-demand in us-east-1 is ~$0.04048/vCPU-hour and ~$0.004445/GB-hour.\n vcpu_seconds: 0.002,\n gb_seconds: 0.00025,\n // $0.20 per million requests.\n requests: 0.00002,\n // ~$0.012 per build-minute.\n build_seconds: 0.02,\n // $0.05 per GB-month, charged per MB-month.\n storage_mb: 0.005,\n // $0.50 per thousand.\n emails_sent: 0.05,\n // ~$3/month for a managed schema, charged per day it exists.\n db_days: 10,\n};\n\n/** Human unit for each metric, for a bill a person has to read. */\nexport const METRIC_LABELS: Record<UsageMetric, string> = {\n task_seconds: \"Task-seconds served\",\n vcpu_seconds: \"vCPU-seconds\",\n gb_seconds: \"GB-seconds\",\n requests: \"Requests\",\n build_seconds: \"Build seconds\",\n storage_mb: \"Object storage (MB-month)\",\n emails_sent: \"Emails sent\",\n db_days: \"Managed Postgres (app-days)\",\n};\n\nexport interface Plan {\n id: string;\n name: string;\n /** Monthly subscription, in cents, before usage. */\n baseCents: number;\n /**\n * Usage covered by the base fee, in cents. An org that stays under this pays\n * exactly `baseCents` -- so the free plan is a real free tier rather than a\n * $0.03 invoice for a weekend project.\n */\n includedUsageCents: number;\n /** Apps that are not soft-deleted. */\n maxApps: number;\n maxInstancesPerApp: number;\n /** Ceilings on Fargate task size, which is the one knob that scales the bill. */\n maxCpu: number;\n maxMemory: number;\n /** Object-storage quota, enforced on upload. */\n maxStorageMb: number;\n postgres: boolean;\n customDomains: boolean;\n}\n\n/**\n * The plans.\n *\n * The limits that exist are the ones that bound *spend*: app count, instance\n * count and task size. There is deliberately no limit on requests, builds or\n * deploys -- an agent-built app that gets popular should get a bill, not an\n * outage, and a platform whose selling point is \"push and it is live\" cannot\n * answer a deploy with \"not on your plan\".\n */\nexport const PLANS: Record<string, Plan> = {\n free: {\n id: \"free\",\n name: \"Free\",\n baseCents: 0,\n includedUsageCents: 300,\n maxApps: 3,\n maxInstancesPerApp: 1,\n // One app at this size, running all month, is inside the included usage.\n maxCpu: 512,\n maxMemory: 1024,\n maxStorageMb: 1024,\n postgres: true,\n customDomains: false,\n },\n pro: {\n id: \"pro\",\n name: \"Pro\",\n baseCents: 2000,\n includedUsageCents: 2000,\n maxApps: 50,\n maxInstancesPerApp: 4,\n maxCpu: 4096,\n maxMemory: 8192,\n maxStorageMb: 100 * 1024,\n postgres: true,\n customDomains: true,\n },\n scale: {\n id: \"scale\",\n name: \"Scale\",\n baseCents: 20000,\n includedUsageCents: 20000,\n maxApps: 500,\n maxInstancesPerApp: 10,\n maxCpu: 16384,\n maxMemory: 122880,\n maxStorageMb: 1024 * 1024,\n postgres: true,\n customDomains: true,\n },\n};\n\n/**\n * The plan for a stored `orgs.plan` value.\n *\n * Falls back to free rather than throwing: the column is free text and an\n * unrecognised value must not take an org's whole control surface down with a\n * 500. Free is the safe direction -- its limits are the tightest, so a typo\n * cannot silently grant a larger allowance than anyone agreed to.\n */\nexport function planFor(plan: string | null | undefined): Plan {\n return PLANS[plan || \"free\"] ?? PLANS.free;\n}\n\nexport interface UsageLine {\n metric: UsageMetric | string;\n label: string;\n quantity: number;\n unitPriceCents: number;\n /** Rounded to whole cents only at the line, never per unit. */\n cents: number;\n}\n\nexport interface Invoice {\n plan: string;\n periodStart: string;\n periodEnd: string;\n lines: UsageLine[];\n /** Everything the usage lines add up to, before the included allowance. */\n usageCents: number;\n baseCents: number;\n includedUsageCents: number;\n /** Usage beyond the allowance. Zero, never negative: credit does not roll over. */\n overageCents: number;\n totalCents: number;\n}\n\n/**\n * Prices a period's usage.\n *\n * `quantities` is metric \u2192 quantity, already aggregated over the period (sums for\n * counters, averages for gauges -- see `GAUGE_METRICS`, and note that this\n * function cannot tell which it was given, so aggregating wrongly produces a\n * plausible bill rather than an error).\n */\nexport function priceUsage(\n quantities: Record<string, number>,\n plan: Plan,\n period: { start: Date; end: Date },\n): Invoice {\n const lines: UsageLine[] = [];\n for (const metric of USAGE_METRICS) {\n const quantity = quantities[metric] ?? 0;\n const rate = RATES[metric];\n // A zero-priced metric is still reported when there is something to report:\n // task-seconds is how an owner checks that the compute line is plausible.\n if (quantity === 0) continue;\n lines.push({\n metric,\n label: METRIC_LABELS[metric],\n quantity: Math.round(quantity * 100) / 100,\n unitPriceCents: rate,\n cents: Math.round(quantity * rate),\n });\n }\n // Metrics recorded by a newer collector than this pricing table knows about.\n // Listed at zero rather than dropped: an unpriced metric that vanishes from the\n // bill is indistinguishable from one that was never collected.\n for (const metric of Object.keys(quantities)) {\n if ((USAGE_METRICS as string[]).includes(metric)) continue;\n if (!quantities[metric]) continue;\n lines.push({\n metric,\n label: metric,\n quantity: quantities[metric],\n unitPriceCents: 0,\n cents: 0,\n });\n }\n\n const usageCents = lines.reduce((acc, l) => acc + l.cents, 0);\n const overageCents = Math.max(0, usageCents - plan.includedUsageCents);\n return {\n plan: plan.id,\n periodStart: period.start.toISOString(),\n periodEnd: period.end.toISOString(),\n lines,\n usageCents,\n baseCents: plan.baseCents,\n includedUsageCents: plan.includedUsageCents,\n overageCents,\n totalCents: plan.baseCents + overageCents,\n };\n}\n\n/** `1234` \u2192 `\"$12.34\"`. For output a person reads, not for arithmetic. */\nexport function formatCents(cents: number): string {\n const sign = cents < 0 ? \"-\" : \"\";\n const abs = Math.abs(Math.round(cents));\n return `${sign}$${Math.floor(abs / 100)}.${String(abs % 100).padStart(2, \"0\")}`;\n}\n\nexport interface LimitCheck {\n ok: boolean;\n /** Names the limit and the plan, so the error says what to do about it. */\n error?: string;\n code?: string;\n}\n\nexport function allowed(): LimitCheck {\n return { ok: true };\n}\n\nfunction denied(code: string, error: string): LimitCheck {\n return { ok: false, error, code };\n}\n\n/** Whether one more app is within the plan. `current` excludes deleted apps. */\nexport function checkAppCount(plan: Plan, current: number): LimitCheck {\n if (current < plan.maxApps) return allowed();\n return denied(\n \"PLAN_LIMIT_APPS\",\n `The ${plan.name} plan allows ${plan.maxApps} app${plan.maxApps === 1 ? \"\" : \"s\"} ` +\n `and this org has ${current}. Delete one or upgrade the plan.`,\n );\n}\n\n/**\n * Whether a requested task shape is within the plan.\n *\n * Checked as a triple rather than three separate limits because they multiply:\n * the thing being bounded is the bill, and 4 instances of a small task costs the\n * same as one large one.\n */\nexport function checkTaskShape(\n plan: Plan,\n shape: { cpu?: number | null; memory?: number | null; instances?: number | null },\n): LimitCheck {\n if (shape.instances != null && shape.instances > plan.maxInstancesPerApp) {\n return denied(\n \"PLAN_LIMIT_INSTANCES\",\n `The ${plan.name} plan allows ${plan.maxInstancesPerApp} instance` +\n `${plan.maxInstancesPerApp === 1 ? \"\" : \"s\"} per app (asked for ${shape.instances}).`,\n );\n }\n if (shape.cpu != null && shape.cpu > plan.maxCpu) {\n return denied(\n \"PLAN_LIMIT_CPU\",\n `The ${plan.name} plan allows up to ${plan.maxCpu} CPU units per task (asked for ${shape.cpu}).`,\n );\n }\n if (shape.memory != null && shape.memory > plan.maxMemory) {\n return denied(\n \"PLAN_LIMIT_MEMORY\",\n `The ${plan.name} plan allows up to ${plan.maxMemory} MB per task (asked for ${shape.memory}).`,\n );\n }\n return allowed();\n}\n\n/** Whether a custom domain is within the plan. */\nexport function checkCustomDomain(plan: Plan): LimitCheck {\n if (plan.customDomains) return allowed();\n return denied(\n \"PLAN_LIMIT_DOMAINS\",\n `Custom domains are not included in the ${plan.name} plan. Every app keeps its ` +\n `platform hostname, which needs no configuration.`,\n );\n}\n", "import type {\n App,\n Snapshot,\n Deployment,\n Secret,\n Organization,\n OrgMember,\n LogEntry,\n LogPage,\n AppMetrics,\n CreateAppRequest,\n ApiResponse,\n Environment,\n AppHealth,\n BuildLogs,\n ApiKey,\n ApiKeyWithSecret,\n Job,\n OrgUsage,\n AppUsage,\n PlanInfo,\n Visibility,\n} from \"@cloud/shared\";\nimport { DEFAULT_API_URL } from \"@cloud/shared\";\n\n/**\n * Only all-lowercase snake_case, which is what the API emits for its own fields.\n *\n * Deliberately narrow. Data the platform carries on behalf of a user also\n * travels through here -- secret names like `DATABASE_URL`, file paths like\n * `app/page.js` -- and rewriting one of those would corrupt it. Uppercase, dots\n * and slashes all fail this test, so those pass through untouched.\n */\nconst SNAKE_KEY = /^[a-z0-9]+(_[a-z0-9]+)+$/;\n\n/**\n * Fields whose *contents* belong to the caller, not to the API.\n *\n * A job's payload is a blob the app wrote and the app will read back; renaming\n * `order_id` inside it to `orderId` would corrupt the app's own data on its way\n * through the SDK. Same reasoning as the narrow key pattern above -- the key\n * itself is still converted, only what hangs off it is left alone.\n */\nconst OPAQUE_KEYS = new Set([\"payload\", \"files\", \"metadata\"]);\n\n/**\n * Recursively rewrites snake_case keys to camelCase.\n *\n * The API's wire format is snake_case (`created_at`, `key_prefix`); the SDK's\n * types are camelCase. Nothing used to bridge the two -- `response.json()` was\n * simply cast to the typed shape -- so every such field was `undefined` at\n * runtime while the compiler insisted it was a string. That is the worst\n * possible failure mode for a typed client: `deployment.createdAt` produced\n * `NaN` elapsed times and `key.keyPrefix` printed \"undefined\u2026\", with no error\n * anywhere. The conversion belongs here rather than in the API, which other\n * consumers already read as snake_case.\n */\nexport function camelizeDeep(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(camelizeDeep);\n if (value === null || typeof value !== \"object\") return value;\n // Dates survive JSON as strings, so anything object-shaped here is a plain\n // object from JSON.parse.\n const out: Record<string, unknown> = {};\n for (const [key, v] of Object.entries(value as Record<string, unknown>)) {\n const camel = SNAKE_KEY.test(key)\n ? key.replace(/_([a-z0-9])/g, (_, c: string) => c.toUpperCase())\n : key;\n out[camel] = OPAQUE_KEYS.has(camel) ? v : camelizeDeep(v);\n }\n return out;\n}\n\n/**\n * The type-level counterpart of `camelizeDeep`.\n *\n * Some shared types describe the *wire* shape and keep its snake_case (`LogPage`,\n * `BuildLogs`), because that is what a non-SDK consumer reading the API sees. The\n * SDK rewrites those keys at runtime, so returning the wire type from an SDK\n * method would reintroduce exactly the bug `camelizeDeep` was written to fix: a\n * field the compiler swears is a string and that is `undefined` at runtime. This\n * makes the declared type follow the conversion instead of contradicting it.\n */\ntype CamelKey<K extends string> = K extends `${infer A}_${infer B}`\n ? `${A}${Capitalize<CamelKey<B>>}`\n : K;\n\nexport type Camelize<T> = T extends (infer U)[]\n ? Camelize<U>[]\n : T extends object\n ? { [K in keyof T as K extends string ? CamelKey<K> : K]: Camelize<T[K]> }\n : T;\n\nexport class CloudError extends Error {\n public readonly code: string;\n public readonly status: number;\n public readonly details?: Record<string, unknown>;\n\n constructor(message: string, code: string, status: number, details?: Record<string, unknown>) {\n super(message);\n this.name = \"CloudError\";\n this.code = code;\n this.status = status;\n this.details = details;\n }\n}\n\nexport interface CloudClientOptions {\n apiKey: string;\n baseUrl?: string;\n}\n\nexport class CloudClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n\n public readonly apps: AppsNamespace;\n public readonly secrets: SecretsNamespace;\n public readonly orgs: OrgsNamespace;\n public readonly apiKeys: ApiKeysNamespace;\n public readonly storage: StorageNamespace;\n public readonly email: EmailNamespace;\n public readonly jobs: JobsNamespace;\n\n constructor(options: CloudClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_API_URL).replace(/\\/$/, \"\");\n this.apps = new AppsNamespace(this);\n this.secrets = new SecretsNamespace(this);\n this.orgs = new OrgsNamespace(this);\n this.apiKeys = new ApiKeysNamespace(this);\n this.storage = new StorageNamespace(this);\n this.email = new EmailNamespace(this);\n this.jobs = new JobsNamespace(this);\n }\n\n /**\n * The plan catalogue. Unauthenticated on the API, so this works with any key --\n * including a placeholder one -- and can be called before an account exists to\n * show what an upgrade would allow.\n */\n async plans(): Promise<PlanInfo[]> {\n const res = await this.request<ApiResponse<PlanInfo[]>>(\"GET\", \"/plans\");\n return res.data;\n }\n\n async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n \"Authorization\": `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n };\n\n // `fetch` reports every transport failure as the same bare `TypeError: fetch\n // failed`, with the cause one level down and the URL nowhere in it. A caller\n // seeing that cannot tell a DNS mistake from a reset connection from an API\n // that is down, which is the same class of unhelpfulness as the old\n // \"check your credentials\" for a 404. Status 0 says the request never got an\n // answer, so a retry is reasonable -- unlike a 4xx.\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n } catch (e: any) {\n const cause = e?.cause?.code || e?.cause?.message || e?.message || \"unknown error\";\n throw new CloudError(\n `Could not reach ${url} (${cause}).`,\n \"network_error\",\n 0,\n );\n }\n\n if (!response.ok) {\n const errorBody = await response.json().catch(() => ({}));\n const err = (errorBody as { error?: { code?: string; message?: string; details?: Record<string, unknown> } }).error;\n throw new CloudError(\n err?.message ?? `Request failed with status ${response.status}`,\n err?.code ?? \"unknown_error\",\n response.status,\n err?.details,\n );\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return camelizeDeep(await response.json()) as T;\n }\n}\n\nclass AppsNamespace {\n constructor(private client: CloudClient) {}\n\n async create(opts: {\n name: string;\n orgId: string;\n postgres?: boolean;\n /** Gives the app an object-storage prefix; see `client.storage`. */\n storage?: boolean;\n /** Lets the app send mail through the platform; see `client.email`. */\n email?: boolean;\n /**\n * Who may reach the running app: \"private\" | \"org\" | \"authenticated\" |\n * \"public\", narrowest first. Defaults to \"org\". Prefer this over\n * `authRequired`, which cannot express the difference between \"only the\n * people I invite\" and \"anyone in my org\".\n */\n visibility?: Visibility;\n /** @deprecated Use `visibility`. false is equivalent to \"public\". */\n authRequired?: boolean;\n }): Promise<App> {\n const body: CreateAppRequest = {\n name: opts.name,\n org_id: opts.orgId,\n postgres_enabled: opts.postgres,\n storage_enabled: opts.storage,\n email_enabled: opts.email,\n auth_required: opts.authRequired,\n visibility: opts.visibility,\n };\n const res = await this.client.request<ApiResponse<App>>(\"POST\", \"/apps\", body);\n return res.data;\n }\n\n /**\n * Changes an app's settings.\n *\n * `restartRequired` is true when the change only takes effect on a new\n * container -- size, scale and postgres. The API reports it rather than\n * restarting on its own: a restart is a brief interruption, and doing it as a\n * side effect of a settings write is not the caller's decision to discover\n * afterwards. Follow with `restart()` when it comes back true.\n */\n async update(\n appId: string,\n changes: {\n name?: string;\n /**\n * Who may reach the running app. Admin-level: an editor may deploy the\n * app but not change who can open it.\n *\n * Note that `authRequired: true` will not narrow an app that is already\n * gated -- the boolean cannot tell \"private\" from \"org\", so the API\n * leaves the tier alone rather than risk widening a private app. Send\n * `visibility` to move between the gated tiers.\n */\n visibility?: Visibility;\n /** @deprecated Use `visibility`. false is equivalent to \"public\". */\n authRequired?: boolean;\n /** \"active\" or \"paused\". */\n status?: \"active\" | \"paused\";\n cpu?: number;\n memory?: number;\n instances?: number;\n /** Requests per minute per client, or null to remove the limit. */\n rateLimitPerMinute?: number | null;\n postgres?: boolean;\n storage?: boolean;\n email?: boolean;\n },\n ): Promise<App & { restartRequired?: boolean }> {\n const body: Record<string, unknown> = {};\n if (changes.name !== undefined) body.name = changes.name;\n if (changes.authRequired !== undefined) body.auth_required = changes.authRequired;\n if (changes.visibility !== undefined) body.visibility = changes.visibility;\n if (changes.status !== undefined) body.status = changes.status;\n if (changes.cpu !== undefined) body.cpu = changes.cpu;\n if (changes.memory !== undefined) body.memory = changes.memory;\n if (changes.instances !== undefined) body.instances = changes.instances;\n // Sent when explicitly null, which is how a limit is removed -- omitting it\n // would leave the old limit in place and look like the call did nothing.\n if (changes.rateLimitPerMinute !== undefined) {\n body.rate_limit_per_minute = changes.rateLimitPerMinute;\n }\n if (changes.postgres !== undefined) body.postgres_enabled = changes.postgres;\n if (changes.storage !== undefined) body.storage_enabled = changes.storage;\n if (changes.email !== undefined) body.email_enabled = changes.email;\n\n const res = await this.client.request<ApiResponse<App & { restartRequired?: boolean }>>(\n \"PATCH\",\n `/apps/${appId}`,\n body,\n );\n return res.data;\n }\n\n async list(orgId: string): Promise<App[]> {\n const res = await this.client.request<ApiResponse<App[]>>(\n \"GET\",\n `/apps?org_id=${encodeURIComponent(orgId)}`,\n );\n return res.data;\n }\n\n async get(id: string): Promise<App> {\n const res = await this.client.request<ApiResponse<App>>(\"GET\", `/apps/${id}`);\n return res.data;\n }\n\n /**\n * Deletes the app and tears down its AWS resources.\n *\n * Teardown is fault-isolated per resource, so a partial failure still deletes\n * the app and reports what leaked in `warnings` (HTTP 207) rather than\n * aborting. An empty array means everything was released.\n */\n async delete(id: string): Promise<{ warnings: { step: string; error?: string }[] }> {\n const res = await this.client.request<{\n data: App;\n warnings?: { step: string; error?: string }[];\n }>(\"DELETE\", `/apps/${id}`);\n return { warnings: res?.warnings ?? [] };\n }\n\n /**\n * Pushes a snapshot.\n *\n * `files` carries text. Anything that is not valid UTF-8 \u2014 an image, a\n * favicon, a compiled binary \u2014 must go in `binaryFiles` as base64, because\n * JSON cannot carry arbitrary bytes in a string and a value that is silently\n * re-encoded arrives corrupted. The two are separate maps rather than one\n * with a flag: base64 is not detectable (`\"data\"` is valid base64 and valid\n * text), so the encoding has to be stated by the caller.\n */\n async push(\n appId: string,\n files: Record<string, string>,\n message?: string,\n binaryFiles?: Record<string, string>,\n ): Promise<Snapshot> {\n const res = await this.client.request<ApiResponse<Snapshot>>(\"POST\", `/apps/${appId}/push`, {\n files,\n message,\n // Request bodies are not camelized \u2014 only responses are \u2014 so the wire\n // name has to be written out here.\n ...(binaryFiles && Object.keys(binaryFiles).length > 0 ? { binary_files: binaryFiles } : {}),\n });\n return res.data;\n }\n\n async deploy(appId: string, snapshotId: string, environment?: Environment): Promise<Deployment> {\n const res = await this.client.request<ApiResponse<Deployment>>(\"POST\", `/apps/${appId}/deploy`, {\n snapshot_id: snapshotId,\n environment,\n });\n return res.data;\n }\n\n async promote(deploymentId: string): Promise<Deployment> {\n const res = await this.client.request<ApiResponse<Deployment>>(\"POST\", `/deployments/${deploymentId}/promote`, {});\n return res.data;\n }\n\n async rollback(appId: string): Promise<Deployment> {\n const res = await this.client.request<ApiResponse<Deployment>>(\"POST\", `/apps/${appId}/rollback`, {});\n return res.data;\n }\n\n async checkDeployment(deploymentId: string): Promise<Deployment> {\n const res = await this.client.request<ApiResponse<Deployment>>(\"POST\", `/deployments/${deploymentId}/status`, {});\n return res.data;\n }\n\n /**\n * A page of the app's logs, newest last.\n *\n * Returns a page rather than a bare array of entries, which is what this used to\n * be: an array cannot say whether there is more to fetch, and the endpoint\n * behind it silently answered with the newest few log streams as though they\n * were the whole app. To page, pass the previous response's `nextToken`; to\n * follow, pass the last event's `timestamp` as `since`.\n *\n * `since`/`until` accept an ISO timestamp, epoch millis, or an offset like\n * `15m`. `q` is a literal substring; `pattern` is CloudWatch filter syntax --\n * pass one or the other, not both.\n */\n async logs(\n appId: string,\n opts?: {\n limit?: number;\n since?: string;\n until?: string;\n q?: string;\n pattern?: string;\n /** Log stream prefix, to read one instance instead of all of them. */\n instance?: string;\n nextToken?: string;\n },\n ): Promise<Camelize<LogPage>> {\n const params = new URLSearchParams();\n if (opts?.limit) params.set(\"limit\", String(opts.limit));\n if (opts?.since) params.set(\"since\", opts.since);\n if (opts?.until) params.set(\"until\", opts.until);\n if (opts?.q) params.set(\"q\", opts.q);\n if (opts?.pattern) params.set(\"pattern\", opts.pattern);\n if (opts?.instance) params.set(\"instance\", opts.instance);\n if (opts?.nextToken) params.set(\"next_token\", opts.nextToken);\n const query = params.toString();\n const path = `/apps/${appId}/logs${query ? `?${query}` : \"\"}`;\n const res = await this.client.request<ApiResponse<Camelize<LogPage>>>(\"GET\", path);\n return res.data;\n }\n\n /**\n * Follows the app's logs, yielding each line as it appears.\n *\n * Polling rather than the API's SSE tail: an async generator works in node\n * without `EventSource`, and it carries the bearer token the same way as every\n * other call. The cursor is the last event's timestamp and the window is\n * reopened *at* it rather than after it -- several lines share a millisecond, so\n * advancing past it would drop the rest of them -- with the boundary\n * millisecond's lines remembered to suppress the repeat.\n */\n async *followLogs(\n appId: string,\n opts?: { since?: string; q?: string; pattern?: string; instance?: string; intervalMs?: number },\n ): AsyncGenerator<LogEntry> {\n const interval = opts?.intervalMs ?? 2000;\n let since = opts?.since ?? \"60s\";\n let seenAtCursor = new Set<string>();\n\n while (true) {\n const page = await this.logs(appId, {\n since,\n limit: 500,\n q: opts?.q,\n pattern: opts?.pattern,\n instance: opts?.instance,\n });\n\n for (const event of page.events) {\n const key = `${event.stream || \"\"} ${event.message}`;\n if (event.timestamp === since) {\n if (seenAtCursor.has(key)) continue;\n seenAtCursor.add(key);\n } else {\n since = event.timestamp;\n seenAtCursor = new Set([key]);\n }\n yield event;\n }\n\n await new Promise((r) => setTimeout(r, interval));\n }\n }\n\n /**\n * Traffic, latency and resource use over a window.\n *\n * `since`/`until` take the same values as `logs`, deliberately: an owner who\n * spots a spike here reads the logs for the same period next.\n *\n * Note the series keys arrive camelized like every other field on this client,\n * so the API's `client_errors` is `clientErrors` and `latency_p95` is\n * `latencyP95`.\n */\n async metrics(\n appId: string,\n opts?: { since?: string; until?: string },\n ): Promise<Camelize<AppMetrics>> {\n const params = new URLSearchParams();\n if (opts?.since) params.set(\"since\", opts.since);\n if (opts?.until) params.set(\"until\", opts.until);\n const query = params.toString();\n const res = await this.client.request<ApiResponse<Camelize<AppMetrics>>>(\n \"GET\",\n `/apps/${appId}/metrics${query ? `?${query}` : \"\"}`,\n );\n return res.data;\n }\n\n /**\n * Live runtime state, including the container's exit code when it has crashed.\n * A deployment stays \"running\" in the database after the task dies, so this is\n * the only way to tell a healthy app from a crash loop.\n */\n /**\n * What this app cost in a month (`YYYY-MM`, default the month in progress),\n * priced at list rates with no allowance applied -- the plan's included usage\n * belongs to the org, so per-app figures would otherwise sum past the invoice.\n */\n async usage(appId: string, period?: string): Promise<AppUsage> {\n const query = period ? `?period=${encodeURIComponent(period)}` : \"\";\n const res = await this.client.request<ApiResponse<AppUsage>>(\n \"GET\",\n `/apps/${appId}/usage${query}`,\n );\n return res.data;\n }\n\n async health(appId: string): Promise<AppHealth> {\n const res = await this.client.request<ApiResponse<AppHealth>>(\"GET\", `/apps/${appId}/health`);\n return res.data;\n }\n\n /**\n * Build output for a deployment. Poll with the previous response's `next_token`\n * to stream a build as it runs.\n */\n async buildLogs(deploymentId: string, nextToken?: string): Promise<Camelize<BuildLogs>> {\n const query = nextToken ? `?next_token=${encodeURIComponent(nextToken)}` : \"\";\n const res = await this.client.request<ApiResponse<Camelize<BuildLogs>>>(\n \"GET\",\n `/deployments/${deploymentId}/build-logs${query}`,\n );\n return res.data;\n }\n}\n\nclass ApiKeysNamespace {\n constructor(private client: CloudClient) {}\n\n /**\n * Creates a key. The plaintext `key` is present on this response only -- the\n * server stores a hash and cannot return it again.\n */\n async create(opts: {\n name: string;\n orgId: string;\n expiresInDays?: number;\n /**\n * Pass an app id for a **service token**: a credential pinned to that one app,\n * for code running inside it. It cannot reach another app, issue further keys,\n * list the org's keys or revoke anything -- which is what makes it safe to\n * ship inside a container. A key without this acts as its creator across\n * every app in the org, so do not put one in a deployed app.\n */\n appId?: string;\n }): Promise<ApiKeyWithSecret> {\n const res = await this.client.request<ApiResponse<ApiKeyWithSecret>>(\"POST\", \"/api-keys\", {\n name: opts.name,\n org_id: opts.orgId,\n expires_in_days: opts.expiresInDays,\n app_id: opts.appId,\n });\n return res.data;\n }\n\n async list(orgId: string): Promise<ApiKey[]> {\n const res = await this.client.request<ApiResponse<ApiKey[]>>(\n \"GET\",\n `/api-keys?org_id=${encodeURIComponent(orgId)}`,\n );\n return res.data;\n }\n\n async revoke(id: string): Promise<void> {\n await this.client.request<void>(\"DELETE\", `/api-keys/${id}`);\n }\n}\n\nclass SecretsNamespace {\n constructor(private client: CloudClient) {}\n\n async set(appId: string, key: string, value: string): Promise<Secret> {\n const res = await this.client.request<ApiResponse<Secret>>(\"POST\", `/apps/${appId}/secrets`, {\n key,\n value,\n });\n return res.data;\n }\n\n async list(appId: string): Promise<Secret[]> {\n const res = await this.client.request<ApiResponse<Secret[]>>(\"GET\", `/apps/${appId}/secrets`);\n return res.data;\n }\n\n async delete(appId: string, key: string): Promise<void> {\n await this.client.request<void>(\"DELETE\", `/apps/${appId}/secrets/${key}`);\n }\n}\n\nexport interface StoredObject {\n key: string;\n size: number;\n lastModified: string | null;\n etag: string | null;\n}\n\n/**\n * Object storage for an app.\n *\n * Bytes never pass through the control API: it hands out a presigned S3 URL and\n * the transfer goes direct. `upload` and `download` wrap that two-step for the\n * common case; `presign` is there for handing a URL to a browser so an upload\n * skips the app's own server entirely.\n *\n * Best reached with a **service token** (`apiKeys.create({ appId })`) from inside\n * the app, so the credential in the container cannot touch anything else.\n */\nclass StorageNamespace {\n constructor(private client: CloudClient) {}\n\n async list(\n appId: string,\n opts: { prefix?: string; limit?: number; cursor?: string } = {},\n ): Promise<{ objects: StoredObject[]; nextCursor: string | null }> {\n const q = new URLSearchParams();\n if (opts.prefix) q.set(\"prefix\", opts.prefix);\n if (opts.limit) q.set(\"limit\", String(opts.limit));\n if (opts.cursor) q.set(\"cursor\", opts.cursor);\n const query = q.toString() ? `?${q}` : \"\";\n const res = await this.client.request<\n ApiResponse<{ objects: StoredObject[]; nextCursor: string | null }>\n >(\"GET\", `/apps/${appId}/storage/objects${query}`);\n return res.data;\n }\n\n /** Every object under the prefix, paged through for you. */\n async listAll(appId: string, prefix?: string): Promise<StoredObject[]> {\n const all: StoredObject[] = [];\n let cursor: string | undefined;\n do {\n const page = await this.list(appId, { prefix, cursor, limit: 1000 });\n all.push(...page.objects);\n cursor = page.nextCursor ?? undefined;\n } while (cursor);\n return all;\n }\n\n async usage(appId: string): Promise<{ objects: number; bytes: number }> {\n const res = await this.client.request<ApiResponse<{ objects: number; bytes: number }>>(\n \"GET\",\n `/apps/${appId}/storage/usage`,\n );\n return res.data;\n }\n\n /** Metadata for one object, or null when it is not there. */\n async head(appId: string, key: string): Promise<StoredObject | null> {\n try {\n const res = await this.client.request<ApiResponse<StoredObject>>(\n \"GET\",\n `/apps/${appId}/storage/object?key=${encodeURIComponent(key)}`,\n );\n return res.data;\n } catch (e) {\n if (e instanceof CloudError && e.status === 404) return null;\n throw e;\n }\n }\n\n async delete(appId: string, key: string): Promise<void> {\n await this.client.request<ApiResponse<unknown>>(\n \"DELETE\",\n `/apps/${appId}/storage/object?key=${encodeURIComponent(key)}`,\n );\n }\n\n /**\n * A short-lived URL for one key and one method. Hand a `put` URL to a browser to\n * upload without the bytes touching the app, or a `get` URL to share a private\n * object for a few minutes. Treat it as a credential: anyone holding it has that\n * access until it expires.\n */\n async presign(\n appId: string,\n key: string,\n opts: {\n method?: \"put\" | \"get\";\n expiresIn?: number;\n contentType?: string;\n download?: string;\n } = {},\n ): Promise<{ url: string; method: string; key: string; expiresIn: number }> {\n const res = await this.client.request<\n ApiResponse<{ url: string; method: string; key: string; expiresIn: number }>\n >(\"POST\", `/apps/${appId}/storage/presign`, {\n key,\n method: opts.method ?? \"get\",\n expires_in: opts.expiresIn,\n content_type: opts.contentType,\n download: opts.download,\n });\n return res.data;\n }\n\n /**\n * Presigns and uploads in one call.\n *\n * `contentType` is signed into the URL, so it is sent on the PUT as well --\n * omitting it there would make S3 reject the signature with an opaque 403.\n */\n async upload(\n appId: string,\n key: string,\n body: Uint8Array | ArrayBuffer | string | Blob,\n opts: { contentType?: string } = {},\n ): Promise<StoredObject> {\n const signed = await this.presign(appId, key, {\n method: \"put\",\n contentType: opts.contentType,\n });\n const res = await fetch(signed.url, {\n method: \"PUT\",\n headers: opts.contentType ? { \"Content-Type\": opts.contentType } : undefined,\n body: body as BodyInit,\n });\n if (!res.ok) {\n // S3's own error is XML, not the platform's JSON envelope, so it is passed\n // through as text rather than parsed into a CloudError shape it does not have.\n throw new CloudError(\n `Upload failed with status ${res.status}: ${(await res.text()).slice(0, 300)}`,\n \"upload_failed\",\n res.status,\n );\n }\n return { key, size: 0, lastModified: null, etag: res.headers.get(\"etag\") };\n }\n\n /** Presigns and fetches. Returns the raw bytes; decode as the caller sees fit. */\n async download(appId: string, key: string): Promise<Uint8Array> {\n const signed = await this.presign(appId, key, { method: \"get\" });\n const res = await fetch(signed.url);\n if (!res.ok) {\n throw new CloudError(\n `Download failed with status ${res.status}`,\n res.status === 404 ? \"not_found\" : \"download_failed\",\n res.status,\n );\n }\n return new Uint8Array(await res.arrayBuffer());\n }\n}\n\nexport interface EmailQuota {\n sent: number;\n quota: number;\n remaining: number;\n /** The API sends `resets_at`; `camelizeDeep` renames it on the way in. */\n resetsAt: string;\n}\n\nexport interface SentEmail {\n messageId: string | null;\n to: string[];\n from: string;\n quota: EmailQuota;\n}\n\n/**\n * Transactional email sent by the platform on the app's behalf.\n *\n * There is no `from`: mail goes out as `app-<slug>@<platform domain>`, because an\n * app able to choose its own From could send a credible password-reset email as\n * the platform. Use `replyTo` to route replies to your own address.\n */\nclass EmailNamespace {\n constructor(private client: CloudClient) {}\n\n /**\n * Sends one message, to up to 50 recipients, as a single all-or-nothing send.\n *\n * Throws `CloudError` with status 429 once the app's daily quota is used up, and\n * 502 when the provider rejected the message -- the message text carries the\n * reason, which while the sending account is sandboxed is usually that the\n * recipient address is not verified.\n */\n async send(\n appId: string,\n message: {\n to: string | string[];\n subject: string;\n text?: string;\n html?: string;\n replyTo?: string;\n },\n ): Promise<SentEmail> {\n const res = await this.client.request<ApiResponse<SentEmail>>(\n \"POST\",\n `/apps/${appId}/email`,\n {\n to: message.to,\n subject: message.subject,\n text: message.text,\n html: message.html,\n reply_to: message.replyTo,\n },\n );\n return res.data;\n }\n\n /** Sends used today and what is left. Resets at UTC midnight. */\n async quota(appId: string): Promise<EmailQuota> {\n const res = await this.client.request<ApiResponse<EmailQuota>>(\n \"GET\",\n `/apps/${appId}/email/quota`,\n );\n return res.data;\n }\n}\n\n/**\n * Background jobs.\n *\n * A job is delivered as a POST to a path on the app itself, so the \"worker\" is a\n * route in the app the agent already wrote. Delivery is at least once -- retries\n * mean a handler can see the same job twice -- which is what `idempotencyKey`\n * on the enqueue side and the `x-videan-job-attempt` header on the receiving side\n * are for.\n */\nclass JobsNamespace {\n constructor(private client: CloudClient) {}\n\n /**\n * Enqueues a job.\n *\n * Pass `idempotencyKey` when the caller may retry this enqueue: a repeat returns\n * the job already queued, with `deduplicated: true`, instead of a second copy of\n * the work.\n */\n async enqueue(\n appId: string,\n options: {\n queue?: string;\n /** Path on the app the job is POSTed to. Defaults to `/jobs`. */\n path?: string;\n method?: \"POST\" | \"PUT\" | \"PATCH\";\n payload?: unknown;\n maxAttempts?: number;\n timeoutSeconds?: number;\n delaySeconds?: number;\n idempotencyKey?: string;\n } = {},\n ): Promise<Job> {\n const res = await this.client.request<ApiResponse<Job>>(\"POST\", `/apps/${appId}/jobs`, {\n queue: options.queue,\n path: options.path,\n method: options.method,\n payload: options.payload,\n max_attempts: options.maxAttempts,\n timeout_seconds: options.timeoutSeconds,\n delay_seconds: options.delaySeconds,\n idempotency_key: options.idempotencyKey,\n });\n return res.data;\n }\n\n /** A page of jobs, newest first, with the queue depth per status alongside. */\n async list(\n appId: string,\n options: { status?: string; queue?: string; limit?: number } = {},\n ): Promise<{ jobs: Job[]; counts: Record<string, number> }> {\n const params = new URLSearchParams();\n if (options.status) params.set(\"status\", options.status);\n if (options.queue) params.set(\"queue\", options.queue);\n if (options.limit) params.set(\"limit\", String(options.limit));\n const query = params.toString();\n const res = await this.client.request<ApiResponse<{ jobs: Job[]; counts: Record<string, number> }>>(\n \"GET\",\n `/apps/${appId}/jobs${query ? `?${query}` : \"\"}`,\n );\n return res.data;\n }\n\n async get(appId: string, jobId: string): Promise<Job> {\n const res = await this.client.request<ApiResponse<Job>>(\"GET\", `/apps/${appId}/jobs/${jobId}`);\n return res.data;\n }\n\n /** Runs a dead job again, from a clean attempt count. */\n async retry(appId: string, jobId: string): Promise<Job> {\n const res = await this.client.request<ApiResponse<Job>>(\n \"POST\",\n `/apps/${appId}/jobs/${jobId}/retry`,\n );\n return res.data;\n }\n\n /** Cancels a job that has not started. Throws 409 once it is running. */\n async cancel(appId: string, jobId: string): Promise<Job> {\n const res = await this.client.request<ApiResponse<Job>>(\n \"POST\",\n `/apps/${appId}/jobs/${jobId}/cancel`,\n );\n return res.data;\n }\n}\n\nclass OrgsNamespace {\n constructor(private client: CloudClient) {}\n\n async list(): Promise<Organization[]> {\n const res = await this.client.request<ApiResponse<Organization[]>>(\"GET\", \"/orgs\");\n return res.data;\n }\n\n async create(name: string): Promise<Organization> {\n const res = await this.client.request<ApiResponse<Organization>>(\"POST\", \"/orgs\", { name });\n return res.data;\n }\n\n async get(id: string): Promise<Organization> {\n const res = await this.client.request<ApiResponse<Organization>>(\"GET\", `/orgs/${id}`);\n return res.data;\n }\n\n async members(id: string): Promise<OrgMember[]> {\n const res = await this.client.request<ApiResponse<OrgMember[]>>(\"GET\", `/orgs/${id}/members`);\n return res.data;\n }\n\n async invite(id: string, email: string, role: \"admin\" | \"member\" = \"member\"): Promise<void> {\n await this.client.request<ApiResponse<unknown>>(\"POST\", `/orgs/${id}/members`, { email, role });\n }\n\n async removeMember(id: string, userId: string): Promise<void> {\n await this.client.request<ApiResponse<unknown>>(\"DELETE\", `/orgs/${id}/members/${userId}`);\n }\n\n /**\n * Metered usage and the priced invoice for a month (`YYYY-MM`, default the month\n * in progress). Read-only: nothing in the SDK changes a plan or takes a payment.\n */\n async usage(id: string, period?: string): Promise<OrgUsage> {\n const query = period ? `?period=${encodeURIComponent(period)}` : \"\";\n const res = await this.client.request<ApiResponse<OrgUsage>>(\n \"GET\",\n `/orgs/${id}/usage${query}`,\n );\n return res.data;\n }\n}\n", "export const DEFAULT_PORT = 3000;\n\nexport const SUPPORTED_RUNTIMES = [\n \"node-20\",\n \"node-22\",\n \"python-3.11\",\n \"python-3.12\",\n \"bun-1\",\n \"deno-2\",\n] as const;\n\nexport type SupportedRuntime = (typeof SUPPORTED_RUNTIMES)[number];\n\nexport const DEPLOYMENT_STATUSES = [\n \"building\",\n \"deploying\",\n \"running\",\n \"failed\",\n // A task that was live and then died on its own -- OOM, panic, ECS\n // replacement. The reconcile pass sets it, so anything enumerating statuses\n // has to know about it.\n \"crashed\",\n \"stopped\",\n] as const;\n\nexport const ENVIRONMENTS = [\"preview\", \"production\"] as const;\n\nexport const ROLES = [\"admin\", \"member\"] as const;\n\nexport const DEFAULT_API_URL = \"https://api.videan.xyz/v1\";\n\n/** The zone every app's hostname hangs off. */\nexport const APP_DOMAIN = process.env.CLOUD_APP_DOMAIN || \"videan.xyz\";\n\n/**\n * The public URL of an app, from its slug.\n *\n * One definition, because it was previously written out by hand in three places\n * and one of them omitted the scheme -- so a deployment's `url` came back as a\n * bare `slug.videan.xyz` that no terminal, browser or `fetch` would follow,\n * while the app resource reported the same app as `https://slug.videan.xyz`.\n * HTTP redirects to HTTPS anyway, so the scheme is not optional in practice.\n */\nexport function appUrl(slug: string): string {\n return `https://${slug}.${APP_DOMAIN}`;\n}\n\n/**\n * Prefix for a single deployment's own hostname.\n *\n * Every deployment is reachable before it is promoted, which is what lets an\n * agent verify its own work without production riding on the answer. The label is\n * a hash of the deployment id rather than the id itself: nanoid's alphabet\n * contains `_` and uppercase, neither of which is legal in a DNS label, and\n * lowercasing or substituting would map two distinct deployments onto one\n * hostname -- serving whichever the router looked up first.\n *\n * The prefix keeps the namespace from colliding with app slugs: `*.videan.xyz`\n * is one flat namespace, and an app legitimately slugged the same as some\n * deployment's hash would otherwise steal its traffic.\n */\nexport const PREVIEW_LABEL_PREFIX = \"d-\";\n\nexport function previewUrl(label: string): string {\n return `https://${PREVIEW_LABEL_PREFIX}${label}.${APP_DOMAIN}`;\n}\n\n/** True for a hostname label that belongs to the preview namespace. */\nexport function isPreviewLabel(label: string): boolean {\n return label.startsWith(PREVIEW_LABEL_PREFIX);\n}\n\nexport const CONFIG_FILE_NAME = \"cloud.yaml\";\n\nexport const IGNORE_FILE_NAME = \".cloudignore\";\n\nexport const MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024; // 50MB\n\nexport const MAX_FILES_PER_PUSH = 10_000;\n", "/**\n * Fargate task sizing.\n *\n * Every app used to run at 256 CPU / 512 MB, hardcoded in `ecs-app.ts`. That is\n * below the working set of a stock Next.js server, so those apps were killed by\n * the OOM killer -- which surfaces as a container that exits without a message,\n * indistinguishable from a crash in the app's own code. Sizing is therefore not\n * a tuning knob; at the old default some runtimes could not work at all.\n *\n * Fargate accepts only specific (cpu, memory) pairs and rejects everything else\n * at RegisterTaskDefinition time. Validating here rather than there means the\n * caller is told which values are legal instead of reading an AWS error, and the\n * CLI can reject a bad `--memory` before a build starts.\n */\n\nimport type { Runtime } from \"./detect.js\";\n\n/**\n * Legal memory values (MiB) for each CPU unit, from the Fargate task-size table.\n *\n * Expressed as a range plus a step rather than a literal list because the larger\n * tiers have hundreds of legal values; a list would be unreadable and would drift.\n */\nconst FARGATE_SIZES: Record<number, { min: number; max: number; step: number }> = {\n 256: { min: 512, max: 2048, step: 512 },\n 512: { min: 1024, max: 4096, step: 1024 },\n 1024: { min: 2048, max: 8192, step: 1024 },\n 2048: { min: 4096, max: 16384, step: 1024 },\n 4096: { min: 8192, max: 30720, step: 1024 },\n 8192: { min: 16384, max: 61440, step: 4096 },\n 16384: { min: 32768, max: 122880, step: 8192 },\n};\n\nexport const FARGATE_CPUS = Object.keys(FARGATE_SIZES)\n .map(Number)\n .sort((a, b) => a - b);\n\n/**\n * 256 CPU is a special case: its legal memory values are 512, 1024 and 2048 --\n * it skips 1536, so the uniform step above would admit a value Fargate rejects.\n */\nconst CPU_256_MEMORY = [512, 1024, 2048];\n\nexport interface SizeValidation {\n ok: boolean;\n /** Why the pair is illegal, naming the legal alternatives. */\n error?: string;\n /** The legal memory values for the given CPU, for building an error message. */\n allowed?: number[];\n}\n\nfunction legalMemory(cpu: number): number[] {\n if (cpu === 256) return CPU_256_MEMORY;\n const spec = FARGATE_SIZES[cpu];\n if (!spec) return [];\n const values: number[] = [];\n for (let m = spec.min; m <= spec.max; m += spec.step) values.push(m);\n return values;\n}\n\n/**\n * Checks a (cpu, memory) pair against the Fargate table.\n *\n * Deliberately strict rather than snapping to the nearest legal value: silently\n * giving an app 2 GB when its owner asked for 1.5 GB means the bill and the\n * behaviour do not match what was requested, and a size that is quietly changed\n * is a size nobody can reason about when the app OOMs anyway.\n */\nexport function validateSize(cpu: number, memory: number): SizeValidation {\n if (!FARGATE_SIZES[cpu]) {\n return {\n ok: false,\n error: `cpu must be one of ${FARGATE_CPUS.join(\", \")} (got ${cpu})`,\n };\n }\n const allowed = legalMemory(cpu);\n if (!allowed.includes(memory)) {\n // Long lists are unhelpful in an error message; show the shape instead.\n const shown =\n allowed.length <= 6\n ? allowed.join(\", \")\n : `${allowed[0]}\u2013${allowed[allowed.length - 1]} in steps of ${allowed[1] - allowed[0]}`;\n return {\n ok: false,\n error: `memory ${memory} is not valid for cpu ${cpu}; allowed: ${shown}`,\n allowed,\n };\n }\n return { ok: true };\n}\n\nexport interface TaskSize {\n cpu: number;\n memory: number;\n}\n\n/**\n * The size an app gets when nobody chose one.\n *\n * Picked per runtime because the failure is runtime-specific: `next start` holds\n * a compiled server plus its module graph and does not fit in 512 MB, while a\n * Go binary is comfortable in it. Defaulting everything to the larger size would\n * quadruple the bill for the runtimes that do not need it; defaulting everything\n * to the smaller one is the bug this replaces.\n */\nexport function defaultSizeFor(runtime: Runtime): TaskSize {\n switch (runtime) {\n case \"nextjs\":\n return { cpu: 512, memory: 1024 };\n case \"nodejs\":\n case \"python\":\n // Comfortable for a framework plus dependencies, and the smallest legal\n // pair above the old default.\n return { cpu: 256, memory: 1024 };\n case \"go\":\n return { cpu: 256, memory: 512 };\n case \"custom\":\n // Unknown contents, so assume it is doing something real.\n return { cpu: 512, memory: 1024 };\n }\n}\n\n/**\n * How many tasks a size change or a scale-out may run at once.\n *\n * A bound exists because `instances` is caller-supplied and reaches RunTask\n * directly: a typo of 100 would launch a hundred Fargate tasks and bill for them\n * before anyone noticed. RunTask itself caps a single call at 10.\n */\nexport const MAX_INSTANCES = 10;\n", "/**\n * What a plan allows and what usage costs.\n *\n * Kept here rather than in the control API because three consumers need the same\n * numbers and must not disagree about them: the API enforces the limits, the\n * usage collector prices the metrics it records, and the CLI prints a bill. A\n * rate duplicated in two of those places is a bill that does not match the\n * invoice.\n *\n * Two things this deliberately is *not*:\n *\n * - **A payment integration.** Nothing here charges anyone. It computes what an\n * org owes; collecting it needs a payment processor and a human to accept its\n * terms, the same way SES production access does.\n * - **The authority on AWS cost.** These are the platform's *prices*. The real\n * cost of a Fargate task is in Cost Explorer, and the two will not match --\n * that difference is the margin, and pretending otherwise would make every\n * price change look like a metering bug.\n */\n\n/**\n * Metrics recorded in `usage_records`.\n *\n * `vcpu_seconds` and `gb_seconds` are what Fargate actually charges for, so they\n * are what a compute line is priced from; `task_seconds` is recorded alongside\n * them because it is the number a human recognises (\"this ran for 20 hours\") and\n * cannot be recovered from the other two without knowing the task size.\n *\n * `storage_mb`, not bytes: `usage_records.quantity` is an `integer`, and bytes\n * overflows int32 at 2.1 GB -- silently, wrapping negative, which would read as a\n * credit.\n */\nexport type UsageMetric =\n | \"task_seconds\"\n | \"vcpu_seconds\"\n | \"gb_seconds\"\n | \"requests\"\n | \"build_seconds\"\n | \"storage_mb\"\n | \"emails_sent\"\n | \"db_days\";\n\nexport const USAGE_METRICS: UsageMetric[] = [\n \"task_seconds\",\n \"vcpu_seconds\",\n \"gb_seconds\",\n \"requests\",\n \"build_seconds\",\n \"storage_mb\",\n \"emails_sent\",\n \"db_days\",\n];\n\n/**\n * Metrics that are a level rather than a total.\n *\n * A day's `storage_mb` row is the last sample taken that day, not a sum of\n * samples -- summing a level double-counts every byte for every time it was\n * observed. Billing a level means averaging the samples across the period, which\n * is why the two kinds cannot be aggregated by the same code path.\n */\nexport const GAUGE_METRICS: UsageMetric[] = [\"storage_mb\"];\n\nexport function isGauge(metric: string): boolean {\n return (GAUGE_METRICS as string[]).includes(metric);\n}\n\n/**\n * Price per unit, in cents. Fractional on purpose: a request costs a fifth of a\n * millionth of a cent and rounding each one to a cent would bill $10,000 for a\n * million requests.\n *\n * `task_seconds` is priced at zero because compute is already billed through\n * `vcpu_seconds` and `gb_seconds`. It is in the table rather than absent from it\n * so that a new metric added without a price is a visible zero here instead of an\n * `undefined` multiplied into `NaN` further down.\n */\nexport const RATES: Record<UsageMetric, number> = {\n task_seconds: 0,\n // Fargate on-demand in us-east-1 is ~$0.04048/vCPU-hour and ~$0.004445/GB-hour.\n vcpu_seconds: 0.002,\n gb_seconds: 0.00025,\n // $0.20 per million requests.\n requests: 0.00002,\n // ~$0.012 per build-minute.\n build_seconds: 0.02,\n // $0.05 per GB-month, charged per MB-month.\n storage_mb: 0.005,\n // $0.50 per thousand.\n emails_sent: 0.05,\n // ~$3/month for a managed schema, charged per day it exists.\n db_days: 10,\n};\n\n/** Human unit for each metric, for a bill a person has to read. */\nexport const METRIC_LABELS: Record<UsageMetric, string> = {\n task_seconds: \"Task-seconds served\",\n vcpu_seconds: \"vCPU-seconds\",\n gb_seconds: \"GB-seconds\",\n requests: \"Requests\",\n build_seconds: \"Build seconds\",\n storage_mb: \"Object storage (MB-month)\",\n emails_sent: \"Emails sent\",\n db_days: \"Managed Postgres (app-days)\",\n};\n\nexport interface Plan {\n id: string;\n name: string;\n /** Monthly subscription, in cents, before usage. */\n baseCents: number;\n /**\n * Usage covered by the base fee, in cents. An org that stays under this pays\n * exactly `baseCents` -- so the free plan is a real free tier rather than a\n * $0.03 invoice for a weekend project.\n */\n includedUsageCents: number;\n /** Apps that are not soft-deleted. */\n maxApps: number;\n maxInstancesPerApp: number;\n /** Ceilings on Fargate task size, which is the one knob that scales the bill. */\n maxCpu: number;\n maxMemory: number;\n /** Object-storage quota, enforced on upload. */\n maxStorageMb: number;\n postgres: boolean;\n customDomains: boolean;\n}\n\n/**\n * The plans.\n *\n * The limits that exist are the ones that bound *spend*: app count, instance\n * count and task size. There is deliberately no limit on requests, builds or\n * deploys -- an agent-built app that gets popular should get a bill, not an\n * outage, and a platform whose selling point is \"push and it is live\" cannot\n * answer a deploy with \"not on your plan\".\n */\nexport const PLANS: Record<string, Plan> = {\n free: {\n id: \"free\",\n name: \"Free\",\n baseCents: 0,\n includedUsageCents: 300,\n maxApps: 3,\n maxInstancesPerApp: 1,\n // One app at this size, running all month, is inside the included usage.\n maxCpu: 512,\n maxMemory: 1024,\n maxStorageMb: 1024,\n postgres: true,\n customDomains: false,\n },\n pro: {\n id: \"pro\",\n name: \"Pro\",\n baseCents: 2000,\n includedUsageCents: 2000,\n maxApps: 50,\n maxInstancesPerApp: 4,\n maxCpu: 4096,\n maxMemory: 8192,\n maxStorageMb: 100 * 1024,\n postgres: true,\n customDomains: true,\n },\n scale: {\n id: \"scale\",\n name: \"Scale\",\n baseCents: 20000,\n includedUsageCents: 20000,\n maxApps: 500,\n maxInstancesPerApp: 10,\n maxCpu: 16384,\n maxMemory: 122880,\n maxStorageMb: 1024 * 1024,\n postgres: true,\n customDomains: true,\n },\n};\n\n/**\n * The plan for a stored `orgs.plan` value.\n *\n * Falls back to free rather than throwing: the column is free text and an\n * unrecognised value must not take an org's whole control surface down with a\n * 500. Free is the safe direction -- its limits are the tightest, so a typo\n * cannot silently grant a larger allowance than anyone agreed to.\n */\nexport function planFor(plan: string | null | undefined): Plan {\n return PLANS[plan || \"free\"] ?? PLANS.free;\n}\n\nexport interface UsageLine {\n metric: UsageMetric | string;\n label: string;\n quantity: number;\n unitPriceCents: number;\n /** Rounded to whole cents only at the line, never per unit. */\n cents: number;\n}\n\nexport interface Invoice {\n plan: string;\n periodStart: string;\n periodEnd: string;\n lines: UsageLine[];\n /** Everything the usage lines add up to, before the included allowance. */\n usageCents: number;\n baseCents: number;\n includedUsageCents: number;\n /** Usage beyond the allowance. Zero, never negative: credit does not roll over. */\n overageCents: number;\n totalCents: number;\n}\n\n/**\n * Prices a period's usage.\n *\n * `quantities` is metric \u2192 quantity, already aggregated over the period (sums for\n * counters, averages for gauges -- see `GAUGE_METRICS`, and note that this\n * function cannot tell which it was given, so aggregating wrongly produces a\n * plausible bill rather than an error).\n */\nexport function priceUsage(\n quantities: Record<string, number>,\n plan: Plan,\n period: { start: Date; end: Date },\n): Invoice {\n const lines: UsageLine[] = [];\n for (const metric of USAGE_METRICS) {\n const quantity = quantities[metric] ?? 0;\n const rate = RATES[metric];\n // A zero-priced metric is still reported when there is something to report:\n // task-seconds is how an owner checks that the compute line is plausible.\n if (quantity === 0) continue;\n lines.push({\n metric,\n label: METRIC_LABELS[metric],\n quantity: Math.round(quantity * 100) / 100,\n unitPriceCents: rate,\n cents: Math.round(quantity * rate),\n });\n }\n // Metrics recorded by a newer collector than this pricing table knows about.\n // Listed at zero rather than dropped: an unpriced metric that vanishes from the\n // bill is indistinguishable from one that was never collected.\n for (const metric of Object.keys(quantities)) {\n if ((USAGE_METRICS as string[]).includes(metric)) continue;\n if (!quantities[metric]) continue;\n lines.push({\n metric,\n label: metric,\n quantity: quantities[metric],\n unitPriceCents: 0,\n cents: 0,\n });\n }\n\n const usageCents = lines.reduce((acc, l) => acc + l.cents, 0);\n const overageCents = Math.max(0, usageCents - plan.includedUsageCents);\n return {\n plan: plan.id,\n periodStart: period.start.toISOString(),\n periodEnd: period.end.toISOString(),\n lines,\n usageCents,\n baseCents: plan.baseCents,\n includedUsageCents: plan.includedUsageCents,\n overageCents,\n totalCents: plan.baseCents + overageCents,\n };\n}\n\n/** `1234` \u2192 `\"$12.34\"`. For output a person reads, not for arithmetic. */\nexport function formatCents(cents: number): string {\n const sign = cents < 0 ? \"-\" : \"\";\n const abs = Math.abs(Math.round(cents));\n return `${sign}$${Math.floor(abs / 100)}.${String(abs % 100).padStart(2, \"0\")}`;\n}\n\nexport interface LimitCheck {\n ok: boolean;\n /** Names the limit and the plan, so the error says what to do about it. */\n error?: string;\n code?: string;\n}\n\nexport function allowed(): LimitCheck {\n return { ok: true };\n}\n\nfunction denied(code: string, error: string): LimitCheck {\n return { ok: false, error, code };\n}\n\n/** Whether one more app is within the plan. `current` excludes deleted apps. */\nexport function checkAppCount(plan: Plan, current: number): LimitCheck {\n if (current < plan.maxApps) return allowed();\n return denied(\n \"PLAN_LIMIT_APPS\",\n `The ${plan.name} plan allows ${plan.maxApps} app${plan.maxApps === 1 ? \"\" : \"s\"} ` +\n `and this org has ${current}. Delete one or upgrade the plan.`,\n );\n}\n\n/**\n * Whether a requested task shape is within the plan.\n *\n * Checked as a triple rather than three separate limits because they multiply:\n * the thing being bounded is the bill, and 4 instances of a small task costs the\n * same as one large one.\n */\nexport function checkTaskShape(\n plan: Plan,\n shape: { cpu?: number | null; memory?: number | null; instances?: number | null },\n): LimitCheck {\n if (shape.instances != null && shape.instances > plan.maxInstancesPerApp) {\n return denied(\n \"PLAN_LIMIT_INSTANCES\",\n `The ${plan.name} plan allows ${plan.maxInstancesPerApp} instance` +\n `${plan.maxInstancesPerApp === 1 ? \"\" : \"s\"} per app (asked for ${shape.instances}).`,\n );\n }\n if (shape.cpu != null && shape.cpu > plan.maxCpu) {\n return denied(\n \"PLAN_LIMIT_CPU\",\n `The ${plan.name} plan allows up to ${plan.maxCpu} CPU units per task (asked for ${shape.cpu}).`,\n );\n }\n if (shape.memory != null && shape.memory > plan.maxMemory) {\n return denied(\n \"PLAN_LIMIT_MEMORY\",\n `The ${plan.name} plan allows up to ${plan.maxMemory} MB per task (asked for ${shape.memory}).`,\n );\n }\n return allowed();\n}\n\n/** Whether a custom domain is within the plan. */\nexport function checkCustomDomain(plan: Plan): LimitCheck {\n if (plan.customDomains) return allowed();\n return denied(\n \"PLAN_LIMIT_DOMAINS\",\n `Custom domains are not included in the ${plan.name} plan. Every app keeps its ` +\n `platform hostname, which needs no configuration.`,\n );\n}\n", "/**\n * Who may reach a running app, as a ladder from narrowest to widest.\n *\n * This replaces `auth_required`, which could only distinguish \"gated\" from\n * \"open\" and so collapsed the two settings owners actually reach for -- \"anyone\n * with the link\" and \"only the people I invite\" -- into the same switch as\n * \"anyone in my org\".\n *\n * The tiers are deliberately ordered and each is a strict superset of the one\n * before it, so widening is always one step and there is never a pair of\n * settings whose relative reach is ambiguous.\n *\n * Note what this is *not*: it governs visiting the deployed app at its\n * hostname, not managing it through the API. Those are separate on purpose --\n * `lib/access.ts` answers the second one -- so an org member who cannot open a\n * `private` app in a browser may still hold write on it in the console. The\n * alternative, letting a visibility setting revoke an org member's ability to\n * deploy, would make an access control into an outage.\n */\nexport const VISIBILITIES = [\"private\", \"org\", \"authenticated\", \"public\"] as const;\n\nexport type Visibility = (typeof VISIBILITIES)[number];\n\n/**\n * The default for a new app, and the widest tier that still requires a session.\n *\n * Matches what `auth_required` defaulted to (true, meaning org-or-share), so\n * creating an app has not changed who can reach it.\n */\nexport const DEFAULT_VISIBILITY: Visibility = \"org\";\n\nexport function isVisibility(value: unknown): value is Visibility {\n return typeof value === \"string\" && (VISIBILITIES as readonly string[]).includes(value);\n}\n\n/**\n * Reads a stored value as a tier, treating anything unrecognized as the\n * **narrowest** one.\n *\n * The column is `text`, and this repo has twice shipped a value nothing reads\n * (`org_members.role = 'owner'`, `deployments.status = 'rolled_back'`) -- both\n * stored happily and were silently ignored. Here the same slip would decide\n * whether strangers can read a tenant's app, so an unknown value must fail\n * closed. `private` is still reachable by its org's admins, so the worst case of\n * failing closed is an app its owners can fix; the worst case of failing open is\n * a disclosure they cannot undo.\n */\nexport function visibilityOf(value: unknown): Visibility {\n return isVisibility(value) ? value : \"private\";\n}\n\n/**\n * Whether a tier admits a visitor with no session at all.\n *\n * This is what the legacy `auth_required` boolean encodes, which is why every\n * write to `visibility` also writes `auth_required = !isPublic(v)`: the deployed\n * edge router may still be reading only the boolean.\n */\nexport function isPublic(v: Visibility): boolean {\n return v === \"public\";\n}\n\n/** Human-readable label, shared by the console and the CLI. */\nexport const VISIBILITY_LABELS: Record<Visibility, string> = {\n private: \"Only people with access\",\n org: \"Anyone in the organization\",\n authenticated: \"Anyone signed in to Videan\",\n public: \"Anyone with the link\",\n};\n", "import Conf from \"conf\";\n\ninterface CloudConfig {\n apiKey?: string;\n defaultOrg?: string;\n currentApp?: string;\n baseUrl?: string;\n}\n\nconst config = new Conf<CloudConfig>({\n projectName: \"cloud-cli\",\n schema: {\n apiKey: { type: \"string\" },\n defaultOrg: { type: \"string\" },\n currentApp: { type: \"string\" },\n baseUrl: { type: \"string\" },\n },\n});\n\n/**\n * An override from the environment, checked under both prefixes.\n *\n * The bin is `videan`; the packages are `@cloud/*`. Accepting both spellings is\n * cheaper than being wrong about which one someone reaches for.\n */\nfunction fromEnv(name: string): string | undefined {\n const value = process.env[`VIDEAN_${name}`] || process.env[`CLOUD_${name}`];\n return value ? value : undefined;\n}\n\n/**\n * The environment wins over the saved config.\n *\n * The platform's premise is that an agent does the deploying, and an agent runs\n * in a non-interactive shell with no config file and no way to answer a password\n * prompt. `VIDEAN_API_KEY` is how it authenticates without `login` at all.\n */\nexport function getApiKey(): string | undefined {\n return fromEnv(\"API_KEY\") || config.get(\"apiKey\");\n}\n\nexport function setApiKey(key: string): void {\n config.set(\"apiKey\", key);\n}\n\nexport function getDefaultOrg(): string | undefined {\n return fromEnv(\"ORG\") || config.get(\"defaultOrg\");\n}\n\nexport function setDefaultOrg(org: string): void {\n config.set(\"defaultOrg\", org);\n}\n\nexport function getCurrentApp(): string | undefined {\n return fromEnv(\"APP\") || config.get(\"currentApp\");\n}\n\nexport function setCurrentApp(appId: string): void {\n config.set(\"currentApp\", appId);\n}\n\nexport function getBaseUrl(): string | undefined {\n return fromEnv(\"API_URL\") || config.get(\"baseUrl\");\n}\n\nexport function setBaseUrl(url: string): void {\n config.set(\"baseUrl\", url);\n}\n\n/** Where the saved config lives, so a stale value can be found and inspected. */\nexport function configPath(): string {\n return config.path;\n}\n\nexport function clearConfig(): void {\n config.clear();\n}\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { clearConfig, configPath } from \"../config.js\";\n\nexport const logoutCommand = new Command(\"logout\")\n .description(\"Forget the saved key, org, app and API URL\")\n .action(() => {\n // Clears everything, not just the key. The saved `baseUrl` is the value most\n // likely to be wrong and was, until now, only reachable by editing the\n // config file: a leftover URL from an earlier environment made every command\n // fail against a host that no longer served the API.\n const where = configPath();\n clearConfig();\n console.log(chalk.green(\"Logged out.\"));\n console.log(chalk.gray(` Cleared ${where}`));\n });\n", "import { Command } from \"commander\";\nimport inquirer from \"inquirer\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { SUPPORTED_RUNTIMES, CONFIG_FILE_NAME } from \"@cloud/shared\";\n\nexport const initCommand = new Command(\"init\")\n .description(\"Initialize a new Cloud app in the current directory\")\n .action(async () => {\n const configPath = path.join(process.cwd(), CONFIG_FILE_NAME);\n\n if (await fs.pathExists(configPath)) {\n console.log(chalk.yellow(`${CONFIG_FILE_NAME} already exists in this directory.`));\n const { overwrite } = await inquirer.prompt([\n { type: \"confirm\", name: \"overwrite\", message: \"Overwrite?\", default: false },\n ]);\n if (!overwrite) return;\n }\n\n const answers = await inquirer.prompt([\n { type: \"input\", name: \"name\", message: \"App name:\", default: path.basename(process.cwd()) },\n {\n type: \"list\",\n name: \"runtime\",\n message: \"Runtime:\",\n choices: SUPPORTED_RUNTIMES as unknown as string[],\n },\n { type: \"input\", name: \"entrypoint\", message: \"Entrypoint:\", default: \"index.ts\" },\n ]);\n\n const config = [\n `name: ${answers.name}`,\n `runtime: ${answers.runtime}`,\n `entrypoint: ${answers.entrypoint}`,\n \"\",\n ].join(\"\\n\");\n\n await fs.writeFile(configPath, config, \"utf-8\");\n console.log(chalk.green(`Created ${CONFIG_FILE_NAME}`));\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { collectFiles, requireApiKey, formatStatus } from \"../util.js\";\n\nexport const deployCommand = new Command(\"deploy\")\n .description(\"Deploy the current directory\")\n .option(\"-a, --app <id>\", \"App ID to deploy to\")\n .option(\"-m, --message <msg>\", \"Deployment message\")\n .option(\"--env <environment>\", \"preview or production (default: production)\")\n .action(async (opts) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or run `videan init` first.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n\n // Collect files\n const spinner = ora(\"Collecting files...\").start();\n const { files, binaryFiles, skipped } = await collectFiles(process.cwd());\n const binaryCount = Object.keys(binaryFiles).length;\n const fileCount = Object.keys(files).length + binaryCount;\n if (!fileCount) {\n spinner.fail(chalk.red(`Nothing to deploy: no files under ${process.cwd()}.`));\n process.exit(1);\n }\n if (skipped.length) {\n // Named, not counted. A snapshot silently missing an image is a bug report\n // from the future; the operator can act on a list.\n spinner.warn(chalk.yellow(`Skipped ${skipped.length} file(s):`));\n for (const file of skipped) console.log(chalk.gray(` ${file.path} \u2014 ${file.reason}`));\n spinner.start();\n }\n spinner.text = `Pushing ${fileCount} files${binaryCount ? ` (${binaryCount} binary)` : \"\"}...`;\n\n // Push\n const snapshot = await client.apps.push(appId, files, opts.message, binaryFiles);\n spinner.text = \"Triggering deployment...\";\n\n // Deploy\n if (opts.env && opts.env !== \"preview\" && opts.env !== \"production\") {\n spinner.fail(chalk.red(`--env must be preview or production, not ${opts.env}`));\n process.exit(1);\n }\n const deployment = await client.apps.deploy(appId, snapshot.id, opts.env);\n spinner.text = `Deploying (${deployment.status})...`;\n\n // Poll for status. A build takes minutes, so a single failed request must\n // not end the watch -- it used to `break`, which reported the deployment as\n // stuck in `building` when in fact nothing was wrong with it but one HTTP\n // call. Give up only after several consecutive failures, and say so.\n let current = deployment;\n let consecutiveErrors = 0;\n let lastError = \"\";\n while (current.status === \"building\" || current.status === \"deploying\") {\n await new Promise((r) => setTimeout(r, 5000));\n const elapsed = Math.round((Date.now() - Date.parse(current.createdAt)) / 1000);\n spinner.text = `${current.status === \"building\" ? \"Building\" : \"Starting\"}... (${elapsed}s)`;\n try {\n current = await client.apps.checkDeployment(deployment.id);\n consecutiveErrors = 0;\n } catch (e: any) {\n lastError = e?.message || String(e);\n if (++consecutiveErrors >= 5) {\n spinner.fail(chalk.red(`Lost track of the deployment: ${lastError}`));\n console.log(chalk.gray(` It may still finish. Check with \\`videan status\\`.`));\n process.exit(1);\n }\n }\n }\n\n if (current.status === \"running\") {\n spinner.succeed(chalk.green(`Deployed successfully!`));\n if (current.url) {\n // Deployments promoted before the API started storing a full URL have a\n // bare hostname here, which no terminal will linkify and no fetch will\n // follow.\n const url = /^https?:\\/\\//.test(current.url) ? current.url : `https://${current.url}`;\n console.log(chalk.cyan(` URL: ${url}`));\n }\n if (current.previewUrl) {\n // This version's own address. Live from the moment its tasks are up --\n // which is before promotion, so it is what an agent checks its own work\n // against -- and only for as long as they are: the poller retires the\n // version this deploy replaced, and a retired version's address stops\n // resolving with it.\n console.log(chalk.gray(` This version: ${current.previewUrl}`));\n }\n } else if (current.status === \"failed\" || current.status === \"crashed\") {\n // `crashed` means the container started and then died -- a failure the\n // caller has to see, and one this used to report as mere information with\n // a zero exit code, so a scripted deploy counted it as a success.\n spinner.fail(chalk.red(`Deployment ${current.status}: ${current.error || \"unknown error\"}`));\n console.log(chalk.gray(` Logs: videan logs --app ${appId}`));\n process.exit(1);\n } else {\n spinner.info(`Deployment status: ${formatStatus(current.status)}`);\n process.exit(1);\n }\n });\n", "import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport ignore from \"ignore\";\nimport chalk from \"chalk\";\n\n/** Larger than this and the push is refused rather than silently trimmed. */\nexport const MAX_FILE_BYTES = 10 * 1024 * 1024;\n\nexport interface CollectedFiles {\n /** Relative path \u2192 UTF-8 contents, ready for the push wire format. */\n files: Record<string, string>;\n /** Relative path \u2192 base64 contents, for files that are not valid UTF-8. */\n binaryFiles: Record<string, string>;\n /**\n * Relative paths left out, with the reason. Only oversized files land here\n * now that binaries have somewhere to go.\n */\n skipped: { path: string; reason: string }[];\n}\n\n/**\n * Collect all files from a directory, respecting .gitignore and .cloudignore.\n */\nexport async function collectFiles(dir: string): Promise<CollectedFiles> {\n const ig = ignore();\n\n // Always ignored, whether or not the project has a .gitignore -- and many\n // agent-generated projects do not.\n //\n // `.next`, `.turbo` and `coverage` are local build output. Uploading them is\n // not merely wasteful: the container runs `next build` over whatever it is\n // given, and a `.next` produced on a different platform and Node version is\n // exactly the kind of stale cache that makes a build fail or, worse, succeed\n // with the previous code in it.\n ig.add([\n \".git\",\n \"node_modules\",\n \".env\",\n \".env.*\",\n \".next\",\n \".turbo\",\n \"coverage\",\n \".DS_Store\",\n \"*.log\",\n ]);\n\n // Load .gitignore\n const gitignorePath = path.join(dir, \".gitignore\");\n if (await fs.pathExists(gitignorePath)) {\n const content = await fs.readFile(gitignorePath, \"utf-8\");\n ig.add(content);\n }\n\n // Load .cloudignore\n const cloudignorePath = path.join(dir, \".cloudignore\");\n if (await fs.pathExists(cloudignorePath)) {\n const content = await fs.readFile(cloudignorePath, \"utf-8\");\n ig.add(content);\n }\n\n const files: Record<string, string> = {};\n const binaryFiles: Record<string, string> = {};\n const skipped: { path: string; reason: string }[] = [];\n\n async function walk(currentDir: string): Promise<void> {\n const entries = await fs.readdir(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n const relativePath = path.relative(dir, fullPath);\n\n // ignore() matches directories only when the path is marked as one, and\n // pattern semantics differ between \"dir\" and \"dir/\" for anchored rules.\n const ignorePath = entry.isDirectory() ? `${relativePath}/` : relativePath;\n if (ig.ignores(ignorePath)) continue;\n\n if (entry.isDirectory()) {\n await walk(fullPath);\n } else if (entry.isFile()) {\n // Read bytes, not a string. `readFile(path, \"utf-8\")` replaces every\n // byte that is not valid UTF-8 with U+FFFD and reports success, so a\n // PNG read as text arrives corrupted with nothing to indicate it. The\n // round-trip is what decides which map a file belongs in: text goes in\n // `files` verbatim, everything else is base64 in `binaryFiles`. It is a\n // test of the bytes rather than of the extension, so an unknown\n // extension or a text file with one byte of Latin-1 in it is handled on\n // what it contains.\n const buffer = await fs.readFile(fullPath);\n if (buffer.byteLength > MAX_FILE_BYTES) {\n // Refused, not trimmed: the push is one JSON body, and a 200MB asset\n // would be an out-of-memory on the control API rather than a rejected\n // request. Named here so the fix is `.cloudignore` or object storage.\n skipped.push({\n path: relativePath,\n reason: `${Math.round(buffer.byteLength / 1024 / 1024)}MB, over the ${MAX_FILE_BYTES / 1024 / 1024}MB limit`,\n });\n continue;\n }\n const text = buffer.toString(\"utf-8\");\n if (Buffer.from(text, \"utf-8\").equals(buffer)) {\n files[relativePath] = text;\n } else {\n binaryFiles[relativePath] = buffer.toString(\"base64\");\n }\n }\n }\n }\n\n await walk(dir);\n return { files, binaryFiles, skipped };\n}\n\n/**\n * Format a deployment status with color.\n */\nexport function formatStatus(status: string): string {\n switch (status) {\n case \"running\":\n return chalk.green(status);\n case \"building\":\n case \"deploying\":\n return chalk.yellow(status);\n case \"failed\":\n case \"crashed\":\n return chalk.red(status);\n case \"stopped\":\n return chalk.gray(status);\n default:\n return status;\n }\n}\n\n/**\n * Format a table row for display.\n */\nexport function formatRow(columns: string[], widths: number[]): string {\n return columns.map((col, i) => col.padEnd(widths[i] || 20)).join(\" \");\n}\n\n/**\n * Require an API key or exit.\n */\nexport function requireApiKey(apiKey: string | undefined): asserts apiKey is string {\n if (!apiKey) {\n console.error(chalk.red(\"Not logged in. Run `videan login` first.\"));\n process.exit(1);\n }\n}\n\n/**\n * Require an organization or exit. Every app lives in an org, so commands that\n * list or create apps need one from --org or the saved default.\n */\nexport function requireOrg(orgId: string | undefined): string {\n if (!orgId) {\n console.error(chalk.red(\"No organization. Pass --org <id> or run `videan login` again.\"));\n process.exit(1);\n }\n return orgId;\n}\n\n// Re-exported rather than redefined: the CLI and the API have to agree on the\n// hostname, and they did not while each built it by hand.\nexport { appUrl } from \"@cloud/shared\";\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey } from \"../util.js\";\n\nexport const logsCommand = new Command(\"logs\")\n .description(\"View app logs\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-f, --follow\", \"Follow log output\")\n .option(\"-n, --lines <n>\", \"Number of lines to show\", \"50\")\n .option(\"-s, --since <when>\", \"Start of the window: ISO timestamp or an offset like 15m, 2h, 7d\", \"1h\")\n .option(\"--until <when>\", \"End of the window (same formats as --since)\")\n .option(\"-q, --search <text>\", \"Only lines containing this text\")\n .option(\"--pattern <pattern>\", \"CloudWatch filter pattern, for the real syntax\")\n .option(\"--instance <prefix>\", \"Only one instance, by log stream prefix\")\n .action(async (opts) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n\n if (opts.search && opts.pattern) {\n console.error(chalk.red(\"Use either --search or --pattern, not both.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const filters = {\n q: opts.search as string | undefined,\n pattern: opts.pattern as string | undefined,\n instance: opts.instance as string | undefined,\n };\n\n if (opts.follow) {\n // The generator holds the cursor, so a line is printed once. The old loop\n // re-fetched the same window every two seconds and reprinted all of it.\n for await (const entry of client.apps.followLogs(appId, { since: opts.since, ...filters })) {\n print(entry);\n }\n return;\n }\n\n const page = await client.apps.logs(appId, {\n limit: parseInt(opts.lines, 10),\n since: opts.since,\n until: opts.until,\n ...filters,\n });\n\n // Oldest first, so the newest line is the one left next to the prompt.\n for (const entry of page.events) print(entry);\n\n if (page.events.length === 0) {\n console.log(chalk.gray(`No log lines since ${page.start}.`));\n }\n if (page.truncated) {\n // Said out loud: otherwise a window with more lines than one scan can read\n // looks like a window that simply contained these.\n console.log(\n chalk.yellow(\n \"\\nThis is part of the window -- there are more lines than one request reads. Narrow --since or add --search.\",\n ),\n );\n }\n });\n\nfunction print(entry: { timestamp: string; level?: string; message: string }): void {\n console.log(`${chalk.gray(entry.timestamp)} ${formatLevel(entry.level)} ${entry.message}`);\n}\n\nfunction formatLevel(level?: string): string {\n switch (level) {\n case \"error\":\n return chalk.red(\"[ERR]\");\n case \"warn\":\n return chalk.yellow(\"[WRN]\");\n case \"info\":\n return chalk.blue(\"[INF]\");\n case \"debug\":\n return chalk.gray(\"[DBG]\");\n default:\n return chalk.gray(\"[LOG]\");\n }\n}\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey } from \"../util.js\";\n\n/**\n * `videan metrics` -- the window summary, and optionally the buckets.\n *\n * Summary by default rather than the series: a terminal cannot plot 60 buckets\n * usefully, and the question being asked (\"is anything hitting my app, and is it\n * erroring\") is answered by the totals. `--series` prints the buckets for piping\n * somewhere that can graph them.\n */\nexport const metricsCommand = new Command(\"metrics\")\n .description(\"Traffic, latency and resource use for an app\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-s, --since <when>\", \"Start of the window: ISO timestamp or an offset like 15m, 2h, 7d\", \"1h\")\n .option(\"--until <when>\", \"End of the window (same formats as --since)\")\n .option(\"--series\", \"Print each bucket instead of just the summary\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (opts) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const metrics = await client.apps.metrics(appId, { since: opts.since, until: opts.until });\n\n if (opts.json) {\n console.log(JSON.stringify(metrics, null, 2));\n return;\n }\n\n const t = metrics.totals;\n console.log(\n chalk.dim(`${metrics.start} \u2192 ${metrics.end} (${metrics.period}s buckets)`),\n );\n console.log();\n console.log(` ${label(\"Requests\")} ${t.requests}`);\n console.log(` ${label(\"4xx\")} ${count(t.clientErrors)}`);\n console.log(` ${label(\"5xx\")} ${count(t.serverErrors, true)}`);\n // Named for what it is rather than \"auth\": these are visitors the gate turned\n // away, which is the answer when an owner says their app looks idle.\n console.log(` ${label(\"Gate denied\")} ${count(t.gateDenied)}`);\n console.log(` ${label(\"Latency avg\")} ${ms(t.latencyAvgMs)}`);\n console.log(` ${label(\"Latency p95\")} ${ms(t.latencyP95Ms)} ${chalk.dim(\"(sampled)\")}`);\n console.log(` ${label(\"CPU avg\")} ${units(t.cpuAvg)}`);\n console.log(` ${label(\"Memory avg\")} ${mb(t.memoryAvgMb)}`);\n\n if (t.requests === 0) {\n // A gap is not published as a zero, so an app that has never been reached and\n // an app that is not deployed look the same here.\n console.log();\n console.log(chalk.dim(\"No requests recorded in this window.\"));\n }\n\n if (opts.series) {\n console.log();\n for (const [name, points] of Object.entries(metrics.series)) {\n if (points.length === 0) continue;\n console.log(chalk.bold(name));\n for (const p of points) console.log(` ${chalk.dim(p.t)} ${p.v}`);\n }\n }\n });\n\nfunction label(text: string): string {\n return chalk.dim(text.padEnd(13));\n}\n\nfunction count(n: number, severe = false): string {\n if (n === 0) return chalk.dim(\"0\");\n return severe ? chalk.red(String(n)) : chalk.yellow(String(n));\n}\n\n/** Null means nothing was reported, which is not the same as zero. */\nfunction ms(v: number | null): string {\n return v === null ? chalk.dim(\"\u2014\") : `${v} ms`;\n}\n\nfunction mb(v: number | null): string {\n return v === null ? chalk.dim(\"\u2014\") : `${v} MB`;\n}\n\nfunction units(v: number | null): string {\n return v === null ? chalk.dim(\"\u2014\") : `${v} CPU units`;\n}\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey } from \"../util.js\";\n\nexport const rollbackCommand = new Command(\"rollback\")\n .description(\"Rollback to the previous production deployment\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (opts) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const spinner = ora(\"Rolling back...\").start();\n\n try {\n const deployment = await client.apps.rollback(appId);\n spinner.succeed(chalk.green(\"Rollback successful!\"));\n if (deployment.url) {\n console.log(chalk.cyan(` URL: ${deployment.url}`));\n }\n } catch (error: any) {\n spinner.fail(chalk.red(`Rollback failed: ${error.message}`));\n process.exit(1);\n }\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport inquirer from \"inquirer\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey, formatRow } from \"../util.js\";\n\nexport const secretsCommand = new Command(\"secrets\")\n .description(\"Manage app secrets\");\n\nsecretsCommand\n .command(\"set <key> [value]\")\n .description(\"Set a secret\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (key: string, value: string | undefined, opts: any) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified.\"));\n process.exit(1);\n }\n\n if (!value) {\n const answers = await inquirer.prompt([\n { type: \"password\", name: \"value\", message: `Value for ${key}:` },\n ]);\n value = answers.value;\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n await client.secrets.set(appId, key, value!);\n console.log(chalk.green(`Secret \"${key}\" set successfully.`));\n });\n\nsecretsCommand\n .command(\"list\")\n .description(\"List all secrets\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (opts: any) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const secrets = await client.secrets.list(appId);\n\n if (secrets.length === 0) {\n console.log(chalk.gray(\"No secrets configured.\"));\n return;\n }\n\n console.log(formatRow([\"KEY\", \"UPDATED\"], [30, 24]));\n for (const secret of secrets) {\n console.log(formatRow([secret.key, secret.updatedAt], [30, 24]));\n }\n });\n\nsecretsCommand\n .command(\"remove <key>\")\n .description(\"Remove a secret\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (key: string, opts: any) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n await client.secrets.delete(appId, key);\n console.log(chalk.green(`Secret \"${key}\" removed.`));\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport inquirer from \"inquirer\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp, getDefaultOrg, setCurrentApp } from \"../config.js\";\nimport { requireApiKey, requireOrg, formatRow, appUrl } from \"../util.js\";\nimport {\n DEFAULT_VISIBILITY,\n VISIBILITIES,\n VISIBILITY_LABELS,\n isVisibility,\n visibilityOf,\n type App,\n type Visibility,\n} from \"@cloud/shared\";\n\nexport const appsCommand = new Command(\"apps\")\n .description(\"Manage apps\");\n\n/**\n * Validates `--access` here rather than letting the API answer 400.\n *\n * A tier is a security setting, so a typo has to fail loudly and name the legal\n * values \u2014 and it must fail *before* the rest of a `set` call is applied, since\n * a partially-applied settings write is worse than a refused one.\n */\nfunction accessOption(value: string | undefined): Visibility | undefined {\n if (value === undefined) return undefined;\n const tier = value.trim().toLowerCase();\n if (!isVisibility(tier)) {\n console.error(chalk.red(`Unknown --access value \"${value}\". Use one of: ${VISIBILITIES.join(\", \")}`));\n process.exit(1);\n }\n return tier;\n}\n\n/** Reads the tier from a response, falling back to the legacy boolean. */\nfunction describeAccess(app: Pick<App, \"authRequired\"> & { visibility?: string }): string {\n // An older API that does not send `visibility` still sends the boolean, and a\n // gated app is org-wide by default there.\n const tier = app.visibility ? visibilityOf(app.visibility) : app.authRequired ? \"org\" : \"public\";\n return `${tier} \u2014 ${VISIBILITY_LABELS[tier].toLowerCase()}`;\n}\n\nappsCommand\n .command(\"list\")\n .description(\"List all apps\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .action(async (opts: { org?: string }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const orgId = requireOrg(opts.org || getDefaultOrg());\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const apps = await client.apps.list(orgId);\n\n if (apps.length === 0) {\n console.log(chalk.gray(\"No apps yet. Create one with `videan apps create`.\"));\n return;\n }\n\n const widths = [20, 24, 10, 44];\n console.log(formatRow([\"NAME\", \"ID\", \"STATUS\", \"URL\"], widths));\n for (const app of apps) {\n console.log(formatRow([app.name, app.id, app.status, appUrl(app.slug)], widths));\n }\n });\n\nappsCommand\n .command(\"create\")\n .description(\"Create a new app\")\n .option(\"-n, --name <name>\", \"App name\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .option(\"--postgres\", \"Provision a managed Postgres database\")\n // Both off unless asked for: storage outlives the code that wrote it and is\n // billed, and sending mail spends the platform's shared reputation.\n .option(\"--storage\", \"Give the app an object-storage prefix\")\n .option(\"--email\", \"Let the app send mail through the platform\")\n // The platform gates apps behind login by default; this opts out.\n .option(\"--public\", \"Serve the app without the platform login gate (same as --access public)\")\n .option(\"--access <tier>\", `Who may open the app: ${VISIBILITIES.join(\" | \")} (default: ${DEFAULT_VISIBILITY})`)\n .action(\n async (opts: {\n name?: string;\n org?: string;\n postgres?: boolean;\n storage?: boolean;\n email?: boolean;\n public?: boolean;\n access?: string;\n }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const orgId = requireOrg(opts.org || getDefaultOrg());\n\n let name = opts.name;\n if (!name) {\n const answers = await inquirer.prompt([\n { type: \"input\", name: \"name\", message: \"App name:\" },\n ]);\n name = answers.name;\n }\n if (!name) {\n console.error(chalk.red(\"An app name is required.\"));\n process.exit(1);\n }\n\n const visibility = accessOption(opts.access) ?? (opts.public ? \"public\" : undefined);\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const app = await client.apps.create({\n name,\n orgId,\n postgres: opts.postgres ?? false,\n storage: opts.storage ?? false,\n email: opts.email ?? false,\n visibility,\n });\n setCurrentApp(app.id);\n\n console.log(chalk.green(`App \"${app.name}\" created (${app.id})`));\n console.log(chalk.gray(` Access: ${describeAccess(app)}`));\n console.log(chalk.gray(` URL after first deploy: ${appUrl(app.slug)}`));\n // Runtime is detected from the pushed files, so there is nothing to pick here.\n console.log(chalk.gray(\" Push code with `videan deploy` \u2014 the runtime is auto-detected.\"));\n },\n );\n\nappsCommand\n .command(\"set\")\n .description(\"Change an app's settings (scale, rate limit, gate, capabilities)\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-n, --name <name>\", \"Rename the app (the URL keeps its original slug)\")\n .option(\"--cpu <units>\", \"CPU units per instance (256 = 0.25 vCPU)\")\n .option(\"--memory <mib>\", \"Memory per instance, in MiB\")\n .option(\"--instances <n>\", \"Number of instances to run\")\n .option(\"--rate-limit <rpm>\", \"Requests per minute per client\")\n .option(\"--no-rate-limit\", \"Remove the rate limit\")\n .option(\"--access <tier>\", `Who may open the app: ${VISIBILITIES.join(\" | \")}`)\n .option(\"--public\", \"Serve without the platform login gate (same as --access public)\")\n .option(\"--private\", \"Require platform login (leaves the tier alone if it is already gated)\")\n .option(\"--postgres\", \"Provision a managed Postgres database\")\n .option(\"--storage\", \"Give the app an object-storage prefix\")\n .option(\"--email\", \"Let the app send mail through the platform\")\n .option(\"--json\", \"Print the raw response\")\n .action(\n async (opts: {\n app?: string;\n name?: string;\n cpu?: string;\n memory?: string;\n instances?: string;\n // commander sets this to false for --no-rate-limit and to the string for\n // --rate-limit, so the three states (untouched / removed / set) are\n // distinguishable: undefined, false, \"120\".\n rateLimit?: string | boolean;\n access?: string;\n public?: boolean;\n private?: boolean;\n postgres?: boolean;\n storage?: boolean;\n email?: boolean;\n json?: boolean;\n }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n\n if (opts.public && opts.private) {\n console.error(chalk.red(\"--public and --private contradict each other.\"));\n process.exit(1);\n }\n const access = accessOption(opts.access);\n if (access && (opts.public || opts.private)) {\n // Both would be sent and the API resolves `visibility` first, so the\n // boolean would be silently ignored. Refusing beats applying one of two\n // access settings the caller asked for.\n console.error(chalk.red(\"--access already says who may open the app; drop --public/--private.\"));\n process.exit(1);\n }\n\n const changes: Parameters<CloudClient[\"apps\"][\"update\"]>[1] = {};\n if (opts.name) changes.name = opts.name;\n if (opts.cpu !== undefined) changes.cpu = intOption(\"--cpu\", opts.cpu);\n if (opts.memory !== undefined) changes.memory = intOption(\"--memory\", opts.memory);\n if (opts.instances !== undefined) {\n changes.instances = intOption(\"--instances\", opts.instances);\n }\n if (opts.rateLimit === false) changes.rateLimitPerMinute = null;\n else if (typeof opts.rateLimit === \"string\") {\n changes.rateLimitPerMinute = intOption(\"--rate-limit\", opts.rateLimit);\n }\n if (access) changes.visibility = access;\n if (opts.public) changes.authRequired = false;\n if (opts.private) changes.authRequired = true;\n if (opts.postgres) changes.postgres = true;\n if (opts.storage) changes.storage = true;\n if (opts.email) changes.email = true;\n\n if (Object.keys(changes).length === 0) {\n // Otherwise this reports success having changed nothing, which reads as the\n // setting being applied.\n console.error(chalk.red(\"Nothing to change. Pass at least one option.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const app = await client.apps.update(appId, changes);\n\n if (opts.json) {\n console.log(JSON.stringify(app, null, 2));\n return;\n }\n\n console.log(chalk.green(`Updated ${app.name} (${app.id})`));\n console.log(` Access: ${describeAccess(app)}`);\n console.log(` Scale: ${app.cpu ?? \"default\"} CPU / ${app.memory ?? \"default\"} MiB`);\n console.log(\n ` Rate limit: ${app.rateLimitPerMinute ? `${app.rateLimitPerMinute}/min per client` : \"none\"}`,\n );\n if (app.restartRequired) {\n // Reported, not done: a restart is a brief interruption, and taking one as a\n // side effect of a settings write is not something to discover afterwards.\n console.log(\n chalk.yellow(\"\\n These settings apply to the next deploy. Run `videan deploy` to pick them up.\"),\n );\n }\n },\n );\n\n/** Parse a numeric flag, failing on junk rather than sending NaN to the API. */\nfunction intOption(flag: string, raw: string): number {\n const n = Number(raw);\n if (!Number.isInteger(n) || n <= 0) {\n console.error(chalk.red(`${flag} expects a positive whole number, got \"${raw}\".`));\n process.exit(1);\n }\n return n;\n}\n\nappsCommand\n .command(\"delete <id>\")\n .description(\"Delete an app and all its resources\")\n .action(async (id: string) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const { confirm } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"confirm\",\n message: `Delete app ${id}? This stops the app and destroys its database, secrets and snapshots.`,\n default: false,\n },\n ]);\n\n if (!confirm) return;\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const { warnings } = await client.apps.delete(id);\n\n console.log(chalk.green(\"App deleted.\"));\n if (warnings.length > 0) {\n // Say so loudly: leaked AWS resources keep costing money.\n console.log(chalk.yellow(\"\\nSome resources could not be released:\"));\n for (const w of warnings) {\n console.log(chalk.yellow(` ${w.step}: ${w.error || \"unknown error\"}`));\n }\n }\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey, formatStatus, appUrl } from \"../util.js\";\nimport { VISIBILITY_LABELS, visibilityOf, type App } from \"@cloud/shared\";\n\n/**\n * Falls back to the legacy boolean, which is all an older API sends. A gated app\n * is org-wide there, so that is what the boolean means.\n */\nfunction accessLine(app: Pick<App, \"authRequired\"> & { visibility?: string }): string {\n const tier = app.visibility ? visibilityOf(app.visibility) : app.authRequired ? \"org\" : \"public\";\n return `${tier} \u2014 ${VISIBILITY_LABELS[tier].toLowerCase()}`;\n}\n\nexport const statusCommand = new Command(\"status\")\n .description(\"Show current app status\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (opts) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const app = await client.apps.get(appId);\n // Health reads ECS rather than the deployment row, which keeps saying\n // \"running\" after the container dies.\n const health = await client.apps.health(appId);\n\n console.log(chalk.bold(app.name));\n console.log(` ID: ${app.id}`);\n console.log(` Created: ${app.createdAt}`);\n console.log(` Postgres: ${app.postgresEnabled ? \"enabled\" : \"disabled\"}`);\n console.log(` Access: ${accessLine(app)}`);\n console.log(` State: ${formatStatus(health.state)}`);\n console.log(` Healthy: ${health.healthy ? chalk.green(\"yes\") : chalk.red(\"no\")}`);\n console.log(` URL: ${chalk.cyan(health.url || appUrl(app.slug))}`);\n\n const task = health.task;\n if (task) {\n if (task.exit_code !== undefined && task.exit_code !== null) {\n const code = String(task.exit_code);\n console.log(` Exit code: ${task.exit_code === 0 ? code : chalk.red(code)}`);\n }\n if (task.stopped_reason) {\n console.log(` Stopped: ${chalk.yellow(task.stopped_reason)}`);\n }\n if (task.container_reason) {\n console.log(` Detail: ${chalk.yellow(task.container_reason)}`);\n }\n }\n\n if (!health.healthy) {\n console.log(chalk.gray(\"\\nRun `videan logs` to see why.\"));\n }\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport inquirer from \"inquirer\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getDefaultOrg } from \"../config.js\";\nimport { requireApiKey, requireOrg, formatRow } from \"../util.js\";\n\nexport const keysCommand = new Command(\"keys\")\n .description(\"Manage API keys for programmatic access\");\n\nkeysCommand\n .command(\"create <name>\")\n .description(\"Create an API key\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .option(\"-e, --expires <days>\", \"Expire the key after N days\")\n .option(\n \"--app <id>\",\n \"Pin the key to one app (a service token, for code running inside it)\",\n )\n .action(async (name: string, opts: { org?: string; expires?: string; app?: string }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const orgId = requireOrg(opts.org || getDefaultOrg());\n\n let expiresInDays: number | undefined;\n if (opts.expires !== undefined) {\n expiresInDays = Number(opts.expires);\n if (!Number.isInteger(expiresInDays) || expiresInDays < 1) {\n console.error(chalk.red(\"--expires must be a whole number of days, at least 1.\"));\n process.exit(1);\n }\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const key = await client.apiKeys.create({\n name,\n orgId,\n expiresInDays,\n appId: opts.app,\n });\n\n console.log(chalk.green(`Created key \"${key.name}\" (${key.id})`));\n // Printed once and never retrievable -- the server only stores a hash.\n console.log(`\\n ${chalk.bold(key.key)}\\n`);\n console.log(chalk.yellow(\"Copy it now. It cannot be shown again.\"));\n if (key.appId) {\n // Worth stating: this is the only kind of key that is safe to ship inside a\n // deployed app, and the difference is invisible in the key itself.\n console.log(\n chalk.gray(`Service token, scoped to app ${key.appId}. It cannot reach anything else.`),\n );\n } else {\n console.log(\n chalk.gray(\"Acts as you across every app in the org -- do not deploy it inside an app.\"),\n );\n }\n if (key.expiresAt) {\n console.log(chalk.gray(`Expires ${key.expiresAt}`));\n }\n });\n\nkeysCommand\n .command(\"list\")\n .description(\"List API keys\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .action(async (opts: { org?: string }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const orgId = requireOrg(opts.org || getDefaultOrg());\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const keys = await client.apiKeys.list(orgId);\n\n if (keys.length === 0) {\n console.log(chalk.gray(\"No API keys. Create one with `videan keys create <name>`.\"));\n return;\n }\n\n const widths = [24, 24, 16, 22, 12, 24];\n console.log(formatRow([\"NAME\", \"ID\", \"PREFIX\", \"LAST USED\", \"STATE\", \"SCOPE\"], widths));\n for (const key of keys) {\n const state = key.revokedAt\n ? chalk.red(\"revoked\")\n : key.expiresAt && new Date(key.expiresAt) < new Date()\n ? chalk.yellow(\"expired\")\n : chalk.green(\"active\");\n console.log(formatRow(\n [\n key.name,\n key.id,\n `${key.keyPrefix}\u2026`,\n key.lastUsedAt || \"never\",\n state,\n key.appId ? `app ${key.appId}` : \"org-wide\",\n ],\n widths,\n ));\n }\n });\n\nkeysCommand\n .command(\"revoke <id>\")\n .description(\"Revoke an API key\")\n .action(async (id: string) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const { confirm } = await inquirer.prompt([\n { type: \"confirm\", name: \"confirm\", message: `Revoke key ${id}?`, default: false },\n ]);\n if (!confirm) return;\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n await client.apiKeys.revoke(id);\n console.log(chalk.green(\"Key revoked.\"));\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getDefaultOrg, setDefaultOrg } from \"../config.js\";\nimport { requireApiKey, requireOrg, formatRow } from \"../util.js\";\n\nexport const orgsCommand = new Command(\"orgs\")\n .description(\"Manage organizations\");\n\norgsCommand\n .command(\"list\")\n .description(\"List your organizations\")\n .action(async () => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const orgs = await client.orgs.list();\n const current = getDefaultOrg();\n\n if (orgs.length === 0) {\n console.log(chalk.gray(\"No organizations. Create one with `videan orgs create <name>`.\"));\n return;\n }\n\n const widths = [24, 24, 10, 8];\n console.log(formatRow([\"NAME\", \"ID\", \"PLAN\", \"\"], widths));\n for (const org of orgs) {\n console.log(formatRow(\n [org.name, org.id, org.plan, org.id === current ? chalk.green(\"default\") : \"\"],\n widths,\n ));\n }\n });\n\norgsCommand\n .command(\"create <name>\")\n .description(\"Create an organization\")\n .action(async (name: string) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const org = await client.orgs.create(name);\n // First org becomes the default so subsequent commands need no --org.\n if (!getDefaultOrg()) setDefaultOrg(org.id);\n\n console.log(chalk.green(`Organization \"${org.name}\" created (${org.id})`));\n });\n\norgsCommand\n .command(\"use <id>\")\n .description(\"Set the default organization for this machine\")\n .action(async (id: string) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n // Verify membership before saving, so a typo fails here instead of on every\n // later command.\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const org = await client.orgs.get(id);\n setDefaultOrg(org.id);\n\n console.log(chalk.green(`Default organization set to \"${org.name}\".`));\n });\n\norgsCommand\n .command(\"members\")\n .description(\"List organization members\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .action(async (opts: { org?: string }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const orgId = requireOrg(opts.org || getDefaultOrg());\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const members = await client.orgs.members(orgId);\n\n const widths = [32, 24, 10];\n console.log(formatRow([\"EMAIL\", \"NAME\", \"ROLE\"], widths));\n for (const member of members) {\n console.log(formatRow(\n [member.email || member.user_id, member.name || \"-\", member.role],\n widths,\n ));\n }\n });\n\norgsCommand\n .command(\"invite <email>\")\n .description(\"Invite a member by email\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .action(async (email: string, opts: { org?: string }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const orgId = requireOrg(opts.org || getDefaultOrg());\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n await client.orgs.invite(orgId, email);\n console.log(chalk.green(`Invited ${email}.`));\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey, formatRow } from \"../util.js\";\n\n/**\n * `videan storage` -- files an app keeps for itself, separate from its code.\n *\n * Upload and download go direct to S3 through a presigned URL, so a large file\n * does not travel through the control API. That is also why `put` reads and\n * writes real bytes rather than the text-only path `videan deploy` uses for\n * snapshots: this is where binaries belong.\n */\nexport const storageCommand = new Command(\"storage\").description(\"Store files for an app\");\n\nfunction client() {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n return new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n}\n\nfunction requireApp(opt?: string): string {\n const appId = opt || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n return appId;\n}\n\n/** 1.2 KB rather than 1234 -- the size is being read, not summed. */\nfunction human(bytes: number): string {\n const units = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\"];\n let n = bytes;\n let i = 0;\n while (n >= 1024 && i < units.length - 1) {\n n /= 1024;\n i++;\n }\n return `${i === 0 ? n : n.toFixed(1)} ${units[i]}`;\n}\n\nstorageCommand\n .command(\"ls [prefix]\")\n .description(\"List stored objects\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (prefix: string | undefined, opts: { app?: string; json?: boolean }) => {\n const appId = requireApp(opts.app);\n // Every page, not the first: a truncated listing that looks complete is how a\n // caller concludes a file was never uploaded.\n const objects = await client().storage.listAll(appId, prefix);\n\n if (opts.json) {\n console.log(JSON.stringify(objects, null, 2));\n return;\n }\n if (objects.length === 0) {\n console.log(chalk.gray(\"No objects stored. Upload one with `videan storage put <file>`.\"));\n return;\n }\n\n const widths = [52, 12, 24];\n console.log(formatRow([\"KEY\", \"SIZE\", \"MODIFIED\"], widths));\n for (const o of objects) {\n console.log(formatRow([o.key, human(o.size), o.lastModified || \"-\"], widths));\n }\n const total = objects.reduce((sum, o) => sum + o.size, 0);\n console.log(chalk.dim(`\\n${objects.length} object(s), ${human(total)}`));\n });\n\nstorageCommand\n .command(\"put <file> [key]\")\n .description(\"Upload a file (key defaults to the file's name)\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-t, --type <mime>\", \"Content type\")\n .action(async (file: string, key: string | undefined, opts: { app?: string; type?: string }) => {\n const appId = requireApp(opts.app);\n if (!(await fs.pathExists(file))) {\n console.error(chalk.red(`No such file: ${file}`));\n process.exit(1);\n }\n const body = await fs.readFile(file);\n const objectKey = key || path.basename(file);\n\n const stored = await client().storage.upload(appId, objectKey, body, {\n contentType: opts.type,\n });\n console.log(\n chalk.green(`Uploaded ${objectKey}`) + chalk.dim(` (${human(body.length)})`),\n );\n if (stored.etag) console.log(chalk.dim(`etag ${stored.etag}`));\n });\n\nstorageCommand\n .command(\"get <key> [file]\")\n .description(\"Download an object (defaults to the key's basename)\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (key: string, file: string | undefined, opts: { app?: string }) => {\n const appId = requireApp(opts.app);\n const bytes = await client().storage.download(appId, key);\n const dest = file || path.basename(key);\n await fs.writeFile(dest, bytes);\n console.log(chalk.green(`Wrote ${dest}`) + chalk.dim(` (${human(bytes.length)})`));\n });\n\nstorageCommand\n .command(\"rm <key>\")\n .description(\"Delete an object\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (key: string, opts: { app?: string }) => {\n const appId = requireApp(opts.app);\n await client().storage.delete(appId, key);\n // Deliberately not \"not found\" when it was already gone: delete is idempotent\n // server-side, and the state the caller wanted is the state they have.\n console.log(chalk.green(`Deleted ${key}`));\n });\n\nstorageCommand\n .command(\"url <key>\")\n .description(\"Print a temporary link to an object\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-e, --expires <seconds>\", \"Lifetime in seconds (30-3600)\", \"900\")\n .option(\"--upload\", \"Sign an upload (PUT) URL instead of a download\")\n .option(\"-d, --download <filename>\", \"Serve as a download with this filename\")\n .action(async (key: string, opts: any) => {\n const appId = requireApp(opts.app);\n const expiresIn = Number(opts.expires);\n if (!Number.isInteger(expiresIn) || expiresIn < 30 || expiresIn > 3600) {\n console.error(chalk.red(\"--expires must be a whole number of seconds between 30 and 3600.\"));\n process.exit(1);\n }\n\n const signed = await client().storage.presign(appId, key, {\n method: opts.upload ? \"put\" : \"get\",\n expiresIn,\n download: opts.download,\n });\n console.log(signed.url);\n // Said plainly because the URL looks like an ordinary link and is not one:\n // anyone who holds it has that access without logging in.\n console.error(\n chalk.yellow(\n `This ${signed.method} link works for ${expiresIn}s for anyone who has it.`,\n ),\n );\n });\n\nstorageCommand\n .command(\"usage\")\n .description(\"Total objects and bytes stored\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (opts: { app?: string }) => {\n const appId = requireApp(opts.app);\n const { objects, bytes } = await client().storage.usage(appId);\n console.log(`${objects} object(s), ${human(bytes)}`);\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey } from \"../util.js\";\n\n/**\n * `videan email` -- send mail as an app, through the platform's verified domain.\n *\n * There is no `--from`. Mail goes out as `app-<slug>@<platform domain>`, which is\n * what keeps an app from sending as the platform's own `no-reply@` -- the address\n * password resets come from. `--reply-to` is the lever for routing replies\n * somewhere the app owns.\n */\nexport const emailCommand = new Command(\"email\").description(\"Send email from an app\");\n\nfunction client() {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n return new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n}\n\nfunction requireApp(opt?: string): string {\n const appId = opt || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n return appId;\n}\n\nemailCommand\n .command(\"send\")\n .description(\"Send an email\")\n .requiredOption(\"-t, --to <address...>\", \"Recipient address (repeatable)\")\n .requiredOption(\"-s, --subject <subject>\", \"Subject line\")\n .option(\"--text <body>\", \"Plain-text body\")\n .option(\"--html <body>\", \"HTML body\")\n .option(\"--body-file <path>\", \"Read the body from a file\")\n .option(\"--reply-to <address>\", \"Where replies should go\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"--json\", \"Print the raw response\")\n .action(\n async (opts: {\n to: string[];\n subject: string;\n text?: string;\n html?: string;\n bodyFile?: string;\n replyTo?: string;\n app?: string;\n json?: boolean;\n }) => {\n const appId = requireApp(opts.app);\n\n let text = opts.text;\n let html = opts.html;\n if (opts.bodyFile) {\n const contents = await fs.readFile(opts.bodyFile, \"utf-8\");\n // The extension decides which part it becomes: sending HTML as the plain\n // part delivers visible markup, which looks like a broken app rather than\n // a wrong flag.\n if (/\\.html?$/i.test(opts.bodyFile)) html = contents;\n else text = contents;\n }\n if (!text && !html) {\n console.error(chalk.red(\"Nothing to send. Pass --text, --html or --body-file.\"));\n process.exit(1);\n }\n\n const sent = await client().email.send(appId, {\n to: opts.to,\n subject: opts.subject,\n text,\n html,\n replyTo: opts.replyTo,\n });\n\n if (opts.json) {\n console.log(JSON.stringify(sent, null, 2));\n return;\n }\n\n console.log(chalk.green(\"Sent\"));\n console.log(` From: ${sent.from}`);\n console.log(` To: ${sent.to.join(\", \")}`);\n console.log(` Message: ${sent.messageId ?? \"(no id returned)\"}`);\n // Printed on every send: the quota is per day and shared with nothing else,\n // so the moment to notice it is running low is before it runs out.\n console.log(\n chalk.dim(\n ` Quota: ${sent.quota.sent}/${sent.quota.quota} today, resets ${sent.quota.resetsAt}`,\n ),\n );\n },\n );\n\nemailCommand\n .command(\"quota\")\n .description(\"Show today's sending allowance\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (opts: { app?: string; json?: boolean }) => {\n const quota = await client().email.quota(requireApp(opts.app));\n if (opts.json) {\n console.log(JSON.stringify(quota, null, 2));\n return;\n }\n console.log(`Sent today: ${quota.sent}`);\n console.log(`Daily quota: ${quota.quota}`);\n console.log(`Remaining: ${quota.remaining}`);\n console.log(chalk.dim(`Resets at: ${quota.resetsAt}`));\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey } from \"../util.js\";\n\n/**\n * `videan jobs` -- the background queue.\n *\n * A job is a POST the platform makes to a path on the app itself, so there is no\n * worker to deploy: the handler is a route in the app, and `videan jobs enqueue`\n * is a way to trigger it out of band. Retries mean a handler can see the same job\n * twice -- `--key` is how a caller stops its *own* retry from becoming two jobs.\n */\nexport const jobsCommand = new Command(\"jobs\").description(\"Enqueue and inspect background jobs\");\n\nfunction client() {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n return new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n}\n\nfunction requireApp(opt?: string): string {\n const appId = opt || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or run `videan init` first.\"));\n process.exit(1);\n }\n return appId;\n}\n\n/** Parse a numeric flag, failing on junk rather than sending NaN to the API. */\nfunction intOption(flag: string, raw: string): number {\n const n = Number(raw);\n if (!Number.isInteger(n) || n < 0) {\n console.error(chalk.red(`${flag} expects a whole number, got \"${raw}\".`));\n process.exit(1);\n }\n return n;\n}\n\nconst STATUS_COLOR: Record<string, (s: string) => string> = {\n queued: chalk.yellow,\n running: chalk.cyan,\n succeeded: chalk.green,\n dead: chalk.red,\n cancelled: chalk.gray,\n};\n\nfunction statusLabel(status: string): string {\n return (STATUS_COLOR[status] ?? chalk.white)(status);\n}\n\njobsCommand\n .command(\"enqueue\")\n .description(\"Queue a job for the app to run\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-q, --queue <name>\", \"Queue name (default: default)\")\n .option(\"-p, --path <path>\", \"Path on the app to POST to (default: /jobs)\")\n .option(\"-d, --data <json>\", \"JSON payload\")\n .option(\"-f, --file <path>\", \"Read the JSON payload from a file\")\n .option(\"--delay <seconds>\", \"Run no earlier than this many seconds from now\")\n .option(\"--attempts <n>\", \"Attempts before the job is given up on (default: 3)\")\n .option(\"--timeout <seconds>\", \"How long the handler gets per attempt (default: 60)\")\n .option(\"--key <key>\", \"Idempotency key -- a repeat returns the same job\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (opts) => {\n const appId = requireApp(opts.app);\n\n // Read from a file or a flag, and refuse invalid JSON here rather than letting\n // the API reject it: the payload is usually the thing being iterated on, and a\n // round trip to say \"bad JSON\" is a slow way to learn about a typo.\n let payload: unknown;\n const raw = opts.file ? await fs.readFile(opts.file, \"utf-8\") : opts.data;\n if (raw !== undefined) {\n try {\n payload = JSON.parse(raw);\n } catch (e: any) {\n console.error(chalk.red(`--${opts.file ? \"file\" : \"data\"} is not valid JSON: ${e.message}`));\n process.exit(1);\n }\n }\n\n const job = await client().jobs.enqueue(appId, {\n queue: opts.queue,\n path: opts.path,\n payload,\n delaySeconds: opts.delay !== undefined ? intOption(\"--delay\", opts.delay) : undefined,\n maxAttempts: opts.attempts !== undefined ? intOption(\"--attempts\", opts.attempts) : undefined,\n timeoutSeconds: opts.timeout !== undefined ? intOption(\"--timeout\", opts.timeout) : undefined,\n idempotencyKey: opts.key,\n });\n\n if (opts.json) {\n console.log(JSON.stringify(job, null, 2));\n return;\n }\n\n if (job.deduplicated) {\n // Said plainly, because the alternative reading -- that the job was queued\n // again -- is the one that leads to work being counted twice.\n console.log(chalk.yellow(`Already queued as ${job.id} (idempotency key \"${opts.key}\")`));\n } else {\n console.log(chalk.green(`Queued ${job.id}`));\n }\n console.log(chalk.gray(` ${job.method} ${job.path} on queue \"${job.queue}\"`));\n if (job.runAt && Date.parse(job.runAt) > Date.now() + 1000) {\n console.log(chalk.gray(` Runs at ${new Date(job.runAt).toLocaleString()}`));\n }\n });\n\njobsCommand\n .command(\"list\")\n .description(\"List jobs, newest first\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-s, --status <status>\", \"queued, running, succeeded, dead or cancelled\")\n .option(\"-q, --queue <name>\", \"Only this queue\")\n .option(\"-n, --limit <n>\", \"How many to show (default: 20)\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (opts) => {\n const appId = requireApp(opts.app);\n const { jobs, counts } = await client().jobs.list(appId, {\n status: opts.status,\n queue: opts.queue,\n limit: opts.limit !== undefined ? intOption(\"--limit\", opts.limit) : 20,\n });\n\n if (opts.json) {\n console.log(JSON.stringify({ jobs, counts }, null, 2));\n return;\n }\n\n // Depth first: a page of 20 cannot say how far behind the queue is, and that\n // is the question someone running this is usually asking.\n const depth = Object.entries(counts)\n .map(([status, n]) => `${statusLabel(status)} ${n}`)\n .join(\" \");\n console.log(depth || chalk.gray(\"No jobs yet.\"));\n\n if (jobs.length === 0) return;\n console.log();\n for (const job of jobs) {\n const attempts = job.attempts > 0 ? chalk.gray(` ${job.attempts}/${job.maxAttempts}`) : \"\";\n console.log(\n `${statusLabel(job.status).padEnd(20)} ${chalk.white(job.id)} ${chalk.gray(\n `${job.queue} ${job.path}`,\n )}${attempts}`,\n );\n // Only the last error, and only when there is one: a queued job with an\n // error is a job that failed and is waiting to be retried, which reads as\n // healthy without it.\n if (job.error) console.log(chalk.red(` ${job.error}`));\n }\n });\n\njobsCommand\n .command(\"get <job-id>\")\n .description(\"Show one job in full\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (jobId, opts) => {\n const job = await client().jobs.get(requireApp(opts.app), jobId);\n if (opts.json) {\n console.log(JSON.stringify(job, null, 2));\n return;\n }\n console.log(`${chalk.white(job.id)} ${statusLabel(job.status)}`);\n console.log(chalk.gray(` ${job.method} ${job.path} on queue \"${job.queue}\"`));\n console.log(chalk.gray(` Attempts: ${job.attempts}/${job.maxAttempts}`));\n if (job.statusCode) console.log(chalk.gray(` Last response: HTTP ${job.statusCode}`));\n if (job.durationMs) console.log(chalk.gray(` Took: ${job.durationMs}ms`));\n if (job.error) console.log(chalk.red(` Error: ${job.error}`));\n if (job.status === \"queued\" && job.attempts > 0) {\n console.log(chalk.yellow(` Retrying at ${new Date(job.runAt).toLocaleString()}`));\n }\n if (job.payload !== null && job.payload !== undefined) {\n console.log(chalk.gray(\" Payload:\"));\n console.log(\n JSON.stringify(job.payload, null, 2)\n .split(\"\\n\")\n .map((l) => ` ${l}`)\n .join(\"\\n\"),\n );\n }\n });\n\njobsCommand\n .command(\"retry <job-id>\")\n .description(\"Run a dead job again, from a clean attempt count\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (jobId, opts) => {\n const job = await client().jobs.retry(requireApp(opts.app), jobId);\n console.log(chalk.green(`Requeued ${job.id}`));\n });\n\njobsCommand\n .command(\"cancel <job-id>\")\n .description(\"Cancel a job that has not started yet\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (jobId, opts) => {\n const job = await client().jobs.cancel(requireApp(opts.app), jobId);\n console.log(chalk.green(`Cancelled ${job.id}`));\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { CloudClient, type UsageQuantity } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp, getDefaultOrg } from \"../config.js\";\nimport { requireApiKey } from \"../util.js\";\n\n/**\n * `videan usage` -- what the month costs, and where it went.\n *\n * Org-level by default, because that is the number that gets invoiced; `--app`\n * narrows to one app's share. The two do not add up to the same figure on purpose:\n * the plan's included allowance applies once to the org, so per-app lines are list\n * price with no allowance and the org total subtracts it exactly once.\n *\n * Nothing here changes a plan or pays anything. `videan usage plans` prints the\n * catalogue so an upgrade can be priced before anyone talks to a card.\n */\nexport const usageCommand = new Command(\"usage\")\n .description(\"Metered usage and cost for the current month\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .option(\"-a, --app <id>\", \"Show one app's share instead of the whole org\")\n .option(\"-p, --period <YYYY-MM>\", \"Month to report on (default: the month in progress)\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (opts) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n\n if (opts.app || (!opts.org && getCurrentApp() && !getDefaultOrg())) {\n const appId = opts.app || getCurrentApp()!;\n const report = await client.apps.usage(appId, opts.period);\n if (opts.json) return void console.log(JSON.stringify(report, null, 2));\n\n console.log(chalk.dim(`${period(report.periodStart, report.periodEnd)} app ${appId}`));\n console.log();\n printMetrics(report.metrics);\n console.log();\n for (const line of report.lines) {\n console.log(` ${chalk.dim(line.label.padEnd(22))} ${money(line.cents)}`);\n }\n console.log(` ${chalk.bold(\"Share of the bill\".padEnd(22))} ${chalk.bold(report.cost)}`);\n console.log();\n console.log(\n chalk.dim(\"At list price, with no plan allowance applied \u2014 see `videan usage` for the org total.\"),\n );\n return;\n }\n\n const orgId = opts.org || getDefaultOrg();\n if (!orgId) {\n console.error(chalk.red(\"No org specified. Use --org, or --app for a single app.\"));\n process.exit(1);\n }\n\n const report = await client.orgs.usage(orgId, opts.period);\n if (opts.json) return void console.log(JSON.stringify(report, null, 2));\n\n const inv = report.invoice;\n console.log(\n chalk.dim(`${period(report.periodStart, report.periodEnd)} org ${orgId} plan ${report.plan}`),\n );\n console.log();\n printMetrics(report.metrics);\n\n if (report.apps.length > 0) {\n console.log();\n console.log(chalk.bold(\"By app\"));\n // Descending, because the question is which app is costing the money.\n for (const app of [...report.apps].sort((a, b) => b.cents - a.cents)) {\n const name = app.slug || app.name || app.appId || \"(deleted apps)\";\n console.log(` ${chalk.dim(String(name).padEnd(24))} ${money(app.cents)}`);\n }\n }\n\n console.log();\n for (const line of inv.lines) {\n console.log(\n ` ${chalk.dim(line.label.padEnd(22))} ${money(line.cents)} ${chalk.dim(\n `(${line.quantity} \u00D7 ${line.unitPriceCents}\u00A2)`,\n )}`,\n );\n }\n console.log(` ${chalk.dim(\"Usage\".padEnd(22))} ${money(inv.usageCents)}`);\n if (inv.includedUsageCents > 0) {\n console.log(\n ` ${chalk.dim(\"Included\".padEnd(22))} ${chalk.green(`-${money(Math.min(inv.usageCents, inv.includedUsageCents))}`)}`,\n );\n }\n if (inv.baseCents > 0) {\n console.log(` ${chalk.dim(\"Plan\".padEnd(22))} ${money(inv.baseCents)}`);\n }\n console.log(` ${chalk.bold(\"Total\".padEnd(22))} ${chalk.bold(report.total)}`);\n console.log();\n // Said explicitly: the month is not over, so this is what has accrued rather\n // than what will be charged.\n console.log(chalk.dim(\"Usage to date. The period is priced as it stands right now.\"));\n });\n\nusageCommand\n .command(\"plans\")\n .description(\"The plan catalogue and what each one allows\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (opts) => {\n // No key needed by the API, but the client requires one; an empty string is\n // enough and keeps `videan usage plans` working before login.\n const client = new CloudClient({ apiKey: getApiKey() || \"\", baseUrl: getBaseUrl() });\n const plans = await client.plans();\n if (opts.json) return void console.log(JSON.stringify(plans, null, 2));\n\n for (const plan of plans) {\n console.log(\n `${chalk.bold(plan.name)} ${chalk.dim(`(${plan.id})`)} ${plan.base}/mo` +\n (plan.includedUsageCents > 0 ? chalk.dim(`, ${plan.includedUsage} usage included`) : \"\"),\n );\n const l = plan.limits;\n console.log(\n chalk.dim(\n ` ${l.apps} apps \u00B7 ${l.instancesPerApp} instances/app \u00B7 up to ${l.maxCpu} CPU / ${l.maxMemory} MB \u00B7 ${l.maxStorageMb} MB storage` +\n `${l.postgres ? \" \u00B7 postgres\" : \"\"}${l.customDomains ? \" \u00B7 custom domains\" : \"\"}`,\n ),\n );\n console.log();\n }\n });\n\nfunction printMetrics(metrics: UsageQuantity[]): void {\n if (metrics.length === 0) {\n console.log(chalk.dim(\" Nothing metered in this period yet.\"));\n return;\n }\n for (const m of metrics) {\n console.log(` ${chalk.dim(m.metric.padEnd(22))} ${round(m.quantity)}`);\n }\n}\n\n/** Two decimals, and no trailing `.00` on a whole number. */\nfunction round(n: number): string {\n const v = Math.round(n * 100) / 100;\n return Number.isInteger(v) ? String(v) : v.toFixed(2);\n}\n\nfunction money(cents: number): string {\n return `$${(cents / 100).toFixed(2)}`;\n}\n\nfunction period(start: string, end: string): string {\n return `${start.slice(0, 10)} \u2192 ${end.slice(0, 10)}`;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { logoutCommand } from \"./commands/logout.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { deployCommand } from \"./commands/deploy.js\";\nimport { logsCommand } from \"./commands/logs.js\";\nimport { metricsCommand } from \"./commands/metrics.js\";\nimport { rollbackCommand } from \"./commands/rollback.js\";\nimport { secretsCommand } from \"./commands/secrets.js\";\nimport { appsCommand } from \"./commands/apps.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { keysCommand } from \"./commands/keys.js\";\nimport { orgsCommand } from \"./commands/orgs.js\";\nimport { storageCommand } from \"./commands/storage.js\";\nimport { emailCommand } from \"./commands/email.js\";\nimport { jobsCommand } from \"./commands/jobs.js\";\nimport { usageCommand } from \"./commands/usage.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"videan\")\n .description(\"Videan CLI \u2014 deploy apps in seconds\")\n .version(\"0.1.0\");\n\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(initCommand);\nprogram.addCommand(deployCommand);\nprogram.addCommand(logsCommand);\nprogram.addCommand(metricsCommand);\nprogram.addCommand(rollbackCommand);\nprogram.addCommand(secretsCommand);\nprogram.addCommand(appsCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(keysCommand);\nprogram.addCommand(orgsCommand);\nprogram.addCommand(storageCommand);\nprogram.addCommand(emailCommand);\nprogram.addCommand(jobsCommand);\nprogram.addCommand(usageCommand);\n\n/**\n * Commander does not await an async action's rejection, so anything a command\n * throws lands as an unhandled rejection and node prints a stack trace with\n * `triggerUncaughtException` at the top of it. That is what a user saw for a\n * connection reset. `parseAsync` gives the rejection somewhere to go; the\n * handler is the backstop for a throw outside a command's own promise.\n */\nfunction die(e: any): never {\n console.error(`Error: ${e?.message || e}`);\n // Only when asked: the message is the actionable part, and a stack trace on\n // every network blip trains people to ignore CLI output.\n if (process.env.VIDEAN_DEBUG && e?.stack) console.error(e.stack);\n process.exit(1);\n}\n\nprocess.on(\"unhandledRejection\", die);\n\nprogram.parseAsync().catch(die);\n", "import { Command } from \"commander\";\nimport inquirer from \"inquirer\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport os from \"node:os\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { DEFAULT_API_URL } from \"@cloud/shared\";\nimport { setApiKey, setDefaultOrg, getBaseUrl, setBaseUrl } from \"../config.js\";\n\nexport const loginCommand = new Command(\"login\")\n .description(\"Log in to Cloud\")\n .option(\"-e, --email <email>\", \"Email (skips the prompt)\")\n .option(\"-p, --password <password>\", \"Password (skips the prompt; prefer VIDEAN_PASSWORD)\")\n .option(\"-o, --org <id>\", \"Organization to scope the key to (skips the picker)\")\n .option(\"--api-url <url>\", \"API base URL to use and remember (default: the public API)\")\n .action(async (opts) => {\n // Anything not supplied has to be prompted for, and prompting needs a\n // terminal. Without this the command hung on a closed stdin and then died\n // inside readline with `ERR_USE_AFTER_CLOSE` -- an agent driving the CLI, the\n // platform's whole intended caller, could not log in and could not tell why.\n const password = opts.password || process.env.VIDEAN_PASSWORD || process.env.CLOUD_PASSWORD;\n if ((!opts.email || !password) && !process.stdin.isTTY) {\n console.error(\n chalk.red(\n \"login needs a terminal to prompt. Non-interactively, pass --email and --password \" +\n \"(or VIDEAN_PASSWORD), or skip login entirely by setting VIDEAN_API_KEY.\",\n ),\n );\n process.exit(1);\n }\n\n const prompts = [\n ...(opts.email ? [] : [{ type: \"input\", name: \"email\", message: \"Email:\" }]),\n ...(password ? [] : [{ type: \"password\", name: \"password\", message: \"Password:\" }]),\n ];\n const answers = {\n email: opts.email,\n password,\n ...(prompts.length ? await inquirer.prompt(prompts) : {}),\n };\n\n // Same base as the SDK uses, so a custom baseUrl works for both. Saved\n // before the request, so that a wrong --api-url can be corrected by another\n // login rather than by editing the config file by hand.\n if (opts.apiUrl) setBaseUrl(opts.apiUrl.replace(/\\/$/, \"\"));\n const baseUrl = (getBaseUrl() || DEFAULT_API_URL).replace(/\\/$/, \"\");\n const spinner = ora(\"Logging in...\").start();\n\n let token: string;\n try {\n const response = await fetch(`${baseUrl}/auth/login`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ email: answers.email, password: answers.password }),\n });\n\n if (!response.ok) {\n // Only 401 means the credentials are wrong. Everything else is the CLI\n // talking to the wrong place, and blaming the password for it sends the\n // user off resetting a password that was never the problem -- a stale\n // saved `baseUrl` pointing at a host that no longer serves /v1 reported\n // \"check your credentials\" for a plain 404.\n if (response.status === 401) {\n spinner.fail(\"Login failed. Check your credentials.\");\n } else {\n spinner.fail(`Login failed: ${response.status} from ${baseUrl}/auth/login`);\n console.error(\n chalk.gray(\" Wrong API URL? Re-run with --api-url <url>, or `videan logout` to reset.\"),\n );\n }\n process.exit(1);\n }\n\n const data = (await response.json()) as { data: { token: string } };\n token = data.data.token;\n } catch (e: any) {\n spinner.fail(`Login failed: could not reach ${baseUrl} (${e?.message || e})`);\n process.exit(1);\n }\n\n // The login JWT expires in days. Trade it for an API key so the CLI keeps\n // working, and so a stolen config file can be revoked without a password\n // change. Requires an org, since keys are scoped to one.\n const session = new CloudClient({ apiKey: token, baseUrl });\n\n let orgId: string | undefined;\n try {\n const orgs = await session.orgs.list();\n if (opts.org) {\n // Named explicitly, so verify it rather than trusting it: scoping a key\n // to an org the user is not a member of produces a key that fails on\n // every call, at some later point, with no hint as to why.\n const match = orgs.find((o) => o.id === opts.org || o.name === opts.org);\n if (!match) {\n spinner.fail(`No organization ${opts.org} for this account.`);\n process.exit(1);\n }\n orgId = match.id;\n } else if (orgs.length > 1 && !process.stdin.isTTY) {\n spinner.fail(\n `Several organizations (${orgs.map((o) => o.id).join(\", \")}). Pass --org <id>.`,\n );\n process.exit(1);\n } else if (orgs.length > 1) {\n spinner.stop();\n const pick = await inquirer.prompt([\n {\n type: \"list\",\n name: \"orgId\",\n message: \"Organization:\",\n choices: orgs.map((o) => ({ name: `${o.name} (${o.id})`, value: o.id })),\n },\n ]);\n orgId = pick.orgId;\n spinner.start(\"Creating CLI key...\");\n } else {\n // One org, or none yet -- the caller below handles the empty case.\n orgId = orgs[0]?.id;\n }\n } catch (e: any) {\n spinner.fail(`Logged in, but could not list organizations: ${e?.message}`);\n process.exit(1);\n }\n\n if (!orgId) {\n // Nothing to scope a key to yet; the session token still works for the\n // one call needed to create an org.\n setApiKey(token);\n spinner.warn(\n chalk.yellow(\"Logged in, but you have no organization yet. Run `videan orgs create <name>`.\"),\n );\n return;\n }\n\n try {\n const key = await session.apiKeys.create({\n name: `cli@${os.hostname()}`,\n orgId,\n });\n setApiKey(key.key);\n setDefaultOrg(orgId);\n spinner.succeed(chalk.green(\"Logged in.\"));\n console.log(chalk.gray(` Org: ${orgId}`));\n console.log(chalk.gray(` Key: ${key.keyPrefix}\u2026 (revoke with \\`videan keys revoke ${key.id}\\`)`));\n } catch (e: any) {\n // Fall back to the session token rather than leaving the user logged out.\n setApiKey(token);\n setDefaultOrg(orgId);\n spinner.warn(\n chalk.yellow(`Logged in with a temporary session (key creation failed: ${e?.message}).`),\n );\n }\n });\n", "export const DEFAULT_PORT = 3000;\n\nexport const SUPPORTED_RUNTIMES = [\n \"node-20\",\n \"node-22\",\n \"python-3.11\",\n \"python-3.12\",\n \"bun-1\",\n \"deno-2\",\n] as const;\n\nexport type SupportedRuntime = (typeof SUPPORTED_RUNTIMES)[number];\n\nexport const DEPLOYMENT_STATUSES = [\n \"building\",\n \"deploying\",\n \"running\",\n \"failed\",\n // A task that was live and then died on its own -- OOM, panic, ECS\n // replacement. The reconcile pass sets it, so anything enumerating statuses\n // has to know about it.\n \"crashed\",\n \"stopped\",\n] as const;\n\nexport const ENVIRONMENTS = [\"preview\", \"production\"] as const;\n\nexport const ROLES = [\"admin\", \"member\"] as const;\n\nexport const DEFAULT_API_URL = \"https://api.videan.xyz/v1\";\n\n/** The zone every app's hostname hangs off. */\nexport const APP_DOMAIN = process.env.CLOUD_APP_DOMAIN || \"videan.xyz\";\n\n/**\n * The public URL of an app, from its slug.\n *\n * One definition, because it was previously written out by hand in three places\n * and one of them omitted the scheme -- so a deployment's `url` came back as a\n * bare `slug.videan.xyz` that no terminal, browser or `fetch` would follow,\n * while the app resource reported the same app as `https://slug.videan.xyz`.\n * HTTP redirects to HTTPS anyway, so the scheme is not optional in practice.\n */\nexport function appUrl(slug: string): string {\n return `https://${slug}.${APP_DOMAIN}`;\n}\n\n/**\n * Prefix for a single deployment's own hostname.\n *\n * Every deployment is reachable before it is promoted, which is what lets an\n * agent verify its own work without production riding on the answer. The label is\n * a hash of the deployment id rather than the id itself: nanoid's alphabet\n * contains `_` and uppercase, neither of which is legal in a DNS label, and\n * lowercasing or substituting would map two distinct deployments onto one\n * hostname -- serving whichever the router looked up first.\n *\n * The prefix keeps the namespace from colliding with app slugs: `*.videan.xyz`\n * is one flat namespace, and an app legitimately slugged the same as some\n * deployment's hash would otherwise steal its traffic.\n */\nexport const PREVIEW_LABEL_PREFIX = \"d-\";\n\nexport function previewUrl(label: string): string {\n return `https://${PREVIEW_LABEL_PREFIX}${label}.${APP_DOMAIN}`;\n}\n\n/** True for a hostname label that belongs to the preview namespace. */\nexport function isPreviewLabel(label: string): boolean {\n return label.startsWith(PREVIEW_LABEL_PREFIX);\n}\n\nexport const CONFIG_FILE_NAME = \"cloud.yaml\";\n\nexport const IGNORE_FILE_NAME = \".cloudignore\";\n\nexport const MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024; // 50MB\n\nexport const MAX_FILES_PER_PUSH = 10_000;\n", "/**\n * Fargate task sizing.\n *\n * Every app used to run at 256 CPU / 512 MB, hardcoded in `ecs-app.ts`. That is\n * below the working set of a stock Next.js server, so those apps were killed by\n * the OOM killer -- which surfaces as a container that exits without a message,\n * indistinguishable from a crash in the app's own code. Sizing is therefore not\n * a tuning knob; at the old default some runtimes could not work at all.\n *\n * Fargate accepts only specific (cpu, memory) pairs and rejects everything else\n * at RegisterTaskDefinition time. Validating here rather than there means the\n * caller is told which values are legal instead of reading an AWS error, and the\n * CLI can reject a bad `--memory` before a build starts.\n */\n\nimport type { Runtime } from \"./detect.js\";\n\n/**\n * Legal memory values (MiB) for each CPU unit, from the Fargate task-size table.\n *\n * Expressed as a range plus a step rather than a literal list because the larger\n * tiers have hundreds of legal values; a list would be unreadable and would drift.\n */\nconst FARGATE_SIZES: Record<number, { min: number; max: number; step: number }> = {\n 256: { min: 512, max: 2048, step: 512 },\n 512: { min: 1024, max: 4096, step: 1024 },\n 1024: { min: 2048, max: 8192, step: 1024 },\n 2048: { min: 4096, max: 16384, step: 1024 },\n 4096: { min: 8192, max: 30720, step: 1024 },\n 8192: { min: 16384, max: 61440, step: 4096 },\n 16384: { min: 32768, max: 122880, step: 8192 },\n};\n\nexport const FARGATE_CPUS = Object.keys(FARGATE_SIZES)\n .map(Number)\n .sort((a, b) => a - b);\n\n/**\n * 256 CPU is a special case: its legal memory values are 512, 1024 and 2048 --\n * it skips 1536, so the uniform step above would admit a value Fargate rejects.\n */\nconst CPU_256_MEMORY = [512, 1024, 2048];\n\nexport interface SizeValidation {\n ok: boolean;\n /** Why the pair is illegal, naming the legal alternatives. */\n error?: string;\n /** The legal memory values for the given CPU, for building an error message. */\n allowed?: number[];\n}\n\nfunction legalMemory(cpu: number): number[] {\n if (cpu === 256) return CPU_256_MEMORY;\n const spec = FARGATE_SIZES[cpu];\n if (!spec) return [];\n const values: number[] = [];\n for (let m = spec.min; m <= spec.max; m += spec.step) values.push(m);\n return values;\n}\n\n/**\n * Checks a (cpu, memory) pair against the Fargate table.\n *\n * Deliberately strict rather than snapping to the nearest legal value: silently\n * giving an app 2 GB when its owner asked for 1.5 GB means the bill and the\n * behaviour do not match what was requested, and a size that is quietly changed\n * is a size nobody can reason about when the app OOMs anyway.\n */\nexport function validateSize(cpu: number, memory: number): SizeValidation {\n if (!FARGATE_SIZES[cpu]) {\n return {\n ok: false,\n error: `cpu must be one of ${FARGATE_CPUS.join(\", \")} (got ${cpu})`,\n };\n }\n const allowed = legalMemory(cpu);\n if (!allowed.includes(memory)) {\n // Long lists are unhelpful in an error message; show the shape instead.\n const shown =\n allowed.length <= 6\n ? allowed.join(\", \")\n : `${allowed[0]}\u2013${allowed[allowed.length - 1]} in steps of ${allowed[1] - allowed[0]}`;\n return {\n ok: false,\n error: `memory ${memory} is not valid for cpu ${cpu}; allowed: ${shown}`,\n allowed,\n };\n }\n return { ok: true };\n}\n\nexport interface TaskSize {\n cpu: number;\n memory: number;\n}\n\n/**\n * The size an app gets when nobody chose one.\n *\n * Picked per runtime because the failure is runtime-specific: `next start` holds\n * a compiled server plus its module graph and does not fit in 512 MB, while a\n * Go binary is comfortable in it. Defaulting everything to the larger size would\n * quadruple the bill for the runtimes that do not need it; defaulting everything\n * to the smaller one is the bug this replaces.\n */\nexport function defaultSizeFor(runtime: Runtime): TaskSize {\n switch (runtime) {\n case \"nextjs\":\n return { cpu: 512, memory: 1024 };\n case \"nodejs\":\n case \"python\":\n // Comfortable for a framework plus dependencies, and the smallest legal\n // pair above the old default.\n return { cpu: 256, memory: 1024 };\n case \"go\":\n return { cpu: 256, memory: 512 };\n case \"custom\":\n // Unknown contents, so assume it is doing something real.\n return { cpu: 512, memory: 1024 };\n }\n}\n\n/**\n * How many tasks a size change or a scale-out may run at once.\n *\n * A bound exists because `instances` is caller-supplied and reaches RunTask\n * directly: a typo of 100 would launch a hundred Fargate tasks and bill for them\n * before anyone noticed. RunTask itself caps a single call at 10.\n */\nexport const MAX_INSTANCES = 10;\n", "/**\n * What a plan allows and what usage costs.\n *\n * Kept here rather than in the control API because three consumers need the same\n * numbers and must not disagree about them: the API enforces the limits, the\n * usage collector prices the metrics it records, and the CLI prints a bill. A\n * rate duplicated in two of those places is a bill that does not match the\n * invoice.\n *\n * Two things this deliberately is *not*:\n *\n * - **A payment integration.** Nothing here charges anyone. It computes what an\n * org owes; collecting it needs a payment processor and a human to accept its\n * terms, the same way SES production access does.\n * - **The authority on AWS cost.** These are the platform's *prices*. The real\n * cost of a Fargate task is in Cost Explorer, and the two will not match --\n * that difference is the margin, and pretending otherwise would make every\n * price change look like a metering bug.\n */\n\n/**\n * Metrics recorded in `usage_records`.\n *\n * `vcpu_seconds` and `gb_seconds` are what Fargate actually charges for, so they\n * are what a compute line is priced from; `task_seconds` is recorded alongside\n * them because it is the number a human recognises (\"this ran for 20 hours\") and\n * cannot be recovered from the other two without knowing the task size.\n *\n * `storage_mb`, not bytes: `usage_records.quantity` is an `integer`, and bytes\n * overflows int32 at 2.1 GB -- silently, wrapping negative, which would read as a\n * credit.\n */\nexport type UsageMetric =\n | \"task_seconds\"\n | \"vcpu_seconds\"\n | \"gb_seconds\"\n | \"requests\"\n | \"build_seconds\"\n | \"storage_mb\"\n | \"emails_sent\"\n | \"db_days\";\n\nexport const USAGE_METRICS: UsageMetric[] = [\n \"task_seconds\",\n \"vcpu_seconds\",\n \"gb_seconds\",\n \"requests\",\n \"build_seconds\",\n \"storage_mb\",\n \"emails_sent\",\n \"db_days\",\n];\n\n/**\n * Metrics that are a level rather than a total.\n *\n * A day's `storage_mb` row is the last sample taken that day, not a sum of\n * samples -- summing a level double-counts every byte for every time it was\n * observed. Billing a level means averaging the samples across the period, which\n * is why the two kinds cannot be aggregated by the same code path.\n */\nexport const GAUGE_METRICS: UsageMetric[] = [\"storage_mb\"];\n\nexport function isGauge(metric: string): boolean {\n return (GAUGE_METRICS as string[]).includes(metric);\n}\n\n/**\n * Price per unit, in cents. Fractional on purpose: a request costs a fifth of a\n * millionth of a cent and rounding each one to a cent would bill $10,000 for a\n * million requests.\n *\n * `task_seconds` is priced at zero because compute is already billed through\n * `vcpu_seconds` and `gb_seconds`. It is in the table rather than absent from it\n * so that a new metric added without a price is a visible zero here instead of an\n * `undefined` multiplied into `NaN` further down.\n */\nexport const RATES: Record<UsageMetric, number> = {\n task_seconds: 0,\n // Fargate on-demand in us-east-1 is ~$0.04048/vCPU-hour and ~$0.004445/GB-hour.\n vcpu_seconds: 0.002,\n gb_seconds: 0.00025,\n // $0.20 per million requests.\n requests: 0.00002,\n // ~$0.012 per build-minute.\n build_seconds: 0.02,\n // $0.05 per GB-month, charged per MB-month.\n storage_mb: 0.005,\n // $0.50 per thousand.\n emails_sent: 0.05,\n // ~$3/month for a managed schema, charged per day it exists.\n db_days: 10,\n};\n\n/** Human unit for each metric, for a bill a person has to read. */\nexport const METRIC_LABELS: Record<UsageMetric, string> = {\n task_seconds: \"Task-seconds served\",\n vcpu_seconds: \"vCPU-seconds\",\n gb_seconds: \"GB-seconds\",\n requests: \"Requests\",\n build_seconds: \"Build seconds\",\n storage_mb: \"Object storage (MB-month)\",\n emails_sent: \"Emails sent\",\n db_days: \"Managed Postgres (app-days)\",\n};\n\nexport interface Plan {\n id: string;\n name: string;\n /** Monthly subscription, in cents, before usage. */\n baseCents: number;\n /**\n * Usage covered by the base fee, in cents. An org that stays under this pays\n * exactly `baseCents` -- so the free plan is a real free tier rather than a\n * $0.03 invoice for a weekend project.\n */\n includedUsageCents: number;\n /** Apps that are not soft-deleted. */\n maxApps: number;\n maxInstancesPerApp: number;\n /** Ceilings on Fargate task size, which is the one knob that scales the bill. */\n maxCpu: number;\n maxMemory: number;\n /** Object-storage quota, enforced on upload. */\n maxStorageMb: number;\n postgres: boolean;\n customDomains: boolean;\n}\n\n/**\n * The plans.\n *\n * The limits that exist are the ones that bound *spend*: app count, instance\n * count and task size. There is deliberately no limit on requests, builds or\n * deploys -- an agent-built app that gets popular should get a bill, not an\n * outage, and a platform whose selling point is \"push and it is live\" cannot\n * answer a deploy with \"not on your plan\".\n */\nexport const PLANS: Record<string, Plan> = {\n free: {\n id: \"free\",\n name: \"Free\",\n baseCents: 0,\n includedUsageCents: 300,\n maxApps: 3,\n maxInstancesPerApp: 1,\n // One app at this size, running all month, is inside the included usage.\n maxCpu: 512,\n maxMemory: 1024,\n maxStorageMb: 1024,\n postgres: true,\n customDomains: false,\n },\n pro: {\n id: \"pro\",\n name: \"Pro\",\n baseCents: 2000,\n includedUsageCents: 2000,\n maxApps: 50,\n maxInstancesPerApp: 4,\n maxCpu: 4096,\n maxMemory: 8192,\n maxStorageMb: 100 * 1024,\n postgres: true,\n customDomains: true,\n },\n scale: {\n id: \"scale\",\n name: \"Scale\",\n baseCents: 20000,\n includedUsageCents: 20000,\n maxApps: 500,\n maxInstancesPerApp: 10,\n maxCpu: 16384,\n maxMemory: 122880,\n maxStorageMb: 1024 * 1024,\n postgres: true,\n customDomains: true,\n },\n};\n\n/**\n * The plan for a stored `orgs.plan` value.\n *\n * Falls back to free rather than throwing: the column is free text and an\n * unrecognised value must not take an org's whole control surface down with a\n * 500. Free is the safe direction -- its limits are the tightest, so a typo\n * cannot silently grant a larger allowance than anyone agreed to.\n */\nexport function planFor(plan: string | null | undefined): Plan {\n return PLANS[plan || \"free\"] ?? PLANS.free;\n}\n\nexport interface UsageLine {\n metric: UsageMetric | string;\n label: string;\n quantity: number;\n unitPriceCents: number;\n /** Rounded to whole cents only at the line, never per unit. */\n cents: number;\n}\n\nexport interface Invoice {\n plan: string;\n periodStart: string;\n periodEnd: string;\n lines: UsageLine[];\n /** Everything the usage lines add up to, before the included allowance. */\n usageCents: number;\n baseCents: number;\n includedUsageCents: number;\n /** Usage beyond the allowance. Zero, never negative: credit does not roll over. */\n overageCents: number;\n totalCents: number;\n}\n\n/**\n * Prices a period's usage.\n *\n * `quantities` is metric \u2192 quantity, already aggregated over the period (sums for\n * counters, averages for gauges -- see `GAUGE_METRICS`, and note that this\n * function cannot tell which it was given, so aggregating wrongly produces a\n * plausible bill rather than an error).\n */\nexport function priceUsage(\n quantities: Record<string, number>,\n plan: Plan,\n period: { start: Date; end: Date },\n): Invoice {\n const lines: UsageLine[] = [];\n for (const metric of USAGE_METRICS) {\n const quantity = quantities[metric] ?? 0;\n const rate = RATES[metric];\n // A zero-priced metric is still reported when there is something to report:\n // task-seconds is how an owner checks that the compute line is plausible.\n if (quantity === 0) continue;\n lines.push({\n metric,\n label: METRIC_LABELS[metric],\n quantity: Math.round(quantity * 100) / 100,\n unitPriceCents: rate,\n cents: Math.round(quantity * rate),\n });\n }\n // Metrics recorded by a newer collector than this pricing table knows about.\n // Listed at zero rather than dropped: an unpriced metric that vanishes from the\n // bill is indistinguishable from one that was never collected.\n for (const metric of Object.keys(quantities)) {\n if ((USAGE_METRICS as string[]).includes(metric)) continue;\n if (!quantities[metric]) continue;\n lines.push({\n metric,\n label: metric,\n quantity: quantities[metric],\n unitPriceCents: 0,\n cents: 0,\n });\n }\n\n const usageCents = lines.reduce((acc, l) => acc + l.cents, 0);\n const overageCents = Math.max(0, usageCents - plan.includedUsageCents);\n return {\n plan: plan.id,\n periodStart: period.start.toISOString(),\n periodEnd: period.end.toISOString(),\n lines,\n usageCents,\n baseCents: plan.baseCents,\n includedUsageCents: plan.includedUsageCents,\n overageCents,\n totalCents: plan.baseCents + overageCents,\n };\n}\n\n/** `1234` \u2192 `\"$12.34\"`. For output a person reads, not for arithmetic. */\nexport function formatCents(cents: number): string {\n const sign = cents < 0 ? \"-\" : \"\";\n const abs = Math.abs(Math.round(cents));\n return `${sign}$${Math.floor(abs / 100)}.${String(abs % 100).padStart(2, \"0\")}`;\n}\n\nexport interface LimitCheck {\n ok: boolean;\n /** Names the limit and the plan, so the error says what to do about it. */\n error?: string;\n code?: string;\n}\n\nexport function allowed(): LimitCheck {\n return { ok: true };\n}\n\nfunction denied(code: string, error: string): LimitCheck {\n return { ok: false, error, code };\n}\n\n/** Whether one more app is within the plan. `current` excludes deleted apps. */\nexport function checkAppCount(plan: Plan, current: number): LimitCheck {\n if (current < plan.maxApps) return allowed();\n return denied(\n \"PLAN_LIMIT_APPS\",\n `The ${plan.name} plan allows ${plan.maxApps} app${plan.maxApps === 1 ? \"\" : \"s\"} ` +\n `and this org has ${current}. Delete one or upgrade the plan.`,\n );\n}\n\n/**\n * Whether a requested task shape is within the plan.\n *\n * Checked as a triple rather than three separate limits because they multiply:\n * the thing being bounded is the bill, and 4 instances of a small task costs the\n * same as one large one.\n */\nexport function checkTaskShape(\n plan: Plan,\n shape: { cpu?: number | null; memory?: number | null; instances?: number | null },\n): LimitCheck {\n if (shape.instances != null && shape.instances > plan.maxInstancesPerApp) {\n return denied(\n \"PLAN_LIMIT_INSTANCES\",\n `The ${plan.name} plan allows ${plan.maxInstancesPerApp} instance` +\n `${plan.maxInstancesPerApp === 1 ? \"\" : \"s\"} per app (asked for ${shape.instances}).`,\n );\n }\n if (shape.cpu != null && shape.cpu > plan.maxCpu) {\n return denied(\n \"PLAN_LIMIT_CPU\",\n `The ${plan.name} plan allows up to ${plan.maxCpu} CPU units per task (asked for ${shape.cpu}).`,\n );\n }\n if (shape.memory != null && shape.memory > plan.maxMemory) {\n return denied(\n \"PLAN_LIMIT_MEMORY\",\n `The ${plan.name} plan allows up to ${plan.maxMemory} MB per task (asked for ${shape.memory}).`,\n );\n }\n return allowed();\n}\n\n/** Whether a custom domain is within the plan. */\nexport function checkCustomDomain(plan: Plan): LimitCheck {\n if (plan.customDomains) return allowed();\n return denied(\n \"PLAN_LIMIT_DOMAINS\",\n `Custom domains are not included in the ${plan.name} plan. Every app keeps its ` +\n `platform hostname, which needs no configuration.`,\n );\n}\n", "import type {\n App,\n Snapshot,\n Deployment,\n Secret,\n Organization,\n OrgMember,\n LogEntry,\n LogPage,\n AppMetrics,\n CreateAppRequest,\n ApiResponse,\n Environment,\n AppHealth,\n BuildLogs,\n ApiKey,\n ApiKeyWithSecret,\n Job,\n OrgUsage,\n AppUsage,\n PlanInfo,\n Visibility,\n} from \"@cloud/shared\";\nimport { DEFAULT_API_URL } from \"@cloud/shared\";\n\n/**\n * Only all-lowercase snake_case, which is what the API emits for its own fields.\n *\n * Deliberately narrow. Data the platform carries on behalf of a user also\n * travels through here -- secret names like `DATABASE_URL`, file paths like\n * `app/page.js` -- and rewriting one of those would corrupt it. Uppercase, dots\n * and slashes all fail this test, so those pass through untouched.\n */\nconst SNAKE_KEY = /^[a-z0-9]+(_[a-z0-9]+)+$/;\n\n/**\n * Fields whose *contents* belong to the caller, not to the API.\n *\n * A job's payload is a blob the app wrote and the app will read back; renaming\n * `order_id` inside it to `orderId` would corrupt the app's own data on its way\n * through the SDK. Same reasoning as the narrow key pattern above -- the key\n * itself is still converted, only what hangs off it is left alone.\n */\nconst OPAQUE_KEYS = new Set([\"payload\", \"files\", \"metadata\"]);\n\n/**\n * Recursively rewrites snake_case keys to camelCase.\n *\n * The API's wire format is snake_case (`created_at`, `key_prefix`); the SDK's\n * types are camelCase. Nothing used to bridge the two -- `response.json()` was\n * simply cast to the typed shape -- so every such field was `undefined` at\n * runtime while the compiler insisted it was a string. That is the worst\n * possible failure mode for a typed client: `deployment.createdAt` produced\n * `NaN` elapsed times and `key.keyPrefix` printed \"undefined\u2026\", with no error\n * anywhere. The conversion belongs here rather than in the API, which other\n * consumers already read as snake_case.\n */\nexport function camelizeDeep(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(camelizeDeep);\n if (value === null || typeof value !== \"object\") return value;\n // Dates survive JSON as strings, so anything object-shaped here is a plain\n // object from JSON.parse.\n const out: Record<string, unknown> = {};\n for (const [key, v] of Object.entries(value as Record<string, unknown>)) {\n const camel = SNAKE_KEY.test(key)\n ? key.replace(/_([a-z0-9])/g, (_, c: string) => c.toUpperCase())\n : key;\n out[camel] = OPAQUE_KEYS.has(camel) ? v : camelizeDeep(v);\n }\n return out;\n}\n\n/**\n * The type-level counterpart of `camelizeDeep`.\n *\n * Some shared types describe the *wire* shape and keep its snake_case (`LogPage`,\n * `BuildLogs`), because that is what a non-SDK consumer reading the API sees. The\n * SDK rewrites those keys at runtime, so returning the wire type from an SDK\n * method would reintroduce exactly the bug `camelizeDeep` was written to fix: a\n * field the compiler swears is a string and that is `undefined` at runtime. This\n * makes the declared type follow the conversion instead of contradicting it.\n */\ntype CamelKey<K extends string> = K extends `${infer A}_${infer B}`\n ? `${A}${Capitalize<CamelKey<B>>}`\n : K;\n\nexport type Camelize<T> = T extends (infer U)[]\n ? Camelize<U>[]\n : T extends object\n ? { [K in keyof T as K extends string ? CamelKey<K> : K]: Camelize<T[K]> }\n : T;\n\nexport class CloudError extends Error {\n public readonly code: string;\n public readonly status: number;\n public readonly details?: Record<string, unknown>;\n\n constructor(message: string, code: string, status: number, details?: Record<string, unknown>) {\n super(message);\n this.name = \"CloudError\";\n this.code = code;\n this.status = status;\n this.details = details;\n }\n}\n\nexport interface CloudClientOptions {\n apiKey: string;\n baseUrl?: string;\n}\n\nexport class CloudClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n\n public readonly apps: AppsNamespace;\n public readonly secrets: SecretsNamespace;\n public readonly orgs: OrgsNamespace;\n public readonly apiKeys: ApiKeysNamespace;\n public readonly storage: StorageNamespace;\n public readonly email: EmailNamespace;\n public readonly jobs: JobsNamespace;\n\n constructor(options: CloudClientOptions) {\n this.apiKey = options.apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULT_API_URL).replace(/\\/$/, \"\");\n this.apps = new AppsNamespace(this);\n this.secrets = new SecretsNamespace(this);\n this.orgs = new OrgsNamespace(this);\n this.apiKeys = new ApiKeysNamespace(this);\n this.storage = new StorageNamespace(this);\n this.email = new EmailNamespace(this);\n this.jobs = new JobsNamespace(this);\n }\n\n /**\n * The plan catalogue. Unauthenticated on the API, so this works with any key --\n * including a placeholder one -- and can be called before an account exists to\n * show what an upgrade would allow.\n */\n async plans(): Promise<PlanInfo[]> {\n const res = await this.request<ApiResponse<PlanInfo[]>>(\"GET\", \"/plans\");\n return res.data;\n }\n\n async request<T>(method: string, path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n \"Authorization\": `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n };\n\n // `fetch` reports every transport failure as the same bare `TypeError: fetch\n // failed`, with the cause one level down and the URL nowhere in it. A caller\n // seeing that cannot tell a DNS mistake from a reset connection from an API\n // that is down, which is the same class of unhelpfulness as the old\n // \"check your credentials\" for a 404. Status 0 says the request never got an\n // answer, so a retry is reasonable -- unlike a 4xx.\n let response: Response;\n try {\n response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n } catch (e: any) {\n const cause = e?.cause?.code || e?.cause?.message || e?.message || \"unknown error\";\n throw new CloudError(\n `Could not reach ${url} (${cause}).`,\n \"network_error\",\n 0,\n );\n }\n\n if (!response.ok) {\n const errorBody = await response.json().catch(() => ({}));\n const err = (errorBody as { error?: { code?: string; message?: string; details?: Record<string, unknown> } }).error;\n throw new CloudError(\n err?.message ?? `Request failed with status ${response.status}`,\n err?.code ?? \"unknown_error\",\n response.status,\n err?.details,\n );\n }\n\n if (response.status === 204) {\n return undefined as T;\n }\n\n return camelizeDeep(await response.json()) as T;\n }\n}\n\nclass AppsNamespace {\n constructor(private client: CloudClient) {}\n\n async create(opts: {\n name: string;\n orgId: string;\n postgres?: boolean;\n /** Gives the app an object-storage prefix; see `client.storage`. */\n storage?: boolean;\n /** Lets the app send mail through the platform; see `client.email`. */\n email?: boolean;\n /**\n * Who may reach the running app: \"private\" | \"org\" | \"authenticated\" |\n * \"public\", narrowest first. Defaults to \"org\". Prefer this over\n * `authRequired`, which cannot express the difference between \"only the\n * people I invite\" and \"anyone in my org\".\n */\n visibility?: Visibility;\n /** @deprecated Use `visibility`. false is equivalent to \"public\". */\n authRequired?: boolean;\n }): Promise<App> {\n const body: CreateAppRequest = {\n name: opts.name,\n org_id: opts.orgId,\n postgres_enabled: opts.postgres,\n storage_enabled: opts.storage,\n email_enabled: opts.email,\n auth_required: opts.authRequired,\n visibility: opts.visibility,\n };\n const res = await this.client.request<ApiResponse<App>>(\"POST\", \"/apps\", body);\n return res.data;\n }\n\n /**\n * Changes an app's settings.\n *\n * `restartRequired` is true when the change only takes effect on a new\n * container -- size, scale and postgres. The API reports it rather than\n * restarting on its own: a restart is a brief interruption, and doing it as a\n * side effect of a settings write is not the caller's decision to discover\n * afterwards. Follow with `restart()` when it comes back true.\n */\n async update(\n appId: string,\n changes: {\n name?: string;\n /**\n * Who may reach the running app. Admin-level: an editor may deploy the\n * app but not change who can open it.\n *\n * Note that `authRequired: true` will not narrow an app that is already\n * gated -- the boolean cannot tell \"private\" from \"org\", so the API\n * leaves the tier alone rather than risk widening a private app. Send\n * `visibility` to move between the gated tiers.\n */\n visibility?: Visibility;\n /** @deprecated Use `visibility`. false is equivalent to \"public\". */\n authRequired?: boolean;\n /** \"active\" or \"paused\". */\n status?: \"active\" | \"paused\";\n cpu?: number;\n memory?: number;\n instances?: number;\n /** Requests per minute per client, or null to remove the limit. */\n rateLimitPerMinute?: number | null;\n postgres?: boolean;\n storage?: boolean;\n email?: boolean;\n },\n ): Promise<App & { restartRequired?: boolean }> {\n const body: Record<string, unknown> = {};\n if (changes.name !== undefined) body.name = changes.name;\n if (changes.authRequired !== undefined) body.auth_required = changes.authRequired;\n if (changes.visibility !== undefined) body.visibility = changes.visibility;\n if (changes.status !== undefined) body.status = changes.status;\n if (changes.cpu !== undefined) body.cpu = changes.cpu;\n if (changes.memory !== undefined) body.memory = changes.memory;\n if (changes.instances !== undefined) body.instances = changes.instances;\n // Sent when explicitly null, which is how a limit is removed -- omitting it\n // would leave the old limit in place and look like the call did nothing.\n if (changes.rateLimitPerMinute !== undefined) {\n body.rate_limit_per_minute = changes.rateLimitPerMinute;\n }\n if (changes.postgres !== undefined) body.postgres_enabled = changes.postgres;\n if (changes.storage !== undefined) body.storage_enabled = changes.storage;\n if (changes.email !== undefined) body.email_enabled = changes.email;\n\n const res = await this.client.request<ApiResponse<App & { restartRequired?: boolean }>>(\n \"PATCH\",\n `/apps/${appId}`,\n body,\n );\n return res.data;\n }\n\n async list(orgId: string): Promise<App[]> {\n const res = await this.client.request<ApiResponse<App[]>>(\n \"GET\",\n `/apps?org_id=${encodeURIComponent(orgId)}`,\n );\n return res.data;\n }\n\n async get(id: string): Promise<App> {\n const res = await this.client.request<ApiResponse<App>>(\"GET\", `/apps/${id}`);\n return res.data;\n }\n\n /**\n * Deletes the app and tears down its AWS resources.\n *\n * Teardown is fault-isolated per resource, so a partial failure still deletes\n * the app and reports what leaked in `warnings` (HTTP 207) rather than\n * aborting. An empty array means everything was released.\n */\n async delete(id: string): Promise<{ warnings: { step: string; error?: string }[] }> {\n const res = await this.client.request<{\n data: App;\n warnings?: { step: string; error?: string }[];\n }>(\"DELETE\", `/apps/${id}`);\n return { warnings: res?.warnings ?? [] };\n }\n\n /**\n * Pushes a snapshot.\n *\n * `files` carries text. Anything that is not valid UTF-8 \u2014 an image, a\n * favicon, a compiled binary \u2014 must go in `binaryFiles` as base64, because\n * JSON cannot carry arbitrary bytes in a string and a value that is silently\n * re-encoded arrives corrupted. The two are separate maps rather than one\n * with a flag: base64 is not detectable (`\"data\"` is valid base64 and valid\n * text), so the encoding has to be stated by the caller.\n */\n async push(\n appId: string,\n files: Record<string, string>,\n message?: string,\n binaryFiles?: Record<string, string>,\n ): Promise<Snapshot> {\n const res = await this.client.request<ApiResponse<Snapshot>>(\"POST\", `/apps/${appId}/push`, {\n files,\n message,\n // Request bodies are not camelized \u2014 only responses are \u2014 so the wire\n // name has to be written out here.\n ...(binaryFiles && Object.keys(binaryFiles).length > 0 ? { binary_files: binaryFiles } : {}),\n });\n return res.data;\n }\n\n async deploy(appId: string, snapshotId: string, environment?: Environment): Promise<Deployment> {\n const res = await this.client.request<ApiResponse<Deployment>>(\"POST\", `/apps/${appId}/deploy`, {\n snapshot_id: snapshotId,\n environment,\n });\n return res.data;\n }\n\n async promote(deploymentId: string): Promise<Deployment> {\n const res = await this.client.request<ApiResponse<Deployment>>(\"POST\", `/deployments/${deploymentId}/promote`, {});\n return res.data;\n }\n\n async rollback(appId: string): Promise<Deployment> {\n const res = await this.client.request<ApiResponse<Deployment>>(\"POST\", `/apps/${appId}/rollback`, {});\n return res.data;\n }\n\n async checkDeployment(deploymentId: string): Promise<Deployment> {\n const res = await this.client.request<ApiResponse<Deployment>>(\"POST\", `/deployments/${deploymentId}/status`, {});\n return res.data;\n }\n\n /**\n * A page of the app's logs, newest last.\n *\n * Returns a page rather than a bare array of entries, which is what this used to\n * be: an array cannot say whether there is more to fetch, and the endpoint\n * behind it silently answered with the newest few log streams as though they\n * were the whole app. To page, pass the previous response's `nextToken`; to\n * follow, pass the last event's `timestamp` as `since`.\n *\n * `since`/`until` accept an ISO timestamp, epoch millis, or an offset like\n * `15m`. `q` is a literal substring; `pattern` is CloudWatch filter syntax --\n * pass one or the other, not both.\n */\n async logs(\n appId: string,\n opts?: {\n limit?: number;\n since?: string;\n until?: string;\n q?: string;\n pattern?: string;\n /** Log stream prefix, to read one instance instead of all of them. */\n instance?: string;\n nextToken?: string;\n },\n ): Promise<Camelize<LogPage>> {\n const params = new URLSearchParams();\n if (opts?.limit) params.set(\"limit\", String(opts.limit));\n if (opts?.since) params.set(\"since\", opts.since);\n if (opts?.until) params.set(\"until\", opts.until);\n if (opts?.q) params.set(\"q\", opts.q);\n if (opts?.pattern) params.set(\"pattern\", opts.pattern);\n if (opts?.instance) params.set(\"instance\", opts.instance);\n if (opts?.nextToken) params.set(\"next_token\", opts.nextToken);\n const query = params.toString();\n const path = `/apps/${appId}/logs${query ? `?${query}` : \"\"}`;\n const res = await this.client.request<ApiResponse<Camelize<LogPage>>>(\"GET\", path);\n return res.data;\n }\n\n /**\n * Follows the app's logs, yielding each line as it appears.\n *\n * Polling rather than the API's SSE tail: an async generator works in node\n * without `EventSource`, and it carries the bearer token the same way as every\n * other call. The cursor is the last event's timestamp and the window is\n * reopened *at* it rather than after it -- several lines share a millisecond, so\n * advancing past it would drop the rest of them -- with the boundary\n * millisecond's lines remembered to suppress the repeat.\n */\n async *followLogs(\n appId: string,\n opts?: { since?: string; q?: string; pattern?: string; instance?: string; intervalMs?: number },\n ): AsyncGenerator<LogEntry> {\n const interval = opts?.intervalMs ?? 2000;\n let since = opts?.since ?? \"60s\";\n let seenAtCursor = new Set<string>();\n\n while (true) {\n const page = await this.logs(appId, {\n since,\n limit: 500,\n q: opts?.q,\n pattern: opts?.pattern,\n instance: opts?.instance,\n });\n\n for (const event of page.events) {\n const key = `${event.stream || \"\"} ${event.message}`;\n if (event.timestamp === since) {\n if (seenAtCursor.has(key)) continue;\n seenAtCursor.add(key);\n } else {\n since = event.timestamp;\n seenAtCursor = new Set([key]);\n }\n yield event;\n }\n\n await new Promise((r) => setTimeout(r, interval));\n }\n }\n\n /**\n * Traffic, latency and resource use over a window.\n *\n * `since`/`until` take the same values as `logs`, deliberately: an owner who\n * spots a spike here reads the logs for the same period next.\n *\n * Note the series keys arrive camelized like every other field on this client,\n * so the API's `client_errors` is `clientErrors` and `latency_p95` is\n * `latencyP95`.\n */\n async metrics(\n appId: string,\n opts?: { since?: string; until?: string },\n ): Promise<Camelize<AppMetrics>> {\n const params = new URLSearchParams();\n if (opts?.since) params.set(\"since\", opts.since);\n if (opts?.until) params.set(\"until\", opts.until);\n const query = params.toString();\n const res = await this.client.request<ApiResponse<Camelize<AppMetrics>>>(\n \"GET\",\n `/apps/${appId}/metrics${query ? `?${query}` : \"\"}`,\n );\n return res.data;\n }\n\n /**\n * Live runtime state, including the container's exit code when it has crashed.\n * A deployment stays \"running\" in the database after the task dies, so this is\n * the only way to tell a healthy app from a crash loop.\n */\n /**\n * What this app cost in a month (`YYYY-MM`, default the month in progress),\n * priced at list rates with no allowance applied -- the plan's included usage\n * belongs to the org, so per-app figures would otherwise sum past the invoice.\n */\n async usage(appId: string, period?: string): Promise<AppUsage> {\n const query = period ? `?period=${encodeURIComponent(period)}` : \"\";\n const res = await this.client.request<ApiResponse<AppUsage>>(\n \"GET\",\n `/apps/${appId}/usage${query}`,\n );\n return res.data;\n }\n\n async health(appId: string): Promise<AppHealth> {\n const res = await this.client.request<ApiResponse<AppHealth>>(\"GET\", `/apps/${appId}/health`);\n return res.data;\n }\n\n /**\n * Build output for a deployment. Poll with the previous response's `next_token`\n * to stream a build as it runs.\n */\n async buildLogs(deploymentId: string, nextToken?: string): Promise<Camelize<BuildLogs>> {\n const query = nextToken ? `?next_token=${encodeURIComponent(nextToken)}` : \"\";\n const res = await this.client.request<ApiResponse<Camelize<BuildLogs>>>(\n \"GET\",\n `/deployments/${deploymentId}/build-logs${query}`,\n );\n return res.data;\n }\n}\n\nclass ApiKeysNamespace {\n constructor(private client: CloudClient) {}\n\n /**\n * Creates a key. The plaintext `key` is present on this response only -- the\n * server stores a hash and cannot return it again.\n */\n async create(opts: {\n name: string;\n orgId: string;\n expiresInDays?: number;\n /**\n * Pass an app id for a **service token**: a credential pinned to that one app,\n * for code running inside it. It cannot reach another app, issue further keys,\n * list the org's keys or revoke anything -- which is what makes it safe to\n * ship inside a container. A key without this acts as its creator across\n * every app in the org, so do not put one in a deployed app.\n */\n appId?: string;\n }): Promise<ApiKeyWithSecret> {\n const res = await this.client.request<ApiResponse<ApiKeyWithSecret>>(\"POST\", \"/api-keys\", {\n name: opts.name,\n org_id: opts.orgId,\n expires_in_days: opts.expiresInDays,\n app_id: opts.appId,\n });\n return res.data;\n }\n\n async list(orgId: string): Promise<ApiKey[]> {\n const res = await this.client.request<ApiResponse<ApiKey[]>>(\n \"GET\",\n `/api-keys?org_id=${encodeURIComponent(orgId)}`,\n );\n return res.data;\n }\n\n async revoke(id: string): Promise<void> {\n await this.client.request<void>(\"DELETE\", `/api-keys/${id}`);\n }\n}\n\nclass SecretsNamespace {\n constructor(private client: CloudClient) {}\n\n async set(appId: string, key: string, value: string): Promise<Secret> {\n const res = await this.client.request<ApiResponse<Secret>>(\"POST\", `/apps/${appId}/secrets`, {\n key,\n value,\n });\n return res.data;\n }\n\n async list(appId: string): Promise<Secret[]> {\n const res = await this.client.request<ApiResponse<Secret[]>>(\"GET\", `/apps/${appId}/secrets`);\n return res.data;\n }\n\n async delete(appId: string, key: string): Promise<void> {\n await this.client.request<void>(\"DELETE\", `/apps/${appId}/secrets/${key}`);\n }\n}\n\nexport interface StoredObject {\n key: string;\n size: number;\n lastModified: string | null;\n etag: string | null;\n}\n\n/**\n * Object storage for an app.\n *\n * Bytes never pass through the control API: it hands out a presigned S3 URL and\n * the transfer goes direct. `upload` and `download` wrap that two-step for the\n * common case; `presign` is there for handing a URL to a browser so an upload\n * skips the app's own server entirely.\n *\n * Best reached with a **service token** (`apiKeys.create({ appId })`) from inside\n * the app, so the credential in the container cannot touch anything else.\n */\nclass StorageNamespace {\n constructor(private client: CloudClient) {}\n\n async list(\n appId: string,\n opts: { prefix?: string; limit?: number; cursor?: string } = {},\n ): Promise<{ objects: StoredObject[]; nextCursor: string | null }> {\n const q = new URLSearchParams();\n if (opts.prefix) q.set(\"prefix\", opts.prefix);\n if (opts.limit) q.set(\"limit\", String(opts.limit));\n if (opts.cursor) q.set(\"cursor\", opts.cursor);\n const query = q.toString() ? `?${q}` : \"\";\n const res = await this.client.request<\n ApiResponse<{ objects: StoredObject[]; nextCursor: string | null }>\n >(\"GET\", `/apps/${appId}/storage/objects${query}`);\n return res.data;\n }\n\n /** Every object under the prefix, paged through for you. */\n async listAll(appId: string, prefix?: string): Promise<StoredObject[]> {\n const all: StoredObject[] = [];\n let cursor: string | undefined;\n do {\n const page = await this.list(appId, { prefix, cursor, limit: 1000 });\n all.push(...page.objects);\n cursor = page.nextCursor ?? undefined;\n } while (cursor);\n return all;\n }\n\n async usage(appId: string): Promise<{ objects: number; bytes: number }> {\n const res = await this.client.request<ApiResponse<{ objects: number; bytes: number }>>(\n \"GET\",\n `/apps/${appId}/storage/usage`,\n );\n return res.data;\n }\n\n /** Metadata for one object, or null when it is not there. */\n async head(appId: string, key: string): Promise<StoredObject | null> {\n try {\n const res = await this.client.request<ApiResponse<StoredObject>>(\n \"GET\",\n `/apps/${appId}/storage/object?key=${encodeURIComponent(key)}`,\n );\n return res.data;\n } catch (e) {\n if (e instanceof CloudError && e.status === 404) return null;\n throw e;\n }\n }\n\n async delete(appId: string, key: string): Promise<void> {\n await this.client.request<ApiResponse<unknown>>(\n \"DELETE\",\n `/apps/${appId}/storage/object?key=${encodeURIComponent(key)}`,\n );\n }\n\n /**\n * A short-lived URL for one key and one method. Hand a `put` URL to a browser to\n * upload without the bytes touching the app, or a `get` URL to share a private\n * object for a few minutes. Treat it as a credential: anyone holding it has that\n * access until it expires.\n */\n async presign(\n appId: string,\n key: string,\n opts: {\n method?: \"put\" | \"get\";\n expiresIn?: number;\n contentType?: string;\n download?: string;\n } = {},\n ): Promise<{ url: string; method: string; key: string; expiresIn: number }> {\n const res = await this.client.request<\n ApiResponse<{ url: string; method: string; key: string; expiresIn: number }>\n >(\"POST\", `/apps/${appId}/storage/presign`, {\n key,\n method: opts.method ?? \"get\",\n expires_in: opts.expiresIn,\n content_type: opts.contentType,\n download: opts.download,\n });\n return res.data;\n }\n\n /**\n * Presigns and uploads in one call.\n *\n * `contentType` is signed into the URL, so it is sent on the PUT as well --\n * omitting it there would make S3 reject the signature with an opaque 403.\n */\n async upload(\n appId: string,\n key: string,\n body: Uint8Array | ArrayBuffer | string | Blob,\n opts: { contentType?: string } = {},\n ): Promise<StoredObject> {\n const signed = await this.presign(appId, key, {\n method: \"put\",\n contentType: opts.contentType,\n });\n const res = await fetch(signed.url, {\n method: \"PUT\",\n headers: opts.contentType ? { \"Content-Type\": opts.contentType } : undefined,\n body: body as BodyInit,\n });\n if (!res.ok) {\n // S3's own error is XML, not the platform's JSON envelope, so it is passed\n // through as text rather than parsed into a CloudError shape it does not have.\n throw new CloudError(\n `Upload failed with status ${res.status}: ${(await res.text()).slice(0, 300)}`,\n \"upload_failed\",\n res.status,\n );\n }\n return { key, size: 0, lastModified: null, etag: res.headers.get(\"etag\") };\n }\n\n /** Presigns and fetches. Returns the raw bytes; decode as the caller sees fit. */\n async download(appId: string, key: string): Promise<Uint8Array> {\n const signed = await this.presign(appId, key, { method: \"get\" });\n const res = await fetch(signed.url);\n if (!res.ok) {\n throw new CloudError(\n `Download failed with status ${res.status}`,\n res.status === 404 ? \"not_found\" : \"download_failed\",\n res.status,\n );\n }\n return new Uint8Array(await res.arrayBuffer());\n }\n}\n\nexport interface EmailQuota {\n sent: number;\n quota: number;\n remaining: number;\n /** The API sends `resets_at`; `camelizeDeep` renames it on the way in. */\n resetsAt: string;\n}\n\nexport interface SentEmail {\n messageId: string | null;\n to: string[];\n from: string;\n quota: EmailQuota;\n}\n\n/**\n * Transactional email sent by the platform on the app's behalf.\n *\n * There is no `from`: mail goes out as `app-<slug>@<platform domain>`, because an\n * app able to choose its own From could send a credible password-reset email as\n * the platform. Use `replyTo` to route replies to your own address.\n */\nclass EmailNamespace {\n constructor(private client: CloudClient) {}\n\n /**\n * Sends one message, to up to 50 recipients, as a single all-or-nothing send.\n *\n * Throws `CloudError` with status 429 once the app's daily quota is used up, and\n * 502 when the provider rejected the message -- the message text carries the\n * reason, which while the sending account is sandboxed is usually that the\n * recipient address is not verified.\n */\n async send(\n appId: string,\n message: {\n to: string | string[];\n subject: string;\n text?: string;\n html?: string;\n replyTo?: string;\n },\n ): Promise<SentEmail> {\n const res = await this.client.request<ApiResponse<SentEmail>>(\n \"POST\",\n `/apps/${appId}/email`,\n {\n to: message.to,\n subject: message.subject,\n text: message.text,\n html: message.html,\n reply_to: message.replyTo,\n },\n );\n return res.data;\n }\n\n /** Sends used today and what is left. Resets at UTC midnight. */\n async quota(appId: string): Promise<EmailQuota> {\n const res = await this.client.request<ApiResponse<EmailQuota>>(\n \"GET\",\n `/apps/${appId}/email/quota`,\n );\n return res.data;\n }\n}\n\n/**\n * Background jobs.\n *\n * A job is delivered as a POST to a path on the app itself, so the \"worker\" is a\n * route in the app the agent already wrote. Delivery is at least once -- retries\n * mean a handler can see the same job twice -- which is what `idempotencyKey`\n * on the enqueue side and the `x-videan-job-attempt` header on the receiving side\n * are for.\n */\nclass JobsNamespace {\n constructor(private client: CloudClient) {}\n\n /**\n * Enqueues a job.\n *\n * Pass `idempotencyKey` when the caller may retry this enqueue: a repeat returns\n * the job already queued, with `deduplicated: true`, instead of a second copy of\n * the work.\n */\n async enqueue(\n appId: string,\n options: {\n queue?: string;\n /** Path on the app the job is POSTed to. Defaults to `/jobs`. */\n path?: string;\n method?: \"POST\" | \"PUT\" | \"PATCH\";\n payload?: unknown;\n maxAttempts?: number;\n timeoutSeconds?: number;\n delaySeconds?: number;\n idempotencyKey?: string;\n } = {},\n ): Promise<Job> {\n const res = await this.client.request<ApiResponse<Job>>(\"POST\", `/apps/${appId}/jobs`, {\n queue: options.queue,\n path: options.path,\n method: options.method,\n payload: options.payload,\n max_attempts: options.maxAttempts,\n timeout_seconds: options.timeoutSeconds,\n delay_seconds: options.delaySeconds,\n idempotency_key: options.idempotencyKey,\n });\n return res.data;\n }\n\n /** A page of jobs, newest first, with the queue depth per status alongside. */\n async list(\n appId: string,\n options: { status?: string; queue?: string; limit?: number } = {},\n ): Promise<{ jobs: Job[]; counts: Record<string, number> }> {\n const params = new URLSearchParams();\n if (options.status) params.set(\"status\", options.status);\n if (options.queue) params.set(\"queue\", options.queue);\n if (options.limit) params.set(\"limit\", String(options.limit));\n const query = params.toString();\n const res = await this.client.request<ApiResponse<{ jobs: Job[]; counts: Record<string, number> }>>(\n \"GET\",\n `/apps/${appId}/jobs${query ? `?${query}` : \"\"}`,\n );\n return res.data;\n }\n\n async get(appId: string, jobId: string): Promise<Job> {\n const res = await this.client.request<ApiResponse<Job>>(\"GET\", `/apps/${appId}/jobs/${jobId}`);\n return res.data;\n }\n\n /** Runs a dead job again, from a clean attempt count. */\n async retry(appId: string, jobId: string): Promise<Job> {\n const res = await this.client.request<ApiResponse<Job>>(\n \"POST\",\n `/apps/${appId}/jobs/${jobId}/retry`,\n );\n return res.data;\n }\n\n /** Cancels a job that has not started. Throws 409 once it is running. */\n async cancel(appId: string, jobId: string): Promise<Job> {\n const res = await this.client.request<ApiResponse<Job>>(\n \"POST\",\n `/apps/${appId}/jobs/${jobId}/cancel`,\n );\n return res.data;\n }\n}\n\nclass OrgsNamespace {\n constructor(private client: CloudClient) {}\n\n async list(): Promise<Organization[]> {\n const res = await this.client.request<ApiResponse<Organization[]>>(\"GET\", \"/orgs\");\n return res.data;\n }\n\n async create(name: string): Promise<Organization> {\n const res = await this.client.request<ApiResponse<Organization>>(\"POST\", \"/orgs\", { name });\n return res.data;\n }\n\n async get(id: string): Promise<Organization> {\n const res = await this.client.request<ApiResponse<Organization>>(\"GET\", `/orgs/${id}`);\n return res.data;\n }\n\n async members(id: string): Promise<OrgMember[]> {\n const res = await this.client.request<ApiResponse<OrgMember[]>>(\"GET\", `/orgs/${id}/members`);\n return res.data;\n }\n\n async invite(id: string, email: string, role: \"admin\" | \"member\" = \"member\"): Promise<void> {\n await this.client.request<ApiResponse<unknown>>(\"POST\", `/orgs/${id}/members`, { email, role });\n }\n\n async removeMember(id: string, userId: string): Promise<void> {\n await this.client.request<ApiResponse<unknown>>(\"DELETE\", `/orgs/${id}/members/${userId}`);\n }\n\n /**\n * Metered usage and the priced invoice for a month (`YYYY-MM`, default the month\n * in progress). Read-only: nothing in the SDK changes a plan or takes a payment.\n */\n async usage(id: string, period?: string): Promise<OrgUsage> {\n const query = period ? `?period=${encodeURIComponent(period)}` : \"\";\n const res = await this.client.request<ApiResponse<OrgUsage>>(\n \"GET\",\n `/orgs/${id}/usage${query}`,\n );\n return res.data;\n }\n}\n", "export const DEFAULT_PORT = 3000;\n\nexport const SUPPORTED_RUNTIMES = [\n \"node-20\",\n \"node-22\",\n \"python-3.11\",\n \"python-3.12\",\n \"bun-1\",\n \"deno-2\",\n] as const;\n\nexport type SupportedRuntime = (typeof SUPPORTED_RUNTIMES)[number];\n\nexport const DEPLOYMENT_STATUSES = [\n \"building\",\n \"deploying\",\n \"running\",\n \"failed\",\n // A task that was live and then died on its own -- OOM, panic, ECS\n // replacement. The reconcile pass sets it, so anything enumerating statuses\n // has to know about it.\n \"crashed\",\n \"stopped\",\n] as const;\n\nexport const ENVIRONMENTS = [\"preview\", \"production\"] as const;\n\nexport const ROLES = [\"admin\", \"member\"] as const;\n\nexport const DEFAULT_API_URL = \"https://api.videan.xyz/v1\";\n\n/** The zone every app's hostname hangs off. */\nexport const APP_DOMAIN = process.env.CLOUD_APP_DOMAIN || \"videan.xyz\";\n\n/**\n * The public URL of an app, from its slug.\n *\n * One definition, because it was previously written out by hand in three places\n * and one of them omitted the scheme -- so a deployment's `url` came back as a\n * bare `slug.videan.xyz` that no terminal, browser or `fetch` would follow,\n * while the app resource reported the same app as `https://slug.videan.xyz`.\n * HTTP redirects to HTTPS anyway, so the scheme is not optional in practice.\n */\nexport function appUrl(slug: string): string {\n return `https://${slug}.${APP_DOMAIN}`;\n}\n\n/**\n * Prefix for a single deployment's own hostname.\n *\n * Every deployment is reachable before it is promoted, which is what lets an\n * agent verify its own work without production riding on the answer. The label is\n * a hash of the deployment id rather than the id itself: nanoid's alphabet\n * contains `_` and uppercase, neither of which is legal in a DNS label, and\n * lowercasing or substituting would map two distinct deployments onto one\n * hostname -- serving whichever the router looked up first.\n *\n * The prefix keeps the namespace from colliding with app slugs: `*.videan.xyz`\n * is one flat namespace, and an app legitimately slugged the same as some\n * deployment's hash would otherwise steal its traffic.\n */\nexport const PREVIEW_LABEL_PREFIX = \"d-\";\n\nexport function previewUrl(label: string): string {\n return `https://${PREVIEW_LABEL_PREFIX}${label}.${APP_DOMAIN}`;\n}\n\n/** True for a hostname label that belongs to the preview namespace. */\nexport function isPreviewLabel(label: string): boolean {\n return label.startsWith(PREVIEW_LABEL_PREFIX);\n}\n\nexport const CONFIG_FILE_NAME = \"cloud.yaml\";\n\nexport const IGNORE_FILE_NAME = \".cloudignore\";\n\nexport const MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024; // 50MB\n\nexport const MAX_FILES_PER_PUSH = 10_000;\n", "/**\n * Fargate task sizing.\n *\n * Every app used to run at 256 CPU / 512 MB, hardcoded in `ecs-app.ts`. That is\n * below the working set of a stock Next.js server, so those apps were killed by\n * the OOM killer -- which surfaces as a container that exits without a message,\n * indistinguishable from a crash in the app's own code. Sizing is therefore not\n * a tuning knob; at the old default some runtimes could not work at all.\n *\n * Fargate accepts only specific (cpu, memory) pairs and rejects everything else\n * at RegisterTaskDefinition time. Validating here rather than there means the\n * caller is told which values are legal instead of reading an AWS error, and the\n * CLI can reject a bad `--memory` before a build starts.\n */\n\nimport type { Runtime } from \"./detect.js\";\n\n/**\n * Legal memory values (MiB) for each CPU unit, from the Fargate task-size table.\n *\n * Expressed as a range plus a step rather than a literal list because the larger\n * tiers have hundreds of legal values; a list would be unreadable and would drift.\n */\nconst FARGATE_SIZES: Record<number, { min: number; max: number; step: number }> = {\n 256: { min: 512, max: 2048, step: 512 },\n 512: { min: 1024, max: 4096, step: 1024 },\n 1024: { min: 2048, max: 8192, step: 1024 },\n 2048: { min: 4096, max: 16384, step: 1024 },\n 4096: { min: 8192, max: 30720, step: 1024 },\n 8192: { min: 16384, max: 61440, step: 4096 },\n 16384: { min: 32768, max: 122880, step: 8192 },\n};\n\nexport const FARGATE_CPUS = Object.keys(FARGATE_SIZES)\n .map(Number)\n .sort((a, b) => a - b);\n\n/**\n * 256 CPU is a special case: its legal memory values are 512, 1024 and 2048 --\n * it skips 1536, so the uniform step above would admit a value Fargate rejects.\n */\nconst CPU_256_MEMORY = [512, 1024, 2048];\n\nexport interface SizeValidation {\n ok: boolean;\n /** Why the pair is illegal, naming the legal alternatives. */\n error?: string;\n /** The legal memory values for the given CPU, for building an error message. */\n allowed?: number[];\n}\n\nfunction legalMemory(cpu: number): number[] {\n if (cpu === 256) return CPU_256_MEMORY;\n const spec = FARGATE_SIZES[cpu];\n if (!spec) return [];\n const values: number[] = [];\n for (let m = spec.min; m <= spec.max; m += spec.step) values.push(m);\n return values;\n}\n\n/**\n * Checks a (cpu, memory) pair against the Fargate table.\n *\n * Deliberately strict rather than snapping to the nearest legal value: silently\n * giving an app 2 GB when its owner asked for 1.5 GB means the bill and the\n * behaviour do not match what was requested, and a size that is quietly changed\n * is a size nobody can reason about when the app OOMs anyway.\n */\nexport function validateSize(cpu: number, memory: number): SizeValidation {\n if (!FARGATE_SIZES[cpu]) {\n return {\n ok: false,\n error: `cpu must be one of ${FARGATE_CPUS.join(\", \")} (got ${cpu})`,\n };\n }\n const allowed = legalMemory(cpu);\n if (!allowed.includes(memory)) {\n // Long lists are unhelpful in an error message; show the shape instead.\n const shown =\n allowed.length <= 6\n ? allowed.join(\", \")\n : `${allowed[0]}\u2013${allowed[allowed.length - 1]} in steps of ${allowed[1] - allowed[0]}`;\n return {\n ok: false,\n error: `memory ${memory} is not valid for cpu ${cpu}; allowed: ${shown}`,\n allowed,\n };\n }\n return { ok: true };\n}\n\nexport interface TaskSize {\n cpu: number;\n memory: number;\n}\n\n/**\n * The size an app gets when nobody chose one.\n *\n * Picked per runtime because the failure is runtime-specific: `next start` holds\n * a compiled server plus its module graph and does not fit in 512 MB, while a\n * Go binary is comfortable in it. Defaulting everything to the larger size would\n * quadruple the bill for the runtimes that do not need it; defaulting everything\n * to the smaller one is the bug this replaces.\n */\nexport function defaultSizeFor(runtime: Runtime): TaskSize {\n switch (runtime) {\n case \"nextjs\":\n return { cpu: 512, memory: 1024 };\n case \"nodejs\":\n case \"python\":\n // Comfortable for a framework plus dependencies, and the smallest legal\n // pair above the old default.\n return { cpu: 256, memory: 1024 };\n case \"go\":\n return { cpu: 256, memory: 512 };\n case \"custom\":\n // Unknown contents, so assume it is doing something real.\n return { cpu: 512, memory: 1024 };\n }\n}\n\n/**\n * How many tasks a size change or a scale-out may run at once.\n *\n * A bound exists because `instances` is caller-supplied and reaches RunTask\n * directly: a typo of 100 would launch a hundred Fargate tasks and bill for them\n * before anyone noticed. RunTask itself caps a single call at 10.\n */\nexport const MAX_INSTANCES = 10;\n", "/**\n * What a plan allows and what usage costs.\n *\n * Kept here rather than in the control API because three consumers need the same\n * numbers and must not disagree about them: the API enforces the limits, the\n * usage collector prices the metrics it records, and the CLI prints a bill. A\n * rate duplicated in two of those places is a bill that does not match the\n * invoice.\n *\n * Two things this deliberately is *not*:\n *\n * - **A payment integration.** Nothing here charges anyone. It computes what an\n * org owes; collecting it needs a payment processor and a human to accept its\n * terms, the same way SES production access does.\n * - **The authority on AWS cost.** These are the platform's *prices*. The real\n * cost of a Fargate task is in Cost Explorer, and the two will not match --\n * that difference is the margin, and pretending otherwise would make every\n * price change look like a metering bug.\n */\n\n/**\n * Metrics recorded in `usage_records`.\n *\n * `vcpu_seconds` and `gb_seconds` are what Fargate actually charges for, so they\n * are what a compute line is priced from; `task_seconds` is recorded alongside\n * them because it is the number a human recognises (\"this ran for 20 hours\") and\n * cannot be recovered from the other two without knowing the task size.\n *\n * `storage_mb`, not bytes: `usage_records.quantity` is an `integer`, and bytes\n * overflows int32 at 2.1 GB -- silently, wrapping negative, which would read as a\n * credit.\n */\nexport type UsageMetric =\n | \"task_seconds\"\n | \"vcpu_seconds\"\n | \"gb_seconds\"\n | \"requests\"\n | \"build_seconds\"\n | \"storage_mb\"\n | \"emails_sent\"\n | \"db_days\";\n\nexport const USAGE_METRICS: UsageMetric[] = [\n \"task_seconds\",\n \"vcpu_seconds\",\n \"gb_seconds\",\n \"requests\",\n \"build_seconds\",\n \"storage_mb\",\n \"emails_sent\",\n \"db_days\",\n];\n\n/**\n * Metrics that are a level rather than a total.\n *\n * A day's `storage_mb` row is the last sample taken that day, not a sum of\n * samples -- summing a level double-counts every byte for every time it was\n * observed. Billing a level means averaging the samples across the period, which\n * is why the two kinds cannot be aggregated by the same code path.\n */\nexport const GAUGE_METRICS: UsageMetric[] = [\"storage_mb\"];\n\nexport function isGauge(metric: string): boolean {\n return (GAUGE_METRICS as string[]).includes(metric);\n}\n\n/**\n * Price per unit, in cents. Fractional on purpose: a request costs a fifth of a\n * millionth of a cent and rounding each one to a cent would bill $10,000 for a\n * million requests.\n *\n * `task_seconds` is priced at zero because compute is already billed through\n * `vcpu_seconds` and `gb_seconds`. It is in the table rather than absent from it\n * so that a new metric added without a price is a visible zero here instead of an\n * `undefined` multiplied into `NaN` further down.\n */\nexport const RATES: Record<UsageMetric, number> = {\n task_seconds: 0,\n // Fargate on-demand in us-east-1 is ~$0.04048/vCPU-hour and ~$0.004445/GB-hour.\n vcpu_seconds: 0.002,\n gb_seconds: 0.00025,\n // $0.20 per million requests.\n requests: 0.00002,\n // ~$0.012 per build-minute.\n build_seconds: 0.02,\n // $0.05 per GB-month, charged per MB-month.\n storage_mb: 0.005,\n // $0.50 per thousand.\n emails_sent: 0.05,\n // ~$3/month for a managed schema, charged per day it exists.\n db_days: 10,\n};\n\n/** Human unit for each metric, for a bill a person has to read. */\nexport const METRIC_LABELS: Record<UsageMetric, string> = {\n task_seconds: \"Task-seconds served\",\n vcpu_seconds: \"vCPU-seconds\",\n gb_seconds: \"GB-seconds\",\n requests: \"Requests\",\n build_seconds: \"Build seconds\",\n storage_mb: \"Object storage (MB-month)\",\n emails_sent: \"Emails sent\",\n db_days: \"Managed Postgres (app-days)\",\n};\n\nexport interface Plan {\n id: string;\n name: string;\n /** Monthly subscription, in cents, before usage. */\n baseCents: number;\n /**\n * Usage covered by the base fee, in cents. An org that stays under this pays\n * exactly `baseCents` -- so the free plan is a real free tier rather than a\n * $0.03 invoice for a weekend project.\n */\n includedUsageCents: number;\n /** Apps that are not soft-deleted. */\n maxApps: number;\n maxInstancesPerApp: number;\n /** Ceilings on Fargate task size, which is the one knob that scales the bill. */\n maxCpu: number;\n maxMemory: number;\n /** Object-storage quota, enforced on upload. */\n maxStorageMb: number;\n postgres: boolean;\n customDomains: boolean;\n}\n\n/**\n * The plans.\n *\n * The limits that exist are the ones that bound *spend*: app count, instance\n * count and task size. There is deliberately no limit on requests, builds or\n * deploys -- an agent-built app that gets popular should get a bill, not an\n * outage, and a platform whose selling point is \"push and it is live\" cannot\n * answer a deploy with \"not on your plan\".\n */\nexport const PLANS: Record<string, Plan> = {\n free: {\n id: \"free\",\n name: \"Free\",\n baseCents: 0,\n includedUsageCents: 300,\n maxApps: 3,\n maxInstancesPerApp: 1,\n // One app at this size, running all month, is inside the included usage.\n maxCpu: 512,\n maxMemory: 1024,\n maxStorageMb: 1024,\n postgres: true,\n customDomains: false,\n },\n pro: {\n id: \"pro\",\n name: \"Pro\",\n baseCents: 2000,\n includedUsageCents: 2000,\n maxApps: 50,\n maxInstancesPerApp: 4,\n maxCpu: 4096,\n maxMemory: 8192,\n maxStorageMb: 100 * 1024,\n postgres: true,\n customDomains: true,\n },\n scale: {\n id: \"scale\",\n name: \"Scale\",\n baseCents: 20000,\n includedUsageCents: 20000,\n maxApps: 500,\n maxInstancesPerApp: 10,\n maxCpu: 16384,\n maxMemory: 122880,\n maxStorageMb: 1024 * 1024,\n postgres: true,\n customDomains: true,\n },\n};\n\n/**\n * The plan for a stored `orgs.plan` value.\n *\n * Falls back to free rather than throwing: the column is free text and an\n * unrecognised value must not take an org's whole control surface down with a\n * 500. Free is the safe direction -- its limits are the tightest, so a typo\n * cannot silently grant a larger allowance than anyone agreed to.\n */\nexport function planFor(plan: string | null | undefined): Plan {\n return PLANS[plan || \"free\"] ?? PLANS.free;\n}\n\nexport interface UsageLine {\n metric: UsageMetric | string;\n label: string;\n quantity: number;\n unitPriceCents: number;\n /** Rounded to whole cents only at the line, never per unit. */\n cents: number;\n}\n\nexport interface Invoice {\n plan: string;\n periodStart: string;\n periodEnd: string;\n lines: UsageLine[];\n /** Everything the usage lines add up to, before the included allowance. */\n usageCents: number;\n baseCents: number;\n includedUsageCents: number;\n /** Usage beyond the allowance. Zero, never negative: credit does not roll over. */\n overageCents: number;\n totalCents: number;\n}\n\n/**\n * Prices a period's usage.\n *\n * `quantities` is metric \u2192 quantity, already aggregated over the period (sums for\n * counters, averages for gauges -- see `GAUGE_METRICS`, and note that this\n * function cannot tell which it was given, so aggregating wrongly produces a\n * plausible bill rather than an error).\n */\nexport function priceUsage(\n quantities: Record<string, number>,\n plan: Plan,\n period: { start: Date; end: Date },\n): Invoice {\n const lines: UsageLine[] = [];\n for (const metric of USAGE_METRICS) {\n const quantity = quantities[metric] ?? 0;\n const rate = RATES[metric];\n // A zero-priced metric is still reported when there is something to report:\n // task-seconds is how an owner checks that the compute line is plausible.\n if (quantity === 0) continue;\n lines.push({\n metric,\n label: METRIC_LABELS[metric],\n quantity: Math.round(quantity * 100) / 100,\n unitPriceCents: rate,\n cents: Math.round(quantity * rate),\n });\n }\n // Metrics recorded by a newer collector than this pricing table knows about.\n // Listed at zero rather than dropped: an unpriced metric that vanishes from the\n // bill is indistinguishable from one that was never collected.\n for (const metric of Object.keys(quantities)) {\n if ((USAGE_METRICS as string[]).includes(metric)) continue;\n if (!quantities[metric]) continue;\n lines.push({\n metric,\n label: metric,\n quantity: quantities[metric],\n unitPriceCents: 0,\n cents: 0,\n });\n }\n\n const usageCents = lines.reduce((acc, l) => acc + l.cents, 0);\n const overageCents = Math.max(0, usageCents - plan.includedUsageCents);\n return {\n plan: plan.id,\n periodStart: period.start.toISOString(),\n periodEnd: period.end.toISOString(),\n lines,\n usageCents,\n baseCents: plan.baseCents,\n includedUsageCents: plan.includedUsageCents,\n overageCents,\n totalCents: plan.baseCents + overageCents,\n };\n}\n\n/** `1234` \u2192 `\"$12.34\"`. For output a person reads, not for arithmetic. */\nexport function formatCents(cents: number): string {\n const sign = cents < 0 ? \"-\" : \"\";\n const abs = Math.abs(Math.round(cents));\n return `${sign}$${Math.floor(abs / 100)}.${String(abs % 100).padStart(2, \"0\")}`;\n}\n\nexport interface LimitCheck {\n ok: boolean;\n /** Names the limit and the plan, so the error says what to do about it. */\n error?: string;\n code?: string;\n}\n\nexport function allowed(): LimitCheck {\n return { ok: true };\n}\n\nfunction denied(code: string, error: string): LimitCheck {\n return { ok: false, error, code };\n}\n\n/** Whether one more app is within the plan. `current` excludes deleted apps. */\nexport function checkAppCount(plan: Plan, current: number): LimitCheck {\n if (current < plan.maxApps) return allowed();\n return denied(\n \"PLAN_LIMIT_APPS\",\n `The ${plan.name} plan allows ${plan.maxApps} app${plan.maxApps === 1 ? \"\" : \"s\"} ` +\n `and this org has ${current}. Delete one or upgrade the plan.`,\n );\n}\n\n/**\n * Whether a requested task shape is within the plan.\n *\n * Checked as a triple rather than three separate limits because they multiply:\n * the thing being bounded is the bill, and 4 instances of a small task costs the\n * same as one large one.\n */\nexport function checkTaskShape(\n plan: Plan,\n shape: { cpu?: number | null; memory?: number | null; instances?: number | null },\n): LimitCheck {\n if (shape.instances != null && shape.instances > plan.maxInstancesPerApp) {\n return denied(\n \"PLAN_LIMIT_INSTANCES\",\n `The ${plan.name} plan allows ${plan.maxInstancesPerApp} instance` +\n `${plan.maxInstancesPerApp === 1 ? \"\" : \"s\"} per app (asked for ${shape.instances}).`,\n );\n }\n if (shape.cpu != null && shape.cpu > plan.maxCpu) {\n return denied(\n \"PLAN_LIMIT_CPU\",\n `The ${plan.name} plan allows up to ${plan.maxCpu} CPU units per task (asked for ${shape.cpu}).`,\n );\n }\n if (shape.memory != null && shape.memory > plan.maxMemory) {\n return denied(\n \"PLAN_LIMIT_MEMORY\",\n `The ${plan.name} plan allows up to ${plan.maxMemory} MB per task (asked for ${shape.memory}).`,\n );\n }\n return allowed();\n}\n\n/** Whether a custom domain is within the plan. */\nexport function checkCustomDomain(plan: Plan): LimitCheck {\n if (plan.customDomains) return allowed();\n return denied(\n \"PLAN_LIMIT_DOMAINS\",\n `Custom domains are not included in the ${plan.name} plan. Every app keeps its ` +\n `platform hostname, which needs no configuration.`,\n );\n}\n", "/**\n * Who may reach a running app, as a ladder from narrowest to widest.\n *\n * This replaces `auth_required`, which could only distinguish \"gated\" from\n * \"open\" and so collapsed the two settings owners actually reach for -- \"anyone\n * with the link\" and \"only the people I invite\" -- into the same switch as\n * \"anyone in my org\".\n *\n * The tiers are deliberately ordered and each is a strict superset of the one\n * before it, so widening is always one step and there is never a pair of\n * settings whose relative reach is ambiguous.\n *\n * Note what this is *not*: it governs visiting the deployed app at its\n * hostname, not managing it through the API. Those are separate on purpose --\n * `lib/access.ts` answers the second one -- so an org member who cannot open a\n * `private` app in a browser may still hold write on it in the console. The\n * alternative, letting a visibility setting revoke an org member's ability to\n * deploy, would make an access control into an outage.\n */\nexport const VISIBILITIES = [\"private\", \"org\", \"authenticated\", \"public\"] as const;\n\nexport type Visibility = (typeof VISIBILITIES)[number];\n\n/**\n * The default for a new app, and the widest tier that still requires a session.\n *\n * Matches what `auth_required` defaulted to (true, meaning org-or-share), so\n * creating an app has not changed who can reach it.\n */\nexport const DEFAULT_VISIBILITY: Visibility = \"org\";\n\nexport function isVisibility(value: unknown): value is Visibility {\n return typeof value === \"string\" && (VISIBILITIES as readonly string[]).includes(value);\n}\n\n/**\n * Reads a stored value as a tier, treating anything unrecognized as the\n * **narrowest** one.\n *\n * The column is `text`, and this repo has twice shipped a value nothing reads\n * (`org_members.role = 'owner'`, `deployments.status = 'rolled_back'`) -- both\n * stored happily and were silently ignored. Here the same slip would decide\n * whether strangers can read a tenant's app, so an unknown value must fail\n * closed. `private` is still reachable by its org's admins, so the worst case of\n * failing closed is an app its owners can fix; the worst case of failing open is\n * a disclosure they cannot undo.\n */\nexport function visibilityOf(value: unknown): Visibility {\n return isVisibility(value) ? value : \"private\";\n}\n\n/**\n * Whether a tier admits a visitor with no session at all.\n *\n * This is what the legacy `auth_required` boolean encodes, which is why every\n * write to `visibility` also writes `auth_required = !isPublic(v)`: the deployed\n * edge router may still be reading only the boolean.\n */\nexport function isPublic(v: Visibility): boolean {\n return v === \"public\";\n}\n\n/** Human-readable label, shared by the console and the CLI. */\nexport const VISIBILITY_LABELS: Record<Visibility, string> = {\n private: \"Only people with access\",\n org: \"Anyone in the organization\",\n authenticated: \"Anyone signed in to Videan\",\n public: \"Anyone with the link\",\n};\n", "import Conf from \"conf\";\n\ninterface CloudConfig {\n apiKey?: string;\n defaultOrg?: string;\n currentApp?: string;\n baseUrl?: string;\n}\n\nconst config = new Conf<CloudConfig>({\n projectName: \"cloud-cli\",\n schema: {\n apiKey: { type: \"string\" },\n defaultOrg: { type: \"string\" },\n currentApp: { type: \"string\" },\n baseUrl: { type: \"string\" },\n },\n});\n\n/**\n * An override from the environment, checked under both prefixes.\n *\n * The bin is `videan`; the packages are `@cloud/*`. Accepting both spellings is\n * cheaper than being wrong about which one someone reaches for.\n */\nfunction fromEnv(name: string): string | undefined {\n const value = process.env[`VIDEAN_${name}`] || process.env[`CLOUD_${name}`];\n return value ? value : undefined;\n}\n\n/**\n * The environment wins over the saved config.\n *\n * The platform's premise is that an agent does the deploying, and an agent runs\n * in a non-interactive shell with no config file and no way to answer a password\n * prompt. `VIDEAN_API_KEY` is how it authenticates without `login` at all.\n */\nexport function getApiKey(): string | undefined {\n return fromEnv(\"API_KEY\") || config.get(\"apiKey\");\n}\n\nexport function setApiKey(key: string): void {\n config.set(\"apiKey\", key);\n}\n\nexport function getDefaultOrg(): string | undefined {\n // Both spellings again: the README documents VIDEAN_ORG_ID (the value *is*\n // an id), and the first real user set exactly that while the code read only\n // VIDEAN_ORG \u2014 so the CLI silently fell back to a stale saved org and\n // answered \"Not a member of this organization\" for a key that was fine.\n return fromEnv(\"ORG_ID\") || fromEnv(\"ORG\") || config.get(\"defaultOrg\");\n}\n\nexport function setDefaultOrg(org: string): void {\n config.set(\"defaultOrg\", org);\n}\n\nexport function getCurrentApp(): string | undefined {\n return fromEnv(\"APP_ID\") || fromEnv(\"APP\") || config.get(\"currentApp\");\n}\n\nexport function setCurrentApp(appId: string): void {\n config.set(\"currentApp\", appId);\n}\n\nexport function getBaseUrl(): string | undefined {\n return fromEnv(\"API_URL\") || config.get(\"baseUrl\");\n}\n\nexport function setBaseUrl(url: string): void {\n config.set(\"baseUrl\", url);\n}\n\n/** Where the saved config lives, so a stale value can be found and inspected. */\nexport function configPath(): string {\n return config.path;\n}\n\nexport function clearConfig(): void {\n config.clear();\n}\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { clearConfig, configPath } from \"../config.js\";\n\nexport const logoutCommand = new Command(\"logout\")\n .description(\"Forget the saved key, org, app and API URL\")\n .action(() => {\n // Clears everything, not just the key. The saved `baseUrl` is the value most\n // likely to be wrong and was, until now, only reachable by editing the\n // config file: a leftover URL from an earlier environment made every command\n // fail against a host that no longer served the API.\n const where = configPath();\n clearConfig();\n console.log(chalk.green(\"Logged out.\"));\n console.log(chalk.gray(` Cleared ${where}`));\n });\n", "import { Command } from \"commander\";\nimport inquirer from \"inquirer\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { SUPPORTED_RUNTIMES, CONFIG_FILE_NAME } from \"@cloud/shared\";\n\nexport const initCommand = new Command(\"init\")\n .description(\"Initialize a new Cloud app in the current directory\")\n .action(async () => {\n const configPath = path.join(process.cwd(), CONFIG_FILE_NAME);\n\n if (await fs.pathExists(configPath)) {\n console.log(chalk.yellow(`${CONFIG_FILE_NAME} already exists in this directory.`));\n const { overwrite } = await inquirer.prompt([\n { type: \"confirm\", name: \"overwrite\", message: \"Overwrite?\", default: false },\n ]);\n if (!overwrite) return;\n }\n\n const answers = await inquirer.prompt([\n { type: \"input\", name: \"name\", message: \"App name:\", default: path.basename(process.cwd()) },\n {\n type: \"list\",\n name: \"runtime\",\n message: \"Runtime:\",\n choices: SUPPORTED_RUNTIMES as unknown as string[],\n },\n { type: \"input\", name: \"entrypoint\", message: \"Entrypoint:\", default: \"index.ts\" },\n ]);\n\n const config = [\n `name: ${answers.name}`,\n `runtime: ${answers.runtime}`,\n `entrypoint: ${answers.entrypoint}`,\n \"\",\n ].join(\"\\n\");\n\n await fs.writeFile(configPath, config, \"utf-8\");\n console.log(chalk.green(`Created ${CONFIG_FILE_NAME}`));\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { collectFiles, requireApiKey, formatStatus } from \"../util.js\";\n\nexport const deployCommand = new Command(\"deploy\")\n .description(\"Deploy the current directory\")\n .option(\"-a, --app <id>\", \"App ID to deploy to\")\n .option(\"-m, --message <msg>\", \"Deployment message\")\n .option(\"--env <environment>\", \"preview or production (default: production)\")\n .action(async (opts) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or run `videan init` first.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n\n // Collect files\n const spinner = ora(\"Collecting files...\").start();\n const { files, binaryFiles, skipped } = await collectFiles(process.cwd());\n const binaryCount = Object.keys(binaryFiles).length;\n const fileCount = Object.keys(files).length + binaryCount;\n if (!fileCount) {\n spinner.fail(chalk.red(`Nothing to deploy: no files under ${process.cwd()}.`));\n process.exit(1);\n }\n if (skipped.length) {\n // Named, not counted. A snapshot silently missing an image is a bug report\n // from the future; the operator can act on a list.\n spinner.warn(chalk.yellow(`Skipped ${skipped.length} file(s):`));\n for (const file of skipped) console.log(chalk.gray(` ${file.path} \u2014 ${file.reason}`));\n spinner.start();\n }\n spinner.text = `Pushing ${fileCount} files${binaryCount ? ` (${binaryCount} binary)` : \"\"}...`;\n\n // Push\n const snapshot = await client.apps.push(appId, files, opts.message, binaryFiles);\n spinner.text = \"Triggering deployment...\";\n\n // Deploy\n if (opts.env && opts.env !== \"preview\" && opts.env !== \"production\") {\n spinner.fail(chalk.red(`--env must be preview or production, not ${opts.env}`));\n process.exit(1);\n }\n const deployment = await client.apps.deploy(appId, snapshot.id, opts.env);\n spinner.text = `Deploying (${deployment.status})...`;\n\n // Poll for status. A build takes minutes, so a single failed request must\n // not end the watch -- it used to `break`, which reported the deployment as\n // stuck in `building` when in fact nothing was wrong with it but one HTTP\n // call. Give up only after several consecutive failures, and say so.\n let current = deployment;\n let consecutiveErrors = 0;\n let lastError = \"\";\n while (current.status === \"building\" || current.status === \"deploying\") {\n await new Promise((r) => setTimeout(r, 5000));\n const elapsed = Math.round((Date.now() - Date.parse(current.createdAt)) / 1000);\n spinner.text = `${current.status === \"building\" ? \"Building\" : \"Starting\"}... (${elapsed}s)`;\n try {\n current = await client.apps.checkDeployment(deployment.id);\n consecutiveErrors = 0;\n } catch (e: any) {\n lastError = e?.message || String(e);\n if (++consecutiveErrors >= 5) {\n spinner.fail(chalk.red(`Lost track of the deployment: ${lastError}`));\n console.log(chalk.gray(` It may still finish. Check with \\`videan status\\`.`));\n process.exit(1);\n }\n }\n }\n\n if (current.status === \"running\") {\n spinner.succeed(chalk.green(`Deployed successfully!`));\n if (current.url) {\n // Deployments promoted before the API started storing a full URL have a\n // bare hostname here, which no terminal will linkify and no fetch will\n // follow.\n const url = /^https?:\\/\\//.test(current.url) ? current.url : `https://${current.url}`;\n console.log(chalk.cyan(` URL: ${url}`));\n }\n if (current.previewUrl) {\n // This version's own address. Live from the moment its tasks are up --\n // which is before promotion, so it is what an agent checks its own work\n // against -- and only for as long as they are: the poller retires the\n // version this deploy replaced, and a retired version's address stops\n // resolving with it.\n console.log(chalk.gray(` This version: ${current.previewUrl}`));\n }\n } else if (current.status === \"failed\" || current.status === \"crashed\") {\n // `crashed` means the container started and then died -- a failure the\n // caller has to see, and one this used to report as mere information with\n // a zero exit code, so a scripted deploy counted it as a success.\n spinner.fail(chalk.red(`Deployment ${current.status}: ${current.error || \"unknown error\"}`));\n console.log(chalk.gray(` Logs: videan logs --app ${appId}`));\n process.exit(1);\n } else {\n spinner.info(`Deployment status: ${formatStatus(current.status)}`);\n process.exit(1);\n }\n });\n", "import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport ignore from \"ignore\";\nimport chalk from \"chalk\";\n\n/** Larger than this and the push is refused rather than silently trimmed. */\nexport const MAX_FILE_BYTES = 10 * 1024 * 1024;\n\nexport interface CollectedFiles {\n /** Relative path \u2192 UTF-8 contents, ready for the push wire format. */\n files: Record<string, string>;\n /** Relative path \u2192 base64 contents, for files that are not valid UTF-8. */\n binaryFiles: Record<string, string>;\n /**\n * Relative paths left out, with the reason. Only oversized files land here\n * now that binaries have somewhere to go.\n */\n skipped: { path: string; reason: string }[];\n}\n\n/**\n * Collect all files from a directory, respecting .gitignore and .cloudignore.\n */\nexport async function collectFiles(dir: string): Promise<CollectedFiles> {\n const ig = ignore();\n\n // Always ignored, whether or not the project has a .gitignore -- and many\n // agent-generated projects do not.\n //\n // `.next`, `.turbo` and `coverage` are local build output. Uploading them is\n // not merely wasteful: the container runs `next build` over whatever it is\n // given, and a `.next` produced on a different platform and Node version is\n // exactly the kind of stale cache that makes a build fail or, worse, succeed\n // with the previous code in it.\n ig.add([\n \".git\",\n \"node_modules\",\n \".env\",\n \".env.*\",\n \".next\",\n \".turbo\",\n \"coverage\",\n \".DS_Store\",\n \"*.log\",\n ]);\n\n // Load .gitignore\n const gitignorePath = path.join(dir, \".gitignore\");\n if (await fs.pathExists(gitignorePath)) {\n const content = await fs.readFile(gitignorePath, \"utf-8\");\n ig.add(content);\n }\n\n // Load .cloudignore\n const cloudignorePath = path.join(dir, \".cloudignore\");\n if (await fs.pathExists(cloudignorePath)) {\n const content = await fs.readFile(cloudignorePath, \"utf-8\");\n ig.add(content);\n }\n\n const files: Record<string, string> = {};\n const binaryFiles: Record<string, string> = {};\n const skipped: { path: string; reason: string }[] = [];\n\n async function walk(currentDir: string): Promise<void> {\n const entries = await fs.readdir(currentDir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(currentDir, entry.name);\n const relativePath = path.relative(dir, fullPath);\n\n // ignore() matches directories only when the path is marked as one, and\n // pattern semantics differ between \"dir\" and \"dir/\" for anchored rules.\n const ignorePath = entry.isDirectory() ? `${relativePath}/` : relativePath;\n if (ig.ignores(ignorePath)) continue;\n\n if (entry.isDirectory()) {\n await walk(fullPath);\n } else if (entry.isFile()) {\n // Read bytes, not a string. `readFile(path, \"utf-8\")` replaces every\n // byte that is not valid UTF-8 with U+FFFD and reports success, so a\n // PNG read as text arrives corrupted with nothing to indicate it. The\n // round-trip is what decides which map a file belongs in: text goes in\n // `files` verbatim, everything else is base64 in `binaryFiles`. It is a\n // test of the bytes rather than of the extension, so an unknown\n // extension or a text file with one byte of Latin-1 in it is handled on\n // what it contains.\n const buffer = await fs.readFile(fullPath);\n if (buffer.byteLength > MAX_FILE_BYTES) {\n // Refused, not trimmed: the push is one JSON body, and a 200MB asset\n // would be an out-of-memory on the control API rather than a rejected\n // request. Named here so the fix is `.cloudignore` or object storage.\n skipped.push({\n path: relativePath,\n reason: `${Math.round(buffer.byteLength / 1024 / 1024)}MB, over the ${MAX_FILE_BYTES / 1024 / 1024}MB limit`,\n });\n continue;\n }\n const text = buffer.toString(\"utf-8\");\n if (Buffer.from(text, \"utf-8\").equals(buffer)) {\n files[relativePath] = text;\n } else {\n binaryFiles[relativePath] = buffer.toString(\"base64\");\n }\n }\n }\n }\n\n await walk(dir);\n return { files, binaryFiles, skipped };\n}\n\n/**\n * Format a deployment status with color.\n */\nexport function formatStatus(status: string): string {\n switch (status) {\n case \"running\":\n return chalk.green(status);\n case \"building\":\n case \"deploying\":\n return chalk.yellow(status);\n case \"failed\":\n case \"crashed\":\n return chalk.red(status);\n case \"stopped\":\n return chalk.gray(status);\n default:\n return status;\n }\n}\n\n/**\n * Format a table row for display.\n */\nexport function formatRow(columns: string[], widths: number[]): string {\n return columns.map((col, i) => col.padEnd(widths[i] || 20)).join(\" \");\n}\n\n/**\n * Require an API key or exit.\n */\nexport function requireApiKey(apiKey: string | undefined): asserts apiKey is string {\n if (!apiKey) {\n console.error(chalk.red(\"Not logged in. Run `videan login` first.\"));\n process.exit(1);\n }\n}\n\n/**\n * Require an organization or exit. Every app lives in an org, so commands that\n * list or create apps need one from --org or the saved default.\n */\nexport function requireOrg(orgId: string | undefined): string {\n if (!orgId) {\n console.error(chalk.red(\"No organization. Pass --org <id> or run `videan login` again.\"));\n process.exit(1);\n }\n return orgId;\n}\n\n// Re-exported rather than redefined: the CLI and the API have to agree on the\n// hostname, and they did not while each built it by hand.\nexport { appUrl } from \"@cloud/shared\";\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey } from \"../util.js\";\n\nexport const logsCommand = new Command(\"logs\")\n .description(\"View app logs\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-f, --follow\", \"Follow log output\")\n .option(\"-n, --lines <n>\", \"Number of lines to show\", \"50\")\n .option(\"-s, --since <when>\", \"Start of the window: ISO timestamp or an offset like 15m, 2h, 7d\", \"1h\")\n .option(\"--until <when>\", \"End of the window (same formats as --since)\")\n .option(\"-q, --search <text>\", \"Only lines containing this text\")\n .option(\"--pattern <pattern>\", \"CloudWatch filter pattern, for the real syntax\")\n .option(\"--instance <prefix>\", \"Only one instance, by log stream prefix\")\n .action(async (opts) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n\n if (opts.search && opts.pattern) {\n console.error(chalk.red(\"Use either --search or --pattern, not both.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const filters = {\n q: opts.search as string | undefined,\n pattern: opts.pattern as string | undefined,\n instance: opts.instance as string | undefined,\n };\n\n if (opts.follow) {\n // The generator holds the cursor, so a line is printed once. The old loop\n // re-fetched the same window every two seconds and reprinted all of it.\n for await (const entry of client.apps.followLogs(appId, { since: opts.since, ...filters })) {\n print(entry);\n }\n return;\n }\n\n const page = await client.apps.logs(appId, {\n limit: parseInt(opts.lines, 10),\n since: opts.since,\n until: opts.until,\n ...filters,\n });\n\n // Oldest first, so the newest line is the one left next to the prompt.\n for (const entry of page.events) print(entry);\n\n if (page.events.length === 0) {\n console.log(chalk.gray(`No log lines since ${page.start}.`));\n }\n if (page.truncated) {\n // Said out loud: otherwise a window with more lines than one scan can read\n // looks like a window that simply contained these.\n console.log(\n chalk.yellow(\n \"\\nThis is part of the window -- there are more lines than one request reads. Narrow --since or add --search.\",\n ),\n );\n }\n });\n\nfunction print(entry: { timestamp: string; level?: string; message: string }): void {\n console.log(`${chalk.gray(entry.timestamp)} ${formatLevel(entry.level)} ${entry.message}`);\n}\n\nfunction formatLevel(level?: string): string {\n switch (level) {\n case \"error\":\n return chalk.red(\"[ERR]\");\n case \"warn\":\n return chalk.yellow(\"[WRN]\");\n case \"info\":\n return chalk.blue(\"[INF]\");\n case \"debug\":\n return chalk.gray(\"[DBG]\");\n default:\n return chalk.gray(\"[LOG]\");\n }\n}\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey } from \"../util.js\";\n\n/**\n * `videan metrics` -- the window summary, and optionally the buckets.\n *\n * Summary by default rather than the series: a terminal cannot plot 60 buckets\n * usefully, and the question being asked (\"is anything hitting my app, and is it\n * erroring\") is answered by the totals. `--series` prints the buckets for piping\n * somewhere that can graph them.\n */\nexport const metricsCommand = new Command(\"metrics\")\n .description(\"Traffic, latency and resource use for an app\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-s, --since <when>\", \"Start of the window: ISO timestamp or an offset like 15m, 2h, 7d\", \"1h\")\n .option(\"--until <when>\", \"End of the window (same formats as --since)\")\n .option(\"--series\", \"Print each bucket instead of just the summary\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (opts) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const metrics = await client.apps.metrics(appId, { since: opts.since, until: opts.until });\n\n if (opts.json) {\n console.log(JSON.stringify(metrics, null, 2));\n return;\n }\n\n const t = metrics.totals;\n console.log(\n chalk.dim(`${metrics.start} \u2192 ${metrics.end} (${metrics.period}s buckets)`),\n );\n console.log();\n console.log(` ${label(\"Requests\")} ${t.requests}`);\n console.log(` ${label(\"4xx\")} ${count(t.clientErrors)}`);\n console.log(` ${label(\"5xx\")} ${count(t.serverErrors, true)}`);\n // Named for what it is rather than \"auth\": these are visitors the gate turned\n // away, which is the answer when an owner says their app looks idle.\n console.log(` ${label(\"Gate denied\")} ${count(t.gateDenied)}`);\n console.log(` ${label(\"Latency avg\")} ${ms(t.latencyAvgMs)}`);\n console.log(` ${label(\"Latency p95\")} ${ms(t.latencyP95Ms)} ${chalk.dim(\"(sampled)\")}`);\n console.log(` ${label(\"CPU avg\")} ${units(t.cpuAvg)}`);\n console.log(` ${label(\"Memory avg\")} ${mb(t.memoryAvgMb)}`);\n\n if (t.requests === 0) {\n // A gap is not published as a zero, so an app that has never been reached and\n // an app that is not deployed look the same here.\n console.log();\n console.log(chalk.dim(\"No requests recorded in this window.\"));\n }\n\n if (opts.series) {\n console.log();\n for (const [name, points] of Object.entries(metrics.series)) {\n if (points.length === 0) continue;\n console.log(chalk.bold(name));\n for (const p of points) console.log(` ${chalk.dim(p.t)} ${p.v}`);\n }\n }\n });\n\nfunction label(text: string): string {\n return chalk.dim(text.padEnd(13));\n}\n\nfunction count(n: number, severe = false): string {\n if (n === 0) return chalk.dim(\"0\");\n return severe ? chalk.red(String(n)) : chalk.yellow(String(n));\n}\n\n/** Null means nothing was reported, which is not the same as zero. */\nfunction ms(v: number | null): string {\n return v === null ? chalk.dim(\"\u2014\") : `${v} ms`;\n}\n\nfunction mb(v: number | null): string {\n return v === null ? chalk.dim(\"\u2014\") : `${v} MB`;\n}\n\nfunction units(v: number | null): string {\n return v === null ? chalk.dim(\"\u2014\") : `${v} CPU units`;\n}\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey } from \"../util.js\";\n\nexport const rollbackCommand = new Command(\"rollback\")\n .description(\"Rollback to the previous production deployment\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (opts) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const spinner = ora(\"Rolling back...\").start();\n\n try {\n const deployment = await client.apps.rollback(appId);\n spinner.succeed(chalk.green(\"Rollback successful!\"));\n if (deployment.url) {\n console.log(chalk.cyan(` URL: ${deployment.url}`));\n }\n } catch (error: any) {\n spinner.fail(chalk.red(`Rollback failed: ${error.message}`));\n process.exit(1);\n }\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport inquirer from \"inquirer\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey, formatRow } from \"../util.js\";\n\nexport const secretsCommand = new Command(\"secrets\")\n .description(\"Manage app secrets\");\n\nsecretsCommand\n .command(\"set <key> [value]\")\n .description(\"Set a secret\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (key: string, value: string | undefined, opts: any) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified.\"));\n process.exit(1);\n }\n\n if (!value) {\n const answers = await inquirer.prompt([\n { type: \"password\", name: \"value\", message: `Value for ${key}:` },\n ]);\n value = answers.value;\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n await client.secrets.set(appId, key, value!);\n console.log(chalk.green(`Secret \"${key}\" set successfully.`));\n });\n\nsecretsCommand\n .command(\"list\")\n .description(\"List all secrets\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (opts: any) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const secrets = await client.secrets.list(appId);\n\n if (secrets.length === 0) {\n console.log(chalk.gray(\"No secrets configured.\"));\n return;\n }\n\n console.log(formatRow([\"KEY\", \"UPDATED\"], [30, 24]));\n for (const secret of secrets) {\n console.log(formatRow([secret.key, secret.updatedAt], [30, 24]));\n }\n });\n\nsecretsCommand\n .command(\"remove <key>\")\n .description(\"Remove a secret\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (key: string, opts: any) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n await client.secrets.delete(appId, key);\n console.log(chalk.green(`Secret \"${key}\" removed.`));\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport inquirer from \"inquirer\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp, getDefaultOrg, setCurrentApp } from \"../config.js\";\nimport { requireApiKey, requireOrg, formatRow, appUrl } from \"../util.js\";\nimport {\n DEFAULT_VISIBILITY,\n VISIBILITIES,\n VISIBILITY_LABELS,\n isVisibility,\n visibilityOf,\n type App,\n type Visibility,\n} from \"@cloud/shared\";\n\nexport const appsCommand = new Command(\"apps\")\n .description(\"Manage apps\");\n\n/**\n * Validates `--access` here rather than letting the API answer 400.\n *\n * A tier is a security setting, so a typo has to fail loudly and name the legal\n * values \u2014 and it must fail *before* the rest of a `set` call is applied, since\n * a partially-applied settings write is worse than a refused one.\n */\nfunction accessOption(value: string | undefined): Visibility | undefined {\n if (value === undefined) return undefined;\n const tier = value.trim().toLowerCase();\n if (!isVisibility(tier)) {\n console.error(chalk.red(`Unknown --access value \"${value}\". Use one of: ${VISIBILITIES.join(\", \")}`));\n process.exit(1);\n }\n return tier;\n}\n\n/** Reads the tier from a response, falling back to the legacy boolean. */\nfunction describeAccess(app: Pick<App, \"authRequired\"> & { visibility?: string }): string {\n // An older API that does not send `visibility` still sends the boolean, and a\n // gated app is org-wide by default there.\n const tier = app.visibility ? visibilityOf(app.visibility) : app.authRequired ? \"org\" : \"public\";\n return `${tier} \u2014 ${VISIBILITY_LABELS[tier].toLowerCase()}`;\n}\n\nappsCommand\n .command(\"list\")\n .description(\"List all apps\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .action(async (opts: { org?: string }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const orgId = requireOrg(opts.org || getDefaultOrg());\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const apps = await client.apps.list(orgId);\n\n if (apps.length === 0) {\n console.log(chalk.gray(\"No apps yet. Create one with `videan apps create`.\"));\n return;\n }\n\n const widths = [20, 24, 10, 44];\n console.log(formatRow([\"NAME\", \"ID\", \"STATUS\", \"URL\"], widths));\n for (const app of apps) {\n console.log(formatRow([app.name, app.id, app.status, appUrl(app.slug)], widths));\n }\n });\n\nappsCommand\n .command(\"create\")\n .description(\"Create a new app\")\n .option(\"-n, --name <name>\", \"App name\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .option(\"--postgres\", \"Provision a managed Postgres database\")\n // Both off unless asked for: storage outlives the code that wrote it and is\n // billed, and sending mail spends the platform's shared reputation.\n .option(\"--storage\", \"Give the app an object-storage prefix\")\n .option(\"--email\", \"Let the app send mail through the platform\")\n // The platform gates apps behind login by default; this opts out.\n .option(\"--public\", \"Serve the app without the platform login gate (same as --access public)\")\n .option(\"--access <tier>\", `Who may open the app: ${VISIBILITIES.join(\" | \")} (default: ${DEFAULT_VISIBILITY})`)\n .action(\n async (opts: {\n name?: string;\n org?: string;\n postgres?: boolean;\n storage?: boolean;\n email?: boolean;\n public?: boolean;\n access?: string;\n }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const orgId = requireOrg(opts.org || getDefaultOrg());\n\n let name = opts.name;\n if (!name) {\n const answers = await inquirer.prompt([\n { type: \"input\", name: \"name\", message: \"App name:\" },\n ]);\n name = answers.name;\n }\n if (!name) {\n console.error(chalk.red(\"An app name is required.\"));\n process.exit(1);\n }\n\n const visibility = accessOption(opts.access) ?? (opts.public ? \"public\" : undefined);\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const app = await client.apps.create({\n name,\n orgId,\n postgres: opts.postgres ?? false,\n storage: opts.storage ?? false,\n email: opts.email ?? false,\n visibility,\n });\n setCurrentApp(app.id);\n\n console.log(chalk.green(`App \"${app.name}\" created (${app.id})`));\n console.log(chalk.gray(` Access: ${describeAccess(app)}`));\n console.log(chalk.gray(` URL after first deploy: ${appUrl(app.slug)}`));\n // Runtime is detected from the pushed files, so there is nothing to pick here.\n console.log(chalk.gray(\" Push code with `videan deploy` \u2014 the runtime is auto-detected.\"));\n },\n );\n\nappsCommand\n .command(\"set\")\n .description(\"Change an app's settings (scale, rate limit, gate, capabilities)\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-n, --name <name>\", \"Rename the app (the URL keeps its original slug)\")\n .option(\"--cpu <units>\", \"CPU units per instance (256 = 0.25 vCPU)\")\n .option(\"--memory <mib>\", \"Memory per instance, in MiB\")\n .option(\"--instances <n>\", \"Number of instances to run\")\n .option(\"--rate-limit <rpm>\", \"Requests per minute per client\")\n .option(\"--no-rate-limit\", \"Remove the rate limit\")\n .option(\"--access <tier>\", `Who may open the app: ${VISIBILITIES.join(\" | \")}`)\n .option(\"--public\", \"Serve without the platform login gate (same as --access public)\")\n .option(\"--private\", \"Require platform login (leaves the tier alone if it is already gated)\")\n .option(\"--postgres\", \"Provision a managed Postgres database\")\n .option(\"--storage\", \"Give the app an object-storage prefix\")\n .option(\"--email\", \"Let the app send mail through the platform\")\n .option(\"--json\", \"Print the raw response\")\n .action(\n async (opts: {\n app?: string;\n name?: string;\n cpu?: string;\n memory?: string;\n instances?: string;\n // commander sets this to false for --no-rate-limit and to the string for\n // --rate-limit, so the three states (untouched / removed / set) are\n // distinguishable: undefined, false, \"120\".\n rateLimit?: string | boolean;\n access?: string;\n public?: boolean;\n private?: boolean;\n postgres?: boolean;\n storage?: boolean;\n email?: boolean;\n json?: boolean;\n }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n\n if (opts.public && opts.private) {\n console.error(chalk.red(\"--public and --private contradict each other.\"));\n process.exit(1);\n }\n const access = accessOption(opts.access);\n if (access && (opts.public || opts.private)) {\n // Both would be sent and the API resolves `visibility` first, so the\n // boolean would be silently ignored. Refusing beats applying one of two\n // access settings the caller asked for.\n console.error(chalk.red(\"--access already says who may open the app; drop --public/--private.\"));\n process.exit(1);\n }\n\n const changes: Parameters<CloudClient[\"apps\"][\"update\"]>[1] = {};\n if (opts.name) changes.name = opts.name;\n if (opts.cpu !== undefined) changes.cpu = intOption(\"--cpu\", opts.cpu);\n if (opts.memory !== undefined) changes.memory = intOption(\"--memory\", opts.memory);\n if (opts.instances !== undefined) {\n changes.instances = intOption(\"--instances\", opts.instances);\n }\n if (opts.rateLimit === false) changes.rateLimitPerMinute = null;\n else if (typeof opts.rateLimit === \"string\") {\n changes.rateLimitPerMinute = intOption(\"--rate-limit\", opts.rateLimit);\n }\n if (access) changes.visibility = access;\n if (opts.public) changes.authRequired = false;\n if (opts.private) changes.authRequired = true;\n if (opts.postgres) changes.postgres = true;\n if (opts.storage) changes.storage = true;\n if (opts.email) changes.email = true;\n\n if (Object.keys(changes).length === 0) {\n // Otherwise this reports success having changed nothing, which reads as the\n // setting being applied.\n console.error(chalk.red(\"Nothing to change. Pass at least one option.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const app = await client.apps.update(appId, changes);\n\n if (opts.json) {\n console.log(JSON.stringify(app, null, 2));\n return;\n }\n\n console.log(chalk.green(`Updated ${app.name} (${app.id})`));\n console.log(` Access: ${describeAccess(app)}`);\n console.log(` Scale: ${app.cpu ?? \"default\"} CPU / ${app.memory ?? \"default\"} MiB`);\n console.log(\n ` Rate limit: ${app.rateLimitPerMinute ? `${app.rateLimitPerMinute}/min per client` : \"none\"}`,\n );\n if (app.restartRequired) {\n // Reported, not done: a restart is a brief interruption, and taking one as a\n // side effect of a settings write is not something to discover afterwards.\n console.log(\n chalk.yellow(\"\\n These settings apply to the next deploy. Run `videan deploy` to pick them up.\"),\n );\n }\n },\n );\n\n/** Parse a numeric flag, failing on junk rather than sending NaN to the API. */\nfunction intOption(flag: string, raw: string): number {\n const n = Number(raw);\n if (!Number.isInteger(n) || n <= 0) {\n console.error(chalk.red(`${flag} expects a positive whole number, got \"${raw}\".`));\n process.exit(1);\n }\n return n;\n}\n\nappsCommand\n .command(\"delete <id>\")\n .description(\"Delete an app and all its resources\")\n .action(async (id: string) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const { confirm } = await inquirer.prompt([\n {\n type: \"confirm\",\n name: \"confirm\",\n message: `Delete app ${id}? This stops the app and destroys its database, secrets and snapshots.`,\n default: false,\n },\n ]);\n\n if (!confirm) return;\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const { warnings } = await client.apps.delete(id);\n\n console.log(chalk.green(\"App deleted.\"));\n if (warnings.length > 0) {\n // Say so loudly: leaked AWS resources keep costing money.\n console.log(chalk.yellow(\"\\nSome resources could not be released:\"));\n for (const w of warnings) {\n console.log(chalk.yellow(` ${w.step}: ${w.error || \"unknown error\"}`));\n }\n }\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey, formatStatus, appUrl } from \"../util.js\";\nimport { VISIBILITY_LABELS, visibilityOf, type App } from \"@cloud/shared\";\n\n/**\n * Falls back to the legacy boolean, which is all an older API sends. A gated app\n * is org-wide there, so that is what the boolean means.\n */\nfunction accessLine(app: Pick<App, \"authRequired\"> & { visibility?: string }): string {\n const tier = app.visibility ? visibilityOf(app.visibility) : app.authRequired ? \"org\" : \"public\";\n return `${tier} \u2014 ${VISIBILITY_LABELS[tier].toLowerCase()}`;\n}\n\nexport const statusCommand = new Command(\"status\")\n .description(\"Show current app status\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (opts) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const appId = opts.app || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const app = await client.apps.get(appId);\n // Health reads ECS rather than the deployment row, which keeps saying\n // \"running\" after the container dies.\n const health = await client.apps.health(appId);\n\n console.log(chalk.bold(app.name));\n console.log(` ID: ${app.id}`);\n console.log(` Created: ${app.createdAt}`);\n console.log(` Postgres: ${app.postgresEnabled ? \"enabled\" : \"disabled\"}`);\n console.log(` Access: ${accessLine(app)}`);\n console.log(` State: ${formatStatus(health.state)}`);\n console.log(` Healthy: ${health.healthy ? chalk.green(\"yes\") : chalk.red(\"no\")}`);\n console.log(` URL: ${chalk.cyan(health.url || appUrl(app.slug))}`);\n\n const task = health.task;\n if (task) {\n if (task.exit_code !== undefined && task.exit_code !== null) {\n const code = String(task.exit_code);\n console.log(` Exit code: ${task.exit_code === 0 ? code : chalk.red(code)}`);\n }\n if (task.stopped_reason) {\n console.log(` Stopped: ${chalk.yellow(task.stopped_reason)}`);\n }\n if (task.container_reason) {\n console.log(` Detail: ${chalk.yellow(task.container_reason)}`);\n }\n }\n\n if (!health.healthy) {\n console.log(chalk.gray(\"\\nRun `videan logs` to see why.\"));\n }\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport inquirer from \"inquirer\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getDefaultOrg } from \"../config.js\";\nimport { requireApiKey, requireOrg, formatRow } from \"../util.js\";\n\nexport const keysCommand = new Command(\"keys\")\n .description(\"Manage API keys for programmatic access\");\n\nkeysCommand\n .command(\"create <name>\")\n .description(\"Create an API key\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .option(\"-e, --expires <days>\", \"Expire the key after N days\")\n .option(\n \"--app <id>\",\n \"Pin the key to one app (a service token, for code running inside it)\",\n )\n .action(async (name: string, opts: { org?: string; expires?: string; app?: string }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const orgId = requireOrg(opts.org || getDefaultOrg());\n\n let expiresInDays: number | undefined;\n if (opts.expires !== undefined) {\n expiresInDays = Number(opts.expires);\n if (!Number.isInteger(expiresInDays) || expiresInDays < 1) {\n console.error(chalk.red(\"--expires must be a whole number of days, at least 1.\"));\n process.exit(1);\n }\n }\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const key = await client.apiKeys.create({\n name,\n orgId,\n expiresInDays,\n appId: opts.app,\n });\n\n console.log(chalk.green(`Created key \"${key.name}\" (${key.id})`));\n // Printed once and never retrievable -- the server only stores a hash.\n console.log(`\\n ${chalk.bold(key.key)}\\n`);\n console.log(chalk.yellow(\"Copy it now. It cannot be shown again.\"));\n if (key.appId) {\n // Worth stating: this is the only kind of key that is safe to ship inside a\n // deployed app, and the difference is invisible in the key itself.\n console.log(\n chalk.gray(`Service token, scoped to app ${key.appId}. It cannot reach anything else.`),\n );\n } else {\n console.log(\n chalk.gray(\"Acts as you across every app in the org -- do not deploy it inside an app.\"),\n );\n }\n if (key.expiresAt) {\n console.log(chalk.gray(`Expires ${key.expiresAt}`));\n }\n });\n\nkeysCommand\n .command(\"list\")\n .description(\"List API keys\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .action(async (opts: { org?: string }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const orgId = requireOrg(opts.org || getDefaultOrg());\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const keys = await client.apiKeys.list(orgId);\n\n if (keys.length === 0) {\n console.log(chalk.gray(\"No API keys. Create one with `videan keys create <name>`.\"));\n return;\n }\n\n const widths = [24, 24, 16, 22, 12, 24];\n console.log(formatRow([\"NAME\", \"ID\", \"PREFIX\", \"LAST USED\", \"STATE\", \"SCOPE\"], widths));\n for (const key of keys) {\n const state = key.revokedAt\n ? chalk.red(\"revoked\")\n : key.expiresAt && new Date(key.expiresAt) < new Date()\n ? chalk.yellow(\"expired\")\n : chalk.green(\"active\");\n console.log(formatRow(\n [\n key.name,\n key.id,\n `${key.keyPrefix}\u2026`,\n key.lastUsedAt || \"never\",\n state,\n key.appId ? `app ${key.appId}` : \"org-wide\",\n ],\n widths,\n ));\n }\n });\n\nkeysCommand\n .command(\"revoke <id>\")\n .description(\"Revoke an API key\")\n .action(async (id: string) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const { confirm } = await inquirer.prompt([\n { type: \"confirm\", name: \"confirm\", message: `Revoke key ${id}?`, default: false },\n ]);\n if (!confirm) return;\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n await client.apiKeys.revoke(id);\n console.log(chalk.green(\"Key revoked.\"));\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getDefaultOrg, setDefaultOrg } from \"../config.js\";\nimport { requireApiKey, requireOrg, formatRow } from \"../util.js\";\n\nexport const orgsCommand = new Command(\"orgs\")\n .description(\"Manage organizations\");\n\norgsCommand\n .command(\"list\")\n .description(\"List your organizations\")\n .action(async () => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const orgs = await client.orgs.list();\n const current = getDefaultOrg();\n\n if (orgs.length === 0) {\n console.log(chalk.gray(\"No organizations. Create one with `videan orgs create <name>`.\"));\n return;\n }\n\n const widths = [24, 24, 10, 8];\n console.log(formatRow([\"NAME\", \"ID\", \"PLAN\", \"\"], widths));\n for (const org of orgs) {\n console.log(formatRow(\n [org.name, org.id, org.plan, org.id === current ? chalk.green(\"default\") : \"\"],\n widths,\n ));\n }\n });\n\norgsCommand\n .command(\"create <name>\")\n .description(\"Create an organization\")\n .action(async (name: string) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const org = await client.orgs.create(name);\n // First org becomes the default so subsequent commands need no --org.\n if (!getDefaultOrg()) setDefaultOrg(org.id);\n\n console.log(chalk.green(`Organization \"${org.name}\" created (${org.id})`));\n });\n\norgsCommand\n .command(\"use <id>\")\n .description(\"Set the default organization for this machine\")\n .action(async (id: string) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n\n // Verify membership before saving, so a typo fails here instead of on every\n // later command.\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const org = await client.orgs.get(id);\n setDefaultOrg(org.id);\n\n console.log(chalk.green(`Default organization set to \"${org.name}\".`));\n });\n\norgsCommand\n .command(\"members\")\n .description(\"List organization members\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .action(async (opts: { org?: string }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const orgId = requireOrg(opts.org || getDefaultOrg());\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n const members = await client.orgs.members(orgId);\n\n const widths = [32, 24, 10];\n console.log(formatRow([\"EMAIL\", \"NAME\", \"ROLE\"], widths));\n for (const member of members) {\n console.log(formatRow(\n [member.email || member.user_id, member.name || \"-\", member.role],\n widths,\n ));\n }\n });\n\norgsCommand\n .command(\"invite <email>\")\n .description(\"Invite a member by email\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .action(async (email: string, opts: { org?: string }) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const orgId = requireOrg(opts.org || getDefaultOrg());\n\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n await client.orgs.invite(orgId, email);\n console.log(chalk.green(`Invited ${email}.`));\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey, formatRow } from \"../util.js\";\n\n/**\n * `videan storage` -- files an app keeps for itself, separate from its code.\n *\n * Upload and download go direct to S3 through a presigned URL, so a large file\n * does not travel through the control API. That is also why `put` reads and\n * writes real bytes rather than the text-only path `videan deploy` uses for\n * snapshots: this is where binaries belong.\n */\nexport const storageCommand = new Command(\"storage\").description(\"Store files for an app\");\n\nfunction client() {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n return new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n}\n\nfunction requireApp(opt?: string): string {\n const appId = opt || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n return appId;\n}\n\n/** 1.2 KB rather than 1234 -- the size is being read, not summed. */\nfunction human(bytes: number): string {\n const units = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\"];\n let n = bytes;\n let i = 0;\n while (n >= 1024 && i < units.length - 1) {\n n /= 1024;\n i++;\n }\n return `${i === 0 ? n : n.toFixed(1)} ${units[i]}`;\n}\n\nstorageCommand\n .command(\"ls [prefix]\")\n .description(\"List stored objects\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (prefix: string | undefined, opts: { app?: string; json?: boolean }) => {\n const appId = requireApp(opts.app);\n // Every page, not the first: a truncated listing that looks complete is how a\n // caller concludes a file was never uploaded.\n const objects = await client().storage.listAll(appId, prefix);\n\n if (opts.json) {\n console.log(JSON.stringify(objects, null, 2));\n return;\n }\n if (objects.length === 0) {\n console.log(chalk.gray(\"No objects stored. Upload one with `videan storage put <file>`.\"));\n return;\n }\n\n const widths = [52, 12, 24];\n console.log(formatRow([\"KEY\", \"SIZE\", \"MODIFIED\"], widths));\n for (const o of objects) {\n console.log(formatRow([o.key, human(o.size), o.lastModified || \"-\"], widths));\n }\n const total = objects.reduce((sum, o) => sum + o.size, 0);\n console.log(chalk.dim(`\\n${objects.length} object(s), ${human(total)}`));\n });\n\nstorageCommand\n .command(\"put <file> [key]\")\n .description(\"Upload a file (key defaults to the file's name)\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-t, --type <mime>\", \"Content type\")\n .action(async (file: string, key: string | undefined, opts: { app?: string; type?: string }) => {\n const appId = requireApp(opts.app);\n if (!(await fs.pathExists(file))) {\n console.error(chalk.red(`No such file: ${file}`));\n process.exit(1);\n }\n const body = await fs.readFile(file);\n const objectKey = key || path.basename(file);\n\n const stored = await client().storage.upload(appId, objectKey, body, {\n contentType: opts.type,\n });\n console.log(\n chalk.green(`Uploaded ${objectKey}`) + chalk.dim(` (${human(body.length)})`),\n );\n if (stored.etag) console.log(chalk.dim(`etag ${stored.etag}`));\n });\n\nstorageCommand\n .command(\"get <key> [file]\")\n .description(\"Download an object (defaults to the key's basename)\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (key: string, file: string | undefined, opts: { app?: string }) => {\n const appId = requireApp(opts.app);\n const bytes = await client().storage.download(appId, key);\n const dest = file || path.basename(key);\n await fs.writeFile(dest, bytes);\n console.log(chalk.green(`Wrote ${dest}`) + chalk.dim(` (${human(bytes.length)})`));\n });\n\nstorageCommand\n .command(\"rm <key>\")\n .description(\"Delete an object\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (key: string, opts: { app?: string }) => {\n const appId = requireApp(opts.app);\n await client().storage.delete(appId, key);\n // Deliberately not \"not found\" when it was already gone: delete is idempotent\n // server-side, and the state the caller wanted is the state they have.\n console.log(chalk.green(`Deleted ${key}`));\n });\n\nstorageCommand\n .command(\"url <key>\")\n .description(\"Print a temporary link to an object\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-e, --expires <seconds>\", \"Lifetime in seconds (30-3600)\", \"900\")\n .option(\"--upload\", \"Sign an upload (PUT) URL instead of a download\")\n .option(\"-d, --download <filename>\", \"Serve as a download with this filename\")\n .action(async (key: string, opts: any) => {\n const appId = requireApp(opts.app);\n const expiresIn = Number(opts.expires);\n if (!Number.isInteger(expiresIn) || expiresIn < 30 || expiresIn > 3600) {\n console.error(chalk.red(\"--expires must be a whole number of seconds between 30 and 3600.\"));\n process.exit(1);\n }\n\n const signed = await client().storage.presign(appId, key, {\n method: opts.upload ? \"put\" : \"get\",\n expiresIn,\n download: opts.download,\n });\n console.log(signed.url);\n // Said plainly because the URL looks like an ordinary link and is not one:\n // anyone who holds it has that access without logging in.\n console.error(\n chalk.yellow(\n `This ${signed.method} link works for ${expiresIn}s for anyone who has it.`,\n ),\n );\n });\n\nstorageCommand\n .command(\"usage\")\n .description(\"Total objects and bytes stored\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (opts: { app?: string }) => {\n const appId = requireApp(opts.app);\n const { objects, bytes } = await client().storage.usage(appId);\n console.log(`${objects} object(s), ${human(bytes)}`);\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey } from \"../util.js\";\n\n/**\n * `videan email` -- send mail as an app, through the platform's verified domain.\n *\n * There is no `--from`. Mail goes out as `app-<slug>@<platform domain>`, which is\n * what keeps an app from sending as the platform's own `no-reply@` -- the address\n * password resets come from. `--reply-to` is the lever for routing replies\n * somewhere the app owns.\n */\nexport const emailCommand = new Command(\"email\").description(\"Send email from an app\");\n\nfunction client() {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n return new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n}\n\nfunction requireApp(opt?: string): string {\n const appId = opt || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or link an app.\"));\n process.exit(1);\n }\n return appId;\n}\n\nemailCommand\n .command(\"send\")\n .description(\"Send an email\")\n .requiredOption(\"-t, --to <address...>\", \"Recipient address (repeatable)\")\n .requiredOption(\"-s, --subject <subject>\", \"Subject line\")\n .option(\"--text <body>\", \"Plain-text body\")\n .option(\"--html <body>\", \"HTML body\")\n .option(\"--body-file <path>\", \"Read the body from a file\")\n .option(\"--reply-to <address>\", \"Where replies should go\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"--json\", \"Print the raw response\")\n .action(\n async (opts: {\n to: string[];\n subject: string;\n text?: string;\n html?: string;\n bodyFile?: string;\n replyTo?: string;\n app?: string;\n json?: boolean;\n }) => {\n const appId = requireApp(opts.app);\n\n let text = opts.text;\n let html = opts.html;\n if (opts.bodyFile) {\n const contents = await fs.readFile(opts.bodyFile, \"utf-8\");\n // The extension decides which part it becomes: sending HTML as the plain\n // part delivers visible markup, which looks like a broken app rather than\n // a wrong flag.\n if (/\\.html?$/i.test(opts.bodyFile)) html = contents;\n else text = contents;\n }\n if (!text && !html) {\n console.error(chalk.red(\"Nothing to send. Pass --text, --html or --body-file.\"));\n process.exit(1);\n }\n\n const sent = await client().email.send(appId, {\n to: opts.to,\n subject: opts.subject,\n text,\n html,\n replyTo: opts.replyTo,\n });\n\n if (opts.json) {\n console.log(JSON.stringify(sent, null, 2));\n return;\n }\n\n console.log(chalk.green(\"Sent\"));\n console.log(` From: ${sent.from}`);\n console.log(` To: ${sent.to.join(\", \")}`);\n console.log(` Message: ${sent.messageId ?? \"(no id returned)\"}`);\n // Printed on every send: the quota is per day and shared with nothing else,\n // so the moment to notice it is running low is before it runs out.\n console.log(\n chalk.dim(\n ` Quota: ${sent.quota.sent}/${sent.quota.quota} today, resets ${sent.quota.resetsAt}`,\n ),\n );\n },\n );\n\nemailCommand\n .command(\"quota\")\n .description(\"Show today's sending allowance\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (opts: { app?: string; json?: boolean }) => {\n const quota = await client().email.quota(requireApp(opts.app));\n if (opts.json) {\n console.log(JSON.stringify(quota, null, 2));\n return;\n }\n console.log(`Sent today: ${quota.sent}`);\n console.log(`Daily quota: ${quota.quota}`);\n console.log(`Remaining: ${quota.remaining}`);\n console.log(chalk.dim(`Resets at: ${quota.resetsAt}`));\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport { CloudClient } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp } from \"../config.js\";\nimport { requireApiKey } from \"../util.js\";\n\n/**\n * `videan jobs` -- the background queue.\n *\n * A job is a POST the platform makes to a path on the app itself, so there is no\n * worker to deploy: the handler is a route in the app, and `videan jobs enqueue`\n * is a way to trigger it out of band. Retries mean a handler can see the same job\n * twice -- `--key` is how a caller stops its *own* retry from becoming two jobs.\n */\nexport const jobsCommand = new Command(\"jobs\").description(\"Enqueue and inspect background jobs\");\n\nfunction client() {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n return new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n}\n\nfunction requireApp(opt?: string): string {\n const appId = opt || getCurrentApp();\n if (!appId) {\n console.error(chalk.red(\"No app specified. Use --app or run `videan init` first.\"));\n process.exit(1);\n }\n return appId;\n}\n\n/** Parse a numeric flag, failing on junk rather than sending NaN to the API. */\nfunction intOption(flag: string, raw: string): number {\n const n = Number(raw);\n if (!Number.isInteger(n) || n < 0) {\n console.error(chalk.red(`${flag} expects a whole number, got \"${raw}\".`));\n process.exit(1);\n }\n return n;\n}\n\nconst STATUS_COLOR: Record<string, (s: string) => string> = {\n queued: chalk.yellow,\n running: chalk.cyan,\n succeeded: chalk.green,\n dead: chalk.red,\n cancelled: chalk.gray,\n};\n\nfunction statusLabel(status: string): string {\n return (STATUS_COLOR[status] ?? chalk.white)(status);\n}\n\njobsCommand\n .command(\"enqueue\")\n .description(\"Queue a job for the app to run\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-q, --queue <name>\", \"Queue name (default: default)\")\n .option(\"-p, --path <path>\", \"Path on the app to POST to (default: /jobs)\")\n .option(\"-d, --data <json>\", \"JSON payload\")\n .option(\"-f, --file <path>\", \"Read the JSON payload from a file\")\n .option(\"--delay <seconds>\", \"Run no earlier than this many seconds from now\")\n .option(\"--attempts <n>\", \"Attempts before the job is given up on (default: 3)\")\n .option(\"--timeout <seconds>\", \"How long the handler gets per attempt (default: 60)\")\n .option(\"--key <key>\", \"Idempotency key -- a repeat returns the same job\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (opts) => {\n const appId = requireApp(opts.app);\n\n // Read from a file or a flag, and refuse invalid JSON here rather than letting\n // the API reject it: the payload is usually the thing being iterated on, and a\n // round trip to say \"bad JSON\" is a slow way to learn about a typo.\n let payload: unknown;\n const raw = opts.file ? await fs.readFile(opts.file, \"utf-8\") : opts.data;\n if (raw !== undefined) {\n try {\n payload = JSON.parse(raw);\n } catch (e: any) {\n console.error(chalk.red(`--${opts.file ? \"file\" : \"data\"} is not valid JSON: ${e.message}`));\n process.exit(1);\n }\n }\n\n const job = await client().jobs.enqueue(appId, {\n queue: opts.queue,\n path: opts.path,\n payload,\n delaySeconds: opts.delay !== undefined ? intOption(\"--delay\", opts.delay) : undefined,\n maxAttempts: opts.attempts !== undefined ? intOption(\"--attempts\", opts.attempts) : undefined,\n timeoutSeconds: opts.timeout !== undefined ? intOption(\"--timeout\", opts.timeout) : undefined,\n idempotencyKey: opts.key,\n });\n\n if (opts.json) {\n console.log(JSON.stringify(job, null, 2));\n return;\n }\n\n if (job.deduplicated) {\n // Said plainly, because the alternative reading -- that the job was queued\n // again -- is the one that leads to work being counted twice.\n console.log(chalk.yellow(`Already queued as ${job.id} (idempotency key \"${opts.key}\")`));\n } else {\n console.log(chalk.green(`Queued ${job.id}`));\n }\n console.log(chalk.gray(` ${job.method} ${job.path} on queue \"${job.queue}\"`));\n if (job.runAt && Date.parse(job.runAt) > Date.now() + 1000) {\n console.log(chalk.gray(` Runs at ${new Date(job.runAt).toLocaleString()}`));\n }\n });\n\njobsCommand\n .command(\"list\")\n .description(\"List jobs, newest first\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"-s, --status <status>\", \"queued, running, succeeded, dead or cancelled\")\n .option(\"-q, --queue <name>\", \"Only this queue\")\n .option(\"-n, --limit <n>\", \"How many to show (default: 20)\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (opts) => {\n const appId = requireApp(opts.app);\n const { jobs, counts } = await client().jobs.list(appId, {\n status: opts.status,\n queue: opts.queue,\n limit: opts.limit !== undefined ? intOption(\"--limit\", opts.limit) : 20,\n });\n\n if (opts.json) {\n console.log(JSON.stringify({ jobs, counts }, null, 2));\n return;\n }\n\n // Depth first: a page of 20 cannot say how far behind the queue is, and that\n // is the question someone running this is usually asking.\n const depth = Object.entries(counts)\n .map(([status, n]) => `${statusLabel(status)} ${n}`)\n .join(\" \");\n console.log(depth || chalk.gray(\"No jobs yet.\"));\n\n if (jobs.length === 0) return;\n console.log();\n for (const job of jobs) {\n const attempts = job.attempts > 0 ? chalk.gray(` ${job.attempts}/${job.maxAttempts}`) : \"\";\n console.log(\n `${statusLabel(job.status).padEnd(20)} ${chalk.white(job.id)} ${chalk.gray(\n `${job.queue} ${job.path}`,\n )}${attempts}`,\n );\n // Only the last error, and only when there is one: a queued job with an\n // error is a job that failed and is waiting to be retried, which reads as\n // healthy without it.\n if (job.error) console.log(chalk.red(` ${job.error}`));\n }\n });\n\njobsCommand\n .command(\"get <job-id>\")\n .description(\"Show one job in full\")\n .option(\"-a, --app <id>\", \"App ID\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (jobId, opts) => {\n const job = await client().jobs.get(requireApp(opts.app), jobId);\n if (opts.json) {\n console.log(JSON.stringify(job, null, 2));\n return;\n }\n console.log(`${chalk.white(job.id)} ${statusLabel(job.status)}`);\n console.log(chalk.gray(` ${job.method} ${job.path} on queue \"${job.queue}\"`));\n console.log(chalk.gray(` Attempts: ${job.attempts}/${job.maxAttempts}`));\n if (job.statusCode) console.log(chalk.gray(` Last response: HTTP ${job.statusCode}`));\n if (job.durationMs) console.log(chalk.gray(` Took: ${job.durationMs}ms`));\n if (job.error) console.log(chalk.red(` Error: ${job.error}`));\n if (job.status === \"queued\" && job.attempts > 0) {\n console.log(chalk.yellow(` Retrying at ${new Date(job.runAt).toLocaleString()}`));\n }\n if (job.payload !== null && job.payload !== undefined) {\n console.log(chalk.gray(\" Payload:\"));\n console.log(\n JSON.stringify(job.payload, null, 2)\n .split(\"\\n\")\n .map((l) => ` ${l}`)\n .join(\"\\n\"),\n );\n }\n });\n\njobsCommand\n .command(\"retry <job-id>\")\n .description(\"Run a dead job again, from a clean attempt count\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (jobId, opts) => {\n const job = await client().jobs.retry(requireApp(opts.app), jobId);\n console.log(chalk.green(`Requeued ${job.id}`));\n });\n\njobsCommand\n .command(\"cancel <job-id>\")\n .description(\"Cancel a job that has not started yet\")\n .option(\"-a, --app <id>\", \"App ID\")\n .action(async (jobId, opts) => {\n const job = await client().jobs.cancel(requireApp(opts.app), jobId);\n console.log(chalk.green(`Cancelled ${job.id}`));\n });\n", "import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { CloudClient, type UsageQuantity } from \"@videan/sdk\";\nimport { getApiKey, getBaseUrl, getCurrentApp, getDefaultOrg } from \"../config.js\";\nimport { requireApiKey } from \"../util.js\";\n\n/**\n * `videan usage` -- what the month costs, and where it went.\n *\n * Org-level by default, because that is the number that gets invoiced; `--app`\n * narrows to one app's share. The two do not add up to the same figure on purpose:\n * the plan's included allowance applies once to the org, so per-app lines are list\n * price with no allowance and the org total subtracts it exactly once.\n *\n * Nothing here changes a plan or pays anything. `videan usage plans` prints the\n * catalogue so an upgrade can be priced before anyone talks to a card.\n */\nexport const usageCommand = new Command(\"usage\")\n .description(\"Metered usage and cost for the current month\")\n .option(\"-o, --org <id>\", \"Organization ID\")\n .option(\"-a, --app <id>\", \"Show one app's share instead of the whole org\")\n .option(\"-p, --period <YYYY-MM>\", \"Month to report on (default: the month in progress)\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (opts) => {\n const apiKey = getApiKey();\n requireApiKey(apiKey);\n const client = new CloudClient({ apiKey, baseUrl: getBaseUrl() });\n\n if (opts.app || (!opts.org && getCurrentApp() && !getDefaultOrg())) {\n const appId = opts.app || getCurrentApp()!;\n const report = await client.apps.usage(appId, opts.period);\n if (opts.json) return void console.log(JSON.stringify(report, null, 2));\n\n console.log(chalk.dim(`${period(report.periodStart, report.periodEnd)} app ${appId}`));\n console.log();\n printMetrics(report.metrics);\n console.log();\n for (const line of report.lines) {\n console.log(` ${chalk.dim(line.label.padEnd(22))} ${money(line.cents)}`);\n }\n console.log(` ${chalk.bold(\"Share of the bill\".padEnd(22))} ${chalk.bold(report.cost)}`);\n console.log();\n console.log(\n chalk.dim(\"At list price, with no plan allowance applied \u2014 see `videan usage` for the org total.\"),\n );\n return;\n }\n\n const orgId = opts.org || getDefaultOrg();\n if (!orgId) {\n console.error(chalk.red(\"No org specified. Use --org, or --app for a single app.\"));\n process.exit(1);\n }\n\n const report = await client.orgs.usage(orgId, opts.period);\n if (opts.json) return void console.log(JSON.stringify(report, null, 2));\n\n const inv = report.invoice;\n console.log(\n chalk.dim(`${period(report.periodStart, report.periodEnd)} org ${orgId} plan ${report.plan}`),\n );\n console.log();\n printMetrics(report.metrics);\n\n if (report.apps.length > 0) {\n console.log();\n console.log(chalk.bold(\"By app\"));\n // Descending, because the question is which app is costing the money.\n for (const app of [...report.apps].sort((a, b) => b.cents - a.cents)) {\n const name = app.slug || app.name || app.appId || \"(deleted apps)\";\n console.log(` ${chalk.dim(String(name).padEnd(24))} ${money(app.cents)}`);\n }\n }\n\n console.log();\n for (const line of inv.lines) {\n console.log(\n ` ${chalk.dim(line.label.padEnd(22))} ${money(line.cents)} ${chalk.dim(\n `(${line.quantity} \u00D7 ${line.unitPriceCents}\u00A2)`,\n )}`,\n );\n }\n console.log(` ${chalk.dim(\"Usage\".padEnd(22))} ${money(inv.usageCents)}`);\n if (inv.includedUsageCents > 0) {\n console.log(\n ` ${chalk.dim(\"Included\".padEnd(22))} ${chalk.green(`-${money(Math.min(inv.usageCents, inv.includedUsageCents))}`)}`,\n );\n }\n if (inv.baseCents > 0) {\n console.log(` ${chalk.dim(\"Plan\".padEnd(22))} ${money(inv.baseCents)}`);\n }\n console.log(` ${chalk.bold(\"Total\".padEnd(22))} ${chalk.bold(report.total)}`);\n console.log();\n // Said explicitly: the month is not over, so this is what has accrued rather\n // than what will be charged.\n console.log(chalk.dim(\"Usage to date. The period is priced as it stands right now.\"));\n });\n\nusageCommand\n .command(\"plans\")\n .description(\"The plan catalogue and what each one allows\")\n .option(\"--json\", \"Print the raw response\")\n .action(async (opts) => {\n // No key needed by the API, but the client requires one; an empty string is\n // enough and keeps `videan usage plans` working before login.\n const client = new CloudClient({ apiKey: getApiKey() || \"\", baseUrl: getBaseUrl() });\n const plans = await client.plans();\n if (opts.json) return void console.log(JSON.stringify(plans, null, 2));\n\n for (const plan of plans) {\n console.log(\n `${chalk.bold(plan.name)} ${chalk.dim(`(${plan.id})`)} ${plan.base}/mo` +\n (plan.includedUsageCents > 0 ? chalk.dim(`, ${plan.includedUsage} usage included`) : \"\"),\n );\n const l = plan.limits;\n console.log(\n chalk.dim(\n ` ${l.apps} apps \u00B7 ${l.instancesPerApp} instances/app \u00B7 up to ${l.maxCpu} CPU / ${l.maxMemory} MB \u00B7 ${l.maxStorageMb} MB storage` +\n `${l.postgres ? \" \u00B7 postgres\" : \"\"}${l.customDomains ? \" \u00B7 custom domains\" : \"\"}`,\n ),\n );\n console.log();\n }\n });\n\nfunction printMetrics(metrics: UsageQuantity[]): void {\n if (metrics.length === 0) {\n console.log(chalk.dim(\" Nothing metered in this period yet.\"));\n return;\n }\n for (const m of metrics) {\n console.log(` ${chalk.dim(m.metric.padEnd(22))} ${round(m.quantity)}`);\n }\n}\n\n/** Two decimals, and no trailing `.00` on a whole number. */\nfunction round(n: number): string {\n const v = Math.round(n * 100) / 100;\n return Number.isInteger(v) ? String(v) : v.toFixed(2);\n}\n\nfunction money(cents: number): string {\n return `$${(cents / 100).toFixed(2)}`;\n}\n\nfunction period(start: string, end: string): string {\n return `${start.slice(0, 10)} \u2192 ${end.slice(0, 10)}`;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Command", "path", "client", "period", "DEFAULT_API_URL", "APP_DOMAIN", "MAX_FILE_SIZE_BYTES", "FARGATE_SIZES", "FARGATE_CPUS", "PLANS", "DEFAULT_API_URL", "Command", "chalk", "Command", "chalk", "Command", "inquirer", "chalk", "Command", "configPath", "chalk", "inquirer", "config", "Command", "chalk", "ora", "fs", "path", "chalk", "Command", "chalk", "client", "ora", "Command", "chalk", "Command", "chalk", "client", "Command", "chalk", "Command", "chalk", "client", "Command", "chalk", "ora", "Command", "chalk", "client", "ora", "Command", "chalk", "inquirer", "Command", "chalk", "inquirer", "client", "Command", "chalk", "inquirer", "Command", "chalk", "client", "inquirer", "Command", "chalk", "Command", "chalk", "client", "Command", "chalk", "inquirer", "Command", "chalk", "client", "inquirer", "Command", "chalk", "Command", "client", "chalk", "Command", "chalk", "fs", "path", "Command", "chalk", "units", "fs", "path", "Command", "chalk", "fs", "Command", "client", "requireApp", "chalk", "fs", "Command", "chalk", "fs", "Command", "client", "requireApp", "chalk", "intOption", "fs", "Command", "chalk", "Command", "client", "report", "chalk", "Command"]
|
|
7
7
|
}
|