Appearance
Signals
Signals are live events the Hailer host pushes into your app — an activity was created, a ball was passed, the workspace changed. You receive them through the signals callback you pass to HailerApi.
ts
const hailer = new HailerApi({
signals: signal => {
if (signal.name === 'activity.update') {
refreshActivity(signal.data.activityIds);
}
},
});Each signal is a Signal object: { name: string; data: any }.
The signal whitelist
The host only forwards a fixed, renamed set of internal events — you can't subscribe to arbitrary events. These are the names your signals callback can receive:
| Signal name | Fires when | data |
|---|---|---|
activity.create | An activity is created | { activityIds, workflowId, phaseId } |
activity.update | An activity is updated | { activityIds, workflowId, phaseId } |
activity.remove | An activity is removed | { activityIds, workflowId, phaseId } |
activity.ball.passed | A ball is passed | Ball event payload |
activity.ball.taken | A ball is taken | Ball event payload |
activity.ball.cleared | A ball is cleared | Ball event payload |
activity.ball.autoAssigned | A ball is auto-assigned | Ball event payload |
insight.create | An insight is created | Insight payload |
insight.update | An insight is updated | Insight payload |
insight.remove | An insight is removed | Insight payload |
workspace.invitation.new | The user receives a workspace invitation | Invitation payload |
workspace.invitation.remove | A workspace invitation is removed | Invitation payload |
workspace.role.create | A workspace role is created | Role payload |
workspace.role.update | A workspace role is updated | Role payload |
workspace.role.remove | A workspace role is removed | Role payload |
workspace.current | The user switches the active workspace | { workspaceId } |
Names are translated at the boundary
These SDK names differ from Hailer's internal event names — the host renames each event before forwarding it. Match on the SDK name in the table above, not on any internal name you may see elsewhere.
Not every internal event is available
Some events (e.g. workspace reload and feed posts) are deliberately not forwarded — there is no way to subscribe to them from an app. If a change you need isn't in the table above, poll the relevant module instead.
Activity signals carry ids, not activities
activity.create / update / remove give you activityIds, workflowId, and phaseId — not the full activity. Load what you need in response:
ts
signals: async signal => {
if (signal.name === 'activity.update') {
const { activityIds } = signal.data;
const ids = Array.isArray(activityIds) ? activityIds : [activityIds];
for (const id of ids) {
const activity = await hailer.activity.get(id);
// update your view
}
}
},An update to an activity that was removed arrives as activity.remove (not activity.update), so branch on signal.name.
React to workspace switches
workspace.current fires whenever the user changes their active workspace in Hailer. In a private app this is your cue to re-scope what you show:
ts
signals: signal => {
if (signal.name === 'workspace.current') {
reloadForWorkspace(signal.data.workspaceId);
}
},Next steps
- App lifecycle — how the signal listener is registered.
- Reference: activity · ball