@martinelli-hub/sdk
v3.3.0
Published
CLI para criar, desenvolver, validar e empacotar plugins para o HUB Martinelli
Maintainers
Readme
@martinelli-hub/sdk
CLI para criar, desenvolver, validar e empacotar plugins para o HUB Martinelli (Hub_Servicos_Martinelli_V2).
O SDK abstrai toda a complexidade do ecossistema do HUB, gerando scaffold completo (backend Python/FastAPI + frontend Next.js/React + manifest v2 + testes), oferecendo dev server local com mocks, validacao identica a do HUB e geracao automatica do ZIP pronto para upload.
Pre-requisitos
- Node.js >= 18.0.0
- Python >= 3.10 (para o backend dos plugins e HubClient)
- npm (incluido com Node.js)
Instalacao
# Instalar globalmente via npm
npm install -g @martinelli-hub/sdk
# Verificar instalacao
hub-plugin --versionAlternativa: zero install com npx
# Usar sem instalar (executa diretamente do registry)
npx @martinelli-hub/sdk createAtualizando
npm update -g @martinelli-hub/sdkNota: O comando
hub-pluginficara disponivel globalmente apos a instalacao.
Comandos
hub-plugin create — Criar novo plugin
Scaffold interativo que gera a estrutura completa do plugin.
hub-plugin create # Wizard interativo (template blank)
hub-plugin create --template basic # Template com CRUD completo (in-memory)
hub-plugin create --template basic-db # Template com CRUD + MySQL real (SQLAlchemy)
hub-plugin create -t blank # Template minimoTemplates disponiveis:
| Template | Descricao | Quando usar |
|----------|-----------|-------------|
| blank | Template minimo com endpoint /status | Plugin sem dominio de dados (ex: health, ping) |
| basic | CRUD completo (5 endpoints), React + testes, repositorio in-memory | Prototipo / didatico — sem persistencia |
| basic-db | basic + database.py (URL.create + pool_pre_ping + future) + repository com queries SQLAlchemy reais (MySQL) | Plugin de producao com banco externo |
O
basic-dbsegue a receita oficial de integracao com DB: usasqlalchemy.engine.URL.create()para escapar caracteres URL-reservados em senhas (@,!,:,/) — evita o bug classico de "Can't connect to MySQL server on 'M@...'".
O wizard pergunta:
- Nome do plugin (slug)
- Nome de exibicao
- Descricao
- Autor
- Categoria (Tax, Audit, Consultancy, Common)
- Template (blank, basic ou basic-db)
Modo non-interactive (CI/CD, scripts, automation)
Para uso em pipelines, fixtures de teste ou bootstrap automatizado, use a flag --non-interactive
que suprime TODOS os prompts e usa flags + defaults:
# Gerar plugin completo com defaults
hub-plugin create \
--non-interactive \
--slug my-plugin \
--template basic
# Plugin com banco externo (MySQL)
hub-plugin create \
--non-interactive \
--slug api \
--template basic-db \
--external-db \
--db-type mysql
# Plugin frontend-only (sem backend)
hub-plugin create \
--non-interactive \
--slug ui-only \
--no-backend \
--frontendFlags disponiveis em modo non-interactive:
| Flag | Default | Obrigatoria |
|------|---------|-------------|
| --slug <slug> | — | Sim (com --non-interactive) |
| --name <name> | igual ao slug | Nao |
| --description <desc> | "Plugin <slug>" | Nao |
| --author <author> | "Anonymous" | Nao |
| --category <category> | Common | Nao |
| --layout <layout> | standard | Nao |
| --backend / --no-backend | true | Nao |
| --frontend / --no-frontend | true | Nao |
| --external-db / --no-external-db | false | Nao |
| --db-type <type> | — | Sim se --external-db |
| --auth-mode <mode> | hub | Nao |
Valores aceitos:
--category:Tax,Audit,Consultancy,Common--layout:standard,full,headless--db-type:mysql,postgresql,mssql--auth-mode:hub,custom
Exemplo de uso em GitHub Actions:
- name: Scaffold plugin de teste
run: |
hub-plugin create \
--non-interactive \
--slug ci-smoke-test \
--template basic
- name: Validar plugin gerado
working-directory: ci-smoke-test
run: |
npm install
hub-plugin validateModo semi-interactive (pre-popular wizard)
Voce pode passar --slug SEM --non-interactive para abrir o wizard com o slug ja preenchido:
hub-plugin create --slug meu-plugin --template basicO wizard abre normalmente, mas o campo slug ja vem com meu-plugin (apenas Enter para confirmar).
hub-plugin dev — Servidor de desenvolvimento
Inicia o backend (uvicorn) e frontend (Next.js) com mocks de autenticacao e watcher console.
hub-plugin dev # Inicia backend + frontend
hub-plugin dev --port 9000 # Backend na porta 9000
hub-plugin dev --frontend-port 4000 # Frontend na porta 4000
hub-plugin dev --path ./meu-plugin # Especifica diretorio do pluginConfiguracao: O arquivo .hub-dev.json na raiz do plugin permite configurar portas e dados mock de usuario para desenvolvimento.
hub-plugin validate — Validar plugin
Executa as 9 camadas de validacao identicas ao HUB Martinelli.
hub-plugin validate # Valida o plugin no diretorio atual
hub-plugin validate --path ./meu-plugin # Valida plugin em outro diretorio
hub-plugin validate --json # Output em formato JSON
hub-plugin validate --with-db # + tenta conexao DB real (SELECT 1, opt-in)Camadas de validacao:
| # | Camada | Descricao |
|---|--------|-----------|
| 1 | Estrutura ZIP | Verifica estrutura de pastas obrigatoria |
| 2 | Manifest Schema | Valida manifest.json contra schema v2 |
| 3 | Core Guard | Detecta acesso a paths protegidos do core |
| 4 | Design System | Verifica compliance com Design System Martinelli |
| 5 | Dependencias | Detecta dependencias bloqueadas (Python + Node) |
| 6 | Frontend Imports | Verifica imports proibidos no frontend |
| 7 | Env/Database | Verifica vazamento de .env e acesso direto a DB |
| 8 | Watcher | Enforcement de padroes via AST (v2-only) |
| 9 | Infrastructure | Validacao de infraestrutura (v2-only) |
| 10 | DB Connection | Conexao real + SELECT 1 (opt-in via --with-db) |
Flag --with-db: le o .env do plugin, monta DSN com URL.create() (mesma receita do
template basic-db), abre conexao real via pymysql e executa SELECT 1. A senha nunca
aparece nos logs (sempre mascarada). Sem o flag, nenhuma conexao com DB e tentada
(comportamento padrao preservado). Requer Python 3 + sqlalchemy + pymysql no PATH.
Veja docs/database-integration.md para a receita canonica e
a tabela de caracteres URL-reservados que quebram f-strings.
hub-plugin build — Empacotar plugin
Gera o ZIP pronto para upload no HUB, com validacao automatica antes do empacotamento.
hub-plugin build # Gera ZIP do plugin
hub-plugin build --output ./dist # Define diretorio de saida
hub-plugin build --skip-validate # Pula validacao (nao recomendado)
hub-plugin build --path ./meu-plugin # Especifica diretorio do pluginEstrutura de um plugin gerado
meu-plugin/
├── backend/
│ └── app/
│ └── plugins/
│ └── meu_plugin/
│ ├── __init__.py
│ ├── controller.py # Endpoints FastAPI
│ ├── repository.py # Acesso a dados
│ ├── schemas.py # Pydantic models
│ └── services.py # Logica de negocio
├── packages/
│ └── plugins/
│ └── meu-plugin/
│ ├── index.tsx # Componente React principal
│ ├── package.json # Dependencias frontend
│ ├── components/ # Componentes React
│ ├── hooks/ # Custom hooks (useApi, etc.)
│ └── pages/ # Paginas adicionais
├── tests/
│ ├── backend/
│ │ └── test_controller.py # Testes do backend
│ └── frontend/
│ └── index.test.tsx # Testes do frontend
├── manifest.json # Manifest v2 do plugin
├── .hub-dev.json # Config do dev server
└── .gitignoreHubClient — Acesso a dados do HUB
Os plugins gerados incluem o HubClient, um SDK Python para acessar dados do HUB de forma abstrata.
from hub_sdk import hub
# Usuarios
users = await hub.users.list()
user = await hub.users.get_by_username("joao.silva")
# Departamentos
departments = await hub.departments.list()
# Autenticacao
current_user = await hub.auth.me()
# Permissoes
permissions = await hub.permissions.my_permissions()Dual-mode automatico:
- Development (default): retorna dados mockados de
.hub-dev.json - Production (
HUB_RUNTIME=true): chamadas HTTP reais para a API do HUB
Workflow tipico
# 1. Instalar o SDK (ver secao Instalacao acima)
# 2. Criar um novo plugin
hub-plugin create --template basic
# 3. Entrar no diretorio do plugin
cd meu-plugin
# 4. Iniciar dev server
hub-plugin dev
# 5. Desenvolver o plugin...
# 6. Validar antes de empacotar
hub-plugin validate
# 7. Gerar ZIP para upload
hub-plugin build
# 8. Upload do ZIP no HUB Martinelli (via interface web)Manifest v2
Cada plugin requer um manifest.json no formato v2. O SDK gera automaticamente, mas voce pode editar:
{
"manifest_version": 2,
"metadata": {
"slug": "meu-plugin",
"name": "Meu Plugin",
"version": "1.0.0",
"author": "Seu Nome",
"description": "Descricao do plugin",
"category": "Common"
},
"frontend": {
"enabled": true,
"entry": "index.tsx",
"layout": "standard"
},
"backend": {
"enabled": true,
"entry": "controller",
"router_var": "router",
"baseUrl": "/plugins/meu-plugin",
"auth_mode": "hub"
},
"security": {
"modulePermission": "meu_plugin",
"requiredRoles": []
},
"dependencies": {
"python": [],
"node": []
}
}Categorias validas: Tax, Audit, Consultancy, Common
Layouts frontend: standard, full, headless
Slug conventions: Kebab-case no frontend (meu-plugin), underscore no backend Python (meu_plugin). backend.entry deve ser sempre "controller" (Hub ignora o campo e hardcoda este valor).
Nota:
database.externale uma extensao do SDK para documentar bancos externos. O Hub ainda nao valida este campo no upload.
Stack tecnica
| Componente | Tecnologia | |------------|------------| | CLI | TypeScript + Commander.js | | Template engine | Handlebars | | Validacao | 9 validators TypeScript | | Testes | Vitest | | Backend dos plugins | Python + FastAPI | | Frontend dos plugins | Next.js + React | | HubClient | Python + httpx | | Empacotamento | Archiver (ZIP) |
Padroes de import (subpath libs)
Algumas libs tem barrel raiz limitado e exigem subpath dedicado. Sem o subpath, o
Turbopack/Webpack falha em runtime com Export X doesn't exist in target module.
| Lib | Errado | Correto |
|-----|--------|---------|
| @hookform/resolvers | from '@hookform/resolvers' | from '@hookform/resolvers/zod' |
| @hookform/resolvers (yup) | from '@hookform/resolvers' | from '@hookform/resolvers/yup' |
Por que: o package.json da lib usa exports com subpaths. O barrel raiz so re-exporta
helpers internos (toNestErrors, validateFieldsNatively). Os resolvers de schema (zod, yup,
joi, etc.) cada um mora no seu proprio subpath.
Documentacao completa: docs/IMPORT_PATTERNS.md.
Contribuindo com o SDK
Para contribuir com o desenvolvimento do SDK:
# Clonar o repositorio
git clone https://github.com/Martinelli-GitHub/hub-sdk-plugin.git
cd hub-sdk-plugin
# Instalar dependencias
npm install
# Build
npm run build
# Rodar testes (309 testes)
npm test
# Lint
npm run lint
# Typecheck
npm run build # tsc compila e verifica tiposLicenca
UNLICENSED — Uso interno Martinelli Advogados.
