Versioning API
Entity-level version control: save snapshots, restore previous states, compare changes, and implement undo/redo.
Overview
The Versioning API provides Git-like version control for individual entities. Every change can be tracked, compared, and reverted without affecting other entities.
versioning-quickstart.js
import { Brainy, NounType } from '@soulcraft/brainy'
const brain = new Brainy()
await brain.init()
// Create an entity
const userId = await brain.add({
data: "John Smith",
type: NounType.Person,
metadata: { role: "developer", level: 1 }
})
// Save initial version
await brain.versions.save(userId, { tag: 'v1.0' })
// Make changes
await brain.update({ id: userId, metadata: { level: 2 } })
await brain.versions.save(userId, { tag: 'v1.1' })
// Oops! Restore to v1.0
await brain.versions.restore(userId, 'v1.0')
Methods
save(entityId, options?)
Create a version snapshot of the current entity state.
brain.versions.save(entityId: string, options?: SaveOptions): Promise<EntityVersion>
| Option | Type | Description |
|---|---|---|
tag |
string |
Version tag (e.g., 'v1.0', 'release') |
description |
string |
Description of changes |
author |
string |
Who made the change |
createCommit |
boolean |
Also create a workspace commit |
save-examples.js
// Simple save
const version = await brain.versions.save(userId)
// Save with tag and description
const tagged = await brain.versions.save(userId, {
tag: 'v2.0',
description: 'Promoted to senior developer',
author: 'admin@example.com'
})
// Save and create workspace commit
const milestone = await brain.versions.save(userId, {
tag: 'milestone-1',
createCommit: true,
commitMessage: 'Milestone 1 complete'
})
list(entityId, options?)
List all versions of an entity, sorted by version number (newest first).
list-examples.js
// Get all versions
const versions = await brain.versions.list(userId)
console.log(`Found ${versions.length} versions`)
// Get last 10 versions
const recent = await brain.versions.list(userId, { limit: 10 })
// Get tagged versions only
const tagged = await brain.versions.list(userId, { tag: 'v*' })
// Get versions from last 30 days
const lastMonth = await brain.versions.list(userId, {
startDate: Date.now() - 30 * 24 * 60 * 60 * 1000
})
restore(entityId, version, options?)
Restore an entity to a specific version. Overwrites current state.
restore-examples.js
// Restore to version number
await brain.versions.restore(userId, 5)
// Restore by tag
await brain.versions.restore(userId, 'v1.0')
// Restore with safety snapshot (for undo)
await brain.versions.restore(userId, 5, {
createSnapshot: true,
snapshotTag: 'before-restore'
})
compare(entityId, fromVersion, toVersion)
Generate a deep diff showing changes between two versions.
compare-examples.js
// Compare version 2 to version 5
const diff = await brain.versions.compare(userId, 2, 5)
console.log(`Added fields: ${diff.added.length}`)
console.log(`Removed fields: ${diff.removed.length}`)
console.log(`Modified fields: ${diff.modified.length}`)
// Diff structure
// {
// added: [{ path: 'metadata.skills', value: ['typescript'] }],
// removed: [{ path: 'metadata.temporary', oldValue: true }],
// modified: [{ path: 'metadata.level', from: 1, to: 3 }],
// typeChanged: []
// }
// Compare by tags
const tagDiff = await brain.versions.compare(userId, 'v1.0', 'v2.0')
undo(entityId)
Revert to the previous version. Creates a safety snapshot automatically.
undo-example.js
// Made a mistake? Just undo!
await brain.update({ id: userId, metadata: { wrongData: true } })
// Undo the change
const restored = await brain.versions.undo(userId)
if (restored) {
console.log(`Restored to version ${restored.version}`)
} else {
console.log('No previous version to restore')
}
prune(entityId, options)
Remove old versions based on retention policy. Preserves tagged versions by default.
prune-examples.js
// Keep last 10 versions, delete rest
const result = await brain.versions.prune(userId, {
keepRecent: 10
})
console.log(`Deleted ${result.deleted} versions, kept ${result.kept}`)
// Keep last 30 days, preserve tagged versions
await brain.versions.prune(userId, {
keepAfter: Date.now() - 30 * 24 * 60 * 60 * 1000,
keepTagged: true
})
// Dry run - preview what would be deleted
const preview = await brain.versions.prune(userId, {
keepRecent: 5,
dryRun: true
})
console.log(`Would delete ${preview.deleted} versions`)
Other Methods
other-methods.js
// Get specific version
const v5 = await brain.versions.getVersion(userId, 5)
// Get version by tag
const release = await brain.versions.getVersionByTag(userId, 'v1.0')
// Get latest version
const latest = await brain.versions.getLatest(userId)
// Preview version content without restoring
const oldData = await brain.versions.getContent(userId, 5)
// Get version count
const count = await brain.versions.count(userId)
// Check if entity has versions
if (await brain.versions.hasVersions(userId)) {
console.log('Entity is versioned')
}
// Get version history summary
const summary = await brain.versions.history(userId)
// { total: 15, oldest: {...}, newest: {...}, tagged: 3 }
// Tag an existing version
await brain.versions.tag(userId, 5, 'stable')
// Compare current state with a version
const changes = await brain.versions.diffWithCurrent(userId, 'v1.0')
// Clear all versions (DANGER!)
const deleted = await brain.versions.clear(userId)
Use Cases
Document Editor with Undo/Redo
document-editor.js
async function saveDocument(docId, content) {
// Save current state before overwriting
await brain.versions.save(docId)
// Update the document
await brain.update({
id: docId,
data: content,
metadata: { lastModified: Date.now() }
})
}
async function undoDocument(docId) {
return brain.versions.undo(docId)
}
async function getDocumentHistory(docId) {
return brain.versions.list(docId, { limit: 50 })
}
Configuration Management
config-management.js
async function updateConfig(configId, changes, releaseTag) {
// Save with tag for releases
await brain.versions.save(configId, {
tag: releaseTag,
description: `Config update: ${Object.keys(changes).join(', ')}`
})
await brain.update({ id: configId, metadata: changes })
}
async function rollbackConfig(configId, toTag) {
// Restore with safety snapshot
await brain.versions.restore(configId, toTag, {
createSnapshot: true,
snapshotTag: `rollback-from-${Date.now()}`
})
}
See Also
- Branching & Time Travel - Workspace-level version control
- update() - Modifying entities
- VFS API - File versioning through VFS