safe-event v1.1.1
safe-event
A TypeScript event generator library that creates strongly-typed event definitions with runtime validation.
Features
- Generate TypeScript types from JSON schema definitions
- Runtime validation using ajv
- Type-safe event payload access
- Domain-scoped event naming (e.g. "user:profile.updated")
- Support for dot notation in event names
- Support for multiple schema files
Installation
npm install safe-eventQuick Start
1. Configuration
After installation, a safe-event.config.json file is created in your project root:
{
"schemaDir": "./events/schema",
"outputDir": "./events/generated"
}2. Define Events
Create event schema files in your schema directory (e.g. events/schema/user-events.json). The schema format follows the Ajv JSON Schema specification:
{
"domain": "user",
"events": {
"role.assigned": {
"schema": {
"type": "object",
"properties": {
"userId": { "type": "string" },
"role": {
"type": "string",
"enum": ["admin", "editor", "viewer"]
},
"assignedBy": { "type": "string" },
"expiresAt": { "type": "number" }
},
"required": ["userId", "role", "assignedBy"],
"additionalProperties": false
}
}
}
}3. Generate Types
npx safe-eventNote: Run this command whenever you update your event schemas to regenerate the TypeScript types.
4. Use Generated Types
import {
userEvents,
RoleAssignedEventData,
RoleAssignedEventPayload,
} from "./events/generated/user-events";
// Create type-safe event with validation
const event = RoleAssignedEventData.from({
userId: "123",
role: "editor", // Type-safe: only "admin" | "editor" | "viewer" allowed
assignedBy: "456",
expiresAt: Date.now() + 86400000,
});
// Get event type string
const eventType = userEvents["role.assigned"]; // "user:role.assigned"
// Type casting example
function handleEvent(type: string, data: any) {
if (type === userEvents["role.assigned"]) {
// data is now typed as RoleAssignedEventPayload
const payload = data as RoleAssignedEventPayload;
console.log(`${payload.role} role assigned by ${payload.assignedBy}`);
}
}EventBus
A simple way to emit and listen to events across your application.
Basic Example
import { EventBus } from "./EventBus";
import {
UserEvents,
RoleAssignedEventData,
} from "./events/generated/user-events";
// Initialize
const eventBus = EventBus.init();
// Listen for events
eventBus.onEvent({
event: UserEvents["role.assigned"],
callback: (data) => {
console.log("New role assigned:", data.role);
},
});
// Emit events
eventBus.emitEvent({
event: UserEvents["role.assigned"],
data: RoleAssignedEventData.from({
userId: "123",
role: "editor",
assignedBy: "456",
}),
});Advanced Features
Correlation IDs
Use correlation IDs to track related events:
// Emit with correlation ID
eventBus.emitEvent({
event: UserEvents["role.assigned"],
data: RoleAssignedEventData.from({
/* ... */
}),
correlationId: "request-123",
});
// Access correlation ID in listener
eventBus.onEvent({
event: UserEvents["role.assigned"],
callback: (data, correlationId) => {
console.log(`Event ${correlationId}:`, data);
},
});Buffered Events
Wait for multiple related events before processing:
// Listen for multiple events
eventBus.onDependentEvents({
events: [UserEvents["profile.created"], UserEvents["role.assigned"]],
callback: (buffer) => {
// Access events by their names
const profile = buffer[UserEvents["profile.created"]];
const role = buffer[UserEvents["role.assigned"]];
console.log("User setup complete:", { profile, role });
},
});
// Emit related events
eventBus.emitEvent({
event: UserEvents["profile.created"],
data: ProfileCreatedEventData.from({
/* ... */
}),
correlationId: "request-123",
});
eventBus.emitEvent({
event: UserEvents["role.assigned"],
data: RoleAssignedEventData.from({
/* ... */
}),
correlationId: "request-123",
});One-time Events
Listen for a single occurrence of an event with a specific correlation ID:
eventBus.onceEvent({
event: UserEvents["role.assigned"],
correlationId: "request-123",
callback: (data) => {
console.log("Role assigned:", data);
// Listener automatically detaches after this callback
},
});License
MIT
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago