vyndra-js
Version:
Micro Node.js framework with routing, ORM, decorators, and automatic DI
431 lines (325 loc) • 9.66 kB
Markdown
# VyndraJS
**VyndraJS** es un **micro-framework para Node.js y TypeScript** que combina **routing**, **ORM**, **inyección automática de dependencias (DI)** y **decoradores modernos**.
Está diseñado para crear **APIs, microservicios y arquitecturas modulares** de manera rápida, limpia y escalable.
VyndraJS busca ofrecer una **estructura de código coherente, predecible y moderna**, con soporte nativo para **autoimportación de componentes**, **publicación de eventos con RabbitMQ** y un **CLI oficial** para automatizar tareas comunes.
## Instalación
```bash
npm install vyndra-js
npm install -g vyndra-js
```
## Estructura recomendada
```
src/
├─ controllers/
│ └─ user.controller.ts
├─ services/
│ └─ user.service.ts
├─ repositories/
│ └─ user.repository.ts
├─ models/
│ └─ user.model.ts
├─ listeners/
│ └─ auth.listener.ts
└─ main.ts
```
> VyndraJS **autoimporta** automáticamente todos los archivos con sufijos `.controller.js` y `.service.ts` al iniciar la aplicación.
## Requisitos y consideraciones
### Requisitos básicos
Antes de usar VyndraJS, asegúrate de tener:
- **Node.js 18 o superior**
- **TypeScript** instalado global o localmente
```bash
npm install -D typescript ts-node
```
- Archivo `tsconfig.json` configurado con decoradores habilitados:
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "NodeNext",
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
```
### Requisitos opcionales: RabbitMQ
VyndraJS ofrece integración nativa con **RabbitMQ** para manejar **eventos asíncronos** mediante decoradores como `@Publish()` y `@QueueListenerMethod()`.
Puedes habilitar RabbitMQ de dos maneras:
#### 1. Usando variables de entorno:
```bash
MESSAGE_BROKER_PORT=5672
MESSAGE_BROKER_HOST=amqps://user:pass@bunny.cloudamqp.com/vhost
MESSAGE_BROKER_TIMEOUT=15000
MESSAGE_BROKER_AMQP=5672
MESSAGE_BROKER_MANAGEMENT=15672
MESSAGE_BROKER_IMAGE=rabbitmq:3-management
```
#### 2. Dejando que VyndraJS cree un contenedor automáticamente:
```ts
const app = new App({
docker: { os: "windows" } // "linux" | "mac"
});
```
#### 3. Creandolo por comandos CLI:
```ts
vyndra create:broker <os> // "windows" | "linux" | "mac"
```
> Esto descargará la imagen oficial de **RabbitMQ** y creará un contenedor configurado para ejecutarse junto a la aplicación.
> Ideal para entornos de desarrollo sin necesidad de instalar Rabbit manualmente.
### Nota sobre el ORM
> **Los modelos del ORM (entidades y repositorios) se encuentran actualmente en desarrollo.**
>
> Las clases `@Entity`, `@Id`, `@Column` y `CrudRepository` están disponibles en una versión inicial funcional, pero pueden sufrir cambios en futuras versiones para mejorar rendimiento y compatibilidad con PostgreSQL, MySQL y SQLite.
## CLI oficial de VyndraJS
VyndraJS incluye una **CLI potente y minimalista** que automatiza la creación de proyectos y componentes.
### Comandos disponibles
```bash
# Crear un nuevo proyecto base con configuración TypeScript y .env
vyndra create:app <nombre>
# Crear e inicilizar un nuevo contenedor RabbitMQ
vyndra create:broker <os>
# Crear un módulo completo con subcarpetas
vyndra make:module <nombre>
# Crear un controller (crea el módulo si no existe)
vyndra make:controller <nombre>
# Crear un servicio
vyndra make:service <nombre>
# Crear un modelo (ORM)
vyndra make:model <nombre>
# Crear un repositorio
vyndra make:repository <nombre>
# Crear un listener para RabbitMQ
vyndra make:listener <nombre>
```
### Comando `create:app`
El comando `vyndra create:app <nombre>` genera automáticamente una aplicación base con:
- Estructura inicial `src/`
- Configuración de **TypeScript**
- Archivo `.env` listo para usar RabbitMQ
- Configuración inicial de `App` con soporte Docker opcional
Ejemplo:
```bash
vyndra create:app my-project
```
Estructura generada:
```
my-project/
├─ src/
│ ├─ controllers/
│ ├─ services/
│ ├─ repositories/
│ ├─ models/
│ ├─ listeners/
│ └─ index.ts
├─ .env
├─ tsconfig.json
├─ package.json
└─ README.md
```
## Ejemplos de uso
### Definir una entidad
```ts
import { Id, Column, Entity } from "vyndra-js";
@Entity("users")
export class User {
@Id()
id!: number;
@Column({ length: 255, notNull: true })
name!: string;
@Column({ default: true })
isValid!: boolean;
@Column({ withTimezone: true })
createdAt!: Date;
}
```
### Crear un repositorio CRUD
```ts
import { CrudRepository, Injectable, Repository } from "vyndra-js";
import { User } from "../models/user.model.js";
@Injectable()
@Repository(User)
export class UserRepository extends CrudRepository<User> {}
```
### Crear un servicio con AutoWired y Publish
```ts
import { AutoWired, Injectable, Publish } from "vyndra-js";
import { UserRepository } from "../repositories/user.repository.js";
import { User } from "../models/user.model.js";
@Injectable()
export class UserService {
@AutoWired
private userRepository!: UserRepository;
async getAll() {
const data = await this.userRepository.findAll();
return data;
}
async getById(id: number) {
const data = await this.userRepository.findById(id);
return data;
}
async getByField(field: keyof User, value: any) {
const data = await this.userRepository.findByField(field, value);
return data;
}
async post(body: User) {
const data = await this.userRepository.save(body);
return data;
}
async update(id: number, body: User) {
const data = await this.userRepository.update(id, body);
return data;
}
async delete(id: number) {
const data = await this.userRepository.delete(id);
return data;
}
@Publish("event")
async event(message: string) {
return { date: Date.now(), message };
}
}
```
### Crear un controller
```ts
import {
Controller,
Get,
Post,
Response,
Request,
AutoWired,
Patch,
Delete,
} from "vyndra-js";
import { UserService } from "../services/user.service.js";
@Controller("/user")
export class UserController {
@AutoWired
private userService!: UserService;
@Get("/")
async get(req: Request, res: Response) {
try {
const result = await this.userService.getById(Number(req.query?.id));
res.status(200).json(result);
} catch (error) {
res.status(500).json(error);
}
}
@Get("/all")
async getAll(req: Request, res: Response) {
try {
res.status(200).json(await this.userService.getAll());
} catch (error) {
res.status(500).json(error);
}
}
@Post("/")
async post(req: Request, res: Response) {
try {
res.status(200).json(await this.userService.post(req.body));
} catch (error) {
res.status(500).json(error);
}
}
@Post("/field")
async getByField(req: Request, res: Response) {
try {
const { field, value } = req.body;
res.status(200).json(await this.userService.getByField(field, value));
} catch (error) {
res.status(500).json(error);
}
}
@Patch("/")
async patch(req: Request, res: Response) {
try {
res
.status(200)
.json(await this.userService.update(Number(req.query?.id), req.body));
} catch (error) {
res.status(500).json(error);
}
}
@Delete("/")
async delete(req: Request, res: Response) {
try {
res
.status(200)
.json(await this.userService.delete(Number(req.query?.id)));
} catch (error) {
res.status(500).json(error);
}
}
@Post("/all")
async event(req: Request, res: Response) {
try {
res
.status(200)
.json(await this.userService.event(String(req.query?.message)));
} catch (error) {
res.status(500).json(error);
}
}
}
```
### Crear un listener RabbitMQ
```ts
import { QueueListener, QueueListenerMethod } from "vyndra-js";
@QueueListener()
export class UserListener {
@QueueListenerMethod("event")
handleEvent(message: any) {
console.log(message);
}
}
```
## Flujo de eventos con RabbitMQ
```
[Servicio con @Publish] ---> [Cola RabbitMQ] ---> [Listener con @QueueListenerMethod]
```
- Los **servicios** publican eventos con `@Publish("nombreEvento")`.
- RabbitMQ los enruta a la cola correspondiente.
- Los **listeners** los consumen y procesan automáticamente.
## Características principales
- Decoradores modernos (`@Controller`, `@Injectable`, `@Entity`, `@Repository`, `@Get`, `@Post`, etc.)
- nyección automática de dependencias (DI)
- ORM con CRUD básico (en desarrollo activo)
- Autoimportación de módulos y servicios
- Routing automático basado en decoradores
- Integración nativa con RabbitMQ
- CLI oficial para scaffolding rápido
- Diseño preparado para microservicios y gRPC (en próximas versiones)
## Roadmap
| Fase | Estado | Descripción |
| ----- | ------ | ------------------------------------------- |
| 1️⃣ | ✅ | Routing y ORM básico |
| 2️⃣ | 🚧 | Microservicios y gRPC |
| 3️⃣ | ⏳ | Validaciones, autenticación, CLI extendida |
| 4️⃣ | 🔮 | ORM completo con migraciones y relaciones |
## Licencia
**MIT License**
Dependencias:
- drizzle-orm – MIT
- pg / @types/pg – MIT
- reflect-metadata – MIT
- dotenv – MIT
- amqplib / @types/amqplib – MIT
- commander – MIT compatible