v2.0

Projetos e SDK

Como organizar projetos Node.js e Python para rodar no browserMate via upload de ZIP, e como usar o Mini SDK para acessar variáveis e conectores do processo.

Quando usar projetos externos

Use projetos ZIP em vez de código inline quando:

Como enviar um projeto

Codebase: projetos Python e Node.js enviados à plataforma.
Codebase: projetos Python e Node.js enviados à plataforma.
  1. Empacote o projeto como um arquivo .zip (a raiz do ZIP deve conter os arquivos do projeto diretamente, não uma pasta extra).
  2. No Menu, acesse a opção Codebase.
  3. Clique em + Novo Projeto e preencha o formulário com Nome, Descrição, Linguagem e Arquivo de entrada (entrypoint).
  4. Selecione a linguagem (Node.js ou Python) e informe o entry point (arquivo principal a executar).
  5. Faça o upload do ZIP e salve.
  6. Na etapa de código customizado, selecione Modo de Execução: Projeto e escolha o projeto enviado em Projeto de Script.

Versões do projeto

Cada upload de ZIP gera uma versão nova do projeto, numerada em sequência. A versão mais recente é a que os agentes executam, marcada como Em uso, e as anteriores continuam guardadas.

No card do projeto, abra o histórico para ver a lista completa. Cada linha traz o número da versão, a data do upload, o tamanho do pacote e o entry point que valia naquele momento.

Restaurar uma versão anterior Clique em Restaurar na versão desejada. Ela não substitui o histórico: o conteúdo antigo é promovido a uma versão nova no topo, marcada como restaurada da vN. Assim o histórico continua linear e nada se perde, mesmo depois de vários idas e vindas.

O histórico guarda as 10 versões mais recentes. Acima disso, os pacotes mais antigos são descartados para não acumular armazenamento indefinidamente.

O processo referencia o projeto, não a versão A versão do agente guarda apenas a referência ao projeto de código. Publicar uma versão nova do código passa a valer para os agentes que o usam, sem precisar republicar cada agente. É por isso que o histórico e a restauração vivem aqui, no projeto.

Alterações que não mexem no código, como editar nome ou descrição do projeto, não geram versão.

Entry Point O entry point é o arquivo que o runtime executa. Para Node.js use main.js (ou index.js). Para Python use main.py. Esse arquivo deve importar e executar toda a lógica do projeto.

Estrutura Node.js

Estrutura recomendada de projeto Node.js
meu-projeto/
├── main.js          ← entry point
├── package.json     ← dependências
├── src/
│   ├── processador.js
│   ├── validador.js
│   └── formatador.js
└── utils/
    └── helpers.js
package.json
{
  "name": "meu-projeto-bm",
  "version": "1.0.0",
  "main": "main.js",
  "dependencies": {
    "axios":  "^1.6.0",
    "xlsx":   "^0.18.5",
    "xml2js": "^0.6.2"
  }
}
main.js: entry point com Mini SDK
const bm          = require('./browsermate');
const Processador = require('./src/processador');

(async () => {
  // Ler parâmetros de entrada. As chaves usam o formato {variavel}
  const arquivo_base64 = bm.get('{arquivo_entrada}');
  const tipo           = bm.get('{tipo_documento}', 'NFe');

  // Processar
  const proc = new Processador(tipo);
  const resultado = await proc.processar(arquivo_base64);

  bm.bmLog('[OK] Documento processado: ' + resultado.numero);

  // Gravar resultado e encerrar (obrigatório)
  bm.done(resultado.status, {
    '{numero}':      resultado.numero,
    '{valor_total}': resultado.valor,
    '{status}':      resultado.status,
    '{dados}':       resultado.dados
  });
})();

Estrutura Python

Estrutura recomendada de projeto Python
meu-projeto/
├── main.py          ← entry point
├── requirements.txt ← dependências pip
├── src/
│   ├── __init__.py
│   ├── processador.py
│   └── validador.py
└── utils/
    ├── __init__.py
    └── helpers.py
requirements.txt
pandas==2.1.0
openpyxl==3.1.2
requests==2.31.0
PyPDF2==3.0.1
lxml==4.9.3
main.py: entry point com Mini SDK
import browsermate as bm
from src.processador import Processador

