@jadiazinf/hibana
v0.1.4
Published
TypeScript backend framework built on Hono + Bun.js, inspired by Spring Boot, Rails and Laravel
Downloads
607
Readme
import { Hibana, Module, Controller, Get, Param, Injectable, ok } from '@jadiazinf/hibana'
@Injectable()
class GreetingService {
hello(name: string) { return `Hello, ${name}!` }
}
@Controller('/greet')
class GreetController {
constructor(private svc: GreetingService) {}
@Get('/:name')
greet(@Param('name') name: string) {
return ok({ message: this.svc.hello(name) })
}
}
@Module({ services: [GreetingService], controllers: [GreetController] })
class AppModule {}
await Hibana.create(AppModule).listen(3000)
// GET /greet/world → { "message": "Hello, world!" }Controllers, services, DI, routing. All type-safe, all decorator-driven.
Quick Start
# Interactive project creation (recommended)
bunx @jadiazinf/hibana init my-app
# With flags (non-interactive)
bunx @jadiazinf/hibana init my-app --db=sqlite --features=auth,websocket
bunx @jadiazinf/hibana init my-app --db=postgres --features=auth --docker --ci
# Config strategy
bunx @jadiazinf/hibana init my-app --config=env # .env only (default)
bunx @jadiazinf/hibana init my-app --config=yaml # hibana.yml + .env for secrets
# Minimal setup
bunx @jadiazinf/hibana new my-appOr manually:
mkdir my-app && cd my-app
bun init -y
bun add @jadiazinf/hibana hono reflect-metadataCreate src/main.ts:
import 'reflect-metadata'
import { Hibana, Module, Controller, Get } from '@jadiazinf/hibana'
@Controller('/')
class AppController {
@Get('/')
index() { return { message: 'Welcome to Hibana!' } }
}
@Module({ controllers: [AppController] })
class AppModule {}
const app = Hibana.create(AppModule)
// app.setGlobalPrefix('/api/v1') // Optional: prefix all routes
await app.listen(3000)bun run src/main.ts
# 🔥 H I B A N A
# ────────────────────────────────────────
# ➜ Server: http://localhost:3000
# ➜ Routes: 5 endpoints
# ────────────────────────────────────────
# "Compiling dreams, deploying realities"Project Structure
env mode (default — --config=env):
my-app/
src/
app.module.ts # Root module (uses Env.get() directly)
app.controller.ts # Default controller
main.ts # Entry point
.env # All configuration here
tsconfig.json
package.jsonyaml mode (--config=yaml):
my-app/
config/
hibana.yml # Framework configuration
src/
app.module.ts # Root module (loads from YAML)
app.controller.ts # Default controller
main.ts # Entry point
.env # Secrets only (JWT_SECRET, DATABASE_URL)
tsconfig.json
package.jsonWhy Hibana?
If you've used NestJS, you already know Hibana. Same decorator patterns, same DI, same module system. But Hibana runs on Bun, uses Hono under the hood, and ships with batteries that NestJS makes you install separately.
If Bun is the engine and Hono is the chassis, Hibana is the fully assembled car.
| | Hibana | NestJS | Elysia | Hono | |---|:---:|:---:|:---:|:---:| | Decorators + DI | Yes | Yes | No | No | | Built-in ORM | Drizzle | No | No | No | | Auto-CRUD generation | Yes | No | No | No | | OpenAPI auto-gen | Yes | Separate pkg | Yes | Separate | | Auth + JWT + Roles | Yes | Separate | No | No | | WebSockets + Rooms | Yes | Separate | Yes | No | | Admin dashboard | Yes | No | No | No | | Session management | Yes | Separate | No | No | | File storage (S3) | Yes | Separate | No | No | | Mailer | Yes | Separate | No | No | | OAuth (Google/GitHub) | Yes | Separate | No | No | | HTMX integration | Yes | No | No | No | | View engine (EJS/Pug/HBS) | Yes | Separate | No | No | | Runtime | Bun | Node | Bun | Any | | Tests | 1,389 | - | - | - |
One bun add for a full-stack backend. No hunting for packages, no glue code, no version conflicts.
Philosophy
Hibana is built on six foundational ideas:
- Convention Over Configuration — Sensible defaults so you only configure what is truly different
- Decorator-Driven Development — Decorators describe what something is, not how to implement it
- Batteries Included — 33 modules in a single
@jadiazinf/hibanapackage, no transpilation needed - Type Safety First — Built entirely in TypeScript, errors caught at compile time
- Bun-Native Performance — Purpose-built for Bun: native TS execution, no transpilation, web-standard APIs
- Proven Patterns, Modern Execution — Battle-tested architecture (modules, DI, conventions) in a modern runtime
Features
Core
- Dependency Injection -- Constructor injection with
@Injectable,@Inject, circular dependency detection, request-scoped providers - Module System --
@Modulewith imports, exports, services, controllers, gateways. Dynamic modules viaforRoot() - Lifecycle Hooks --
onModuleInit()andonModuleDestroy()on any service - Plugin System --
app.plugin()with register/onInit/onDestroy lifecycle
HTTP
- Decorators --
@Controller,@Get/@Post/@Put/@Delete/@Patch/@Options,@Body/@Param/@Query/@Header/@Ctx/@Req/@UploadedFile - Guards --
@UseGuardfor auth, roles, or custom access control. ExtendHibanaGuardfor type-safe guards - Pipes --
@Validatewith Valibot,ParseIntPipe,ParseBoolPipe,ParseUUIDPipe,ParseFilePipe,DefaultValuePipe - Interceptors --
@UseInterceptorto transform responses, add timing, logging, caching - Exception Filters --
@UseFilterfor custom error handling. ExtendHibanaExceptionFilterfor type safety - Middleware -- Class-based
@UseMiddlewareor globalapp.use(). ExtendHibanaMiddlewarefor type-safe middleware - Exceptions --
HttpException,BadRequestException,UnauthorizedException,ForbiddenException,NotFoundException,ConflictException,UnprocessableEntityException,TooManyRequestsException,InternalServerErrorException - Utilities --
@HttpCode(201)to set response status,@Public()to skip auth guards - SSE/Streaming --
SseResponsefor server-sent events - Versioning --
@Version('2')for API versioning - Global Prefix --
app.setGlobalPrefix('/api/v1')to prefix all routes - Serialization --
@Exclude/@Exposedecorators for response shaping
Database
- Drizzle ORM --
DrizzleRepositorywith type-safe queries, pagination, sorting, filtering - SQLite + PostgreSQL -- Switch drivers with one config change. Auto-detected migration templates
- Migrations --
hibana migrate run/rollback/status, batch tracking, up/down. Async PostgreSQL support - Seeds --
hibana db:seed, per-file seeding - Row-Level Security --
@TenantScope,@OwnerScope,@GlobalScope,@UsePolicyfor automatic WHERE injection
Auth & Security
- JWT Auth --
AuthServicewith access/refresh tokens,JwtAuthGuard,@CurrentUser - Roles --
@Roles('admin')+RolesGuard - Token Blacklist -- Async
revoke()/isRevoked()with pluggable store - Helmet -- Security headers
- CORS -- Configurable origin, credentials, methods
- Rate Limiting -- Per-IP sliding window, Redis-backed for distributed apps
- CSRF -- Double-submit cookie pattern
Real-time
- WebSockets --
@WebSocketGateway,@OnMessage/@OnOpen/@OnClose, rooms, guards on upgrade - Notifications --
send(userId, ...), broadcast, rooms,@OnNotificationhandlers, EventBus auto-forwarding - Events --
EventBusService,@OnEvent, wildcards
Infrastructure
- Cache --
CacheServicewith in-memory (LRU) or Redis store - Queue --
QueueService,@Process, concurrency, retries with capped exponential backoff - Scheduler --
@Cron('*/5 * * * *')or@Cron('every:30s'), dashboard UI - Config -- Two modes: env-only (
.env+Env.get()) or YAML (profiles +.envfor secrets), typed env validation - Logger -- Structured logging, correlation IDs, JSON or pretty format, automatic request logging
- Health Checks --
HealthModule.forRoot(), Redis indicator, custom indicators - Sessions -- Cookie-based with
@Session()decorator, flash data, rolling, store-agnostic - i18n -- Interpolation, pluralization, locale middleware
Ecosystem
- OpenAPI -- Auto-generated spec + optional
@ApiOperation,@ApiResponse,@ApiTags,@ApiExcludeEndpoint. Scalar UI at/docs - GraphQL --
@Resolver,@Query(exported asGqlQuery),@Mutation(exported asGqlMutation),@Arg - Microservices --
@MessagePattern,@EventPattern, transport abstraction - OAuth -- Google + GitHub providers, state validation, JWT pair on callback
- View Engine -- EJS, Handlebars, Pug with
@Renderdecorator - HTMX --
HtmxMiddleware,@HxRequest,@HxTrigger,HtmxResponsebuilder - Admin Panel -- Auto-generated CRUD dashboard from Drizzle schemas
- Scheduler Dashboard -- Task monitoring UI with manual trigger
- Mailer -- Resend + Console transports, template interpolation
- File Storage -- Local disk + S3 (Bun native), multi-disk manager
Developer Tools
- CLI --
hibana generate controller/service/module/crud/guard/pipe/filter/middleware/migration/seeder - Interactive Init --
hibana initwith database, feature selection, Docker/CI generation - Dev Server --
hibana devwith file watching and auto-reload - Testing --
Testing.createTestingModule()withoverrideProvider() - Docker/CI -- Dockerfile, docker-compose, GitHub Actions generators
Module Map
@jadiazinf/hibana
├── Core .............. DI container, modules, lifecycle, plugins
├── HTTP .............. Controllers, guards, pipes, filters, interceptors, SSE
├── ORM ............... Drizzle repository, migrations, seeds
├── Auth .............. JWT, roles, token blacklist
├── Security .......... Helmet, CORS, rate limit, CSRF
├── Cache ............. In-memory (LRU) / Redis
├── Config ............ YAML, profiles, .env, env validation
├── Logger ............ Structured logging, correlation IDs
├── Events ............ EventBus, @OnEvent, wildcards
├── Queue ............. Job processing, retries, concurrency
├── Scheduler ......... Cron jobs, interval tasks, dashboard
├── Session ........... Cookie sessions, flash data
├── i18n .............. Translations, interpolation, pluralization
├── WebSocket ......... Gateways, rooms, guards
├── Notification ...... User targeting, broadcast, rooms
├── Redis ............. Client, cache/rate-limit/blacklist stores
├── OpenAPI ........... Auto spec generation, Scalar UI
├── GraphQL ........... Resolvers, queries, mutations
├── Microservice ...... Message/event patterns, transports
├── OAuth ............. Google, GitHub, extensible providers
├── View .............. EJS, Handlebars, Pug engines
├── HTMX .............. Middleware, guards, response builder
├── Admin ............. Auto-generated CRUD dashboard
├── Mail .............. Resend, console transports
├── Storage ........... Local disk, S3
├── Scope (RLS) ....... Tenant/owner scopes, policies
├── Health ............ Health checks, indicators
├── Testing ........... Test module builder, provider overrides
├── Plugin ............ Plugin lifecycle management
├── Dev ............... Dev server with hot reload
└── CLI ............... Generators, init, migrations, seedsArchitecture
Every HTTP request flows through a layered pipeline:
Request
│
├── Request Logger (auto-registered by LoggerModule)
│ --> GET /users 200 12.5ms
│
├── Middleware (global → controller → route)
│ Session, CORS, Helmet, Rate Limit, CSRF, HTMX
│
├── Guards (global → controller → route)
│ JwtAuthGuard, RolesGuard, HtmxOnlyGuard, custom
│
├── Pipes (parameter transformation + validation)
│ ValidationPipe, ParseIntPipe, ParseFilePipe
│
├── Interceptors (wrap handler execution)
│ SerializationInterceptor, timing, caching
│
├── Handler (your controller method)
│
├── Exception Filters (catch and transform errors)
│
└── ResponseDI is constructor-based with reflect-metadata. Three scopes: @Singleton (default), @Transient, @RequestScoped. Circular dependency detection at resolution time.
Store abstraction (ISP): Cache, rate limiting, and token blacklist share a clean interface pattern — ICacheStore, IRateLimitStore, ITokenBlacklistStore. Each has in-memory and Redis implementations. Swap storage backends without changing application code.
Base classes: Extend HibanaGuard, HibanaMiddleware, HibanaPipe, or HibanaExceptionFilter for type-safe implementations with IDE autocompletion. HibanaService and HibanaController provide auto-CRUD with pagination, sorting, and filtering.
Examples
REST API with Auth and Validation
import {
Hibana, Module, Controller, Get, Post, Body, Param,
UseGuard, JwtAuthGuard, RolesGuard, Roles, CurrentUser,
Validate, AuthModule, ParseUUIDPipe,
} from '@jadiazinf/hibana'
import * as v from 'valibot'
const CreateUserDto = v.object({
email: v.pipe(v.string(), v.email()),
password: v.pipe(v.string(), v.minLength(8)),
name: v.string(),
})
@Controller('/users')
@UseGuard(JwtAuthGuard)
class UserController {
@Post('/')
@Roles('admin')
@UseGuard(RolesGuard)
@Validate(CreateUserDto)
create(@Body() data: v.InferOutput<typeof CreateUserDto>) {
return { created: data.email }
}
@Get('/me')
me(@CurrentUser() user: any) {
return user
}
@Get('/:id')
findOne(@Param('id', ParseUUIDPipe) id: string) {
return { id }
}
}Auto-CRUD Controller
import { HibanaController, HibanaService } from '@jadiazinf/hibana'
// Generates GET /, GET /:id, POST /, PUT /:id, DELETE /:id
// with pagination, sorting, search, and field filtering
class UserController extends HibanaController<User> {
constructor(service: UserService) {
super(service, '/users')
}
}WebSocket Chat
import {
WebSocketGateway, OnMessage, OnOpen, OnClose,
ConnectedSocket, WsPayload, WsServer,
} from '@jadiazinf/hibana'
@WebSocketGateway({ path: '/ws/chat' })
class ChatGateway {
@OnOpen()
onConnect(@ConnectedSocket() ws: any, @WsServer() server: any) {
server.joinRoom(ws, 'general')
}
@OnMessage('chat')
onChat(@WsPayload() data: { text: string }, @WsServer() server: any) {
server.publishToRoom('general', 'chat', data)
}
@OnClose()
onDisconnect(@ConnectedSocket() ws: any) {
// cleanup
}
}Admin Panel from Drizzle Schema
import { Module, DatabaseModule, AdminModule } from '@jadiazinf/hibana'
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
const products = sqliteTable('products', {
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name').notNull(),
price: integer('price').notNull(),
category: text('category'),
})
@Module({
imports: [
DatabaseModule.forRoot({ driver: 'sqlite', filename: './data.db' }),
AdminModule.forRoot({
entities: [{ name: 'Products', table: products }],
title: 'Store Admin',
}),
],
})
class AppModule {}
// 7 routes auto-generated:
// GET /admin → Dashboard with stats
// GET /admin/products → Searchable, paginated table
// GET /admin/products/create → Create form
// POST /admin/products → Handle create
// GET /admin/products/:id → Edit form
// PUT /admin/products/:id → Handle update
// DELETE /admin/products/:id → Handle deleteCron Jobs with Dashboard
import { Injectable, Cron, SchedulerDashboardModule } from '@jadiazinf/hibana'
@Injectable()
class CleanupService {
@Cron('0 3 * * *')
async cleanExpiredSessions() {
// Runs every day at 3 AM
}
@Cron('every:30s')
async checkMetrics() {
// Runs every 30 seconds
}
}
// SchedulerDashboardModule.forRoot({ basePath: '/admin/scheduler' })
// → Task table with run counts, last errors, "Run Now" buttonsOpenAPI (Zero Config)
import {
OpenApiModule, ApiOperation, ApiResponse, ApiTags, ApiExcludeEndpoint,
} from '@jadiazinf/hibana'
@Module({
imports: [
OpenApiModule.forRoot({
info: { title: 'My API', version: '1.0.0' },
}),
],
})
class AppModule {}
// Zero-config: routes, params, Valibot schemas auto-detected
// GET /openapi.json → Full spec
// GET /docs → Scalar UI
// Optional decorators for fine-tuning:
@Controller('/orders')
@ApiTags('Orders')
class OrderController {
@Get('/')
@ApiOperation({ summary: 'List all orders' })
@ApiResponse({ status: 200, description: 'Order list' })
list() { /* ... */ }
@Get('/internal')
@ApiExcludeEndpoint()
internal() { /* hidden from docs */ }
}OAuth Login
import { OAuthModule, GoogleProvider, GithubProvider } from '@jadiazinf/hibana'
@Module({
imports: [
OAuthModule.forRoot({
basePath: '/auth',
providers: [
new GoogleProvider({ clientId: '...', clientSecret: '...', redirectUri: '...' }),
new GithubProvider({ clientId: '...', clientSecret: '...', redirectUri: '...' }),
],
onLogin: async (profile, ctx) => {
// Create/find user, return JWT payload
return { sub: profile.id, email: profile.email }
},
}),
],
})
class AppModule {}
// GET /auth/google → Redirect to Google
// GET /auth/google/callback → Handle callback, return JWT pair
// GET /auth/github → Redirect to GitHub
// GET /auth/github/callback → Handle callback, return JWT pairRow-Level Security
import { ScopedDrizzleRepository, TenantScope, OwnerScope, UsePolicy } from '@jadiazinf/hibana'
@TenantScope('organizationId')
@OwnerScope('createdBy')
class InvoiceRepository extends ScopedDrizzleRepository<typeof invoices> {
constructor(db: any) {
super(db, invoices)
}
}
// Every query auto-injects: WHERE organizationId = :tenantId AND createdBy = :userId
// Admin bypass: repo.withoutScopes().findMany()Security Stack
@Module({
imports: [
SecurityModule.forRoot({
helmet: { contentSecurityPolicy: true },
cors: { origin: 'https://myapp.com', credentials: true },
rateLimit: { max: 100, windowMs: 60_000 },
csrf: { enabled: true },
}),
],
})
class AppModule {}File Storage
import { StorageModule, StorageService } from '@jadiazinf/hibana'
@Module({
imports: [
StorageModule.forRoot({
default: 'local',
disks: {
local: { driver: 'local', root: './uploads', baseUrl: '/files' },
s3: { driver: 's3', bucket: 'my-bucket', region: 'us-east-1' },
},
}),
],
})
class AppModule {}
// In controllers:
@Post('/upload')
async upload(@UploadedFile(ParseFilePipe) file: File) {
const info = await this.storage.put(`uploads/${file.name}`, file)
return { url: info.url }
}Redis Adapters
import { RedisModule } from '@jadiazinf/hibana'
@Module({
imports: [
RedisModule.forRoot({ url: 'redis://localhost:6379' }),
// Redis automatically provides:
// - RedisCacheStore for CacheModule
// - RedisRateLimitStore for SecurityModule
// - RedisBlacklistStore for AuthModule
],
})
class AppModule {}Exception Handling
import {
NotFoundException, ForbiddenException, HibanaExceptionFilter,
UseFilter, HttpCode, Public,
} from '@jadiazinf/hibana'
// Throw built-in exceptions (auto-serialized to JSON)
@Get('/:id')
findOne(@Param('id') id: string) {
const item = db.find(id)
if (!item) throw new NotFoundException(`Item ${id} not found`)
return item
}
// Custom exception filter
class BusinessErrorFilter extends HibanaExceptionFilter {
catch(error: Error, ctx: any) {
return ctx.json({ error: error.message, code: 'BUSINESS_ERROR' }, 422)
}
}
@Post('/')
@HttpCode(201) // Set response status
@Public() // Skip auth guards
@UseFilter(BusinessErrorFilter)
create(@Body() data: any) { /* ... */ }Sessions
import { SessionModule, SessionDecorator, Session } from '@jadiazinf/hibana'
@Module({
imports: [
SessionModule.forRoot({ ttlMs: 3600_000, rolling: true }),
],
})
class AppModule {}
@Controller('/cart')
class CartController {
@Post('/add')
addToCart(@SessionDecorator() session: Session, @Body() item: any) {
const cart = session.get<any[]>('cart') ?? []
cart.push(item)
session.set('cart', cart)
session.flash('message', 'Item added!') // survives 1 request
return { cart }
}
}Logger (Auto Request Logging)
import { Module, LoggerModule } from '@jadiazinf/hibana'
@Module({
imports: [
LoggerModule.forRoot({
level: 'info',
format: 'pretty', // 'json' for production
// requestLogging: true (default) — auto-logs all HTTP requests
}),
],
})
class AppModule {}
// Output:
// [INFO] --> GET /users
// [INFO] <-- GET /users 200 12.5msNo wiring needed — LoggerModule auto-registers request logging middleware.
Global Prefix
const app = Hibana.create(AppModule)
app.setGlobalPrefix('/api/v1')
await app.listen(3000)
// All routes now prefixed:
// GET /api/v1/users
// POST /api/v1/ordersTesting
import { Testing } from '@jadiazinf/hibana'
const module = await Testing.createTestingModule({
imports: [AppModule],
})
.overrideProvider(DatabaseService).useValue(mockDb)
.compile()
const app = module.createApplication()
const res = await app.fetch(new Request('http://localhost/users'))
expect(res.status).toBe(200)CLI
# Project scaffolding
hibana init my-app # Interactive setup (db, features, Docker, CI)
hibana init my-app --config=env # .env only (default)
hibana init my-app --config=yaml # YAML config + .env for secrets
hibana new my-app # Quick project creation
# Code generation
hibana generate controller user # src/user/user.controller.ts
hibana generate service user # src/user/user.service.ts
hibana generate module user # src/user/user.module.ts
hibana generate crud product # Controller + service + module
hibana generate guard auth # src/auth/auth.guard.ts
hibana generate pipe trim # src/trim/trim.pipe.ts
hibana generate filter http-error # src/http-error/http-error.filter.ts
hibana generate middleware logger # src/logger/logger.middleware.ts
# Database
hibana migrate generate create-users # New migration file
hibana migrate run # Run pending migrations
hibana migrate rollback # Rollback last batch
hibana migrate status # Show migration status
hibana db:seed # Run all seeders
hibana db:seed --file=users # Run specific seeder
# Development
hibana dev # Dev server with auto-reload
hibana dev --port 8080 # Custom portConfiguration
Hibana supports two configuration strategies, selected at project creation with --config=env|yaml:
Env mode (default)
All configuration lives in .env. Access values with Env.get():
# .env
PORT=3000
DATABASE_URL=postgres://localhost:5432/myapp
JWT_SECRET=my-secretimport { Env } from '@jadiazinf/hibana'
DatabaseModule.forRoot({
driver: EDatabaseDriver.POSTGRES,
url: Env.get('DATABASE_URL'),
})YAML mode
Structured configuration in config/hibana.yml, with .env for secrets:
# config/hibana.yml
app:
name: my-app
port: 3000
database:
driver: sqlite
filename: ./data.db
auth:
secret: ${JWT_SECRET}
accessTokenExpiry: 15m
refreshTokenExpiry: 7d# config/hibana.production.yml (overrides base)
database:
driver: postgres
host: ${DB_HOST}
port: 5432
database: ${DB_NAME}HIBANA_PROFILE=production bun run src/main.tsEnv validation
ConfigModule.forRoot({
path: './config',
envSchema: {
JWT_SECRET: { type: 'string' },
DB_PORT: { type: 'number', default: 5432 },
DEBUG: { type: 'boolean', default: false },
ALLOWED_ORIGINS: { type: 'string[]' },
},
})Scripts
bun run src/main.ts # Run the application (Bun runs TypeScript directly)
bun run dev # Dev server with auto-reload
bun test # Run all tests
bun run lint # Check code with Biome
bun run format # Format code with Biome
bun run check # Lint + format (auto-fix)Note: Bun executes TypeScript natively — no build/transpilation step needed.
Code Quality
Hibana uses Biome for linting and formatting. The configuration lives in biome.json at the project root:
- Style: 2-space indent, single quotes, semicolons, trailing commas
- Lint rules: recommended set +
noExplicitAny,noUnusedVariables,useConst - Import sorting: automatic via
organizeImports
New projects created with hibana init or hibana new include Biome pre-configured with VS Code format-on-save support.
Requirements
- Bun >= 1.0
- TypeScript >= 5.0
"experimentalDecorators": trueintsconfig.json"emitDecoratorMetadata": trueintsconfig.json
Optional peer dependencies:
bun add ioredis # Redis adapters
bun add ejs # EJS view engine
bun add handlebars # Handlebars view engine
bun add pug # Pug view engineContributing
Contributions welcome. Please open an issue first to discuss what you'd like to change.
git clone https://github.com/jadiazinf/hibana.git
cd hibana
bun install
bun test # 1,389 testsLicense
MIT
