@vitongovisk/forge
v1.2.4
Published
> **Opinionated frontend architecture generator for TypeScript projects.** > Versão `2.0` · Publicado como `@vitongovisk/forge`
Maintainers
Readme
⚒️ Forge CLI
Opinionated frontend architecture generator for TypeScript projects.
Versão2.0· Publicado como@vitongovisk/forge
Forge é um CLI que gera automaticamente todas as camadas de integração com APIs REST no seu frontend: tipos de contrato, cliente HTTP, serviços e hooks TanStack Query — tudo fortemente tipado, a partir de um único comando.
Pré-requisitos
Seu projeto deve ter as seguintes dependências instaladas:
npm install axios @tanstack/react-queryO Forge verifica essas dependências no
forge inite oferece instalação automática caso não estejam presentes.
Node.js: >= 18
Instalação
npm install -D @vitongovisk/forgeOu use globalmente:
npm install -g @vitongovisk/forgeInício Rápido
# 1. Inicializar o Forge no projeto
forge init
# 2. Criar um módulo
forge module users
# 3. Adicionar endpoints ao módulo
forge add users getUser --get
forge add users createUser --post
forge add users updateUser --put
forge add users deleteUser --deletePronto. O Forge gera toda a estrutura de arquivos para você.
Multi-Backend
Se o seu projeto consome mais de uma API (ex: API principal + serviço de pagamentos + serviço de analytics), use o comando forge client para registrar instâncias Axios adicionais:
# 1. Registrar um novo client (instância Axios)
forge client payments
# → injeta `paymentsApi` no api-client.ts e registra em forge.data.json
# 2. Criar um módulo que consome esse client
forge module billing --client paymentsApi
# 3. Adicionar endpoints — herda o client do módulo automaticamente
forge add billing chargeUser --post # usa paymentsApi
forge add billing refund --post --client api # override por endpointUsuários single-backend (só api) não veem essas opções — o fluxo continua idêntico ao Quick Start. Detalhes de cada comando abaixo.
Comandos
forge init
Inicializa o Forge no projeto atual.
forge init
forge init --overwrite # Reconfigura um projeto já inicializadoO que faz:
- Cria o arquivo de configuração
.forge.json(inclui a versão do Forge usada —forgeVersion— pra suportar migrações futuras) - Cria
forge.data.json(registro de intenção dos módulos, comclients: ["api"]por padrão) - Cria
forge.state.json(estado real dos arquivos gerados) - Gera o
api-client.tscom Axios configurado (interceptors de autenticação JWT e unwrap deresponse.data) - Gera os tipos base compartilhados (
api.types.ts,global.types.ts,shared.types.ts) - Gera o utilitário
api.utils.tscomparseApiError
Pergunta apenas: modo de sincronização (auto ou manual).
forge module <name> · alias: forge m
Cria um novo módulo com a estrutura base completa.
forge module users
forge m auth
# Módulo sem tipos inicialmente (para módulos utilitários como auth, session)
forge module auth --minimal
# Multi-backend: especificar qual API client o módulo consome
forge module billing --client paymentsApiOpções:
| Flag | Descrição |
|---|---|
| --minimal | Pula a criação de <module>.types.ts e contracts/ |
| --client <name> | Declara qual instância Axios o módulo consome (default: api). Valida contra os clients registrados em forge.data.json |
| --sync / --no-sync | Força ou pula a sincronização automática após criação |
Se houver mais de um client registrado e --client não for passado, o Forge entra em modo interativo perguntando qual usar.
Estrutura gerada (padrão):
src/modules/users/
├── users.api.ts ← cliente HTTP tipado
├── users.service.ts ← camada de serviço/negócio
└── users.types.ts ← interface base do modeloCom --minimal (sem users.types.ts e sem contracts/):
src/modules/auth/
├── auth.api.ts
└── auth.service.tsforge client <name> · alias: forge c
Registra uma nova instância Axios no api-client.ts, permitindo que módulos consumam APIs diferentes (ex: serviço de pagamentos, analytics, autenticação separada).
forge client payments
forge c analyticsO que faz:
- Injeta no
api-client.ts(via AST, preserva edições manuais existentes):export const paymentsApi = axios.create({ baseURL: import.meta.env.VITE_API_PAYMENTS_URL, timeout: 1000 * 15, }); setupInterceptors(paymentsApi); - Registra
"paymentsApi"emforge.data.json→clients. - Roda
syncautomaticamente (sesync.mode === "auto").
Convenção de nomes: você passa o nome base (ex: payments), o Forge cria a instância com sufixo Api (ex: paymentsApi). A env var segue o padrão VITE_API_<UPPER_SNAKE>_URL (ex: VITE_API_PAYMENTS_URL).
Validação: ao usar forge module --client X ou forge add --client X, o nome X precisa estar registrado em forge.data.json. Caso contrário, o Forge erra com a lista dos clients disponíveis.
forge add <module> <functionName> · alias: forge a
Adiciona um endpoint a um módulo existente, gerando todas as camadas verticalmente.
# Com flag de método explícita
forge add users getUser --get
forge add users createUser --post
forge add users updateUser --put
forge add users deleteUser --delete
# Aliases
forge a users getUser --get
# Sem flag → modo interativo
forge add users getUser
# → Escolha o método:
# 1. GET
# 2. POST
# 3. PUT
# 4. DELETE
# Override por endpoint (multi-backend)
forge add billing refund --post --client api
# → o módulo "billing" usa paymentsApi por default, mas esse
# endpoint específico vai falar com o client "api".
# O Forge adiciona o import de "api" no billing.api.ts
# automaticamente, sem quebrar os outros endpoints.Resolução do client (em ordem de prioridade):
- Flag
--client X(se passada e válida). - Client salvo no módulo (
forge.data.json). - Único client registrado (sem prompt).
- Prompt interativo (se houver >1 client e o módulo ainda não tem um salvo — auto-heal: salva no módulo após a escolha).
Convenção de URLs: módulos e ações são convertidos para kebab-case ao gerar o path HTTP:
| Comando | URL gerado |
|---|---|
| forge add userProfile createUser --post | POST /user-profile/create-user |
| forge add billing chargeUser --post | POST /billing/charge-user |
| forge add userProfile getUser --get | GET `/user-profile/${payload.params.id}` |
| forge add billing refund --delete | DELETE `/billing/${payload.params.id}` |
GET, PUT e DELETE usam o id do payload (não o nome da função) — convenção REST padrão. POST usa /<módulo>/<ação> no kebab.
O que é gerado por chamada:
| Arquivo | Descrição |
|---|---|
| contracts/getUser.types.ts | Tipos de Payload, Response e mapa de erros da operação |
| Injeção em users.api.ts | Método getUser adicionado via AST ao objeto UsersAPI |
| Injeção em users.service.ts | Método getUser com try/catch adicionado ao UsersService |
| hooks/useGetUser.hook.ts | Hook useQuery ou useMutation do TanStack Query |
Estrutura final do módulo após 4 endpoints:
src/modules/users/
├── contracts/
│ ├── createUser.types.ts
│ ├── deleteUser.types.ts
│ ├── getUser.types.ts
│ └── updateUser.types.ts
├── hooks/
│ ├── useCreateUser.hook.ts
│ ├── useDeleteUser.hook.ts
│ ├── useGetUser.hook.ts
│ └── useUpdateUser.hook.ts
├── users.api.ts
├── users.service.ts
└── users.types.tsforge sync · alias: forge s
Sincroniza o estado interno do Forge com o estado real do filesystem.
forge syncO que faz:
- Verifica quais arquivos existem fisicamente no disco
- Atualiza o
forge.state.jsoncom o estado real - Detecta módulos incompletos (api ou service faltando)
- Detecta módulos órfãos (existem no disco mas não foram registrados)
- Exibe um relatório detalhado no terminal
Relatório de exemplo:
🔄 Sincronizando projeto...
✅ Sync finalizado!
📊 Módulos: 2 ativos, 1 incompletos, 1 órfãos
⚠️ Módulos com arquivos faltando:
- billing (faltando: service, contracts)
👻 Módulos órfãos detectados:
- legacy-module
💡 Dica: rode 'forge module legacy-module' para registrá-lo.forge list · alias: forge l
Lista todos os módulos registrados com seu status.
forge list
forge lExemplo de saída:
📦 Módulos (3 total)
✅ users — 4 método(s)
✅ billing — 2 método(s)
⚠️ legacy ← incompleto (faltando: service, contracts)Status possíveis: active (tudo no lugar), missing (arquivo crítico faltando), orphan (existe no disco mas não está registrado em forge.data.json).
Comandos em Desenvolvimento 🚧
Os comandos abaixo já estão registrados no CLI e serão implementados em breve:
| Comando | Alias | Descrição |
|---|---|---|
| forge remove <module> <fn> | forge rm | Remove um endpoint e seus arquivos gerados |
| forge rename <module> <old> <new> | forge rn | Renomeia um endpoint em todas as camadas |
| forge describe <module> | forge d | Exibe detalhes de um módulo (endpoints, hooks, contratos) |
Arquivos de Configuração
.forge.json
Configuração principal do Forge (gerada pelo init, raramente editada manualmente).
{
"forgeVersion": "1.2.0",
"project": {
"architecture": "module",
"modulePath": "src/modules",
"apiFile": "src/modules/api/api-client.ts"
},
"sync": {
"mode": "auto"
}
}| Campo | Valores | Descrição |
|---|---|---|
| forgeVersion | string | Versão do Forge que criou/atualizou o projeto. Usado pra migrações futuras |
| architecture | "module" | Sempre modular no V2 |
| modulePath | string | Pasta raiz dos módulos |
| apiFile | string | Caminho do api-client.ts |
| sync.mode | "auto" | "manual" | Se auto, sync roda após cada operação |
forge.data.json
Registro de intenção — o que você declarou ao Forge que existe no projeto.
{
"clients": ["api", "paymentsApi"],
"resources": [
{
"name": "users",
"methods": ["getUser", "createUser", "updateUser", "deleteUser"],
"client": "api"
},
{
"name": "billing",
"methods": ["chargeUser", "refund"],
"client": "paymentsApi"
}
]
}| Campo | Descrição |
|---|---|
| clients | Instâncias Axios registradas (default ["api"], expandido via forge client) |
| resources[].client | Qual client esse módulo usa por padrão (passa pro scaffold + cada add) |
forge.state.json
Registro de realidade — o que o Forge verificou que existe no filesystem.
{
"project": { "architecture": "module", "lastSync": "2026-05-22T00:00:00.000Z" },
"sync": { "mode": "auto", "lastRun": "2026-05-22T00:00:00.000Z" },
"resources": [
{
"name": "users",
"status": "active",
"client": "api",
"files": {
"api": { "exists": true, "path": "src/modules/users/users.api.ts" },
"service": { "exists": true, "path": "src/modules/users/users.service.ts" },
"types": { "exists": true, "path": "src/modules/users/users.types.ts" },
"contracts": { "exists": true, "path": "src/modules/users/contracts" },
"hooks": { "exists": true, "path": "src/modules/users/hooks" }
},
"methods": {}
}
]
}Arquitetura Gerada
Infraestrutura Global (gerada pelo init)
src/
├── modules/
│ └── api/
│ ├── api-client.ts ← Instâncias Axios com interceptors JWT + unwrap de response.data
│ └── api.types.ts ← Tipos de erro: BaseError, ForbiddenError, NotFoundError, ApiError
├── types/
│ ├── global.types.ts ← BasePayload, BaseSuccessResponse, BaseErrorResponse
│ └── shared.types.ts ← Tipos compartilhados (ex: TFieldValidationError)
└── utils/
└── api.utils.ts ← parseApiError e utilitários HTTPPor Módulo (gerado pelo module + add)
src/modules/<module>/
├── contracts/ ← Tipos específicos por operação
│ └── <fn>.types.ts ← Payload, Response, ErrorMap
├── hooks/ ← Integração TanStack Query
│ └── use<Fn>.hook.ts ← useMutation (POST/PUT/DELETE) ou useQuery (GET)
├── <module>.api.ts ← Objeto API com chamadas Axios tipadas
├── <module>.service.ts ← Camada de serviço com try/catch e parseApiError
└── <module>.types.ts ← Interface base do modelo (ex: User, Product)Fluxo de Camadas
Componente React
│
▼
hooks/useGetUser.hook.ts → useQuery({ queryFn: ... })
│
▼
users.service.ts → try/catch + parseApiError
│
▼
users.api.ts → api.get<GetUserResponse>(...)
│
▼
api-client.ts → Axios com Bearer token automático
│
▼
Backend REST APIExemplo de Uso no Componente
Após rodar forge add users getUser --get, você pode usar diretamente no seu componente:
import { useGetUser } from '@/modules/users/hooks/useGetUser.hook';
export function UserProfile({ id }: { id: string }) {
const { data, isPending, isError } = useGetUser();
if (isPending) return <Spinner />;
if (isError) return <ErrorMessage />;
return <div>{data.user.name}</div>;
}O TypeScript inferirá automaticamente o tipo de data como GetUserResponse.
Roadmap
- [x] Fase 1 — Nova interface CLI (V2 commands, aliases, modo interativo)
- [x] Fase 2 — Generators próprios (lógica extraída para
generator/) - [x] Fase 3 — State engine melhorado (sync V2, tipos consolidados)
- [x] Fase 4 —
forge liste suporte multi-backend (forge client) - [ ]
forge removeeforge rename - [ ]
forge describe - [ ] Sync detectar clients órfãos/missing no
api-client.ts - [ ] Barrel exports automáticos (
index.ts) - [ ] Suporte a WebSocket (
forge ws ...)
Licença
ISC © vitongovisk
