Graphology
Run graph algorithms on your temporal graph by keeping a Graphology instance in sync with temporal97.
Graphology is a graph data structure for JavaScript/TypeScript that ships with a standard library of algorithms: BFS/DFS traversal, shortest paths, connected components, centrality, and more — none of which temporal97 provides.
The combination gives you the best of both: temporal97 owns the history and time travel, Graphology owns the algorithms.
Installation
npm install graphology graphology-traversal graphology-shortest-path graphology-componentsSyncing with Delta
Write a helper that applies a Delta to a Graphology instance:
import Graph from 'graphology';
import { TemporalGraph, type Delta } from 'temporal97';
type NodeAttrs = { label: string };
type EdgeAttrs = { source: string; target: string; weight: number };
const temporal = new TemporalGraph<NodeAttrs, EdgeAttrs>();
const gly = new Graph({ type: 'directed' });
function syncDelta(delta: Delta) {
// Removals first — dropNode also removes connected edges in Graphology
for (const id of delta.nodes.removed) {
if (gly.hasNode(id)) gly.dropNode(id);
}
for (const id of delta.edges.removed) {
if (gly.hasEdge(id)) gly.dropEdge(id);
}
for (const id of delta.nodes.added) {
gly.addNode(id, temporal.getNode(id));
}
for (const id of delta.edges.added) {
const e = temporal.getEdge(id)!;
gly.addEdgeWithKey(id, e.source, e.target, e);
}
for (const id of delta.nodes.updated) {
gly.replaceNodeAttributes(id, temporal.getNode(id)!);
}
for (const id of delta.edges.updated) {
gly.replaceEdgeAttributes(id, temporal.getEdge(id)!);
}
}Pass the Delta from any temporal97 operation straight into syncDelta:
syncDelta(temporal.append({
snapshot: 0,
mutations: [
{ kind: 'node', op: 'set', id: 'alice', value: { label: 'Alice' } },
{ kind: 'node', op: 'set', id: 'bob', value: { label: 'Bob' } },
{ kind: 'edge', op: 'set', id: 'alice->bob', value: { source: 'alice', target: 'bob', weight: 1 } },
],
}));
syncDelta(temporal.append({
snapshot: 1,
mutations: [
{ kind: 'node', op: 'set', id: 'charlie', value: { label: 'Charlie' } },
{ kind: 'edge', op: 'set', id: 'bob->charlie', value: { source: 'bob', target: 'charlie', weight: 2 } },
],
}));
// Rewind — Graphology mirrors the rollback
syncDelta(temporal.rewind(0));Running algorithms
Once Graphology is in sync, run any algorithm from its standard library against the current temporal state.
BFS traversal
import { bfsFromNode } from 'graphology-traversal/bfs';
bfsFromNode(gly, 'alice', (nodeId, attrs, depth) => {
console.log(`${nodeId} at depth ${depth}:`, attrs);
});Shortest path
import { bidirectional } from 'graphology-shortest-path/unweighted';
const path = bidirectional(gly, 'alice', 'charlie');
// ['alice', 'bob', 'charlie']Connected components
import connectedComponents from 'graphology-components';
const components = connectedComponents(gly);
// [['alice', 'bob', 'charlie']]Time travel + algorithms
Because syncDelta works for cursor movements too, you can run algorithms at any point in history:
// Save where you are, then jump to a past snapshot
const savedSnapshot = temporal.currentSnapshot;
syncDelta(temporal.seekTo(0));
const path = bidirectional(gly, 'alice', 'bob');
console.log('Path at snapshot 0:', path);
// Jump back to where you were
syncDelta(temporal.seekTo(savedSnapshot));For read-only lookups that don't need Graphology, use temporal97's historical queries instead — they don't move the cursor at all.