Utilities
Helper functions exported by @mdk/core (formatting, validation, conversions) and @mdk/foundation (settings persistence)
This page documents helper functions exported by the MDK packages.
@mdk/coreships 15 utility modules with functions for formatting, dates, validation, conversions, class-name merging, and more@mdk/foundationcurrently ships a single public utility module (settings-utils) for parsing, validating, and exporting settings JSON
@mdk/core utilities
Prerequisites
- Complete the @mdk/core installation and add the dependency
Import
@mdk/core
import {
formatNumber,
formatHashrate,
formatDate,
formatRelativeTime,
cn,
isEmpty,
isValidEmail,
} from '@mdk/core'Formatting utilities
formatNumber
@mdk/core
Format numbers with locale formatting and configurable options.
import { formatNumber, FALLBACK } from '@mdk/core'
formatNumber(1234.567) // "1,234.57"
formatNumber(null) // "-"
formatNumber(1234, { minimumFractionDigits: 2 }) // "1,234.00"
formatNumber(undefined, {}, 'N/A') // "N/A"formatHashrate
@mdk/core
Format hashrate values with rounding.
import { formatHashrate } from '@mdk/core'
formatHashrate(150.456) // "150.46"
formatHashrate(null) // "-"formatCurrency
@mdk/core
Format currency values.
import { formatCurrency } from '@mdk/core'
formatCurrency(1234.56, 'USD') // "$1,234.56"
formatCurrency(0.00012345, 'BTC') // "₿0.00012345"getPercentFormattedNumber
@mdk/core
Format numbers as percentages.
import { getPercentFormattedNumber } from '@mdk/core'
getPercentFormattedNumber(0.75) // "75%"
getPercentFormattedNumber(0.1234, 1) // "12.3%"formatValueUnit
@mdk/core
Format value-unit objects.
import { formatValueUnit } from '@mdk/core'
formatValueUnit(150, 'TH/s') // "150 TH/s"Date utilities
formatDate
@mdk/core
Format dates with customizable patterns.
import { formatDate } from '@mdk/core'
formatDate(new Date()) // "Jan 15, 2025"
formatDate(1705334400000, { format: 'yyyy-MM-dd' }) // "2025-01-15"formatRelativeTime
@mdk/core
Format dates as relative time strings.
import { formatRelativeTime } from '@mdk/core'
formatRelativeTime(new Date(Date.now() - 3600000)) // "1h ago"
formatRelativeTime(new Date(Date.now() - 86400000)) // "1d ago"formatChartDate
@mdk/core
Format timestamps for chart display.
import { formatChartDate } from '@mdk/core'
formatChartDate(1705334400) // "Jan 15"
formatChartDate(1705334400, true) // "Jan 15, 2025"isValidTimestamp
@mdk/core
Check if a timestamp is valid.
import { isValidTimestamp } from '@mdk/core'
isValidTimestamp(1705334400000) // true
isValidTimestamp('invalid') // falseparseMonthLabelToDate
@mdk/core
Parse month labels to Date objects.
import { parseMonthLabelToDate } from '@mdk/core'
parseMonthLabelToDate('01-26') // Date(2026, 0, 1)
parseMonthLabelToDate('03-2025') // Date(2025, 2, 1)getPastDateFromDate
@mdk/core
Get a date in the past.
import { getPastDateFromDate } from '@mdk/core'
getPastDateFromDate({ dateTs: Date.now(), days: 7 }) // 7 days agoValidation utilities
isEmpty
@mdk/core
Check if a value is empty.
import { isEmpty } from '@mdk/core'
isEmpty(null) // true
isEmpty('') // true
isEmpty([]) // true
isEmpty({}) // true
isEmpty('hello') // false
isEmpty([1, 2, 3]) // falseisValidEmail
@mdk/core
Validate email addresses.
import { isValidEmail } from '@mdk/core'
isValidEmail('user@example.com') // true
isValidEmail('invalid') // falseisValidUrl
@mdk/core
Validate URLs.
import { isValidUrl } from '@mdk/core'
isValidUrl('https://example.com') // true
isValidUrl('not-a-url') // falseisNil
@mdk/core
Check if value is null or undefined.
import { isNil } from '@mdk/core'
isNil(null) // true
isNil(undefined) // true
isNil(0) // false
isNil('') // falseisPlainObject
@mdk/core
Check if value is a plain object.
import { isPlainObject } from '@mdk/core'
isPlainObject({}) // true
isPlainObject({ a: 1 }) // true
isPlainObject([]) // false
isPlainObject(new Date()) // falseClass name utilities
cn
@mdk/core
Merge class names using clsx and tailwind-merge.
import { cn } from '@mdk/core'
cn('px-4', 'py-2') // "px-4 py-2"
cn('text-red', isError && 'bg-red') // conditional classes
cn('p-4', { 'hidden': !visible }) // object syntaxConversion utilities
toMW / toMWh
@mdk/core
Convert watts to megawatts.
import { toMW, toMWh } from '@mdk/core'
toMW(1000000) // 1
toMWh(1000000) // 1toPHS
@mdk/core
Convert raw hashrate to PH/s.
import { toPHS } from '@mdk/core'
toPHS(1000000000000000) // 1convertMpaToBar
@mdk/core
Convert pressure units.
import { convertMpaToBar } from '@mdk/core'
convertMpaToBar(0.1) // 1unitToKilo
@mdk/core
Convert to kilo units.
import { unitToKilo } from '@mdk/core'
unitToKilo(1000) // 1Number utilities
percentage
@mdk/core
Calculate percentage.
import { percentage } from '@mdk/core'
percentage(25, 100) // 25
percentage(1, 4) // 25getPercentChange
@mdk/core
Calculate percentage change.
import { getPercentChange } from '@mdk/core'
getPercentChange(110, 100) // 10
getPercentChange(90, 100) // -10convertUnits
@mdk/core
Convert between SI-prefix units.
import { convertUnits } from '@mdk/core'
convertUnits(1, 'k', 'M') // 0.001
convertUnits(1000, 'decimal', 'k') // 1safeNumber
@mdk/core
Safely convert to number.
import { safeNumber } from '@mdk/core'
safeNumber('123') // 123
safeNumber('invalid') // 0
safeNumber(null) // 0String utilities
toTitleCase
@mdk/core
Convert string to Title Case.
import { toTitleCase } from '@mdk/core'
toTitleCase('hello world') // "Hello World"formatMacAddress
@mdk/core
Format MAC addresses.
import { formatMacAddress } from '@mdk/core'
formatMacAddress('aa:bb:cc:dd:ee:ff') // "AA:BB:CC:DD:EE:FF"safeString
@mdk/core
Safely convert to string.
import { safeString } from '@mdk/core'
safeString(123) // "123"
safeString(null) // ""Time utilities
secondsToMs
@mdk/core
Convert seconds to milliseconds.
import { secondsToMs } from '@mdk/core'
secondsToMs(60) // 60000breakTimeIntoIntervals
@mdk/core
Split time range into intervals.
import { breakTimeIntoIntervals } from '@mdk/core'
breakTimeIntoIntervals(start, end, 3600000) // Array of 1-hour intervalstimeRangeWalker
@mdk/core
Generator for iterating through time ranges.
import { timeRangeWalker } from '@mdk/core'
for (const interval of timeRangeWalker(start, end, duration)) {
// Process each interval
}Color utilities
hexToRgba
@mdk/core
Convert hex color to rgba.
import { hexToRgba } from '@mdk/core'
hexToRgba('#72F59E', 0.5) // "rgba(114, 245, 158, 0.5)"Array utilities
getNestedValue
@mdk/core
Get nested value by dot-path.
import { getNestedValue } from '@mdk/core'
getNestedValue({ a: { b: 1 } }, 'a.b') // 1getWeightedAverage
@mdk/core
Calculate weighted average.
import { getWeightedAverage } from '@mdk/core'
getWeightedAverage(items, 'value', 'weight')circularArrayAccess
@mdk/core
Create infinite cycling generator.
import { circularArrayAccess } from '@mdk/core'
const colors = circularArrayAccess(['red', 'green', 'blue'])
colors.next().value // 'red'
colors.next().value // 'green'
colors.next().value // 'blue'
colors.next().value // 'red' (cycles)@mdk/foundation utilities
Helpers for filtering, formatting, validating, parsing, and exporting settings data.
Prerequisites
- Complete the @mdk/foundation installation and add the dependency
Import
@mdk/foundation
import {
filterUsers,
formatRoleLabel,
formatLastActive,
validateSettingsJson,
parseSettingsFile,
exportSettingsToFile,
} from '@mdk/foundation'Settings utilities
filterUsers
@mdk/foundation
Filter a SettingsUser[] list by email substring (case-insensitive) and exact role match. Used by the user-management table search.
import { filterUsers } from '@mdk/foundation'
filterUsers({
users,
email: 'alice', // partial, case-insensitive match on user.email
role: 'admin', // exact match on user.role; pass null to skip
})| Parameter | Type | Description |
|---|---|---|
users | SettingsUser[] | Source list |
email | string | null | undefined | Substring filter on email (case-insensitive). Skipped when falsy. |
role | string | null | undefined | Exact role match. Skipped when falsy. |
formatRoleLabel
@mdk/foundation
Convert a snake case role identifier to a human-readable Title Case label.
import { formatRoleLabel } from '@mdk/foundation'
formatRoleLabel('site_manager') // "Site Manager"
formatRoleLabel('reporting_tool_manager') // "Reporting Tool Manager"
formatRoleLabel('admin') // "Admin"formatLastActive
@mdk/foundation
Format a timestamp string as MM/DD/YYYY - HH:MM. Returns '-' when the input is missing or invalid.
import { formatLastActive } from '@mdk/foundation'
formatLastActive('2025-01-15T14:30:00Z') // "01/15/2025 - 14:30"
formatLastActive(undefined) // "-"
formatLastActive('not-a-date') // "-"validateSettingsJson
@mdk/foundation
Type-guard that checks whether an unknown value is a valid SettingsExportData. Returns true if the value is an object that contains at least one of headerControls, featureFlags, or timestamp.
import { validateSettingsJson } from '@mdk/foundation'
if (validateSettingsJson(parsed)) {
// parsed is now narrowed to SettingsExportData
}parseSettingsFile
@mdk/foundation
Read a File containing settings JSON, validate it, and resolve to SettingsExportData. Rejects on invalid JSON, an invalid format, or a file read error.
import { parseSettingsFile } from '@mdk/foundation'
try {
const settings = await parseSettingsFile(file)
applySettings(settings)
} catch (err) {
notifyError('Could not import settings', err.message)
}| Throws | Reason |
|---|---|
Invalid settings file format. Please ensure the file is a valid settings export. | The JSON parsed but didn't match the SettingsExportData shape. |
Failed to parse JSON file. Please ensure the file is valid JSON. | The file contents weren't valid JSON. |
Failed to read file. | The browser couldn't read the file. |
exportSettingsToFile
@mdk/foundation
Serialize SettingsExportData to JSON, package it as a downloadable Blob, and trigger a browser download. Returns the generated filename (e.g., miningos-settings-2025-01-15T14-30-00-000Z.json).
import { exportSettingsToFile } from '@mdk/foundation'
const filename = exportSettingsToFile({
headerControls: { poolMiners: true, consumption: false },
featureFlags: { betaCharts: true },
timestamp: new Date().toISOString(),
version: '1.0.0',
})
