npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@martinelli-hub/sdk

v3.3.0

Published

CLI para criar, desenvolver, validar e empacotar plugins para o HUB Martinelli

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 --version

Alternativa: zero install com npx

# Usar sem instalar (executa diretamente do registry)
npx @martinelli-hub/sdk create

Atualizando

npm update -g @martinelli-hub/sdk

Nota: O comando hub-plugin ficara 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 minimo

Templates 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-db segue a receita oficial de integracao com DB: usa sqlalchemy.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 \
  --frontend

Flags 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 validate

Modo 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 basic

O 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 plugin

Configuracao: 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 plugin

Estrutura 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
└── .gitignore

HubClient — 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.external e 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 tipos

Licenca

UNLICENSED — Uso interno Martinelli Advogados.