Functional Weave
Code in TypeScript

Suites · monitoring

Uptime monitoring and status pages

Turn probe results into up, degraded or down, incidents and uptime; drive a public status page; alert on thresholds, anomalies and SLO burn rates.

75 capabilities (25 core, 50 optional) and 12 gaps, in build order. Put each line in the file that calls it, then fune build.

1. Checks

Classify each probe and combine probes into one status per target.

monitor.http-check-result core
Classifies one HTTP probe as up, degraded or down from status, body and latency.
Classify one HTTP probe as up, degraded or down, with a reason and message, from status, body and latency.
import { classifyHttpCheck } from "#fune/monitor.http-check-result@^1";
monitor.check-status core
Combines several locations' probes into one status with a quorum.
Combine the statuses of one target's probes from several locations into one up, degraded or down, with a quorum.
import { aggregateStatus } from "#fune/monitor.check-status@^1";
monitor.cert-expiry optional
Days left on a TLS certificate and whether that is ok, warning, critical or expired.
How long a TLS certificate has left before its notAfter, and whether that is ok, a warning, critical or expired.
import { certExpiry } from "#fune/monitor.cert-expiry@^1";
monitor.cert-check optional
A certificate's expiry state as a check status.
A TLS certificate's expiry state as a check status: ok and warning are up, critical is degraded, expired is down.
import { certCheck } from "#fune/monitor.cert-check@^1";
monitor.heartbeat optional
Whether a cron job that pings on a schedule is new, up, late or down.
Whether a cron job that pings on a schedule is new, up, late or down, from its last ping, period and grace time.
import { heartbeatStatus } from "#fune/monitor.heartbeat@^1";
monitor.heartbeat-check optional
A heartbeat's state as a check status for the status page.
A heartbeat's state as a check status for a status page: up, late as degraded, down as down, new as nothing yet.
import { heartbeatCheck } from "#fune/monitor.heartbeat-check@^1";
net.latency-summary optional
Loss, min/avg/max, p95 and jitter from ping-style probe results.
Summarise probe results: sent, received, loss, min/avg/max, p95 and jitter, in whole microseconds.
import { summariseLatency } from "#fune/net.latency-summary@^1";
net.device-status optional
Up, degraded or down from a latency summary and thresholds.
Classify a device as up, degraded or down from its latency summary and loss, p95 and jitter thresholds.
import { deviceStatus } from "#fune/net.device-status@^1";
  • probes Running the probes: HTTP requests, TLS handshakes and pings from several locations on a schedule are network I/O and yours.

2. Incidents and uptime

Turn check history into incidents and uptime figures.

monitor.incidents core
Turns check series into incidents, ignoring runs too short to confirm.
Turn a series of up, degraded and down checks into incidents, ignoring runs too short to confirm.
import { findIncidents } from "#fune/monitor.incidents@^1";
monitor.uptime core
Time-weighted uptime over a window, with long gaps counted as unknown.
Time-weighted uptime of a target over a window from its checks, with gaps longer than a limit counted as unknown.
import { uptime } from "#fune/monitor.uptime@^1";
monitor.mttr optional
MTTR, MTBF, downtime and incident counts for a reporting window.
MTTR, MTBF, downtime and incident counts for a reporting window, from a list of incidents.
import { reliabilityStats } from "#fune/monitor.mttr@^1";
monitor.maintenance-window optional
The maintenance window in force at a moment, to suppress alerts and uptime.
The scheduled maintenance window in force at a moment, if any, so alerts and uptime can be suppressed during it.
import { activeMaintenance } from "#fune/monitor.maintenance-window@^1";

3. Status page

The public page: overall state, components and history bars.

monitor.component-state core
A component's state from its checks: operational, degraded, partial or major outage, maintenance.
A status page component's state from its checks: operational, degraded, partial or major outage, or maintenance.
import { componentState } from "#fune/monitor.component-state@^1";
monitor.status-page core
The headline, overall state and affected components at the top of the page.
The overall state, headline and affected components at the top of a status page, from each component's state.
import { statusPage } from "#fune/monitor.status-page@^1";
monitor.uptime-bars core
One bar per UTC day of uptime history, oldest first.
One bar per UTC day for a status page's uptime history: seconds in each state, uptime and a colour state, oldest first.
import { uptimeBars } from "#fune/monitor.uptime-bars@^1";
monitor.format-duration optional
Short durations like "3h 12m" for incident lengths.
A number of seconds as a short human duration for dashboards and alerts: "3h 12m", "2d 4h", "45s".
import { formatDuration } from "#fune/monitor.format-duration@^1";

