Guias

O ambiente de desenvolvimento

Ao terminar este guia você roda e testa o backend de um app na sua máquina, sem servidor VSSH por perto: o runtime vssh no caminho do interpretador, o backend numa porta de bancada, o healthcheck e o portão de token exercitados com curl, e a página aberta num navegador com o SDK web degradando como ele promete. O mesmo arranjo vale no CI do app, por uma ação composta.

1. O runtime no caminho

Num servidor, o backend faz require('vssh') ou import vssh e encontra o runtime em /opt/vssh/sdk/{node,python}, porque o lançador põe esses caminhos em NODE_PATH e PYTHONPATH antes de subir o app (o ambiente do backend). Na sua máquina quem faz isso é um script deste repositório, que aponta as duas variáveis para a cópia gerada em runtime/:

source vssh-sdk/scripts/ambiente-de-dev.sh        # bash ou zsh
. .\vssh-sdk\scripts\ambiente-de-dev.ps1          # PowerShell

O script exporta três variáveis: VSSH_SDK, a raiz do checkout; NODE_PATH, com runtime/node à frente do que já houver; e PYTHONPATH, com runtime/python. A raiz sai da localização do próprio script, então dá para fazer o source de dentro do repositório do seu app. Um backend Node escrito em ESM chama createRequire(import.meta.url)('vssh'), porque a resolução de ES modules não consulta NODE_PATH.

A cópia de runtime/ é a do último deploy do sistema, e é a que o servidor tem. Quem trabalha com um checkout do sistema ao lado pode apontar as variáveis para infra/sdk/{node,python} de lá, que é a fonte.

2. O backend numa porta

O endereço de um app é o socket unix de VSSH_APP_SOCKET, e é só o que servidor.escutar abre por padrão. Para a bancada ele aceita --tcp host:porta na linha de comando, e :0 pede uma porta livre:

cd meu-app
VSSH_APP_ID=meu-app VSSH_APP_DATA_DIR=/tmp/meu-app-data VSSH_APP_TOKEN=segredo \
  node backend/server.js --tcp 127.0.0.1:0
# [meu-app] versão dev escutando em 127.0.0.1:53017

O mesmo para python3 backend/main.py --tcp 127.0.0.1:0. A linha que sai no stdout é a que uma bancada lê para descobrir a porta, e é a que aparece no run.log de um app que subiu no servidor. VSSH_APP_DATA_DIR é onde o app.log e o filesystem privado do app moram; sem a variável, o runtime usa ~/.vssh-apps/<id>/data. A versão é dev fora de um pacote instalado.

Isto roda no Windows também: o --tcp existe porque o Python de lá não tem AF_UNIX, e um socket unix continua sendo o que o servidor usa.

3. O token e o /saude

servidor.portao (Node) e servidor.Pedido (Python) ficam na frente de toda rota do app. Eles recusam o pedido que não traz o X-Vssh-App-Token igual ao VSSH_APP_TOKEN do processo, e respondem GET /saude com {ok, versao, pid} antes de chamar o app. É o que o portal faz a cada pedido e a cada sondagem, e é o que o curl faz aqui:

curl -s -i http://127.0.0.1:53017/saude
# HTTP/1.1 403 Forbidden
# X-Vssh-Token: recusado

curl -s -H 'X-Vssh-App-Token: segredo' http://127.0.0.1:53017/saude
# {"ok":true,"versao":"dev","pid":4242}

O 403 do portão leva X-Vssh-Token: recusado, e é esse marcador que o separa de um 403 da sua aplicação. Sem VSSH_APP_TOKEN no ambiente o portão deixa tudo passar, que é o caso de uma bancada que não quer digitar o cabeçalho; a sondagem do portal vai sempre com o token, então healthcheckPath: "/saude" no manifesto é uma rota gateada como qualquer outra.

4. O SDK web sem o shell

A página do app inclui _sdk/vssh.js, e quem responde esse caminho no servidor é o sistema, de dentro do espaço de URL do app. Na sua máquina ninguém o serve: o backend responde 404 e devolve a vez a quem compõe as rotas, de propósito, porque um _sdk/ servido pelo app seria uma cópia vendorizada. Para ver a página com o SDK dentro, sirva api/vssh.js e api/tuff/ deste repositório na frente do backend, no caminho _sdk/. É o arranjo de tests/browser/template-fora-do-ambiente.test.js, um HTTP de vinte linhas que responde _sdk/ do disco e encaminha o resto à porta do app.

Com o SDK carregado numa aba solta, vssh.noAmbiente é false (window.parent === window) e nada lança na carga. Cada verbo degrada de um jeito que a página consegue ler: um diálogo cai no do navegador (window.confirm), um seletor de arquivo responde null, vssh.app.capacidades() responde host: 'none', um aviso vai ao console, e um verbo de disco rejeita com fora do ambiente VSSH: <verbo>. Um app que precisa do outro lado (consentimento de arquivos, bandeja, cofre) mostra isso na tela em vez de seguir como se tivesse recebido resposta; a peça "Ambiente" da galeria dos templates faz exatamente isso. O que precisa do shell de verdade só se exercita instalado num servidor.

5. No CI do app

A ação composta deste repositório faz o passo 1 num job do GitHub Actions: checkout esparso de runtime, api e scripts em _sdk/ no workspace, e VSSH_SDK, NODE_PATH e PYTHONPATH gravados em GITHUB_ENV para os passos seguintes.

steps:
  - uses: actions/checkout@v5
  - uses: colabhd/vssh-sdk/.github/actions/preparar-sdk@main
  - run: npm test

with: { ref: <ref> } fixa outra revisão; o padrão é main, porque runtime/ é gerado a partir do sistema que está no ar, e a ponta de main é a que responde "o servidor de hoje tem este runtime?". A publicação continua sendo o reusable de sempre, num job à parte.

O que fazer em seguida

Os dois templates trazem tudo isto ligado, e são o ponto de partida de um app em Node ou em Python. O fonte do runtime é curto e comentado, um arquivo por módulo em runtime/node/vssh/ e runtime/python/vssh/; para o que cada função aceita, é ele a referência.