bandwidth

Download/upload speed, latency, and jitter from a live measurement, as async global atoms.

Runs a measurement
Reading a measured atom triggers a download/upload test on first subscribe. Call invalidateMeasurement() to discard the result and re-run.

Install

bun add @valdres/bandwidth

Live example

Loading demo…

Usage

import { Component } from "@angular/core"
import { injectValue } from "valdres-angular"
import { downloadSpeedAtom } from "@valdres/bandwidth"

@Component({
    selector: "speed-badge",
    template: `{{ download().toFixed(1) }} Mbps`,
})
export class SpeedBadge {
    download = injectValue(downloadSpeedAtom) // Signal<number>
}

Exports

ExportKindType
downloadSpeedAtomatom (read-only, async)number — Mbps
uploadSpeedAtomatom (read-only, async)number — Mbps
latencyAtomatom (read-only, async)number — ms
jitterAtomatom (read-only, async)number — ms
measurementStatusAtomatom (settable)MeasurementStatus
lastMeasurementAtomatom (settable)number | null — timestamp
invalidateOnAtomatom (settable)GlobalAtom<unknown>[]
measureBandwidthutil fn(options?: MeasureBandwidthOptions) => Promise<BandwidthResult>
invalidateMeasurementutil fn() => void
MeasurementStatustype"idle" | "measuring-latency" | "measuring-download" | "measuring-upload" | "complete" | "error"
BandwidthResulttype{ downloadMbps, uploadMbps, latencyMs, jitterMs, timestamp: number }
MeasureBandwidthOptionstype{ latencySamples?, maxDurationMs?, minDurationMs?, warmupMs?, startStreams?, maxStreams?, stabilityThreshold?: number; signal?: AbortSignal; fresh?: boolean }

Cross-framework

One in-flight measurement is shared across every store and framework. invalidateMeasurement() clears the result and, if anything is subscribed, kicks off a fresh run.