Architecture
Iskra follows a hexagonal architecture (Ports & Adapters) that separates business logic from infrastructure details.
Framework layers
Section titled “Framework layers”┌─────────────────────────────────────────────────┐│ Tu Aplicacion ││ (handlers, servicios, dominio) │├─────────────────────────────────────────────────┤│ Capa de Plugins ││ (extensiones opcionales del framework) │├─────────────────────────────────────────────────┤│ Capa de Drivers ││ WebPlugin │ DbDriver │ SocketDriver │ KV │ … │├─────────────────────────────────────────────────┤│ @iskra-bun/core ││ App │ EventBus │ Logger │ Config │ DI │ Errors│└─────────────────────────────────────────────────┘Core interfaces
Section titled “Core interfaces”Driver
Section titled “Driver”Each framework kit exposes a Driver that registers itself on the App:
interface Driver { name: string; init(app: App): Promise<void> | void; start?(): Promise<void> | void; stop?(): Promise<void> | void;}The lifecycle is: register() → init() → start() → stop().
Plugin
Section titled “Plugin”Plugins are lightweight extensions without a full lifecycle:
interface Plugin { name: string; install(app: App): Promise<void> | void;}Feature (Web Kit)
Section titled “Feature (Web Kit)”Features are modules of the web Kernel with dependency resolution:
interface Feature { name: string; dependencies?: string[]; peerDependencies?: string[]; initialize(kernel: Kernel): Promise<void>; routes?(app: Hono): void; shutdown?(): Promise<void>;}Drivers vs Plugins
Section titled “Drivers vs Plugins”- A Driver has a full lifecycle (
init/start/stop) and is registered withapp.register(driver). Use it when you manage a resource that opens and closes: an HTTP server, a database connection, a WebSocket server. - A Plugin is lightweight and is installed immediately with
app.use(plugin)viainstall(app). Use it to extend behavior without managing a long-lived resource.
Dependency injection
Section titled “Dependency injection”Iskra uses app.context, a Map whose keys are typed through AppContextRegistry (see Core), as a DI container:
// Un driver se registra en el contextoapp.context.set('db', dbDriver);
// Otro componente lo consume, tipado: DbDriver | undefinedconst db = app.context.get('db');Event system
Section titled “Event system”Components communicate through the event bus (based on mitt). Payloads are typed for the events declared in AppEvents:
// Escucharapp.on('order:created', async (ctx) => { const order = ctx.payload; ctx.logger.info({ order }, 'Orden creada');});
// Emitirapp.emit('order:created', { id: 1, total: 150 });Error hierarchy
Section titled “Error hierarchy”Every framework error extends IskraError:
IskraError├── ConfigError├── DriverError├── PluginError├── LifecycleError├── HttpError (web-kit)│ ├── ValidationError│ ├── AuthError│ ├── ForbiddenError│ ├── NotFoundError│ └── ConflictError├── ConnectionError (db-kit)├── QueryError (db-kit)├── MigrationError (db-kit)├── QueueError (worker-kit)├── JobError (worker-kit)├── SocketConnectionError (socket-kit)└── SocketMessageError (socket-kit)Each error has a code, a context (metadata) and supports cause (chaining).