Como ler esta página
Cada comando tem três blocos:
- O comando — o que você digita
- O que ele faz — passo a passo do que rola por baixo
- O que ele cria — arquivos e pastas gerados
A seção "Do zero ao CRUD" segue a ordem real
do README. Siga de cima pra baixo e você tem uma API rodando.
Alpha inicial. As APIs vão mudar sem aviso prévio. Use por sua conta e risco.
🚧 Versão Alpha. O DarkStar ainda está em desenvolvimento ativo. Funcionalidades podem ser adicionadas, alteradas ou removidas sem aviso prévio. Não recomendamos uso em produção até o lançamento da versão estável. Reporte bugs e sugestões no repositório oficial.
db:create
O comando:
darkstar forge db:create
O que ele faz:
- Lê as credenciais do
.env - Conecta ao servidor do banco (sem escolher database)
- Cria o banco com o nome definido no
.env - Não cria tabelas — só o banco vazio
Só serve pra primeira vez. Depois disso, use db:migrate.
make:migration
O comando:
darkstar forge make:migration CreateUsersTable
O que ele faz:
- Cria um arquivo com timestamp no nome (garante ordem de execução)
- Gera os métodos
up()edown() - Você preenche as colunas dentro do
up()
O que ele cria:
database/migrations/20260103120000_CreateUsersTable.ts
Exemplo do arquivo gerado:
import { Schema, Blueprint, Connection } from '@darkstar-cli/orm'
export async function up() {
const schema = new Schema(Connection.get())
await schema.create('users', (table: Blueprint) => {
table.id()
table.string('name')
table.string('email').unique()
table.string('password')
table.boolean('active').default(true)
table.timestamps()
})
}
export async function down() {
const schema = new Schema(Connection.get())
await schema.drop('users')
}
O schema builder é MySQL/MariaDB apenas. Migrations para
PostgreSQL e SQLite precisam usar SQL raw dentro do up().
db:migrate
O comando:
darkstar forge db:migrate
O que ele faz:
- Lê a tabela de controle
migrations - Compara com os arquivos em
database/migrations/ - Roda só as migrations pendentes, em ordem de timestamp
- Registra cada uma como aplicada
Depois disso, sua tabela users existe no banco.
make:api
O comando:
darkstar forge make:api User
O que ele faz:
- Cria o Model
User.ts - Cria o Controller com os 5 métodos REST (index, show, store, update, destroy)
- Cria o Service com a lógica de orquestração
- Cria o Repository com o acesso ao banco
- Cria o Schema (stub vazio — integre Zod ou Joi depois)
- Cria o Middleware da entidade
- Registra as rotas CRUD em
routes/
O que ele cria:
src/
├── controllers/UserController.ts
├── services/UserService.ts
├── repositories/UserRepository.ts
├── models/User.ts
├── schemas/UserSchema.ts
├── middlewares/UserMiddleware.ts
└── routes/user.routes.ts
Exemplo do UserController.ts gerado:
import { DarkstarRequest, DarkstarResponse } from '@darkstar-cli/core'
import { UserService } from '../services/UserService'
export class UserController {
constructor(private userService: UserService) {}
async index(req: DarkstarRequest, res: DarkstarResponse) {
const data = await this.userService.findAll()
return res.ok(data)
}
async show(req: DarkstarRequest, res: DarkstarResponse) {
const data = await this.userService.findById(req.param('id')!)
if (!data) return res.notFound('User não encontrado')
return res.ok(data)
}
async store(req: DarkstarRequest, res: DarkstarResponse) {
const data = await this.userService.create(req.all())
return res.created(data)
}
async update(req: DarkstarRequest, res: DarkstarResponse) {
const data = await this.userService.update(req.param('id')!, req.all())
return res.ok(data)
}
async destroy(req: DarkstarRequest, res: DarkstarResponse) {
await this.userService.delete(req.param('id')!)
return res.noContent()
}
}
É o comando matador. Em 1 segundo você tem toda a cadeia MVC pronta pra editar.
make:seeder
O comando:
darkstar forge make:seeder User
O que ele faz:
- Cria
UserSeeder.ts - Lê os campos da migration automaticamente
- Gera um
run()pronto pra você popular - Registra o seeder no
DatabaseSeeder.ts
O que ele cria:
database/seeders/UserSeeder.ts
Exemplo do arquivo gerado:
import { User } from '../../src/models/User'
export async function run() {
await User.create({
name: 'teste',
email: 'teste@email.com',
password: 'senha123'
})
}
E ele é registrado no DatabaseSeeder.ts:
import * as UserSeeder from './UserSeeder'
export async function run() {
// registre seus seeders aqui
await UserSeeder.run()
}
O auto-registro depende do comentário // registre seus seeders aqui
dentro do DatabaseSeeder.ts. Se você remover ou alterar esse comentário,
o seeder novo não será registrado automaticamente.
db:seed
O comando:
darkstar forge db:seed
O que ele faz:
- Chama o
DatabaseSeeder.ts - Ele chama cada seeder na ordem definida
- Cada seeder insere os dados que você programou
Perfeito pra popular dados de teste após db:migrate.
make:util
O comando:
darkstar forge make:util User
O que ele faz:
- Cria a pasta
src/utils/user/ - Gera
omitPassword.ts(remove o campopasswordde um objeto) - Gera
twoFactor.ts(placeholder de código 2FA)
O que ele cria:
src/utils/user/omitPassword.ts
src/utils/user/twoFactor.ts
O twoFactor.ts gerado não é compatível com RFC 6238.
É só um placeholder. Para 2FA real, use otplib.
make:security
O comando:
darkstar forge make:security
O que ele faz:
- Cria
RateLimitMiddleware.tsemsrc/middlewares/ - Gera 22 limiters prontos (auth, CRUD, upload, SSE, webhook, admin, pagamentos…)
O que ele cria:
src/middlewares/RateLimitMiddleware.ts
Como usar nas rotas:
import { loginLimiter, registerLimiter, globalLimiter } from '../middlewares/RateLimitMiddleware'
router.post('/auth/login', loginLimiter, ...)
router.post('/auth/register', registerLimiter, ...)
router.use('/api', globalLimiter)
darkstar serve
O comando:
darkstar serve
O que ele faz:
- Lê o
darkstar.config.tspra saber a porta e o host - Carrega as variáveis do
.env - Sobe o servidor HTTP (padrão:
http://localhost:3000) - Ativa hot-reload — salva o arquivo, o servidor reinicia
- Registra cada request no terminal com método, rota e status
Por baixo ele roda npm run dev. Se você renomear o script dev no package.json, darkstar serve quebra.
Acessar a rota
Com o servidor rodando, abra o navegador ou use curl:
GET http://localhost:3000/api/users
Resposta esperada (JSON):
[
{ "id": 1, "name": "teste", "email": "teste@email.com" },
{ "id": 2, "name": "teste2", "email": "teste2@email.com" }
]
Se apareceu o JSON, parabéns — você acabou de subir uma API completa com o DarkStar.
Comandos avulsos
Nem tudo é passo-a-passo. Esses aqui são pra casos específicos — quando você quer só uma peça, não a API inteira.
darkstar new
O comando:
darkstar new meu-projeto
O que ele faz:
- Cria a pasta
meu-projeto/ - Copia o esqueleto base do DarkStar pra dentro dela
- Gera o
.envcom as variáveis de ambiente prontas pra preencher - Roda
npm installautomaticamente - Mostra os próximos passos no terminal
O que ele cria:
meu-projeto/
├── src/
│ ├── controllers/
│ ├── services/
│ ├── repositories/
│ ├── models/
│ ├── routes/
│ ├── schemas/
│ ├── middlewares/
│ ├── utils/
│ └── core/
│ └── app.ts
├── database/
│ ├── migrations/
│ └── seeders/
│ ├── Seeder.ts
│ └── DatabaseSeeder.ts
├── .env
├── darkstar.config.ts
└── package.json
O new é o único comando que não precisa estar dentro de um projeto. Os outros, sim.
make:controller
O comando:
darkstar forge make:controller User
O que ele faz:
- Cria
UserController.ts - Já vem com os 5 métodos REST esqueleto
- Injeta o
UserServiceno construtor - Não cria Service, Repository, Model nem rotas
O que ele cria:
src/controllers/UserController.ts
make:service
O comando:
darkstar forge make:service User
O que ele faz:
- Cria
UserService.ts - Já vem com os métodos
findAll,findById,create,update,delete - Injeta o
UserRepositoryno construtor
O que ele cria:
src/services/UserService.ts
make:repository
O comando:
darkstar forge make:repository User
O que ele faz:
- Cria
UserRepository.ts - Importa o
Usermodel - Já traz as 5 operações CRUD mapeadas pro Query Builder
O que ele cria:
src/repositories/UserRepository.ts
O Repository é a única camada que fala com o banco. Trocar de ORM = só editar aqui.
make:schema
O comando:
darkstar forge make:schema User
Exemplo com Zod (integração manual):
import { z } from 'zod'
export const UserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
password: z.string().min(6)
})
⚠️ JWT não vem incluso no DarkStar. Para autenticação com JWT, instale a biblioteca separadamente:
npm install zod jsonwebtoken
npm install -D @types/jsonwebtoken
make:middleware
O comando:
darkstar forge make:middleware User
Exemplo do stub gerado:
import { DarkstarRequest, DarkstarResponse, NextFunction } from '@darkstar-cli/core'
export class UserMiddleware {
handle(req: DarkstarRequest, res: DarkstarResponse, next: NextFunction) {
next()
}
}
db:rollback
O comando:
darkstar forge db:rollback
O que ele faz:
- Descobre qual foi a última migration aplicada
- Roda o método
down()dela - Remove o registro da tabela de controle
Desfaz uma por vez. Rode várias vezes pra voltar várias.
ORM — Referência rápida
Model
import { Model } from '@darkstar-cli/orm'
export class User extends Model {
static table = 'users'
}
QueryBuilder
const users = await User.query().where('active', true).orderBy('created_at', 'desc').limit(10).get()
const user = await User.query().where('email', 'teste@email.com').first()
const total = await User.query().where('role', 'admin').count()
Blueprint
import { Schema, Blueprint, Connection } from '@darkstar-cli/orm'
const schema = new Schema(Connection.get())
await schema.create('users', (table: Blueprint) => {
table.id()
table.string('name')
table.string('email').unique()
table.string('password')
table.boolean('active').default(true)
table.timestamps()
})
Schema
import { Schema, Connection } from '@darkstar-cli/orm'
const schema = new Schema(Connection.get())
await schema.create('products', (table) => { ... })
await schema.drop('products')
const existe = await schema.hasTable('products')
Drivers suportados
| Driver | DB_CONNECTION | Dependência |
|---|---|---|
| MySQL | mysql | mysql2 |
| MariaDB | mariadb | mysql2 |
| PostgreSQL | postgres | pg |
| SQLite | sqlite | better-sqlite3 |
Fluxo de uma request
Convenção, não magia
User → users é pluralização automática.
UserController é sempre injetado com UserService.
UserService é sempre injetado com UserRepository.
make:api User gera tudo porque sabe a convenção.