feat: portable graph export()/import() (BackupData v1) on brain.data()

brain.data() now serializes part or all of a brain to a versioned, portable
JSON document (BackupData) and restores it — the path for partial backups,
cross-environment moves, and 7.x→8.0 migration.

- export(selector?, options?): select by ids, collection (+transitive Contains),
  connected neighbourhood, vfsPath subtree, predicate, or whole brain; structural
  and predicate selectors compose. Options: includeVectors, includeContent (VFS
  blobs), includeSystem, edges ('induced'|'incident'|'none').
- import(backup, options?): onConflict 'merge' (dedup-by-id) | 'replace' | 'skip';
  reembed 'auto' (re-embed from data when no vector carried) | 'never'; remapIds
  to clone a subgraph under fresh ids.
- BackupData v1: format/formatVersion/brainyVersion/createdAt/embedding/entities/
  relations/blobs?/danglingIds?/stats. Reserved fields (subtype, data, confidence,
  weight, service) top-level; metadata custom-only. Current-state, no generations.
- Replaces the prior flat-entity export() (dropped relations) with a graph-complete
  document. Distinct from brain.import(file) ingestion, which is unchanged.
- Export BackupData/BackupEntity/BackupRelation/ExportSelector/ExportOptions/
  ImportOptions/ImportResult/DataAPI from the package root. CLI `brainy export`
  now writes a BackupData document.

Guide: docs/guides/backup-and-export.md. Tests: tests/unit/api/data-backup.test.ts.
This commit is contained in:
David Snelling 2026-06-16 15:52:42 -07:00
parent 89c6d043ba
commit a408d3799d
11 changed files with 1393 additions and 382 deletions

View file

@ -1765,20 +1765,33 @@ await brain.import('https://api.example.com/data.json')
---
### Export & Snapshots
### Export & Import (portable backup)
`brain.data()` exposes a portable graph backup/restore API. `export(selector?, options?)`
serializes part or all of the graph to a versioned, portable `BackupData` document;
`import(backup, options?)` restores it (dedup-by-id merge by default, re-embedding when
vectors are absent).
```typescript
// Export to file
await brain.export('/path/to/backup.brainy')
const data = await brain.data()
// Create instant snapshot using COW fork
await brain.fork('backup-2025-01-19')
// Whole brain → a portable BackupData document
const backup = await data.export()
// Time-travel to specific commit
const snapshot = await brain.asOf(commitId)
const entities = await snapshot.find({ limit: 100 })
// Just one workbench's members, with vectors, then restore elsewhere (merge by id)
const subset = await data.export({ ids }, { includeVectors: true })
await otherBrain.data().then(d => d.import(subset, { onConflict: 'merge' }))
// A collection + its children; a connected neighbourhood; a VFS subtree (+ bytes)
await data.export({ collection: collectionId })
await data.export({ connected: { from: id, depth: 2 } })
await data.export({ vfsPath: '/docs' }, { includeContent: true })
```
The format is versioned (`formatVersion`) and current-state (no generation history) — see
the **[Export & Import guide →](../guides/export-and-import.md)**. This is distinct from
`brain.import(file)` (CSV/PDF/Excel/JSON ingestion).
---
## Configuration