#Internal Events
Alepha uses a hook-based event system for lifecycle management and cross-service communication.
#Confusion Warning
$hookis not a React Hook (e.g. useState) ! But rather event listeners.$hookis not a pub/sub system ! Use$topicfor pub/sub.
#Lifecycle
When alepha.start() is called, the framework emits events in this order:
configure -> start -> ready -> (APP RUNNING) -> stop
| Hook | When | Typical use |
|---|---|---|
configure |
Before start, after container is locked | Register providers, resolve configuration |
start |
After configure | Connect to databases, start listeners |
ready |
After start | Application is fully operational |
stop |
On shutdown (SIGINT/SIGTERM or manual) | Close connections, flush buffers |
configure, start, and ready receive the Alepha instance as payload. stop also receives the Alepha instance.
#Using $hook
Register hooks with the $hook primitive. It must be a class property.
1import { $hook, $logger } from "alepha"; 2 3class DatabaseService { 4 log = $logger(); 5 6 onStart = $hook({ 7 on: "start", 8 handler: async () => { 9 await this.connectToDatabase();10 this.log.info("Database connected");11 },12 });13 14 onStop = $hook({15 on: "stop",16 handler: async () => {17 await this.disconnectFromDatabase();18 this.log.info("Database disconnected");19 },20 });21}
#Hook options
1$hook({2 on: "start", // required: event name3 handler: async () => { /* ... */ }, // required: callback4 priority: "first", // optional: "first" | "last" (default: insertion order)5});
priority: "first" places the hook at the front of the execution queue. priority: "last" places it at the end. Without a priority, hooks execute in registration order (which follows dependency order).
#Hook call tracking
Each $hook instance tracks how many times it has been called:
1const alepha = Alepha.create().with(App);2await alepha.start();3 4const app = alepha.inject(App);5console.log(app.onStart.called); // 1
This is useful for testing to ensure hooks are called the expected number of times.
#Built-in Hooks
The core Hooks interface defines:
1interface Hooks { 2 configure: Alepha; // configuration phase 3 start: Alepha; // start phase 4 ready: Alepha; // ready phase 5 stop: Alepha; // shutdown phase 6 "state:mutate": { // state change notification 7 key: keyof State; 8 value: any; 9 prevValue: any;10 };11}
Other modules extend this interface. For example, alepha/logger adds log, alepha/server adds server-related hooks, and so on.
#Custom Hooks
Define custom hooks using TypeScript module augmentation:
1declare module "alepha" {2 interface Hooks {3 "billing:invoice:created": {4 invoiceId: string;5 amount: number;6 };7 }8}
#Listening to custom hooks
As a class property with $hook:
1class NotificationService {2 onInvoice = $hook({3 on: "billing:invoice:created",4 handler: async ({ invoiceId, amount }) => {5 await this.sendReceipt(invoiceId, amount);6 },7 });8}
Or directly on the event manager:
1alepha.events.on("billing:invoice:created", ({ invoiceId, amount }) => {2 console.log(`Invoice ${invoiceId} created for ${amount}`);3});
alepha.events.on() returns an unsubscribe function:
1const unsubscribe = alepha.events.on("billing:invoice:created", handler);2// later...3unsubscribe();
#Emitting custom hooks
1await alepha.events.emit("billing:invoice:created", {2 invoiceId: "inv_123",3 amount: 99.99,4});
The emit method accepts options:
1await alepha.events.emit("billing:invoice:created", payload, {2 log: true, // log execution timing of each hook3 catch: true, // catch errors and log them instead of throwing4});
#Compiled Events (advanced)
For hot paths (like HTTP request handling), compile events into optimized executors:
1// After all hooks are registered (e.g. after start)2const onRequest = alepha.events.compile("server:onRequest", { catch: true });3 4// In the request handler - returns void if sync, Promise if async5const result = onRequest({ request, route });6if (result) await result;
This avoids the overhead of emit() in performance-critical code paths.