envelor
v0.1.0
Published
Smart deploy recommender for Node.js and TypeScript apps.
Maintainers
Readme
Envelor v0
Deploy inteligente. Custo mínimo deployavel.
Uma CLI que infere o perfil da sua app Node.js/TypeScript, compara targets de deploy, e coloca no ar no mais barato que realmente pode ser deployado no v0 — sem manifest, sem config, sem decisão manual.
Quickstart
npx envelor deploy ./meu-appComandos
| Comando | Descrição |
|---------|-----------|
| envelor deploy <path> | Infere, compara e deploya |
| envelor deploy <path> --dry-run | Planeja sem deployar |
| envelor deploy <path> --target hetzner | Força target específico |
| envelor compare <path> | Mostra tabela comparativa de custo |
| envelor show <path> | Mostra manifest, target selecionado e trilha de decisão |
| envelor migrate <path> | Verifica se há target mais barato disponível |
| envelor doctor <path> | Verifica prontidão do projeto para o fluxo de deploy |
compare aceita --telemetry para registrar um evento local. show e migrate registram telemetria apenas quando o manifest do projeto já está com opt-in ativo.
Por padrão, compare e deploy preferem o target mais barato com deploy real disponível. Targets apenas de dry-run continuam visíveis na tabela e no JSON, mas não viram seleção automática quando existe uma opção deployável suportada.
compare também aceita --mode deploy e --mode planning:
deploy: recomenda o target suportado mais barato com deploy realplanning: recomenda o target suportado mais barato, mesmo que seja dry-run-only em v0
migrate aceita os mesmos modos:
deploy: só recomenda trocas que preservam um caminho real de deployplanning: aponta a menor alternativa suportada no manifest, mesmo que ela seja dry-run-only em v0
--json funciona em todos os comandos para saída estruturada e uso em automações.
Erros também seguem um contrato único:
- saída humana:
Error [CODE]: mensagem, seguida deHint:quando houver ação recomendada - saída JSON:
{ "error": { "code", "message", "hint?", "details?" } }
Saídas de sucesso em --json também seguem um contrato enxuto por comando.
Flags do deploy
| Flag | Descrição |
|------|-----------|
| --dry-run | Planeja e grava manifest sem deployar de fato |
| --target <name> | Força target: fly.io, hetzner, railway, render, vercel |
| --yes | Aceita defaults, reutiliza valores locais de .env |
| --telemetry | Opt-in para telemetria anônima no manifest |
| --region <name> | Override de região (ex: mia, iad) |
| --database-url <url> | DATABASE_URL explícita para o deploy |
| --env KEY=VALUE | Variáveis de ambiente explícitas (pode repetir) |
| --hetzner-host <ip> | Host/IP do VPS Hetzner |
| --hetzner-user <user> | Usuário SSH (default: root) |
| --hetzner-port <port> | Porta SSH (default: 22) |
| --ssh-key-path <path> | Caminho da chave SSH privada |
Frameworks suportados
- Next.js — detecção via package.json + file conventions (
/app,/pages) - Fastify — detecção via package.json + route scan AST
- Express — detecção via package.json + route scan AST
- Hono — detecção via package.json + route scan AST
Bancos suportados
- Postgres — via drivers (pg, postgres, Prisma, Drizzle, Knex) + connection strings
- SQLite — via better-sqlite3, sql.js, Prisma/Drizzle com SQLite
- Nenhum — apps stateless
Targets de deploy
| Target | Status | Custo base | |--------|--------|------------| | Fly.io | Deploy completo | ~$1.94–$6.39/mês | | Hetzner | Deploy completo (VPS + Docker) | ~€3.79–€6.49/mês | | Railway | Dry-run / comparação | ~$5–$15/mês | | Render | Dry-run / comparação | ~$7/mês | | Vercel | Dry-run / comparação | $0–$20/mês |
Doctor
Para um diagnóstico simples antes de tentar deploy:
npx envelor doctor ./meu-appPara checar um target específico:
npx envelor doctor ./meu-app --target fly.ioO comando destaca:
- blockers práticos como
DATABASE_URLausente - se o target suporta deploy real ou só dry-run em v0
- binários locais exigidos para o target escolhido
- próximos passos claros, sem precisar ler o código
Para automação:
npx envelor --json doctor ./meu-app --target railwayContrato de erro
Exemplo humano:
Error [INVALID_ENV_ASSIGNMENT]: Invalid env assignment: JWT_SECRET.
Hint: Use --env KEY=VALUE and repeat the flag for multiple values.Exemplo JSON:
{
"error": {
"code": "MANIFEST_NOT_FOUND",
"message": "Manifest not found for this project.",
"hint": "Run envelor deploy <path> --dry-run first to generate .envelor/manifest.json."
}
}Códigos atuais:
CLI_USAGE_ERRORINVALID_ENV_ASSIGNMENTMANIFEST_NOT_FOUNDCLI_RUNTIME_ERROR
Contrato de sucesso (--json)
Os payloads de sucesso foram reduzidos ao necessário para automação e integração shell.
Princípios:
- cada comando retorna um resumo útil, não a estrutura interna inteira
- custos preservam moeda original e custo normalizado em USD quando relevante
selectedTargetdiferencia recomendação deployável de opções apenas comparáveis em dry-run- a forma textual pode evoluir sem quebrar consumidores de JSON
Exemplo de compare:
{
"command": "compare",
"selectionMode": "deploy",
"selectionReason": "fly.io was selected because deploy mode prefers the cheapest supported target with real deploy capability; vercel is cheaper overall but only supports dry-run in v0.",
"app": {
"name": "my-app",
"framework": "express",
"database": "postgres",
"workload": "micro-api",
"routeCount": 4
},
"selectedTarget": {
"name": "fly.io",
"currency": "USD",
"costEstimate": 3.19,
"normalizedCostUsd": 3.19,
"supportsRealDeploy": true,
"supportsDryRun": true
},
"cheapestOverallTarget": {
"name": "vercel",
"currency": "USD",
"costEstimate": 0,
"normalizedCostUsd": 0,
"supportsRealDeploy": false,
"supportsDryRun": true
},
"targets": []
}Exemplo de doctor:
{
"command": "doctor",
"app": {
"name": "my-app",
"framework": "express",
"database": "postgres",
"workload": "micro-api",
"routeCount": 4,
"ambiguous": false,
"llmResolved": false
},
"target": {
"requested": "railway",
"selected": "railway",
"supportsRealDeploy": false,
"supportsDryRun": true
},
"summary": {
"pass": 0,
"warn": 2,
"fail": 0,
"info": 1
},
"checks": [],
"nextSteps": []
}Exemplo de migrate:
{
"command": "migrate",
"mode": "planning",
"app": {
"name": "my-app",
"framework": "express",
"database": "none",
"workload": "micro-api",
"routeCount": 1
},
"currentTarget": "fly.io",
"recommendation": {
"mode": "planning",
"currentTarget": "fly.io",
"currentCost": 2.03,
"currentCurrency": "USD",
"currentSupportsRealDeploy": true,
"recommendedTarget": "vercel",
"recommendedCost": 0,
"recommendedCurrency": "USD",
"recommendedSupportsRealDeploy": false,
"savingsPercent": 100,
"monthlySavingsUsd": 2.03,
"reason": "Switching from fly.io to vercel saves about USD 2.03/month (~100%) in planning mode, which also considers dry-run-only providers."
}
}Exemplo de show:
{
"command": "show",
"projectPath": "./my-app",
"app": {
"name": "my-app",
"framework": "express",
"database": "none",
"workload": "micro-api",
"routeCount": 1
},
"selectionMode": "deploy",
"selectionReason": "fly.io was selected because deploy mode prefers the cheapest supported target with real deploy capability; vercel is cheaper overall but only supports dry-run in v0.",
"selectedTarget": {
"name": "fly.io",
"currency": "USD",
"costEstimate": 2.03,
"normalizedCostUsd": 2.03,
"supportsRealDeploy": true,
"supportsDryRun": true
}
}Roadmap e distribuição
O plano de distribuição do produto e o roadmap operacional estão em ROADMAP.md.
Resolução de ambiguidade via LLM
Quando a inferência não encontra rotas suficientes para classificar a app com segurança, o Envelor usa uma chamada LLM para resolver a ambiguidade e alimentar a classificação final.
Configure uma das variáveis:
ANTHROPIC_API_KEYouENVELOR_ANTHROPIC_KEY— usa Claude HaikuOPENAI_API_KEYouENVELOR_OPENAI_KEY— usa GPT-4o-mini
Ordem de tentativa: Anthropic, depois OpenAI, e por fim fallback local para api-standard. Timeout por provedor: 5 segundos.
Política de custo e câmbio
- Pricing continua estático em v0, sem chamadas a APIs de providers.
- Rankings e recomendações cross-currency usam custo mensal normalizado para USD.
- A taxa embutida atual é
1 EUR = 1.09 USD. - Para benchmarking interno, é possível sobrescrever a taxa com
ENVELOR_FX_EUR_USD.
Desenvolvimento
npm install # Instalar dependências
npm test # Rodar testes (vitest)
## Validação real
Validação manual executada em repositórios públicos reais durante o fechamento do v0:
- `heroku/node-js-getting-started` (Express)
- `honojs/examples/basic` (Hono)
- `vercel/next-learn/dashboard/final-example` (Next.js + Postgres)
Fluxos verificados:
- `compare --json` passou a selecionar `fly.io` como default quando ele é o target deployável mais barato, mesmo que existam opções dry-run-only mais baratas
- `compare --json --mode planning` continua expondo a visão de menor custo absoluto quando o objetivo é benchmarking ou planejamento
- `doctor --json --target fly.io` continuou reportando blockers reais como `DATABASE_URL` ausente e falta de `flyctl`
- `deploy --dry-run --target fly.io` continuou gerando manifest e plano válidos nos três projetos
npm run test:watch # Testes em watch mode
npm run typecheck # Verificação de tipos
npm run check # Typecheck + testes
npm run build # Compilar TypeScript → dist/
npm run dev # Rodar CLI em modo dev (tsx)Arquitetura
Código → infer → classify → envelope → compare → deploy → report
↓
manifest interno
(.envelor/manifest.json)Estrutura de arquivos
src/
cli.ts ← Ponto de entrada, comandos
infer.ts ← Análise de código (AST + LLM)
classify.ts ← Classificação de workload
envelope.ts ← Cálculo de envelope operacional
compare.ts ← Comparação cross-provider
deploy.ts ← Orquestração de deploy
report.ts ← Formatação CLI
manifest.ts ← Persistência de manifest
llm.ts ← Resolução de ambiguidade via LLM
telemetry.ts ← Eventos locais de deploy/compare/show/migrate
migrate.ts ← Recomendação de migração
portable.ts ← Avaliação de portabilidade VPS
currency.ts ← Normalização cambial para ranking e recomendações
doctor.ts ← Diagnóstico rápido de prontidão
types.ts ← Tipos TypeScript
adapters/
fly.ts ← Adapter Fly.io
hetzner.ts ← Adapter Hetzner VPS
railway.ts ← Adapter Railway (dry-run v0)
render.ts ← Adapter Render (dry-run v0)
vercel.ts ← Adapter Vercel (dry-run v0)
types.ts ← Interface DeployAdapter
data/
pricing.ts ← Tabelas de preço
workloads.ts ← Defaults de envelope por classe
frameworks.ts ← Registry de frameworks (extensível)
providers.ts ← Capacidades e custos por provider
tests/
*.test.ts ← 75 testes (17 arquivos)Licença
MIT v0
Envelor is a CLI that infers the shape of a Node.js or TypeScript app, compares deployment targets, and deploys to the cheapest supported option.
What v0 does
- Detects Express, Fastify, Hono, and Next.js apps
- Detects Postgres, SQLite, or stateless workloads
- Estimates a runtime envelope from the codebase
- Compares Fly.io, Railway, Hetzner, Render, and Vercel
- Deploys through real adapters for Fly.io and Hetzner
- Persists an internal manifest to
.envelor/manifest.json
Install
npm install
npm run buildCommands
Compare targets
node dist/src/cli.js compare ./examples/my-appDry-run deploy
node dist/src/cli.js deploy ./examples/my-app --dry-runFly deploy with guided config
node dist/src/cli.js deploy ./examples/my-app --target fly.ioUseful flags:
node dist/src/cli.js deploy ./examples/my-app \
--target fly.io \
--yes \
--telemetry \
--database-url postgresql://user:pass@host:5432/app \
--env JWT_SECRET=super-secret \
--env REDIS_URL=redis://cache.internal:6379Behavior:
- If
.envor.env.localexists and--yesis passed, Envelor reuses those values. - If Postgres is detected, Envelor requires
DATABASE_URLfor a real deploy. - Fly secrets are sent with
flyctl secrets setbeforeflyctl deploy.
Hetzner deploy
node dist/src/cli.js deploy ./examples/my-app \
--target hetzner \
--hetzner-host 203.0.113.10 \
--hetzner-user root \
--ssh-key-path ~/.ssh/id_ed25519 \
--yesBehavior:
- Assumes Docker is installed on the target VPS.
- Generates a basic Dockerfile if the project does not provide one.
- Uploads the project over SSH and SCP.
- Starts a single container on port 80.
Manifest
Every deploy writes .envelor/manifest.json containing:
- inferred framework and database
- route summary
- workload class
- computed envelope
- cross-provider comparison table
- selected target
- deployment metadata
Show the manifest:
node dist/src/cli.js show ./examples/my-appTest
npm testCurrent limits
- Heuristic inference, not full semantic analysis
- LLM ambiguity resolution is best-effort and intentionally bounded by short timeouts
- Only Fly.io and Hetzner have deploy adapters in v0
- Multi-service topologies, websockets, workers, and long-running jobs remain out of scope
