
Security News
Feross on TBPN: How North Korea Hijacked Axios
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.
@fioc/event-bus
Advanced tools
Type-safe event bus with CQRS support for FIoC. Build event-driven architectures with commands, queries, notifications, and middleware - fully integrated with dependency injection.
FIoC Event Bus provides a comprehensive, type-safe event-driven architecture system built on top of @fioc/core.
It enables CQRS (Command Query Responsibility Segregation), domain events, and event-driven patterns with full dependency injection integration — completely reflection-free and decorator-free.
💡 Built for complex event-driven architectures, microservices, and domain-driven design — without reflection or decorators.
Install via npm, yarn, or pnpm:
npm install @fioc/event-bus @fioc/core
# or
yarn add @fioc/event-bus @fioc/core
# or
pnpm add @fioc/event-bus @fioc/core
The Event Bus package introduces several key abstractions for building event-driven applications:
| Concept | Description |
|---|---|
| INotification | Domain events that can have multiple handlers |
| ICommand | Commands that perform actions (single handler) |
| IQuery | Queries that retrieve data (single handler) |
| IEventBus | Central service for publishing events and invoking commands/queries |
| IHandlerMiddleware | Interceptors for cross-cutting concerns |
Everything is fully typed, DI-integrated, and metadata-aware — no decorators, no reflect-metadata.
import { createNotificationDIToken } from "@fioc/event-bus";
// Define notification payload type
export type UserRegisteredPayload = {
userId: string;
email: string;
timestamp: Date;
};
export interface UserRegisteredNotification
extends INotification<UserRegisteredPayload> {}
// Create notification token
export const UserRegisteredNotificationToken =
createNotificationDIToken<UserRegisteredNotification>().as("UserRegistered", {
generics: [
/* Optional payload token */
],
});
import { createCommandDIToken } from "@fioc/event-bus";
export type CreateUserCommandPayload = {
email: string;
password: string;
name: string;
};
export interface CreateUserCommand
extends ICommand<CreateUserCommandPayload, string> {}
export const CreateUserCommandToken =
createCommandDIToken<CreateUserCommand>().as("CreateUser");
import { createQueryDIToken } from "@fioc/event-bus";
export type GetUserByIdQueryPayload = {
userId: string;
};
export interface GetUserByIdQuery
extends IQuery<GetUserByIdQueryPayload, User> {}
export const GetUserByIdQuery =
createQueryDIToken<GetUserByIdQuery>().as("GetUserById");
import { createNotificationHandlerDIToken } from "@fioc/event-bus";
import { UserRegisteredNotification } from "./events";
export interface SendWelcomeEmailHandler
extends INotificationHandler<UserRegisteredNotification> {}
export const SendWelcomeEmailHandlerToken =
createNotificationHandlerDIToken().as("SendWelcomeEmail", {
generics: [UserRegisteredNotificationToken], // Needs to specify the notification token
});
// Implementation
const sendWelcomeEmailHandlerImpl: SendWelcomeEmailHandler = {
async handle(payload) {
await emailService.sendWelcomeEmail(event.payload.email);
},
};
import { createCommandHandlerDIToken } from "@fioc/event-bus";
import { CreateUserCommand } from "./commands";
export interface CreateUserHandler extends ICommandHandler<CreateUserCommand> {}
export const CreateUserHandlerToken = createCommandHandlerDIToken().as(
"CreateUserHandler",
{
generics: [CreateUserCommandToken], // Needs to specify the command token
}
);
// Implementation
const createUserHandlerImpl: CreateUserHandler = {
async handle(command: { payload: CreateUserCommandPayload }) {
const user = await userService.createUser(command.payload);
return user.id; // Must match command result type
},
};
import { createQueryHandlerDIToken } from "@fioc/event-bus";
import { GetUserByIdQuery } from "./queries";
export interface GetUserByIdHandler extends IQueryHandler<GetUserByIdQuery> {}
export const GetUserByIdHandlerToken = createQueryHandlerDIToken().as(
"GetUserByIdHandler",
{
generics: [GetUserByIdQueryToken], // Needs to specify the query token
}
);
// Implementation
const getUserByIdHandlerImpl: GetUserByIdHandler = {
async handle(query: { payload: GetUserByIdQueryPayload }) {
return await userRepository.findById(query.payload.userId);
},
};
import { buildDIContainer } from "@fioc/core";
import { EventBusFactory, IEventBusToken } from "@fioc/event-bus";
const container = buildDIContainer()
.registerFactory(IEventBusToken, EventBusFactory)
.register(SendWelcomeEmailHandlerToken, sendWelcomeEmailHandler)
.register(CreateUserHandlerToken, createUserHandler)
.register(GetUserByIdHandlerToken, getUserByIdHandler)
.getResult();
const eventBus = container.resolve(IEventBusToken);
// Publish a domain event
await eventBus.publish({
token: UserRegisteredNotification,
payload: {
userId: "123",
email: "user@example.com",
timestamp: new Date(),
},
createdAt: new Date(),
});
// With different execution strategies
await eventBus.publish(notification, "parallel"); // All handlers run concurrently
await eventBus.publish(notification, "sequential"); // Handlers run one after another
await eventBus.publish(notification, "besteffort"); // Parallel but continue on handler errors
// Invoke a command
const userId = await eventBus.invoke({
token: CreateUserCommand,
payload: {
email: "user@example.com",
password: "securepassword",
name: "John Doe",
},
createdAt: new Date(),
});
// Invoke a query
const user = await eventBus.invoke({
token: GetUserByIdQuery,
payload: { userId: "123" },
createdAt: new Date(),
});
Middleware allows you to implement cross-cutting concerns like logging, validation, and error handling.
import { createMiddlewareDIToken, IQueryToken, ICommandToken } from "@fioc/event-bus";
export interface LoggingMiddleware extends IHandlerMiddleware<IQuery<any> | ICommand<any> ,unknown>
export const LoggingMiddleware = createMiddlewareDIToken().as(
"LoggingMiddleware",
{
generics: [IQueryToken, ICommandToken], // Apply to all commands and queries
}
);
const loggingMiddleware = {
async handle(request, next: (request: any) => Promise<any>) {
console.log("Processing request:", request.token.key);
const startTime = Date.now();
try {
const result = await next(request);
console.log("Request completed in", Date.now() - startTime, "ms");
return result;
} catch (error) {
console.error("Request failed:", error);
throw error;
}
},
};
import { MiddleWareOrderToken } from "@fioc/event-bus";
const container = buildDIContainer()
.register(MiddleWareOrderToken, [LoggingMiddleware, ValidationMiddleware]) // Middleware Order declaration
.registerFactory(IEventBusToken, EventBusFactory)
.register(LoggingMiddleware, loggingMiddleware)
.register(ValidationMiddleware, validationMiddleware)
.getResult();
// Apply to all notifications
const NotificationLoggingMiddleware = createMiddlewareDIToken().as(
"NotificationLogging",
{
generics: [INotificationToken], // Apply to all notifications
}
);
// Apply to specific notification
const UserEventMiddleware = createMiddlewareDIToken().as(
"UserEventMiddleware",
{
generics: [UserRegisteredNotification], // Apply only to user registration
}
);
// Apply to multiple types
const CommandQueryMiddleware = createMiddlewareDIToken().as(
"CommandQueryMiddleware",
{
generics: [ICommandToken, IQueryToken], // Apply to all commands and queries
}
);
The event bus supports different execution strategies for notification handlers:
await eventBus.publish(notification, "parallel");
await eventBus.publish(notification, "sequential");
const errors = await eventBus.publish(notification, "besteffort");
| Token | Description |
|---|---|
IEventBusToken | The main event bus service |
MiddleWareOrderToken | Array defining middleware execution order |
INotificationToken | Base token for all notifications |
ICommandToken | Base token for all commands |
IQueryToken | Base token for all queries |
INotificationHandlerToken | Base token for notification handlers |
ICommandHandlerToken | Base token for command handlers |
IQueryHandlerToken | Base token for query handlers |
IHandlerMiddlewareToken | Base token for middleware |
| Function | Description |
|---|---|
createNotificationDIToken() | Creates notification tokens |
createCommandDIToken() | Creates command tokens |
createQueryDIToken() | Creates query tokens |
createNotificationHandlerDIToken() | Creates notification handler tokens |
createCommandHandlerDIToken() | Creates command handler tokens |
createQueryHandlerDIToken() | Creates query handler tokens |
createMiddlewareDIToken() | Creates middleware tokens |
| Interface | Description |
|---|---|
IEventBus | Main event bus interface |
INotification<T> | Domain event interface |
ICommand<T, R> | Command interface |
IQuery<T, R> | Query interface |
INotificationHandler<T> | Notification handler interface |
ICommandHandler<T> | Command handler interface |
IQueryHandler<T> | Query handler interface |
IHandlerMiddleware<T, R> | Middleware interface |
Contributions are welcome!
Open an issue or submit a PR on GitHub.
Please include tests for new features or fixes and keep commits focused.
Licensed under the MIT License.
FAQs
Type-safe event bus with CQRS support for FIoC. Build event-driven architectures with commands, queries, notifications, and middleware - fully integrated with dependency injection.
The npm package @fioc/event-bus receives a total of 4 weekly downloads. As such, @fioc/event-bus popularity was classified as not popular.
We found that @fioc/event-bus demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.

Security News
OpenSSF has issued a high-severity advisory warning open source developers of an active Slack-based campaign using impersonation to deliver malware.

Research
/Security News
Malicious packages published to npm, PyPI, Go Modules, crates.io, and Packagist impersonate developer tooling to fetch staged malware, steal credentials and wallets, and enable remote access.