Skip to content

emmett08/tracegraph

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TraceGraph Core (TypeScript 5+, Node >= 18)

A small, generic trace graph toolkit:

  • TraceEventTraceGraph via a pluggable semantics profile (Strategy pattern)
  • Optional enrichers (Chain of Responsibility) for derived structure:
    • topological order
    • transitive reduction
    • critical path
    • verification monitors (safety/liveness-ish)

Includes adapters for React Flow and ELK (elkjs) so you can render and lay out graphs.

Why this design

  • Single Responsibility:

    • Builder orchestrates ingestion only.
    • Semantics profile decides meaning (nodes/edges).
    • Enrichers derive extra structure (and can be turned on/off).
  • Open/Closed:

    • Add new profiles/enrichers without changing the builder.
  • Liskov + Interface Segregation:

    • Small interfaces (ISemanticsProfile, IEnricher, IVerificationMonitor).
  • Dependency Inversion:

    • The core does not import React Flow or elkjs.
    • Visualisation adapters are plain data shapers; you inject ELK.

Install

npm i @neuralsea/tracegraph

Quick start (build a graph)

import {
  TraceGraphBuilder,
  CompositeSemanticsProfile,
  PartialOrderProfile,
  ProvenanceProfile,
  EnricherPipeline,
  TopologicalSortEnricher,
  VerificationEnricher,
  AcyclicOrderMonitor,
  type TraceEvent
} from "@neuralsea/tracegraph";

type MyPayload = {
  inputs?: string[];
  outputs?: string[];
  durationMs?: number;
};

type MyEvent = TraceEvent<MyPayload>;

const profile = new CompositeSemanticsProfile([
  new PartialOrderProfile({ captureVectorClocks: true }),
  new ProvenanceProfile({ addDerivedFromEdges: true })
]);

const enrichers = new EnricherPipeline([
  new TopologicalSortEnricher(),
  new VerificationEnricher([ new AcyclicOrderMonitor() ])
]);

const builder = new TraceGraphBuilder<MyEvent>({ profile, enrichers });

builder.ingestAll(myEvents);
const graph = builder.build();

console.log(graph.toJSON());

Semantics profiles

Total order

Adds next edges in ingestion order.

new TotalOrderProfile({ edgeLabel: "next", annotateIndexAs: "globalIndex" })

Partial order

Adds:

  • per-actor po edges
  • hb:comm edges for Send(corrId) → Receive(corrId)
  • optional vector clocks stored under vc
new PartialOrderProfile({
  captureVectorClocks: true,
  isSend: (e) => e.kind === "Send",
  isReceive: (e) => e.kind === "Receive"
})

Provenance

Creates value/entity nodes and adds PROV-style edges:

  • Activity → Entity (prov:used, prov:generated)
  • optional Value → Value (prov:derivedFrom)
new ProvenanceProfile({
  addDerivedFromEdges: true,
  getInputs: (e) => (e.payload?.inputs as string[]) ?? [],
  getOutputs: (e) => (e.payload?.outputs as string[]) ?? []
})

Enrichers

  • TopologicalSortEnricher annotates nodes with topoIndex
  • TransitiveReductionEnricher removes redundant edges (on a DAG)
  • CriticalPathEnricher annotates critical nodes and stores criticalPath in graph.meta
  • VerificationEnricher runs monitors and annotates nodes with violations

Visualisation with React Flow + elkjs

Yes: React Flow and elkjs are a good pairing for trace graphs:

  • React Flow provides interaction, custom nodes/edges, animations.
  • ELK handles readable layouts, especially DAG-like traces.

Convert graph → React Flow elements

import { toReactFlowElements } from "@neuralsea/tracegraph";

const rf = toReactFlowElements(graph, {
  nodeFilter: (n) => (n.labels ?? []).includes("Event"),
  edgeFilter: (e) => e.label === "po" || e.label.startsWith("hb"),
  edgeAnimated: (e) => e.label.startsWith("hb")
});

Apply ELK layout

Inject an elk instance (Node or browser):

import ELK from "elkjs/lib/elk.bundled.js";
import { applyElkLayout } from "@neuralsea/tracegraph";

const elk = new ELK();
const laidOut = await applyElkLayout(elk, rf, {
  layoutOptions: { "elk.algorithm": "layered", "elk.direction": "RIGHT" }
});

Animate edges AND arrowheads

  • Edge path animation: React Flow supports edge.animated = true.
  • Arrowhead animation: usually requires a custom edge type (because markers don’t inherit the path animation reliably).

This repo includes a demo custom edge (AnimatedArrowEdge) that animates both:

  • edge path via a dashed stroke animation
  • arrowhead via a pulse animation

See: demos/reactflow/src/AnimatedArrowEdge.tsx.

Demos

Node CLI

npm install
npm run demo:node
npm run demo:node:json
npm run demo:node:dot

React Flow + ELK demo

cd demos/reactflow
npm install
npm run dev

VS Code extension guidance

See: demos/vscode-extension/README.md.

The recommended approach is:

  1. Build the trace graph in the extension host (Node).
  2. Send graph JSON to a webview.
  3. Render with React Flow in the webview.
  4. Layout with ELK either:
    • in the extension host (best for big graphs), or
    • in the webview (fine for small/medium graphs, ideally in a Worker).

Notes

  • The core library intentionally keeps TraceEvent.kind as a string: map your grammar/runtime to the canonical set you want.
  • If you need parallel edges between the same nodes/label, supply unique edge.id via a custom IdFactory.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published