4. Alerting

Decide when to alert and what to send.

monitor.alert-rule core
Evaluates a threshold rule over a metric series: inactive, pending, firing or no-data.
Evaluate a threshold alert rule over a metric series: inactive, pending, firing or no-data, Prometheus style.
import { evaluateAlertRule } from "#fune/monitor.alert-rule@^1";
monitor.alert-state core
Steps an alert through pending, firing and resolved and says which notification to send.
Step an alert through inactive, pending, firing and resolved, and say which notification to send.
import { nextAlertState } from "#fune/monitor.alert-state@^1";
monitor.alert-mute optional
Holds an alert back during maintenance or when a related alert is already firing.
Whether to hold an alert back: its component is under maintenance, or a related alert on it is already firing.
import { muteAlert } from "#fune/monitor.alert-mute@^1";
monitor.anomaly optional
Flags an outlier against history by z-score or median/MAD.
Is a new metric value an outlier against its history? By z-score or by the robust median/MAD modified z-score.
import { detectAnomaly } from "#fune/monitor.anomaly@^1";
  • notifications Delivering alerts by email, SMS, Slack, PagerDuty or webhooks, with retries and on-call schedules.

5. SLOs and error budgets

Track service level objectives.

monitor.error-budget optional
Error budget allowed, used and left from good and bad events.
How much of an SLO's error budget is allowed, used and left, from good and bad event counts or seconds.
import { errorBudget } from "#fune/monitor.error-budget@^1";
monitor.burn-rate optional
How fast the error budget burns, as a multiple of the allowed rate.
How fast an SLO's error budget is burning: the error rate as a multiple of the rate the SLO allows, in thousandths.
import { burnRate } from "#fune/monitor.burn-rate@^1";
monitor.burn-rate-alert optional
Multiwindow, multi-burn-rate SLO alerting rules, Google SRE style.
Multiwindow, multi-burn-rate SLO alerting: which rules fire, from event counts per window (Google SRE workbook).
import { burnRateAlert } from "#fune/monitor.burn-rate-alert@^2";

6. Metrics and logs

Shape raw metrics and access logs for charts and rules.

monitor.rollup optional
Aggregates a series into fixed time buckets: count, min, max, avg, sum, last.
Aggregate a metric series into fixed time buckets (count, min, max, avg, sum, last), empty buckets included.
import { rollup } from "#fune/monitor.rollup@^1";
monitor.series-window optional
The samples between two moments, checking time order.
The samples of a time series from one moment up to (not including) another, checking they are in time order.
import { seriesWindow } from "#fune/monitor.series-window@^1";
monitor.counter-increase optional
Counter growth and rate per second, counting restarts.
How much a monotonic counter grew over a series of samples, counting restarts from zero, and its rate per second.
import { counterIncrease } from "#fune/monitor.counter-increase@^1";
monitor.parse-access-log optional
Parses Apache/NCSA Common or Combined log lines.
Parse one Apache/NCSA Common or Combined Log Format access log line; null for a line in neither format.
import { parseAccessLog } from "#fune/monitor.parse-access-log@^1";
monitor.status-code-summary optional
Counts status codes by class and gives server and client error rates.
Count HTTP status codes by class (1xx to 5xx) and give the server error and client error rates in basis points.
import { summariseStatusCodes } from "#fune/monitor.status-code-summary@^1";
  • metrics-storage Storing time series and logs (a TSDB, Prometheus, a database) and querying them.

7. Whole charts from dashboards

Get complete chart geometry in one call, for the common charts.

charts.line-chart core
Plot area, number or date axes, gridlines, series paths, colours and legend for a line chart.
Complete line chart geometry as data: plot area, number or date axes, gridlines, series paths, colours, legend.
import { lineChart } from "#fune/charts.line-chart@^1";
charts.bar-chart core
Grouped or stacked bar chart geometry: axes, gridlines, bars, colours and legend.
Complete bar chart geometry as data, grouped or stacked: plot area, axes, gridlines, bar rectangles, colours, legend.
import { barChart } from "#fune/charts.bar-chart@^1";
charts.sparkline optional
A sparkline path and end marker for a series in a small box.
A sparkline's SVG path and end marker from a series, fitted into a box, with gaps left as breaks.
import { sparkline } from "#fune/charts.sparkline@^1";