def main():
    # Ler parâmetros de entrada. As chaves usam o formato {variavel}
    arquivo_b64 = bm.get('{arquivo_entrada}', '')
    tipo        = bm.get('{tipo_documento}', 'NFe')

    # Processar
    proc = Processador(tipo)
    resultado = proc.processar(arquivo_b64)

    bm.bmLog('[OK] Documento processado: ' + resultado['numero'])

    # Gravar resultado e encerrar (obrigatório)
    bm.done(resultado['status'], {
        '{numero}':      resultado['numero'],
        '{valor_total}': resultado['valor'],
        '{status}':      resultado['status'],
        '{dados}':       resultado['dados']
    })

if __name__ == '__main__':
    main()

API do Mini SDK

O Mini SDK é o módulo browsermate injetado automaticamente pelo runtime no diretório de execução. Para scripts inline, o import é adicionado antes do seu código; para projetos, importe no topo do entry point:

Import (obrigatório em projetos, automático em inline)
// Node.js
const bm = require('./browsermate');

# Python
import browsermate as bm
Formato das chaves de variável Todas as variáveis do processo usam o formato {variavel}, com chaves, como chave no globalData. Use esse exato formato em bm.get() e em bm.done(). A credencial é a exceção: bm.secret('CHAVE') recebe a chave crua, sem chaves em volta, porque ela não é variável do processo.
APINode.jsPythonDescrição
Ler variável bm.get('{var}', default) bm.get('{var}', default) Lê uma variável do processo, no tipo que ela tem no fluxo: texto, número, lista (array / list) ou objeto (dict no Python). Retorna default se não encontrada.
Todas as variáveis bm.globalData bm.globalData Objeto/dict somente leitura com todas as variáveis. Use bm.done() para escrever.
Ler credencial bm.secret('CHAVE') bm.secret('CHAVE') Lê uma credencial do Cofre de Senhas pela chave, sem chaves em volta. A chave pode ser montada em tempo de execução. Chave inexistente levanta erro listando as disponíveis, em vez de devolver vazio.
Log de execução bm.bmLog(mensagem) bm.bmLog(mensagem) Registra mensagem nos logs oficiais de execução (visível no Control Room)
Finalizar script bm.done(result, updates) bm.done(result, updates) Obrigatório. Grava variáveis de volta ao processo e encerra. Sem essa chamada, nenhum dado é retornado ao fluxo.
ID do processo bm.get('{processID}') bm.get('{processID}') ID do processo atual. É uma variável de sistema comum, não uma env var. Veja Manipulação de Variáveis.
ID da instância bm.get('{instanceID}') bm.get('{instanceID}') ID único desta execução

Credenciais do Cofre no seu código

bm.secret() lê uma credencial do Cofre de Senhas. A chave vai crua, sem chaves em volta, porque a credencial não é variável do processo. E ela pode ser montada em tempo de execução, o que atende o agente que atende vários clientes, cada um com a sua credencial:

Lendo credenciais em Node.js e Python
// Node.js
const senha    = bm.secret('ERP.SENHA');
const porCliente = bm.secret('ERP.SENHA.' + bm.get('{cliente}'));

# Python
senha      = bm.secret('ERP.SENHA')
por_cliente = bm.secret('ERP.SENHA.' + bm.get('{cliente}'))
Três coisas para saber {vault.CHAVE} não funciona dentro de um script: nada substitui {...} ali, e por isso existe o bm.secret(). Chave inexistente levanta erro listando as disponíveis, em vez de devolver vazio e produzir um erro de autenticação incompreensível na outra ponta. E nunca devolva uma credencial em updates: updates grava no fluxo, e ali ela viraria uma variável comum, visível como qualquer outra.

Escrever variáveis de volta ao processo

bm.done(result, updates) é a única forma de gravar variáveis. O parâmetro updates usa o mesmo formato {variavel} como chave:

Escrevendo variáveis em Node.js e Python
// Node.js
bm.done('processado', {
  '{numero_nf}':   'NF-001',
  '{valor_total}': '1500.00',
  '{status}':      'aprovado'
});

# Python
bm.done('processado', {
    '{numero_nf}':   'NF-001',
    '{valor_total}': '1500.00',
    '{status}':      'aprovado'
})

Cada valor é gravado como é: texto, número, lista ou objeto vão direto em updates, e bm.get() devolve do mesmo jeito.

