Events
Snaapi automatically emits events whenever records are created, updated, or deleted. Events follow a Hasura-style data structure that captures the full before/after state of each change, along with session and trace context for auditing and distributed tracing.
Event Types
Events follow the resourceName.action naming convention:
| Event Type | Description |
|---|---|
resource.created |
A new record was created |
resource.updated |
An existing record was modified |
resource.deleted |
A record was deleted (soft or hard) |
For example, a resource named posts would emit posts.created,
posts.updated, and posts.deleted events.
Event Data Structure
Each event record contains the following fields:
| Field | Type | Description |
|---|---|---|
id |
string |
Internal record ID |
eventId |
string |
Unique event ID (UUID) |
eventType |
string |
Event type (e.g., posts.created) |
resourceName |
string |
Name of the resource (e.g., posts) |
resourceId |
string |
ID of the affected resource record |
createdAt |
string |
ISO 8601 timestamp of when the event occurred |
dispatchedAt |
string | null |
Timestamp when dispatched to job executions |
data |
EventData |
Hasura-style old/new/changes object |
sessionVariables |
SessionVariables | null |
Request context (user, role, IP) |
traceContext |
TraceContext | null |
Distributed tracing identifiers |
Hasura-Style Data Object
The data field captures the full state change:
{
"old": null,
"new": { "id": "abc-123", "title": "Hello World" },
"changes": {
"added": ["id", "title", "created_at"],
"updated": [],
"removed": []
}
}
| Field | Type | Description |
|---|---|---|
old |
object | null |
Previous state of the record (null for created) |
new |
object | null |
Current state of the record (null for deleted) |
changes |
EventChanges |
Arrays describing which fields changed |
Changes Object
| Field | Type | Description |
|---|---|---|
added |
string[] |
Fields that were added |
updated |
string[] |
Fields that were modified |
removed |
string[] |
Fields that were removed |
For created events, all fields appear in added. For deleted events, all
fields appear in removed. For updated events, only modified fields appear in
updated.
Session Variables
Session variables capture the request context at the time the event was emitted:
| Field | Type | Description |
|---|---|---|
userId |
string |
ID of the authenticated user |
role |
string |
Role of the authenticated user |
ip |
string |
Client IP address |
userAgent |
string |
Client User-Agent header |
Additional custom properties may also be present.
Trace Context
Trace context enables correlation with distributed tracing systems like OpenTelemetry:
| Field | Type | Description |
|---|---|---|
traceId |
string |
OpenTelemetry trace ID |
spanId |
string |
OpenTelemetry span ID |
parentSpanId |
string |
Parent span ID (if applicable) |
requestId |
string |
Unique ID for the originating HTTP request |
correlationId |
string |
Correlation ID for grouping related events |
Additional custom properties may also be present.
EventEmitter Methods
The EventEmitter class provides methods for emitting and querying events:
| Method | Description |
|---|---|
emit() |
Emit a custom event |
emitCreated() |
Emit a created event (old: null, auto-populates changes.added) |
emitUpdated() |
Emit an updated event (compares old/new, populates changes.updated) |
emitDeleted() |
Emit a deleted event (new: null, auto-populates changes.removed) |
query() |
Query events with filters (resourceName, resourceId, eventType, undispatched, limit) |
findByEventId() |
Find a single event by its eventId |
markDispatched() |
Mark an event as dispatched to job executions |
Event Dispatch Flow
- Event emitted via
EventEmitter.emit*() - Stored in the
_eventstable - Broadcast to active SSE connections via
EventBroadcaster - Job registry processes event and creates
JobExecutionrecords for matching jobs - Event marked as dispatched (
dispatchedAttimestamp set) - Job processors execute (e.g., webhook delivery)