8. Chart building blocks from dashboards

Compose charts of your own from the same parts.

charts.scale core
Maps values to positions and back: linear, log, time, band and point scales, nice domains.
Map data values onto screen positions and back: linear, log, time, band and point scales, and nice domains.
import { linearScale, invertLinear, niceDomain, logScale, timeScale, bandScale, pointScale } from "#fune/charts.scale@^1";
charts.ticks core
Round tick steps and calendar ticks from days to years.
Axis ticks: a round step (1, 2 or 5 x 10^k), the ticks on it, and calendar ticks from days to years.
import { tickStep, niceTicks, timeTickInterval, timeTicks } from "#fune/charts.ticks@^1";
charts.axis core
Tick positions, labels and gridlines for number, time and category axes.
Axis geometry as data: tick positions, tick marks, label anchors and gridlines for number, time and category axes.
import { axisFromTicks, numberAxis, timeAxis, bandAxis, gridLines } from "#fune/charts.axis@^1";
charts.shape optional
SVG paths for lines, areas, steps, curves, bars, arcs and pie slices.
SVG path strings for lines, areas, steps, monotone curves, bars, arcs and pie slices, identical in every language.
import { linePath, areaPath, stepPath, monotoneCurve, barRects, arcPath, pieAngles } from "#fune/charts.shape@^1";
charts.stack optional
Stacks series on zero, normalised to 100% or diverging.
Stack several series for stacked bars and areas: on zero, normalised to 100%, or diverging around zero.
import { stack } from "#fune/charts.stack@^1";
charts.layout optional
Plot area inside margins, legend rows, label collision avoidance.
Chart layout: the plot area inside margins, legend items wrapped into rows, and greedy label collision avoidance.
import { plotArea, legendRows, avoidCollisions } from "#fune/charts.layout@^1";
charts.extent optional
Min and max of a series, skipping gaps.
The minimum and maximum of a series as [min, max], skipping gaps (null), or null when there is no value.
import { extent } from "#fune/charts.extent@^1";
charts.histogram-bins optional
Bins values for a histogram (Sturges, Freedman-Diaconis or fixed width).
Bin values into histogram bins on round edges, by Sturges' rule, Freedman-Diaconis, or a fixed width.
import { histogramBins } from "#fune/charts.histogram-bins@^1";
charts.downsample optional
Thins a long series by LTTB so it draws fast but keeps its shape.
Reduce a long series to a few points that keep its visual shape, by Largest-Triangle-Three-Buckets (LTTB).
import { downsample } from "#fune/charts.downsample@^1";

9. Colour from dashboards

Readable, colour-blind-safe colours.

charts.palette core
n colour-blind-safe series colours (Okabe-Ito or Tol bright).
A categorical palette of n colour-blind-safe colours for chart series: Okabe-Ito or Paul Tol's bright scheme.
import { palette } from "#fune/charts.palette@^1";
charts.interpolate-color optional
Colour along a sequential or diverging ramp, for heatmaps.
The colour at a point along a sequential or diverging ramp, mixed in OKLab so steps look even; hex in, hex out.
import { interpolateColor } from "#fune/charts.interpolate-color@^1";
charts.contrast optional
WCAG contrast ratio and the readable text colour on a background.
WCAG 2.x contrast ratio between two colours, and which text colour reads best on a background.
import { contrastRatio, readableTextColor } from "#fune/charts.contrast@^1";
charts.color optional
Hex to RGB and back, and sRGB to linear light.
Hex colours to RGB and back, and sRGB channels to linear light and back, identically in every language.
import { parseHex, toHex, srgbToLinear, linearToSrgb } from "#fune/charts.color@^1";

10. Figures and statistics from dashboards

The numbers in the tiles and tooltips.

