#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). It is an event listener.$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 |
All four receive the Alepha instance as payload.
#Using $hook
Register hooks with the $hook primitive. It must be a class property.
1import { $hook } from "alepha"; 2import { $logger } from "alepha/logger"; 3 4class DatabaseService { 5 log = $logger(); 6 7 onStart = $hook({ 8 on: "start", 9 handler: async () => {10 await this.connectToDatabase();11 this.log.info("Database connected");12 },13 });14 15 onStop = $hook({16 on: "stop",17 handler: async () => {18 await this.disconnectFromDatabase();19 this.log.info("Database disconnected");20 },21 });22}
#Hook options
1$hook({2 on: "start", // required: event name3 handler: async () => {4 /* ... */5 }, // required: callback6 priority: "first", // optional: "first" | "last" (default: insertion order)7});
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). For finer ordering relative to specific services, before and after accept a service class (or an array of them) that this hook must run before or after.
#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": { 7 // state change notification 8 key: keyof State; 9 value: any;10 prevValue: any;11 };12 "state:register": { atom: Atom }; // an atom was registered13 echo: unknown; // free-form event for testing/debugging14}
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)
emit() already compiles and caches an optimized executor per event, so there is no overhead
to avoid in normal code. compile() exists to hoist that one cache lookup out of a hot loop:
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;