TODO
- Supported data types
- Generator for epos.bus.send
Bus API
A messaging system that allows for cross-context communication in your app. It provides a simple interface for sending messages from any context to any other context (popup, side panel, background, web page, iframe).
Why “bus”?
In computing, a bus is not a 🚌 vehicle, but a communication system that transfers data between different components. It acts as a centralized hub for exchanging messages.
epos.bus.on()
Registers an event listener.
epos.bus.on(name: string, callback: Function, thisArg?: unknown): voidParameters
name- Event namecallback- Function to call when event is triggeredthisArg- Optionalthiscontext for the callback
Example
// Listen for an event
epos.bus.on('user:login', (userId: string) => {
console.log(`User logged in: ${userId}`)
})
// With `this` context
const auth = {
label: 'auth',
init() {
// Pass `this` as third argument
epos.bus.on('user:login', this.handleLogin, this)
},
handleLogin(userId: string) {
// `this` refers to the `auth` object
console.log(`[${this.label}] User logged in: ${userId}`)
},
}epos.bus.off()
Removes an event listener.
epos.bus.off(name: string, callback?: Function): voidParameters
name- Event namecallback- Callback to remove. If not provided, removes all listeners for this event
Example
const handler = (data: string) => {
console.log(`Data: ${data}`)
}
// Register
epos.bus.on('data:update', handler)
// Remove specific handler
epos.bus.off('data:update', handler)
// Remove all handlers for this event
epos.bus.off('data:update')epos.bus.once()
Registers a one-time event listener that automatically removes itself after being called. same as epos.bus.on(), but only triggers once.
epos.bus.once(name: string, callback: Function, thisArg?: unknown): voidParameters
name- Event namecallback- Function to call once when event is triggeredthisArg- Optionalthiscontext for the callback
Example
// Listen once for initialization
epos.bus.once('app:ready', () => {
console.log('App is ready!')
// This handler will be automatically removed after first call
})epos.bus.send()
Sends a message to all remote listeners across all contexts. Does not trigger local listeners.
epos.bus.send<T>(name: string, ...args: any[]): Promise<T | null>Parameters
name- Event nameargs- Arguments to pass to the listeners
Returns
A Promise that resolves to the result from the first listener that returns a value, or null if there are no listeners.
Example
// --- background.ts ---
epos.bus.on('sum', (a: number, b: number) => {
return a + b
})
// --- popup.ts ---
const result = await epos.bus.send<number>('sum', 5, 10)PRO Tip
You can pass function type for epos.bus.send generic to get arguments type checking as well:
// --- background.ts ---
export const sum = (a: number, b: number) => a + b
epos.bus.on('sum', sum)
// --- popup.ts ---
import type { sum } from './background'
const result = await epos.bus.send<typeof sum>('sum', 5, 10) // Full type safetyAdvanced
Alternatively
epos.bus.emit()
Call local listeners for an event. Unlike send(), this only triggers listeners in the current context.
epos.bus.emit<T>(name: string, ...args: any[]): Promise<T | null>Parameters
name- Event nameargs- Arguments to pass to the listeners
Returns
A Promise that resolves to the result from the first listener that returns a value, or null if there are no listeners.
Example
// Register local listener
epos.bus.on('local:update', (data: string) => {
console.log('Local update:', data)
})
// Trigger only local listeners
await epos.bus.emit('local:update', 'new data')epos.bus.setSignal()
Set a signal with an optional value. Signals are useful for synchronization across contexts.
epos.bus.setSignal(name: string, value?: unknown): voidParameters
name- Signal namevalue- Optional value to associate with the signal (defaults totrue)
Example
// Signal that initialization is complete
epos.bus.setSignal('init:complete')
// Signal with data
epos.bus.setSignal('config:loaded', { theme: 'dark', language: 'en' })epos.bus.waitSignal()
Wait for a signal to be set. Useful for synchronization.
epos.bus.waitSignal<T>(name: string, timeout?: number): Promise<T | null>Parameters
name- Signal name to wait fortimeout- Optional timeout in milliseconds
Returns
A Promise that resolves to the signal value when the signal is set, or null if the timeout is reached or there are no listeners.
Example
// Wait for initialization
await epos.bus.waitSignal('init:complete')
console.log('Initialization complete!')
// Wait with timeout (5 seconds)
const config = await epos.bus.waitSignal<Config>('config:loaded', 5000)
if (config) {
console.log('Config loaded:', config)
} else {
console.log('Config loading timed out')
}epos.bus.register()
Register an RPC (Remote Procedure Call) API that can be called from other contexts.
epos.bus.register(name: string, api: Record<string, any>): voidParameters
name- API nameapi- Object with methods to expose
Example
// In background script
const userApi = {
async getUser(id: string) {
return await fetchUser(id)
},
async updateUser(id: string, data: UserData) {
return await updateUser(id, data)
},
}
epos.bus.register('user', userApi)epos.bus.unregister()
Unregister an RPC API.
epos.bus.unregister(name: string): voidParameters
name- API name to unregister
Example
epos.bus.unregister('user')epos.bus.use()
Get a typed proxy for calling a remote RPC API. All methods return Promises.
epos.bus.use<T>(name: string): Rpc<T>Parameters
name- API name to use
Returns
A proxy object where all methods are async versions of the registered API methods.
Example
// Define API type
interface UserApi {
getUser(id: string): Promise<User>
updateUser(id: string, data: UserData): Promise<User>
}
// In popup or content script
const userApi = epos.bus.use<UserApi>('user')
// Call remote methods (they automatically become async)
const user = await userApi.getUser('123')
const updated = await userApi.updateUser('123', { name: 'John' })epos.bus.for()
Create a namespaced bus instance for organizing events and avoiding naming conflicts.
epos.bus.for(namespace: string): {
on: Function
off: Function
once: Function
send: Function
emit: Function
setSignal: Function
waitSignal: Function
register: Function
unregister: Function
use: Function
dispose: Function
}Parameters
namespace- Namespace for the bus instance
Returns
A namespaced bus with all standard methods plus a dispose() method.
Example
// Create namespaced bus
const chatBus = epos.bus.for('chat')
// All events are automatically prefixed
chatBus.on('message', (msg: string) => {
console.log('Chat message:', msg)
})
chatBus.send('message', 'Hello!')
// Clean up when done
chatBus.dispose()