Events API
The Events API provides methods for accessing event history, timelines, and audit trails.
Overview
All operations in Synap SDK are event-sourced - every mutation creates an immutable event record. The Events API allows you to:
- View complete history for any entity
- Access your entire timeline
- Replay events to rebuild state
- Implement audit trails
import { SynapSDK } from '@synap/sdk'
const synap = new SynapSDK({
url: 'https://api.synap.app',
apiKey: 'your-api-key'
})
// Access the Events API
synap.eventsMethods
getHistory()
Get complete event history for a specific entity.
Signature:
getHistory(entityId: string, options?: EventHistoryOptions): Promise<Event[]>Parameters:
interface Event HistoryOptions {
eventTypes?: string[] // Filter by event type
limit?: number // Max results (default: 100)
}Returns:
interface Event {
id: string
aggregateId: string // Entity ID
aggregateType: string // 'entity' | 'relation'
eventType: string // e.g. 'entities.create.validated'
data: Record<string, unknown>
metadata: Record<string, unknown>
version: number
userId: string
createdAt: Date
}Example:
// Get all events for an entity
const history = await synap.events.getHistory(entityId)
history.forEach(event => {
console.log(`${event.createdAt}: ${event.eventType}`)
console.log(event.data)
})
// Filter by event type
const createEvents = await synap.events.getHistory(entityId, {
eventTypes: ['entities.create.validated']
})
// Limit results
const recent = await synap.events.getHistory(entityId, {
limit: 10
})Event Types:
// Entity events
'entities.create.requested'
'entities.create.validated'
'entities.update.requested'
'entities.update.validated'
'entities.delete.requested'
'entities.delete.validated'
// Relation events
'relations.create.requested'
'relations.create.validated'
'relations.delete.requested'
'relations.delete.validated'Use Cases:
// Audit trail
const history = await synap.events.getHistory(taskId)
console.log(`Task was modified ${history.length} times`)
// Find who created entity
const createEvent = history.find(e =>
e.eventType === 'entities.create.validated'
)
console.log(`Created by: ${createEvent.userId}`)
// Track all changes
const updates = history.filter(e =>
e.eventType.includes('update')
)
console.log(`${updates.length} updates`)getTimeline()
Get your complete timeline of events.
Signature:
getTimeline(options?: TimelineOptions): Promise<Event[]>Parameters:
interface TimelineOptions {
limit?: number // Max results (default: 50)
type?: string // Filter by event type
subjectId?: string // Filter by entity
subjectType?: string // Filter by aggregate type
after?: Date // Events after date
before?: Date // Events before date
}Example:
// Get recent activity
const timeline = await synap.events.getTimeline({
limit: 20
})
// Filter by date range
const lastWeek = await synap.events.getTimeline({
after: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000),
limit: 100
})
// Filter by event type
const creates = await synap.events.getTimeline({
type: 'entities.create.validated',
limit: 50
})
// Filter by entity
const taskEvents = await synap.events.getTimeline({
subjectId: taskId,
limit: 100
})Activity Dashboard:
// Build activity dashboard
const timeline = await synap.events.getTimeline({
limit: 50
})
const stats = {
created: timeline.filter(e => e.eventType.includes('create')).length,
updated: timeline.filter(e => e.eventType.includes('update')).length,
deleted: timeline.filter(e => e.eventType.includes('delete')).length
}
console.log('Recent activity:', stats)replay()
Replay events to rebuild entity state.
Signature:
replay(entityId: string): Promise<EntityState>Returns:
interface EntityState {
id: string
version: number
state: Record<string, unknown>
events: Event[]
}Example:
// Rebuild entity state from events
const state = await synap.events.replay(entityId)
console.log('Current version:', state.version)
console.log('State:', state.state)
console.log('Event count:', state.events.length)Time Travel:
// Get state at specific point in time
const history = await synap.events.getHistory(entityId)
// Filter events up to a date
const pastEvents = history.filter(e =>
e.createdAt <= new Date('2024-12-01')
)
// Manually rebuild state
let state = {}
pastEvents.forEach(event => {
if (event.eventType === 'entities.create.validated') {
state = event.data
} else if (event.eventType === 'entities.update.validated') {
state = { ...state, ...event.data }
}
})Common Patterns
Activity Feed
// Build activity feed
async function getActivityFeed (limit = 20) {
const events = await synap.events.getTimeline({ limit })
return events.map(event => ({
timestamp: event.createdAt,
action: getActionLabel(event.eventType),
data: event.data
}))
}
function getActionLabel(eventType: string) {
if (eventType.includes('create')) return 'created'
if (eventType.includes('update')) return 'updated'
if (eventType.includes('delete')) return 'deleted'
return 'modified'
}
const feed = await getActivityFeed()Audit Log
// Generate audit log for entity
async function generateAuditLog(entityId: string) {
const history = await synap.events.getHistory(entityId)
return history.map(event => ({
date: event.createdAt.toISOString(),
user: event.userId,
action: event.eventType,
changes: event.data,
version: event.version
}))
}
const auditLog = await generateAuditLog(taskId)
console.table(auditLog)Change Detection
// Detect what changed
function detectChanges(events: Event[]) {
const changes = []
for (let i = 1; i < events.length; i++) {
const prev = events[i - 1].data
const curr = events[i].data
const changedFields = Object.keys(curr).filter(key =>
JSON.stringify(prev[key]) !== JSON.stringify(curr[key])
)
if (changedFields.length > 0) {
changes.push({
timestamp: events[i].createdAt,
fields: changedFields
})
}
}
return changes
}
const history = await synap.events.getHistory(entityId)
const changes = detectChanges(history)Event Notifications
// Poll for new events
let lastEventTime = new Date()
setInterval(async () => {
const newEvents = await synap.events.getTimeline({
after: lastEventTime,
limit: 100
})
if (newEvents.length > 0) {
handleNewEvents(newEvents)
lastEventTime = newEvents[0].createdAt
}
}, 5000) // Poll every 5 seconds
function handleNewEvents(events: Event[]) {
events.forEach(event => {
console.log('New event:', event.eventType)
// Trigger UI update, notification, etc.
})
}Event Structure
Entity Create Event
{
id: "evt_123",
aggregateId: "entity_456",
aggregateType: "entity",
eventType: "entities.create.validated",
data: {
id: "entity_456",
type: "task",
title: "Review PR",
metadata: {
priority: "high"
}
},
metadata: {},
version: 1,
userId: "user_789",
createdAt: "2024-12-20T10:30:00Z"
}Entity Update Event
{
id: "evt_124",
aggregateId: "entity_456",
aggregateType: "entity",
eventType: "entities.update.validated",
data: {
entityId: "entity_456",
title: "Review PR #123",
metadata: {
status: "done"
}
},
metadata: {},
version: 2,
userId: "user_789",
createdAt: "2024-12-20T15:00:00Z"
}Relation Create Event
{
id: "evt_125",
aggregateId: "rel_999",
aggregateType: "relation",
eventType: "relations.create.validated",
data: {
id: "rel_999",
sourceEntityId: "task_456",
targetEntityId: "person_789",
type: "assigned_to"
},
metadata: {},
version: 1,
userId: "user_789",
createdAt: "2024-12-20T15:05:00Z"
}Best Practices
✅ Do’s
// Use for audit trails
const history = await synap.events.getHistory(entityId)
console.log(`Entity has ${history.length} events`)
// Filter to reduce data
const recent = await synap.events.getHistory(entityId, {
limit: 10
})
// Cache timeline results
let timelineCache = await synap.events.getTimeline({ limit: 50 })
// Use for debugging
const events = await synap.events.getHistory(entityId)
console.log('Event sequence:', events.map(e => e.eventType))❌ Don’ts
// Don't fetch unlimited events
const all = await synap.events.getHistory(entityId) // Use limit!
// Don't poll too frequently
setInterval(() => {
synap.events.getTimeline() // Use SSE or webhooks instead
}, 100) // Too frequent!
// Don't store full history in memory
const massive = await synap.events.getTimeline({ limit: 10000 }) // Too muchUse Cases
1. Audit Trail
Track all changes to sensitive data for compliance.
2. Debugging
Reproduce issues by inspecting event sequence.
3. Analytics
Analyze user behavior from event patterns.
4. Undo/Redo
Implement time travel features in your app.
5. Activity Feed
Show user what’s happening in real-time.
6. Data Recovery
Restore deleted or corrupted entities from events.
Type Safety
Full TypeScript support:
import { Event } from '@synap/sdk'
const events: Event[] = await synap.events.getHistory(entityId)
events.forEach((event: Event) => {
console.log(event.eventType) // Fully typed
})Next Steps
- Core Concepts: Event Sourcing → - Understand the pattern
- Entities API → - Manage entities
- Examples → - See events in action