Suites · health-clinic
Health clinic and practice management
A clinic or practice: appointment slots, patient identifiers and ages, waiting times, and clinical calculators (BMI, BSA, eGFR, NEWS2, weight-based doses, gestational age).
49 capabilities (18 core, 31 optional) and 12 gaps, in build order. Put each line in the file that calls it, then fune build.
Not a medical device and not clinical advice. Every clinical calculator here needs sign-off by a qualified clinician before it is used for real patients, and software that informs diagnosis or treatment may need UKCA/CE marking as a medical device (MHRA).
UK first: NHS numbers, NHS England RTT waits and NEWS2 follow UK rules.
Patient data is special category data under UK GDPR: storage, access control and audit are yours.
TypeScript Python Rust
1. Appointments
Offer bookable slots and keep track of how long patients wait.
health.appointment-slots core Unreviewed
Bookable slots from clinic sessions, a slot length, breaks and existing bookings.
Bookable appointment slots from clinic sessions, a slot length, breaks and existing bookings.
import { appointmentSlots } from "#fune/health.appointment-slots@^1" ;
1.0.1
health.waiting-time optional Unreviewed
NHS England referral-to-treatment wait in days and weekly bands, with the 18-week breach flag.
NHS England referral-to-treatment (RTT) wait in days and weekly bands, with the 18-week breach flag.
import { rttWaitingTime } from "#fune/health.waiting-time@^1" ;
1.0.1
appointment-reminders Reminder texts and emails, and handling did-not-attend and cancellations.clinician-calendars Clinicians' rotas, rooms and leave that make the sessions the slots are cut from.
2. Patients
Identify patients and record their age correctly.
validation.nhs-number core
Checks an NHS number's modulus 11 check digit and normalises it to ten digits.
Check an NHS number's modulus 11 check digit and normalise it to ten digits.
import { validateNhsNumber } from "#fune/validation.nhs-number@^2" ;
2.0.0
health.nhs-number-format core Unreviewed
Displays an NHS number as "943 476 5919" after checking it.
Display an NHS number in the 3-3-4 format ("943 476 5919") after checking its modulus 11 check digit.
import { formatNhsNumber } from "#fune/health.nhs-number-format@^1" ;
1.0.1
dates.age core
Age in whole years on a date, for adult records and age-based rules.
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" ;
1.0.0
health.age-in-months optional Unreviewed
Age in completed months and days, for paediatric charts and doses.
Age in completed months and days on a given date, for paediatric charts and doses; month ends handled like birthdays.
import { ageInMonths } from "#fune/health.age-in-months@^1" ;
1.0.1
patient-lookup Looking a patient up on the NHS Spine (PDS) or another master index is network work and not in caps.clinical-records Clinical notes, coding (SNOMED CT), consent and the audit trail of who saw what.
3. Clinical calculators
Common bedside and consulting-room calculations, each pinned by tests.
health.bmi core Unreviewed
Adult BMI to one decimal place and its NICE/WHO weight category.
Adult body mass index (kg/m², 1 decimal place) and its NICE/WHO weight category.
import { bmi } from "#fune/health.bmi@^1" ;
1.0.1
health.bsa optional Unreviewed
Body surface area by the Mosteller and DuBois formulas.
Body surface area in m² by the Mosteller and the DuBois & DuBois formulas, to 2 decimal places.
import { bodySurfaceArea } from "#fune/health.bsa@^1" ;
1.0.1
health.egfr optional Unreviewed
eGFR by the race-free CKD-EPI 2021 creatinine equation.
eGFR in mL/min/1.73 m² by the race-free CKD-EPI 2021 creatinine equation, from creatinine in µmol/L or mg/dL.
import { egfrCkdEpi2021 } from "#fune/health.egfr@^1" ;
1.0.1
health.news2 optional Unreviewed
NEWS2 score from one set of observations, with its clinical risk band.
NEWS2 early warning score from one set of observations: parameter scores, aggregate and RCP clinical risk band.
import { news2Score } from "#fune/health.news2@^1" ;
1.0.1
health.dose-weight-based optional Unreviewed
Weight-based dose capped at a maximum and rounded to a measurable volume.
Weight-based dose (per kg) capped at a maximum single dose and rounded to a measurable volume, in exact micro-units.
import { weightBasedDose } from "#fune/health.dose-weight-based@^1" ;
1.0.1
health.gestational-age optional Unreviewed
Gestational age and estimated due date from the last menstrual period (Naegele's rule).
Gestational age (weeks+days) and estimated due date from the last menstrual period by Naegele's rule, cycle-adjusted.
import { gestationalAge } from "#fune/health.gestational-age@^1" ;
1.0.1
health.qrisk-inputs-validate optional Unreviewed
Checks a QRISK3 input set against the calculator's published ranges; it does not compute the risk.
Check a QRISK3 cardiovascular risk input set against the calculator's published ranges; does not compute risk.
import { validateQriskInputs } from "#fune/health.qrisk-inputs-validate@^1" ;
1.0.1
qrisk-score The QRISK3 cardiovascular risk itself: use the licensed calculator; Functional Weave only checks its inputs.prescribing Drug interactions, formularies and e-prescribing (EPS): not in caps.
4. Billing (private practice)
Charge for private appointments.
finance.invoice.calculate optional
Totals an invoice for a private appointment, with VAT per line where it applies.
Calculate a complete invoice: line nets, VAT per line, totals and a VAT summary grouped by rate.
import { calculateInvoice } from "#fune/finance.invoice.calculate@^1" ;
1.0.1
money.format optional
Shows fees with the currency's real decimal places.
Render a monetary amount as text, using the currency's real minor-unit precision.
import { formatMoney } from "#fune/money.format@^1" ;
1.0.0
5. 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" ;
1.0.0
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" ;
1.0.0
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" ;
1.0.0
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" ;
1.0.0
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" ;
1.0.0
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" ;
1.0.0
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" ;
1.0.0
6. 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" ;
1.0.0
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" ;
1.0.0
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" ;
1.0.0
7. 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" ;
1.0.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" ;
1.0.0
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" ;
1.0.0
8. 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" ;
1.0.0
9. 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" ;
1.0.0
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" ;
1.0.0
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" ;
1.0.0
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" ;
1.0.0
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" ;
1.0.0
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" ;
1.0.0
Check payee and customer bank details before money moves.
validation.iban core
Checks an IBAN's mod-97 checksum and its country's length.
Check an IBAN against the ISO 13616 mod-97-10 checksum and the registered length for its country.
import { isIban } from "#fune/validation.iban@^1" ;
1.0.0
validation.bic optional
Checks a SWIFT/BIC code's format and splits it.
Check the format of a SWIFT/BIC code (8 or 11 characters) and split it into its parts.
import { validateBic } from "#fune/validation.bic@^1" ;
1.0.0
validation.uk-sort-code-account optional
Checks a UK sort code and account number by the Vocalink modulus rules, against a table you supply.
Check a UK sort code and account number with the Vocalink/Pay.UK modulus rules, against a table you supply.
import { validateUkSortCodeAccount } from "#fune/validation.uk-sort-code-account@^3" ;
3.0.0
validation.uk-modulus-table optional
Parses Vocalink's VALACDOS and SCSUBTAB files into that table.
Parse Vocalink's VALACDOS.txt and SCSUBTAB.txt into the table UK sort code modulus checking needs.
import { parseUkModulusTable } from "#fune/validation.uk-modulus-table@^1" ;
1.0.0
12. Identifiers and check digits from validation-basics
Catch mistyped reference numbers by their check digits.
validation.luhn optional
Luhn mod-10 check, for card numbers and many reference numbers.
Check a digit string against the Luhn mod-10 checksum used by payment cards and many identifiers.
import { isLuhn } from "#fune/validation.luhn@^1" ;
1.0.0
validation.uk-company-number optional
Checks a Companies House number's format and prefix.
Check a Companies House company number's format and prefix (SC, NI, OC, LP...) and zero-pad it to eight characters.
import { validateUkCompanyNumber } from "#fune/validation.uk-company-number@^2" ;
2.0.1
validation.lei optional
Checks a Legal Entity Identifier's check digits.
Check a 20-character Legal Entity Identifier against its ISO 17442 / ISO 7064 MOD 97-10 check digits.
import { validateLei } from "#fune/validation.lei@^1" ;
1.0.0
validation.gtin optional
Checks an EAN/UPC/GTIN barcode number.
Check an EAN-8, UPC-A, EAN-13 or GTIN-14 barcode number against the GS1 mod-10 check digit.
import { validateGtin } from "#fune/validation.gtin@^1" ;
1.1.0
13. Displaying sensitive values from validation-basics
Show stored identifiers without exposing them.
text.mask optional
Masks all but the last digits of a card, account or phone number.
Mask all but the last n characters of a card, account or phone number, optionally keeping separators.
import { mask } from "#fune/text.mask@^1" ;
1.0.0
Gaps What this kind of app usually needs that Functional Weave does not have yet: write these yourself, or use a service.
time-zones Time zones and daylight saving: caps works in ISO dates, UTC and wall-clock times; converting with the IANA tz rules is yours.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.address-lookup Turning a postcode into a list of addresses (Royal Mail PAF or a lookup API) is network work and not in caps.email-deliverability Whether a mailbox exists (MX lookups, a confirmation email): validation.email checks the syntax only.vocalink-data The Vocalink modulus tables themselves: download them from Pay.UK under its terms; caps parses them but does not ship them.