A DCB-inspired Event Store for TypeScript
Events organized via configurable consistency keys, not rigid stream boundaries.
Extract consistency keys from event payloads. Events stay pure business data.
Tamper-proof consistency tokens with HMAC-SHA256 signatures.
Get exactly what changed since your read — with the new token for retry.
Change your consistency config, restart, keys are automatically rebuilt.
Production-ready SQLite storage or in-memory for testing.
Dynamic Consistency Boundaries (DCB) solves optimistic concurrency by attaching consistency keys (tags) to events. Boundless takes this further:
// 1️⃣ READ — Query events by consistency keys
const { events, token } = await store.read({
conditions: [
{ type: 'CourseCreated', key: 'course', value: 'cs101' },
{ type: 'StudentSubscribed', key: 'course', value: 'cs101' },
]
});
// token captures: "I read all events matching these conditions up to position X"
// 2️⃣ DECIDE — Project state and check business rules
const course = events.find(e => e.type === 'CourseCreated');
const enrolled = events.filter(e => e.type === 'StudentSubscribed').length;
if (enrolled >= course.data.capacity) {
throw new Error('Course is full!');
}
// 3️⃣ WRITE — Append with the token from your read
const result = await store.append([
{ type: 'StudentSubscribed', data: { courseId: 'cs101', studentId: 'alice' } }
], token); // ← Token ensures no one else wrote since your read!
if (result.conflict) {
// Someone else enrolled while you were deciding!
console.log('Events since your read:', result.conflictingEvents);
// You get a fresh token to retry
const freshToken = result.newToken;
// Re-read, re-decide, re-write...
} else {
// Success!
console.log('Enrolled at position', result.position);
console.log('New token for next operation:', result.token);
}
// The token captures your exact query scope:
token = {
q: [{ type: 'StudentSubscribed', key: 'course', value: 'cs101' }],
pos: 5 // Position at time of read
}
// On append, Boundless checks:
// "Are there NEW events (pos > 5) that MATCH these conditions?"
// ✅ NO conflict if someone wrote:
// - StudentSubscribed for course='math201' (different key value)
// - CourseCreated for cs101 (different event type)
// ❌ CONFLICT only if:
// - StudentSubscribed for course='cs101' was written
// - (matches your query conditions!)
// Traditional streams: ONE boundary (e.g., per course)
// DCB: Query ANY combination of keys!
// "Has Alice already enrolled in CS101?"
const { events, token } = await store.read({
conditions: [
{ type: 'StudentSubscribed', key: 'course', value: 'cs101' },
{ type: 'StudentSubscribed', key: 'student', value: 'alice' },
]
});
// Checks BOTH course boundary AND student boundary in one query!
// Keys are extracted from event payloads via configuration
// Events stay pure — no tags or metadata pollution!
const consistency = {
eventTypes: {
CourseCreated: {
keys: [
{ name: 'course', path: 'data.courseId' }
]
},
StudentSubscribed: {
keys: [
{ name: 'course', path: 'data.courseId' },
{ name: 'student', path: 'data.studentId' },
{ name: 'semester', path: 'data.semester', transform: 'UPPER' }
]
}
}
};
// When an event is appended:
// { type: 'StudentSubscribed', data: { courseId: 'cs101', studentId: 'alice', semester: 'ws24' } }
//
// Keys are automatically extracted and indexed:
// → course: 'cs101'
// → student: 'alice'
// → semester: 'WS24' (transformed to uppercase)
// The config is hashed and stored in the database
// On startup, Boundless compares hashes:
// stored_hash: "a1b2c3..." (from last run)
// current_hash: "x9y8z7..." (from your config)
if (stored_hash !== current_hash) {
// 🔄 Config changed! Rebuilding key index...
// Old hash: a1b2c3...
// New hash: x9y8z7...
// All events are re-scanned
// Keys are re-extracted with new config
// Index is rebuilt automatically
// ✅ Reindex complete: 1523 events, 4211 keys (847ms)
}
// No manual migration needed!
// Just change your config and restart.
{ type: 'StudentSubscribed', data: { courseId: 'cs101', studentId: 'alice' } }
course → 'cs101', student → 'alice'
event_keys: [pos:1, course, cs101], [pos:1, student, alice]
WHERE (type='StudentSubscribed' AND key='course' AND value='cs101')