@nolag/dash
Live dashboards with real-time metrics, time-series aggregation, and widgets.
Overview
@nolag/dash powers live operational dashboards with streaming metrics and interactive widgets. Agents or servers publish metric data points and widget state snapshots to panels; viewers connected to the same panel receive updates instantly and can query rolling aggregations (average, min, max, sum, count, last) over any time window without hitting a separate time-series database. Your app owns one core NoLag client and injects it into NoLagDash; the wrapper attaches its behaviour to that connection.
Key Features
- Streaming metric ingestion with per-stream data point buffering
- Client-side rolling aggregation over configurable time windows
- Widget state publishing for gauges, charts, counters, tables, text, and custom types
- Tag-based metadata on metrics for multi-dimensional filtering
- Automatic reconnection with panel subscriptions restored
How It Works
NoLagDash attaches to an injected @nolag/js-sdk client. Calling joinPanel() creates a DashboardPanel that subscribes to two topics: metrics for time-series data points and widgets for widget state snapshots. A MetricStore inside the panel accumulates data points per stream ID and provides rolling-window aggregation, while a WidgetManager keeps the latest state for each widget keyed by widget ID. The app owns the socket lifecycle; the wrapper never opens or closes it.
| Topic | Purpose |
|---|---|
metrics | Time-series data points: value, timestamp, unit, tags |
widgets | Widget state snapshots: type, data payload, label, timestamp |
A viewer's buffer starts empty and fills from the data points published after it joined. A fresh subscribe or an ordinary reconnect never replays history; see Replay for the one case where the broker replays messages. If new viewers need a starting state, have your publisher re-send its current widget snapshots on a timer.
Before you start. Create an app from the nolag-dash-sdk blueprint. That seeds the panel this SDK expects (overview) and the online lobby, and returns an app slug with a random suffix. That slug is the appName you pass to the wrapper. You can also do this in the portal: Apps, New App, pick the blueprint.
import { NoLagApi } from "@nolag/js-sdk";
const api = new NoLagApi(process.env.NOLAG_API_KEY); // nlg_live_...
const app = await api.apps.create({ name: "My App", blueprintId: "nolag-dash-sdk" });
console.log(app.slug); // e.g. "my-app-a3f9": this is your appName
const actor = await api.actors.create({ name: "web-client", actorType: "user" });
console.log(actor.accessToken); // shown once; keep itInstallation
npm install @nolag/dash @nolag/js-sdkShared connection. One core NoLag client can back several wrapper SDKs at once, for example a dashboard, chat, and notify on a single socket, as long as each wrapper uses a distinct appName. Each wrapper attaches its handlers on construction and releases them with detach(), and never touches the socket itself. Your app owns connect() and disconnect().
Quick Start
import { NoLag } from '@nolag/js-sdk'
import { NoLagDash } from '@nolag/dash'
// The app owns one core client. In a browser, pass a token provider so the
// SDK can mint fresh short-lived client tokens from your backend.
const client = NoLag(async () => (await (await fetch('/api/nolag-token')).json()).token)
// Inject the client into the dash wrapper
const dash = new NoLagDash({
client,
appName: APP_SLUG, // the slug returned when you created the app
username: 'Alice',
})
await client.connect() // the app owns the connection
await dash.ready() // wrapper setup complete
// Join the seeded panel
const panel = dash.joinPanel('overview')
// Publish a metric (typically called from a server or agent). The point is
// stamped with Date.now() and added to the publisher's own buffer.
panel.publishMetric('cpu.usage', 74.2, {
unit: 'percent',
tags: { host: 'web-01', region: 'us-east-1' },
})
// Listen for incoming metrics from other publishers
panel.on('metric', ({ streamId, value, timestamp }) => {
console.log(`[${streamId}] ${value} @ ${new Date(timestamp).toISOString()}`)
})
// Get all buffered data points for a metric stream
const points = panel.getMetrics('cpu.usage')
console.log('Data points:', points.length)
// Get a rolling aggregation over the last 5 minutes
const agg = panel.getAggregation('cpu.usage', 5 * 60_000)
console.log('Avg CPU:', agg.avg.toFixed(1) + '%')
console.log('Max CPU:', agg.max.toFixed(1) + '%')
// Publish a widget state (e.g. a status counter)
panel.publishWidget('active-sessions', 'counter', { value: 1_248, trend: 'up' }, 'Active Sessions')
// Listen for widget updates
panel.on('widgetUpdate', ({ widgetId, type, data }) => {
console.log(`Widget ${widgetId} (${type}):`, data)
})
// Read current widget state
const widget = panel.getWidget('active-sessions')
// Teardown: the wrapper releases its handlers; the app closes the socket.
dash.detach()
client.disconnect()API Reference
NoLagDash
The main class. Attaches to the injected core client and manages the dashboard panel lifecycle.
Constructor Options
| Option | Type | Description |
|---|---|---|
client | NoLagSocket | Required. The injected core NoLag client the app owns and connects. |
username | string | Optional display name for this viewer. |
metadata | Record<string, unknown> | Optional custom viewer data attached to presence. |
appName | string | The app slug returned when you created the app (default 'dash', which only works if an app with exactly that slug exists). |
panels | string[] | Panels to subscribe to once the wrapper is ready. |
maxMetricPoints | number | Max metric points kept in memory per stream (default 1000). |
aggregationWindow | number | Accepted and stored (default 60000) but not read yet: getAggregation() uses 60000 ms whenever windowMs is omitted. |
debug | boolean | Enable wrapper debug logging (default false). |
| Method | Returns | Description |
|---|---|---|
ready() | Promise<void> | Resolves once wrapper setup completed |
detach() | void | Release this wrapper's handlers and topics; terminal, never closes the socket |
joinPanel(name, opts?) | DashboardPanel | Join a dashboard panel; opts.filters limits metrics and widgets to matching values; throws before ready() |
leavePanel(name) | void | Leave a panel and unsubscribe from its topics |
getPanels() | DashboardPanel[] | All joined panels |
getOnlineViewers() | DashboardViewer[] | All viewers currently online in the lobby |
Events: NoLagDash
| Event | Payload | Description |
|---|---|---|
connected | none | Wrapper setup completed on a fresh connection |
disconnected | reason: string | Connection closed |
reconnecting | none | The client is attempting to reconnect |
reconnected | none | Reconnection successful; panels are restored automatically |
error | error: Error | Unrecoverable error occurred |
viewerOnline | viewer: DashboardViewer | A viewer appeared in the lobby |
viewerOffline | viewer: DashboardViewer | A viewer left the lobby |
DashboardPanel
Returned by joinPanel(). Handles metric ingestion, aggregation, widget state, and per-panel viewer presence.
| Method | Returns | Description |
|---|---|---|
publishMetric(streamId, value, opts?) | MetricPoint | Publish a data point; opts accepts unit, tags, filter, filters. The timestamp is always Date.now() |
publishWidget(widgetId, type, data, label?, opts?) | WidgetUpdate | Publish a widget snapshot; replaces the previous state for that widget ID. type is 'gauge' | 'chart' | 'counter' | 'table' | 'text' | 'custom' |
getMetrics(streamId?) | MetricPoint[] | Buffered data points for one stream, or every stream when omitted |
getAggregation(streamId, windowMs?) | Aggregation | { streamId, min, max, avg, sum, count, last, windowMs } over the last windowMs ms (60000 when omitted) |
getWidget(widgetId) | WidgetUpdate | undefined | Latest state snapshot for a single widget |
getWidgets() | WidgetUpdate[] | Latest state snapshots for all widgets in this panel |
getViewers() | DashboardViewer[] | Remote viewers present in this panel |
setFilters(values, opts?) | void | Replace the panel's subscription filters; see Filters |
Events: DashboardPanel
| Event | Payload | Description |
|---|---|---|
metric | MetricPoint | A data point arrived: { id, streamId, value, unit?, tags?, timestamp, isReplay } |
widgetUpdate | WidgetUpdate | A widget snapshot arrived: { id, widgetId, type, data, label?, timestamp, isReplay } |
viewerJoined | viewer: DashboardViewer | A viewer joined this panel |
viewerLeft | viewer: DashboardViewer | A viewer left this panel |