SpaceNode
The event bus enables decoupled inter-module communication. Modules emit events, other modules react — without importing each other.
From any controller, use the emit function from the request context:
export async function login(request, services) {
const { body, send, emit } = request
const { authService } = services
const result = await authService.login(body.email, body.password)
await emit('auth:login', { userId: result.data.user.id })
send(result.data)
}
In a module's module.js, declare event listeners in the on property:
// modules/notifications/module.js
export default {
name: 'notifications',
prefix: '/notifications',
on: {
'order:created': 'onOrderCreated',
'auth:login': 'onUserLogin',
},
routes: [],
}
The handler function receives event data + services:
// modules/notifications/notifications.controller.js
export function onOrderCreated(data, services) {
console.log('New order!', data.orderId, data.total)
// Send email, push notification, etc.
}
export function onUserLogin(data, services) {
console.log('User logged in:', data.userId)
}
import { EventBus } from 'SpaceNode'
const bus = new EventBus()
bus.on('test', (data) => console.log(data))
bus.once('test', (data) => console.log('only once'))
await bus.emit('test', { hello: 'world' })
bus.off('test')
bus.clear()
| Method | Description |
|---|---|
on(event, fn) | Subscribe to an event |
once(event, fn) | Subscribe once (auto-removes after first emit) |
emit(event, data) | Emit event (sequential execution of listeners) |
off(event, fn?) | Unsubscribe a specific handler or all for that event |
clear() | Remove all listeners |
listEvents() | Get all registered event names |
destroy() | Remove all listeners and prevent future subscriptions |
You can subscribe to events directly on the app instance using app.events:
const app = await createApp()
app.events.on('user:registered', async (data) => {
await sendWelcomeEmail(data.email)
})
app.events for programmatic subscriptions in your entry file or setup code. Use the on property in module.js for declarative, module-scoped event listeners.If an event handler throws an error, it is not swallowed. SpaceNode catches the error, logs it, and re-emits it as an event:error event:
app.events.on('event:error', ({ event, errors }) => {
console.error(`Errors in event "${event}":`, errors)
})
The event:error payload contains:
event — the name of the event that had failureserrors — array of { event, error } objects, one per failed handlerevent:error in production to avoid silent failures in event handlers.