charts.format core
Tick and label text: SI prefixes (1.2k), percentages, dates and money.
Axis and label text for charts: tick numbers, SI prefixes (1.2k, 3.4M), percentages, dates and money.
import { formatTick, formatSi, formatPercent, formatDate, formatMoneyTick } from "#fune/charts.format@^1";
stats.mean-median optional
Mean, median and mode, exactly.
Mean, median and mode of a list of integers, with the mean and median as exact fractions.
import { meanMedianMode } from "#fune/stats.mean-median@^1";
stats.percentile optional
Percentiles (nearest-rank or linear), for p95 tiles.
Percentile of a list of numbers by a named method: nearest-rank, or linear interpolation (R-7, Excel PERCENTILE.INC).
import { percentile } from "#fune/stats.percentile@^2";
stats.moving-average optional
Simple and exponential moving averages for trend lines.
Simple or exponential moving average over a series, one value per full window, rounded to stated decimals.
import { movingAverage } from "#fune/stats.moving-average@^2";
stats.standard-deviation optional
Standard deviation, for bands and variability.
Population or sample standard deviation of a list of numbers, two-pass, rounded to stated decimals.
import { standardDeviation } from "#fune/stats.standard-deviation@^2";
stats.weighted-average optional
Weighted averages with explicit rounding.
Weighted average of integers, computed exactly and rounded once to stated decimals with an explicit rounding mode.
import { weightedAverage } from "#fune/stats.weighted-average@^1";
math.percent-change optional
Change between two values in basis points, for "up 4.2%".
Percentage change from one value to another, in basis points, with an explicit rounding mode.
import { percentChange } from "#fune/math.percent-change@^1";
text.format-decimal optional
Plain decimal text with fixed places and grouping.
Format a float as plain decimal text with fixed or trimmed places and optional grouping, identically in every language.
import { formatDecimal } from "#fune/text.format-decimal@^1";
money.format optional
Money values in tiles with the currency's real decimals.
Render a monetary amount as text, using the currency's real minor-unit precision.
import { formatMoney } from "#fune/money.format@^1";
collections.group-by-key optional
Groups records by a key before charting them.
Group records by the value at one key, preserving input order inside each group.
import { groupByKey } from "#fune/collections.group-by-key@^1";

11. Calendar arithmetic from dates-basics

Move and measure ISO dates exactly, with no date library and no clock reads.

dates.add-days core
Shifts a date by whole days, for due dates and windows.
Shift an ISO date by a whole number of days, forwards or backwards, with exact calendar arithmetic.
import { addDays } from "#fune/dates.add-days@^1";
dates.add-months core
Adds months clamping to month end, so 31 January plus a month is the end of February.
Add calendar months to an ISO date, clamping to the month end: 31 Jan + 1 month is 28 or 29 Feb.
import { addMonths } from "#fune/dates.add-months@^1";
dates.days-between core
Signed calendar days between two dates, for ages of invoices and stays.
Calendar days from one ISO date to another, signed: negative when the second date is earlier.
import { daysBetween } from "#fune/dates.days-between@^1";
dates.month-boundaries core
First and last day of a date's month, for monthly periods and statements.
The first day, last day and length of the calendar month containing a date.
import { monthBoundaries } from "#fune/dates.month-boundaries@^1";
dates.day-of-week core
ISO weekday of a date, for weekend rules and opening hours.
The ISO 8601 day of the week for a date: 1 is Monday through 7 is Sunday.
import { dayOfWeek } from "#fune/dates.day-of-week@^1";
dates.is-leap-year optional
Whether a year is a leap year, for 365/366-day calculations.
Whether a year is a Gregorian leap year: every 4th, except centuries, except every 400th.
import { isLeapYear } from "#fune/dates.is-leap-year@^1";
dates.overlap optional
Days two date ranges share, for prorating and clash checks.
Days two date ranges have in common, with the end of each range stated as inclusive or exclusive.
import { overlapDays } from "#fune/dates.overlap@^1";
dates.age optional
Age in whole years on a date, handling 29 February birthdays.
Age in whole years on a given date, with 29 February birthdays ageing on 1 March in other years.
import { age } from "#fune/dates.age@^1";

12. Periods and reporting dates from dates-basics

Put dates into the periods reports are grouped by.

