Dataservice API
The Next dashboard loads analytics through a versioned envelope keyed $heat-dataservice. In Arbex, build it with heat.dataservice.createBuilder() and return buildRoot() when dataserviceOutput is enabled.
See also Next data service and direct ingestion.
Builder workflow
const ds = heat.dataservice.createBuilder({
version: "1.0", // optional, default "1.0"
defaultRealm: "default", // optional
});
ds.addGroup("analytics", "Analytics"); // required before channels
ds.series(
{ id: "cpu", name: "CPU", groupId: "analytics", metadata: { units: "%" } },
[{ timeMs: 1000, value: 42 }],
);
return ds.buildRoot(); // { $heat-dataservice, dashboard_users: [] }| Step | API | Why |
|---|---|---|
| Start | createBuilder(options?) | Sets version and default realm |
| Group | addGroup(id, name) | UI channel picker sections; every channel needs a groupId |
| Write | Shape helpers (below) | Typed payloads per channel |
| Finish | buildRoot(opts?) | Top-level object for persistence / dimension node |
buildRoot options:
| Option | Effect |
|---|---|
suggestedLayoutConfiguration / layout | Attach v2 layout JSON or a heat.layout builder |
dashboardUsers / dashboard_users | External user GUIDs when the script omits them |
Channel shapes (when to use each)
| Shape | Method | Use for |
|---|---|---|
series | ds.series(spec, points) | Time-varying values and playback ({ timeMs, value }[]) |
value | ds.value(spec, payload) | KPIs, tables, nested JSON ({ value: ... }) |
events | ds.events(spec, points) | Instantaneous flags ({ timeMs, occurred }[]) |
timestamps | ds.timestamps(spec, points) | Labelled instants ({ timeMs, annotation }[]) |
ranges | ds.ranges(spec, points) | Phases and intervals (startTimeMs, endTimeMs, durationMs) |
Rule: Structured data that is not a time series belongs in value, not fake series points.
Low-level ds.channel(spec, data) accepts any shape when you supply spec.shape and matching data.
Channel spec (per write)
| Field | Required | Notes |
|---|---|---|
id | Yes | Stable id; layout channels arrays reference this string |
name | Yes | Display label |
groupId | Yes | Must match addGroup |
realm | No | Overrides builder defaultRealm |
metadata | No | Hints: units, channelType, custom keys for widgets |
Realms
Realms namespace channels (for example per trainee or per run). The same id in two realms is two different series.
- Set
defaultRealmon the builder orrealmon each channel spec. - Keep realm count modest; dimension nodes can enforce limits.
Runtime vs types
The node host implements fluent helpers for series, value, events, timestamps, and ranges.
heat-arbex.d.ts also declares mapdisplay, flightpath, and responseTime. Those fluent methods are not on the host builder yet. Until they are, use ds.channel(spec, data) with the correct spec.shape and payload, or produce data upstream via another node template.
Example: all core shapes
async function run(ctx) {
const ds = heat.dataservice.createBuilder({ version: "1.0", defaultRealm: "default" });
ds.addGroup("analytics", "Analytics");
ds.series(
{ id: "cpu-cores", name: "CPU cores", groupId: "analytics" },
[{ timeMs: 1000, value: 2.5 }, { timeMs: 2000, value: 3.1 }],
);
ds.value(
{ id: "cluster-kpis", name: "Cluster KPIs", groupId: "analytics" },
{ value: { podCount: 12, namespaceCount: 3 } },
);
ds.events(
{ id: "alerts", name: "Alerts", groupId: "analytics", realm: "alerts" },
[{ timeMs: 1500, occurred: true }],
);
ds.timestamps(
{ id: "milestones", name: "Milestones", groupId: "analytics" },
[{ timeMs: 500, annotation: "Session start" }],
);
ds.ranges(
{ id: "phases", name: "Phases", groupId: "analytics" },
[{ startTimeMs: 0, endTimeMs: 5000, durationMs: 5000 }],
);
return ds.buildRoot();
}Node config: dataserviceOutput.enabled: true, persistence: "dataservice-root". Full sample: dataservice-multi-shape.js.
Related
- Layout and ComposableChart (channel id binding)
- Outputs and pipelines
- ComposableChart (widget)