Variáveis de um projeto não entram nas listas No Script Inline, as chaves do bm.done() passam a aparecer sozinhas nos seletores de variáveis das etapas seguintes. Num projeto ZIP isso não acontece, porque o código fica no arquivo enviado e não no cadastro da etapa. As variáveis são gravadas normalmente na execução: escreva o nome com chaves, como {numero_nf}, nos campos que precisarem dele. Da mesma forma, o aviso de erro de sintaxe não confere o código do projeto.
O projeto também respeita o Limite de Tempo do Script. O tempo máximo de execução é da etapa que aponta para o projeto, não do projeto em si: é o campo Limite de Tempo do Script, na própria etapa. O padrão é 1 hora, e o teto é 8 horas. Um projeto que processa lotes grandes costuma ser justamente o caso de aumentar esse valor. Veja Timers.

Desenvolvimento e teste local

Para testar um script ou projeto sem precisar executar pelo runtime completo, crie o arquivo input.mock.json na raiz do projeto com as variáveis que o processo forneceria:

input.mock.json: dados de teste local
{
  "globalData": {
    "{arquivo_entrada}": "JVBERi0x...",
    "{tipo_documento}":  "NFe",
    "{empresa_id}":      "ACME"
  }
}

Ao rodar o script localmente (node main.js ou python main.py), o SDK detecta que está fora do runtime (variável de ambiente BM_INPUT ausente) e lê o input.mock.json. O resultado é gravado em output.json e exibido no console. O bm.bmLog() também imprime no console em modo local.

O arquivo input.mock.json não é enviado ao runtime quando você faz upload do ZIP, e é ignorado na execução real. Use-o livremente para testes sem risco.
O arquivo de teste não leva dado sensível Variáveis marcadas como Dado sensível, segredos do Cofre e o conteúdo de arquivos baixados nunca entram no input.mock.json que a plataforma gera. Para testar na sua máquina com um valor no lugar de um campo sensível, digite você mesmo um valor de teste no seu input.mock.json, e nunca o dado real.

Credenciais num Projeto ZIP

Vale o mesmo do código Inline: bm.secret('CHAVE'), descrito em Credenciais do Cofre no seu código. O SDK é injetado na execução, então o projeto não declara nem instala nada para isso.

Os segredos chegam ao projeto pelo mesmo caminho do globalData, mas num arquivo à parte, que é apagado no fim da execução. Eles nunca entram em input.mock.json, justamente porque esse arquivo fica no disco depois que a execução acaba.

Testando o projeto na sua máquina Fora do browserMate não há Cofre. Para rodar localmente, crie um secrets.mock.json na raiz do projeto, no formato {"ERP.SENHA": "valor-de-mentira"}, e o SDK lê dele. Nunca coloque a credencial de verdade nesse arquivo, e nunca o envie no ZIP.
Nunca hardcode credenciais no código Colar a API Key direto no código expõe o segredo para qualquer pessoa com acesso ao processo, e ele passa a viajar dentro do ZIP e do histórico de versões. Use bm.secret(), ou uma etapa Conectar Serviços, onde a credencial fica no conector e é decifrada no servidor no momento da chamada.
Não devolva credencial em updates updates grava no fluxo. Uma credencial ali deixa de ser segredo e vira variável comum do processo, visível como qualquer outra. Use o valor dentro do script e descarte.

Gerenciamento de dependências

Os projetos rodam sobre Node.js 24 ou Python 3.14, conforme a linguagem escolhida. Declare dependências compatíveis com essas versões. Veja Versões de Node.js e Python.

Num Projeto ZIP as bibliotecas são declaradas em arquivo, na raiz do projeto:

LinguagemArquivoComo o código usa
Node.jspackage.jsonOs pacotes ficam na pasta do projeto, disponíveis via require().
Pythonrequirements.txtAs bibliotecas vão para um ambiente Python isolado do projeto, disponíveis via import.
Versões fixas Sempre especifique versões exatas (ex.: pandas==2.1.0) para garantir reprodutibilidade entre execuções.

O runtime instala isso sozinho ao receber o projeto, sem passo manual. Quando essa instalação acontece, quanto ela demora, como rodar sem acesso aos repositórios de pacotes e por que cada projeto fica isolado dos demais está tratado em um só lugar, porque vale igual para Código Inline e para Projetos ZIP: Visão Geral → Como as dependências são processadas.