kitsune-san
v1.0.0
Published
π¦ A polite, reliable event bus that quietly manages your application's messages with the wisdom of a fox spirit
Maintainers
Readme
π¦ Kitsune-san
"Kitsune-san always delivers messages on time."
A polite, reliable event bus that quietly manages your application's messages with the wisdom of a fox spirit. Perfect for decoupled communication in modern JavaScript and TypeScript applications.
β¨ Features
- π― Type-safe: Full TypeScript support with generic event types
- π Lightweight: Zero dependencies, minimal footprint
- π§ Smart: Priority-based listener ordering and timeout management
- π‘οΈ Reliable: Comprehensive error handling and memory management
- π Flexible: Works with any framework or vanilla JavaScript
- π Observable: Built-in statistics and debugging capabilities
- π§ͺ Well-tested: 100% test coverage with comprehensive test suite
π¦ Installation
npm install kitsune-sanπ Quick Start
Simple Usage
import kitsuneSan from "kitsune-san";
// Listen for events
kitsuneSan.on("user:login", (event) => {
console.log("User logged in:", event.detail);
});
// Emit events
kitsuneSan.emit("user:login", {
userId: 123,
username: "fox-lover",
});Type-Safe Events
import { KitsuneSan } from "kitsune-san";
import type { KitsuneEvent } from "kitsune-san";
interface UserData {
id: number;
name: string;
email: string;
}
const kitsuneSan = new KitsuneSan();
// Type-safe event listener
kitsuneSan.on<UserData>("user:created", (event: KitsuneEvent<UserData>) => {
// event.detail is fully typed as UserData
console.log(`Welcome ${event.detail.name}!`);
});
// Type-safe emission
kitsuneSan.emit<UserData>("user:created", {
id: 456,
name: "Kitsune",
email: "[email protected]",
});π API Reference
KitsuneSan Class
on<T>(eventName, callback, options?)
Registers an event listener with optional configuration.
kitsuneSan.on(
"event:name",
(event) => {
console.log(event.detail);
},
{
once: false, // Remove after first execution
timeout: 5000, // Auto-remove after 5 seconds
priority: 10, // Higher priority listeners execute first
}
);Parameters:
eventName(string): Name of the event to listen forcallback(KitsuneCallback): Function to call when event is emittedoptions(ListenerOptions): Optional configuration object
once<T>(eventName, callback, options?)
Registers a one-time event listener that removes itself after first execution.
kitsuneSan.once("app:ready", (event) => {
console.log("App initialization complete");
});off<T>(eventName, callback)
Removes a specific event listener.
const handler = (event) => console.log(event.detail);
kitsuneSan.on("test:event", handler);
kitsuneSan.off("test:event", handler); // Remove specific listeneremit<T>(eventName, data, errorHandler?)
Emits an event with data to all registered listeners.
kitsuneSan.emit(
"notification:show",
{
message: "Hello from Kitsune-san! π¦",
type: "success",
},
(error, eventName, data) => {
console.error(`Failed to emit ${eventName}:`, error);
}
);removeAllListeners(eventName?)
Removes listeners for a specific event or all events.
kitsuneSan.removeAllListeners("user:logout"); // Remove all listeners for specific event
kitsuneSan.removeAllListeners(); // Remove ALL listenershasListeners(eventName)
Checks if any listeners are registered for an event.
if (kitsuneSan.hasListeners("data:changed")) {
kitsuneSan.emit("data:changed", newData);
}getListenerCount(eventName)
Returns the number of listeners for a specific event.
const count = kitsuneSan.getListenerCount("ui:update");
console.log(`${count} components listening for UI updates`);getEventNames()
Returns an array of all event names with registered listeners.
const activeEvents = kitsuneSan.getEventNames();
console.log("Active events:", activeEvents);getStats()
Returns comprehensive statistics about event bus usage.
const stats = kitsuneSan.getStats();
console.log({
totalEmissions: stats.totalEmissions,
totalListeners: stats.totalListeners,
uniqueEventTypes: stats.uniqueEventTypes,
listenerCounts: stats.listenerCounts,
emissionCounts: stats.emissionCounts,
});resetStats()
Resets emission statistics (listeners remain active).
kitsuneSan.resetStats();π¨ Usage Patterns
React Integration
import { useEffect, useState } from "react";
import kitsuneSan from "kitsune-san";
function UserProfile() {
const [user, setUser] = useState(null);
useEffect(() => {
const handleUserUpdate = (event) => {
setUser(event.detail);
};
kitsuneSan.on("user:updated", handleUserUpdate);
// Cleanup on unmount
return () => {
kitsuneSan.off("user:updated", handleUserUpdate);
};
}, []);
return user ? <div>Hello {user.name}!</div> : <div>Loading...</div>;
}Vue Integration
import { ref, onMounted, onUnmounted } from "vue";
import kitsuneSan from "kitsune-san";
export function useUserData() {
const user = ref(null);
const handleUserData = (event) => {
user.value = event.detail;
};
onMounted(() => {
kitsuneSan.on("user:data", handleUserData);
});
onUnmounted(() => {
kitsuneSan.off("user:data", handleUserData);
});
return { user };
}Microfrontend Communication
// Host application
import kitsuneSan from "kitsune-san";
class HostApp {
broadcastAuthData(authData) {
kitsuneSan.emit("auth:updated", authData);
}
}
// Guest application
import kitsuneSan from "kitsune-san";
class GuestApp {
init() {
kitsuneSan.on("auth:updated", (event) => {
this.updateUserInterface(event.detail);
});
}
}Error Handling
import kitsuneSan from "kitsune-san";
// Global error handler
const globalErrorHandler = (error, eventName, data) => {
console.error(`Event emission failed for '${eventName}':`, error);
// Send to error tracking service
errorTracker.captureException(error, { eventName, data });
};
// Use with all emissions
kitsuneSan.emit("critical:operation", data, globalErrorHandler);Priority-Based Execution
// High priority - security checks
kitsuneSan.on("user:action", securityHandler, { priority: 100 });
// Medium priority - business logic
kitsuneSan.on("user:action", businessLogicHandler, { priority: 50 });
// Low priority - analytics
kitsuneSan.on("user:action", analyticsHandler, { priority: 1 });
// Handlers execute in priority order: security -> business -> analytics
kitsuneSan.emit("user:action", actionData);π§ Advanced Features
Timeout Management
// Auto-cleanup after timeout
kitsuneSan.on("temporary:event", handler, { timeout: 30000 }); // 30 seconds
// One-time listener with timeout
kitsuneSan.once("initialization:complete", handler, { timeout: 10000 });Statistics and Monitoring
// Monitor event bus health
setInterval(() => {
const stats = kitsuneSan.getStats();
if (stats.totalListeners > 1000) {
console.warn("High listener count detected:", stats.totalListeners);
}
console.log("Event activity:", stats.emissionCounts);
}, 60000);Custom Error Handling
class CustomEventBus extends KitsuneSan {
emit(eventName, data, errorHandler) {
const customErrorHandler = (error, eventName, data) => {
// Custom error handling logic
this.logError(error, eventName, data);
errorHandler?.(error, eventName, data);
};
super.emit(eventName, data, customErrorHandler);
}
private logError(error, eventName, data) {
// Custom logging implementation
}
}π§ͺ Testing
Kitsune-san is designed to be easily testable:
import { KitsuneSan } from "kitsune-san";
describe("Component with EventBus", () => {
let kitsuneSan;
beforeEach(() => {
kitsuneSan = new KitsuneSan();
});
afterEach(() => {
kitsuneSan.removeAllListeners();
});
test("should handle user data", () => {
const mockHandler = jest.fn();
kitsuneSan.on("user:data", mockHandler);
kitsuneSan.emit("user:data", { id: 123 });
expect(mockHandler).toHaveBeenCalledWith(
expect.objectContaining({
detail: { id: 123 },
})
);
});
});π Performance
Kitsune-san is optimized for performance:
- Lightweight: ~2KB gzipped
- Fast: Efficient listener management with priority queues
- Memory-safe: Automatic cleanup and leak prevention
- Scalable: Tested with thousands of listeners and rapid emissions
π‘οΈ Browser Support
- Modern browsers: Full ES2018+ support
- Legacy support: Transpile with Babel if needed
- Node.js: Full compatibility for server-side usage
- TypeScript: First-class TypeScript support
π€ Contributing
We welcome contributions! Please see our contributing guidelines for details.
π License
MIT License - see LICENSE file for details.
π Acknowledgments
Inspired by the wisdom of fox spirits in Japanese folklore, Kitsune-san brings that same reliability and intelligence to your application's event system.
Made with β€οΈ and π¦ by the Reval Admin Team