dates.quarter core
Calendar and fiscal quarter of a date for any year-start month.
Calendar quarter and fiscal quarter of a date, with the fiscal year and quarter date ranges, for any start month.
import { quarter } from "#fune/dates.quarter@^1";
dates.week-number optional
ISO week number and week-year, for weekly reports.
ISO 8601 week number and week-numbering year of a date: weeks start Monday, week 1 holds the first Thursday.
import { weekNumber } from "#fune/dates.week-number@^1";
dates.day-count-fraction optional
Year fraction by ACT/365F, ACT/360, 30/360 or ACT/ACT, for interest periods.
Year fraction between two dates by ACT/365F, ACT/360, 30/360, 30E/360 or ACT/ACT ISDA, as an exact fraction.
import { dayCountFraction } from "#fune/dates.day-count-fraction@^1";

13. Working days and holidays from dates-basics

Skip weekends and public holidays when counting or adding days.

dates.bank-holidays core
UK bank holidays for a region and year, as gov.uk publishes them.
UK bank and public holidays for a region and year, as published by gov.uk, including one-off holidays.
import { bankHolidays } from "#fune/dates.bank-holidays@^1";
dates.add-business-days core
Moves a date by working days, skipping weekends and a holiday list.
Move a date forward or back by working days, skipping weekends and a caller-supplied holiday list.
import { addBusinessDays } from "#fune/dates.add-business-days@^1";
dates.business-days-between core
Working days between two dates, for SLAs and notice periods.
Working days between two dates, excluding weekends and a caller-supplied holiday list.
import { businessDaysBetween } from "#fune/dates.business-days-between@^1";

14. Repeating schedules from dates-basics

Generate the dates of something that repeats.

dates.recurrence optional
The next n dates of a rule: monthly on the 31st, last Friday, every two weeks.
The next n dates of a repeating rule: monthly on a day, last weekday of the month, every k days or weeks, yearly.
import { recurrence } from "#fune/dates.recurrence@^1";

15. Times and durations from dates-basics

Work with times of day, durations and timestamps.

time.duration optional
Parses and adds durations like 1h30m in whole minutes, and formats the total.
Parse durations written as 1h30m, 90m or 01:30, add them up in whole minutes, and format the total.
import { duration } from "#fune/time.duration@^1";
time.minutes-between optional
Minutes between two local date-times, across midnight.
Minutes from one local date and time to another, correct across midnight; wall-clock time, no time zones.
import { minutesBetween } from "#fune/time.minutes-between@^1";
time.round-to-increment optional
Rounds minutes to a billing increment such as 6 or 15.
Round a duration in minutes to a billing increment such as 6 or 15 minutes, up, down or to nearest.
import { roundToIncrement } from "#fune/time.round-to-increment@^1";
time.iso-to-unix optional
RFC 3339 timestamps to Unix seconds.
An RFC 3339 timestamp with a Z or offset, such as 2026-09-26T13:00:00+01:00, to Unix time in whole seconds.
import { isoToUnix } from "#fune/time.iso-to-unix@^1";
time.unix-to-iso optional
Unix seconds to an ISO 8601 UTC timestamp.
Unix time in seconds to an ISO 8601 UTC timestamp such as 2026-09-26T12:00:00Z, for years 0001 to 9999.
import { unixToIso } from "#fune/time.unix-to-iso@^1";
time.countdown optional
Seconds left until a moment and a 4:05 style timer text.
Seconds left until a Unix time, whether it has passed, and a timer text like 4:05, for tokens or retry waits.
import { countdown } from "#fune/time.countdown@^1";

Gaps

What this kind of app usually needs that Functional Weave does not have yet: write these yourself, or use a service.

  • scheduler The loop that runs checks every minute and keeps state between runs.
  • subscriber-updates Status page subscriptions and incident updates written by people.
  • rendering Drawing: caps returns numbers and SVG path strings; putting them in SVG, canvas or a chart component is yours.
  • interactivity Tooltips, zoom, pan, brushing and animation.
  • data-queries Querying and aggregating the data at source (SQL, a metrics store); monitor.rollup covers time buckets in memory.
  • pie-donut-chart A complete pie or donut chart: charts.shape gives pieAngles and arcPath, assembling legend and labels is yours.
  • time-zones Time axes in local time zones: charts work in UTC dates and times.
  • locale-formatting Showing dates in a user's language and format ("3 octobre 2026"): caps returns ISO dates, not localised text.
  • non-uk-holidays Public holidays outside the UK: dates.bank-holidays is UK only; pass another country's list to the working-day functions yourself.