General Utilities
General-purpose utility functions
General-purpose helper functions.
Package
@tetherto/mdk-ui-foundation
Utilities
ALERT_TYPE_POOL_NAME
Constant
{ readonly ip_worker_name: "IP worker name"; readonly wrong_miner_pool: "Wrong miner pool"; readonly wrong_worker_name: "Wrong worker name"; readonly wrong_miner_subaccount: "Wrong miner subaccount";…ALERT_TYPE_POOL_VALUE
Constant
{ readonly IP_WORKER_NAME: "ip_worker_name"; readonly WRONG_MINER_POOL: "wrong_miner_pool"; readonly WRONG_WORKER_NAME: "wrong_worker_name"; readonly WRONG_MINER_SUBACCOUNT: "wrong_miner_subaccount";…appendContainerToTag
Function
(deviceId: string) => stringappendIdToTag
Function
(deviceId: string) => stringappendIdToTags
Function
(deviceIdList: string[]) => string[]AUTH_LEVELS
Constant
{ readonly READ: "r"; readonly WRITE: "w"; }AUTH_PERMISSIONS
Constant
{ readonly TEMP: "temp"; readonly MINER: "miner"; readonly USERS: "users"; readonly ALERTS: "alerts"; readonly TICKETS: "tickets"; readonly ACTIONS: "actions"; readonly REVENUE: "revenue"; readonly F…AUTH_TOKEN_QUERY_PARAM
Pure URL helpers shared by the auth flow. Kept framework-agnostic so the react-adapter (and any future framework adapter) can call them without pulling in router-specific APIs.
Constant
"authToken"buildCabinetDetailParams
List-things params for one LV cabinet's family of devices — the powermeters and temperature sensors whose info.pos sits under the cabinet root. Mirrors the reference app's getLvCabinetDevicesByRoot(root); the detail hook groups the r…
Function
(root: string) => ListThingsParamsbuildContainerCrossThing
{ type: 'container', params: { containers } } fan-out for miner-level actions.
Function
(containers: string[]) => DeviceActionCrossThingbuildContainerDetailParams
List-things params for the selected containers' detail snapshots. Takes the raw container keys (the selectedDevicesTags outer keys / info.container names), tags them with container- and filters to t-container things — mirrors the r…
Function
(containerKeys: string[]) => ListThingsParamsbuildContainerWidgetsListParams
List-things params for the Site Overview container widgets grid.
Function
() => ListThingsParamsbuildContainerWidgetsRealtimeTailLogParams
Tail-log params for the Container Widgets realtime snapshot — the latest stat-realtime sample across all miners, grouped so the cards can slice per container.
Function
() => TailLogParamsbuildDeviceActionSubmission
Core submission assembler. Prefer the per-action builders below — they pin each action's param arity/encoding; this is the escape hatch for actions without a dedicated builder. extras is spread first so it can never override the pinned s…
Function
(action: DeviceActionValue, tags: string[], params: VotingActionParam[] = [], extras: Record<string, unknown> = {}) => DeviceActionSubmissionbuildExplorerListThingsParams
List-things params for one Explorer tab: tag-filtered, status-enriched, projected to OP_CENTRE_LIST_THINGS_FIELDS.
Function
(tab: ExplorerTabValue, options: { limit?: number; offset?: number } = {}) => ListThingsParamsbuildMinerCrossThing
{ type: 'miner', params: { containers } } fan-out for container-level actions.
Function
(containers: string[]) => DeviceActionCrossThingbuildRebootAction
reboot — no params.
Function
(tags: string[]) => DeviceActionSubmissionbuildResetAlarmAction
resetAlarm — no params.
Function
(tags: string[]) => DeviceActionSubmissionbuildSetAirExhaustEnabledAction
setAirExhaustEnabled — single boolean param.
Function
(tags: string[], isOn: boolean) => DeviceActionSubmissionbuildSetLedAction
setLED — single boolean param.
Function
(tags: string[], isOn: boolean) => DeviceActionSubmissionbuildSetPlcRegistersAction
setPlcRegisters (Gamma) — single { register: value } map param.
Function
(tags: string[], registers: Record<string, unknown>) => DeviceActionSubmissionbuildSetPowerModeAction
setPowerMode — single power-mode param, optional container fan-out.
Function
(tags: string[], mode: PowerModeValue, crossThing?: DeviceActionCrossThing) => DeviceActionSubmissionbuildSetPowerPctAction
setPowerPct — percentage encoded as a string, optional container fan-out.
Function
(tags: string[], percentage: number, crossThing?: DeviceActionCrossThing) => DeviceActionSubmissionbuildSetTankEnabledAction
setTankEnabled — positional [tankNumber, isOn].
Function
(tags: string[], tankNumber: number, isOn: boolean) => DeviceActionSubmissionbuildSwitchContainerAction
switchContainer — single boolean param.
Function
(tags: string[], isOn: boolean) => DeviceActionSubmissionbuildSwitchCoolingSystemAction
switchCoolingSystem — single boolean param, optional miner fan-out.
Function
(tags: string[], isOn: boolean, crossThing?: DeviceActionCrossThing) => DeviceActionSubmissionbuildSwitchSocketAction
switchSocket — one { pdu, socket, enabled } param per toggled socket.
Function
(tags: string[], sockets: SocketSwitch[]) => DeviceActionSubmissionbuildUpdateThingBatchEntry
One updateThing entry inside a move/add/replace-miner batch — carries the miner's new rack/position/network config plus the owning minerId the backend uses to group batch progress.
Function
(params: UpdateThingParams, minerId: string = params.id) => VotingActionPayloadCABINET_DEVICES_TYPES_NAME_MAP
Constant
{ readonly "powermeter-abb-b24": "Powermeter ABB B24"; readonly "sensor-temp-seneca": "Sensor Temp Seneca"; readonly "powermeter-abb-m4m20": "Powermeter ABB M4M20"; readonly "powermeter-abb-m1m20": "…checkPermission
Check if user has the requested permission
Function
(config: AuthConfig | null | undefined, { perm, write, cap }: PermissionCheck) => booleanCOMPLETE_CONTAINER_TYPE
Constant
{ readonly BITMAIN_HYDRO: "container-as-hk3"; readonly BITDEER_M30: "container-bd-d40-m30"; readonly BITDEER_M56: "container-bd-d40-m56"; readonly MICROBT_ALPHA: "container-mbt-alpha"; readonly BITDE…COMPLETE_MINER_TYPES
Constant
{ readonly ANTMINER_AM_S21: "miner-am-s21"; readonly WHATSMINER_WM_63: "miner-wm-m63"; readonly WHATSMINER_WM_53: "miner-wm-m53s"; readonly AVALON_AV_a1346: "miner-av-a1346"; readonly WHATSMINER_WM_5…CONTAINER_LIST_THINGS_LIMIT
Constant
1000CONTAINER_MODEL
Container tag / type / threshold literals. Data-layer contracts shared across the toolkit — owned by ui-foundation so the React layers stay free of tag strings.
Constant
{ readonly M221: "m221"; readonly GAMMA: "gamma"; readonly BITDEER: "bitdeer"; readonly BITMAIN: "bitmain"; readonly MICROBT: "microbt"; readonly ANTSPACE: "antspace"; readonly BITMAIN_IMM: "bitmain-…CONTAINER_MODEL_FAMILY
Container model families the tab matrix distinguishes. Detection order matters and mirrors the reference app's if/else chain — see resolveContainerModelFamily.
Constant
{ readonly BITDEER: "bitdeer"; readonly ANTSPACE_HYDRO: "antspace-hydro"; readonly ANTSPACE_IMMERSION: "antspace-immersion"; readonly MICROBT: "microbt"; readonly GAMMA: "gamma"; }CONTAINER_SETTINGS_MODEL
Constant
{ BITDEER: string; MICROBT: string; HYDRO: string; IMMERSION: string; }CONTAINER_STATUS
Constant
{ readonly RUNNING: "running"; readonly OFFLINE: "offline"; readonly STOPPED: "stopped"; }CONTAINER_TAB
Container detail-view tab keys. The per-model availability matrix lives in utils/container-tabs.ts.
Constant
{ readonly PDU: "pdu"; readonly HOME: "home"; readonly ALARM: "alarm"; readonly CHARTS: "charts"; readonly HEATMAP: "heatmap"; readonly CONTROLS: "controls"; readonly SETTINGS: "settings"; readonly P…CONTAINER_TAB_LABEL
Display labels for the container detail tabs, mirroring the reference app's containerTabsHelper (PDU renders as "PDU Layout", the rest are capitalised keys).
Constant
{ readonly pdu: "PDU Layout"; readonly home: "Home"; readonly alarm: "Alarm"; readonly charts: "Charts"; readonly heatmap: "Heatmap"; readonly controls: "Controls"; readonly settings: "Settings"; rea…CONTAINER_TAB_MATRIX
Base tab sequence per model family — order is display order. Power Adjustment is intentionally absent here: it is inserted positionally by getSupportedContainerTabs.
Constant
Record<ContainerModelFamily, readonly ContainerTabValue[]>CONTAINER_TACTICS_TYPE
Constant
{ readonly COIN: "coin"; readonly DISABLED: "disabled"; readonly ELECTRICITY: "electricity"; }CONTAINER_TYPE
Constant
{ readonly BITDEER: "bd"; readonly ANTSPACE: "as"; readonly MICROBT: "mbt"; readonly ANTSPACE_HYDRO: "as-hk3"; readonly ANTSPACE_IMMERSION: "as-immersion"; }CONTAINER_TYPE_NAME_MAP
Constant
{ readonly "container-bd-d40-m30": "Bitdeer M30"; readonly "container-bd-d40-m56": "Bitdeer M56"; readonly "container-bd-d40-s19xp": "Bitdeer S19XP"; readonly "container-as-hk3": "Bitmain Hydro"; rea…CONTAINER_WIDGETS_AGGR_FIELD_KEYS
All realtime aggregate fields the cards read — the tail-log aggrFields set.
Constant
readonly string[]CONTAINER_WIDGETS_SUMMARY_FIELD
Realtime summary aggregate field names (these carry the _aggr suffix).
Constant
{ readonly HASHRATE_MHS_1M_SUM: "hashrate_mhs_1m_group_sum_aggr"; readonly TEMPERATURE_MAX: "temperature_c_group_max_aggr"; readonly TEMPERATURE_AVG: "temperature_c_group_avg_aggr"; }CONTAINERS_MINER_TYPE
Constant
{ readonly M56: "m56"; readonly M30: "m30"; readonly A1346: "a1346"; readonly S19XP: "s19xp"; }DEFAULT_HISTORICAL_WINDOW_MS
Default historical-alerts look-back window (14 days), matching the devkit <Alerts> feature default. Wider ranges fan out into more 24h requests — see fetchHistoricalAlertsInChunks.
Constant
numberderiveContainerActivity
Slice the realtime aggregate into one container's per-status miner counts. total is the container's nominal miner capacity; miners not accounted for by any status count collapse into disconnected (never negative). With no realtime samp…
Function
(realtime: TailLogEntry | undefined, containerModel: string, total: number) => ContainerActivityderiveContainerSummary
Function
(realtime: TailLogEntry | undefined, containerModel: string) => ContainerSummaryderiveContainerTanks
Derive the per-tank readings for a container's immersion cooling system — one entry per oil pump, joined with the matching water pump and (when present) the tank pressure. Returns an empty array for containers without an immersion cooling…
Function
(container: ListThingsDevice) => TankReading[]deriveSelectedSockets
Derive the store's selectedSockets map (keyed by container tag) from the selected device-tags — the pure body of the reference app's findAndSetSelectedSockets. Each per-container tag key (pos-… / id-…) is stripped of its pos- pre…
Function
(containers: ContainerSnapshotForSockets[] | undefined, selectedDevicesTags: Record<string, Record<string, unknown>>, allDevices: MinerForSocket[] | undefined) => Record<string, { sockets: DerivedSoc…DEVICE_ACTION
Action identifiers accepted by POST /auth/actions/voting (the reference app's ACTION_TYPES, camelCase vocabulary).
Constant
{ readonly SWITCH_CONTAINER: "switchContainer"; readonly SWITCH_COOLING_SYSTEM: "switchCoolingSystem"; readonly SET_TANK_ENABLED: "setTankEnabled"; readonly SET_AIR_EXHAUST_ENABLED: "setAirExhaustEna…DEVICE_BATCH_ACTION
Batch action identifiers (POST /auth/actions/voting/batch) — each groups a set of per-thing sub-actions under one batchActionUID.
Constant
{ readonly MOVE_MINER: "moveMiner"; readonly DELETE_MINER: "deleteMiner"; readonly ATTACH_SPARE_PARTS: "attachSpareParts"; readonly BULK_ADD_SPARE_PARTS: "bulkAddSpareParts"; readonly BATCH_MOVE_SPAR…EXPLORER_TAB
Explorer list-view tabs.
Constant
{ readonly MINER: "miner"; readonly CABINET: "cabinet"; readonly CONTAINER: "container"; }EXPLORER_TAB_TAGS
Thing tags each Explorer tab lists. The cabinet tab unions powermeters and sensors — there is no dedicated t-cabinet tag.
Constant
Record<ExplorerTabValue, readonly string[]>exportSettingsToFile
Function
(data: SettingsExportData) => stringfilterUsers
Function
({ users, email, role }: FilterUsersParams) => SettingsUser[]findMatchingContainer
Find the container-settings row for a container type: an exact model match first, else the settings-model family fallback. Mirrors the reference app's findMatchingContainer.
Function
(settings: ContainerSettingsEntry[] | undefined, containerType: string | undefined) => ContainerSettingsEntry | nullflattenKernelEnvelope
Flattens the per-Kernel response envelope the gateway wraps around merged worker responses (/auth/list-things, /auth/list-racks, ... return [[row, ...], [row, ...]] — one inner array per Kernel). Null-safe on both levels: a missing e…
Function
(envelope: ReadonlyArray<readonly (T | null | undefined)[] | null | undefined> | null | undefined) => T[]formatLastActive
Function
(timestamp: string | undefined) => stringformatRoleLabel
Function
(role: string) => stringgetAntspaceHydroIndexes
Antspace Hydro position → [rack, pdu, socket].
Function
(pos: string) => string[]getAntspaceImmersionIndexes
Antspace Immersion position → [pdu, socket].
Function
(pos: string) => string[]getBitdeerIndexes
Bitdeer / MicroBT position → [pdu, socket].
Function
(pos: string) => string[]getByIdsQuery
Function
(ids: string[], allowEmptyArray?: boolean) => stringgetByTagsQuery
Function
(filterTags: string[], allowEmptyArray?: boolean) => stringgetByTagsWithAlertsQuery
Function
(filterTags: string[], allowEmptyArray?: boolean) => stringgetByTagsWithCriticalAlertsQuery
Function
(filterTags: string[], allowEmptyArray?: boolean) => stringgetByThingsAttributeQuery
Function
(filterAttributes: FilterAttribute[], selectedTypes: string[], allowEmptyArray?: boolean) => UnknownRecordgetByTypesQuery
Function
(filterTypes: string[], allowEmptyArray?: boolean) => stringgetConnectedMinerForSocket
The selected miner sitting at pos, if any (miners only, exact position).
Function
(devices: MinerForSocket[] | undefined, pos: string) => MinerForSocket | undefinedgetContainerByContainerTagsQuery
Function
(filterTags: string[], allowEmptyArray?: boolean) => stringgetContainerMinersByContainerTagsQuery
Function
(filterTags: string[], allowEmptyArray?: boolean) => stringgetContainerSettingsModel
Map a container type string to its settings-model key (bd / mbt / hydro / immersion), or null for an unknown family. Mirrors the reference app's getContainerSettingsModel.
Function
(containerType: string | undefined) => string | nullgetDeviceByAlertId
Function
(uuid: string) => stringgetFiltersQuery
Function
(filterTags?: string[], filters?: Record<string, string[]>, selectedTypes: string[] = ['t-container']) => UnknownRecordgetListQuery
Function
(filterTags: string[], filters?: Record<string, string[]>, selectedTypes: string[] = ['t-container']) => stringgetLvCabinetDevicesByRoot
Function
(root: string) => stringgetMinersByContainerTagsQuery
Function
(filterTags: string[], allowEmptyArray?: boolean) => stringgetPduByIndex
The PDU row whose pdu matches pduIndex on this container, or undefined.
Function
(container: ContainerSnapshotForSockets | undefined, pduIndex: string | number) => PduSnapshot | undefinedgetPduData
The pdu_data array off a container detail snapshot, or undefined.
Function
(last: ContainerSnapshotForSockets['last']) => PduSnapshot[] | undefinedgetRolesFromAuthToken
Extract roles from authentication token
Function
(authToken?: string) => string[]getSignInRedirectUrl
Get redirect URL based on user's primary role
Function
(authToken: string | null | undefined) => stringgetSitePowerMeterQuery
Function
() => stringgetSocketInfo
Resolve one socket for pos on container: pick the vendor index scheme off the container name, then (for Bitdeer / MicroBT) join the live PDU row so enabled / cooling reflect the snapshot. Hydro / Immersion have no live socket table…
Function
(container: ContainerSnapshotForSockets, pos: string, allDevices: MinerForSocket[] | undefined) => DerivedSocketgetSupportedContainerTabs
Full tab sequence for a container type: the family's base sequence, plus Power Adjustment spliced in after the PDU tab for Whatsminer containers. Unknown types resolve to an empty list.
Function
(type: string | undefined) => ContainerTabValue[]getWidgetAlarmState
Resolve a container's alarm state from its live stats and matched settings.
Function
(_container: ListThingsDevice, _settings: ContainerSettingsEntry | null = null) => ContainerAlarmStateisAntminer
Function
(type: string | undefined) => booleanisAntspaceHydroContainer
Antspace/Bitmain hydro family (as-hk3, antspace-hydro, bitmain-hydro).
Function
(type: string | undefined) => booleanisAntspaceImmersionContainer
Antspace/Bitmain immersion family (as-immersion, bitmain-imm[ersion]).
Function
(type: string | undefined) => booleanisAvalon
Function
(type: string | undefined) => booleanisBitdeerContainer
Bitdeer family — container-bd-* and anything mentioning bitdeer.
Function
(type: string | undefined) => booleanisContainer
Function
(type: string | undefined) => booleanisGammaContainer
Gamma family (m221, gamma).
Function
(type: string | undefined) => booleanisMicroBTContainer
MicroBT family (mbt, microbt).
Function
(type: string | undefined) => booleanisMiner
Function
(type: string | undefined) => booleanisPduContainerTab
The PDU grid renders under the pdu tab key.
Function
(tab: string | undefined) => booleanisWhatsminer
Function
(type: string | undefined) => booleanisWhatsminerContainer
Containers populated with Whatsminer miners (m56 / m30 positions, or any MicroBT container) — the set that gets the Power Adjustment tab.
Function
(type: string | undefined) => booleanLV_CABINET_DEVICES_TAG
Constant
{ readonly POWERMETER: "t-powermeter"; readonly SENSOR_TEMP: "t-sensor-temp"; }LV_CABINET_DEVICES_TYPE
Constant
{ readonly POWERMETER_ABB_B24: "powermeter-abb-b24"; readonly SENSOR_TEMP_SENECA: "sensor-temp-seneca"; readonly POWERMETER_ABB_M1M20: "powermeter-abb-m1m20"; readonly POWERMETER_ABB_M4M20: "powermet…MAINTENANCE_CONTAINER
Constant
"maintenance"MINER_BRAND_NAMES
Constant
{ readonly av: "Avalon"; readonly am: "Antminer"; readonly wm: "Whatsminer"; }MINER_MODEL
Device / miner / power-meter tag + type literals. These are data-layer contracts shared between the API surface and the UI — owned by ui-foundation so the React layers can stay free of tag strings.
Constant
{ readonly AVALON: "avalon"; readonly ANTMINER: "antminer"; readonly WHATSMINER: "whatsminer"; }MINER_MODEL_TO_TYPE_MAP
Constant
{ readonly av: "avalon"; readonly am: "antminer"; readonly wm: "whatsminer"; }MINER_POWER_MODE
Constant
{ readonly SLEEP: "sleep"; readonly LOW: "low"; readonly NORMAL: "normal"; readonly HIGH: "high"; }MINER_TYPE
Constant
{ readonly AVALON: "av"; readonly ANTMINER: "am"; readonly WHATSMINER: "wm"; }MINER_TYPE_MESSAGE
Constant
{ readonly "miner-av-a1346": "A1346 miners do not report consumption individually, so Avg. efficiency cannot be calculated"; }MINER_TYPE_NAME_MAP
Constant
{ readonly "miner-av-a1346": "Avalon A1346"; readonly "miner-am-s21": "Antminer S21"; readonly "miner-wm-m63": "Whatsminer M63"; readonly "miner-wm-m56s": "Whatsminer M56S"; readonly "miner-wm-m53s":…MinerStatuses
Constant
{ readonly MINING: "mining"; readonly OFFLINE: "offline"; readonly SLEEPING: "sleeping"; readonly ERROR: "error"; readonly NOT_MINING: "not_mining"; readonly MAINTENANCE: "maintenance"; readonly ALER…NO_MAINTENANCE_CONTAINER
Constant
"no_maintenance"ONE_DAY_MS
One day in milliseconds — the historical-log fetch window size.
Constant
numberOP_CENTRE_CABINET_DETAIL_FIELDS
The cabinet-detail field projection — the sensor/powermeter fields the LV cabinet detail reads: each device's power_w / temp_c reading, status (for the offline marker) and last.alerts (for the warnings timeline).
Constant
stringOP_CENTRE_CONTAINER_DETAIL_FIELDS
The container-detail field projection — a superset of the list projection that also pulls the full last.snap.stats (so the socket transform sees container_specific.pdu_data, ambient temp, humidity, …) and the full last.snap.config (p…
Constant
stringOP_CENTRE_CONTAINER_WIDGETS_FIELDS
Container list projection for the Site Overview widgets — the lean list fields plus last.snap.stats.container_specific (cooling system: oil / water pumps, tanks) and last.snap.config (per-vendor thresholds), which the vendor boxes (e.g…
Constant
stringOP_CENTRE_LIST_THINGS_FIELDS
The list-things field projection the Explorer tables and Container Widgets cards read — the reference app's LIST_THINGS_FIELDS, kept as one projection so every consumer sees the same row shape.
Constant
stringparseSettingsFile
Function
(file: File) => Promise<SettingsExportData>PM_ATTRIBUTE_LABEL_MAP
Constant
{ readonly 'I1 a': "Current L1"; readonly 'I2 a': "Current L2"; readonly 'I3 a': "Current L3"; readonly 'V3 n v': "Voltage L3-N"; readonly 'V2 n v': "Voltage L2-N"; readonly 'V1 n v': "Voltage L1-N";…POWER_MODE
Miner power modes accepted by setPowerMode.
Constant
{ readonly SLEEP: "sleep"; readonly LOW: "low"; readonly NORMAL: "normal"; readonly HIGH: "high"; }removeContainerPrefix
Function
(text: string) => stringresolveContainerModelFamily
Resolves a raw container type string (e.g. container-bd-d40-m56) to its model family, or undefined for unknown types. First match wins, in the reference app's original branch order.
Function
(type: string | undefined) => ContainerModelFamily | undefinedSITE_OVERVIEW_STATUSES
Constant
{ readonly OFFLINE: "offline"; readonly EMPTY: "empty"; readonly NOT_MINING: "not_mining"; readonly MINING: "mining"; }SOCKET_STATUSES
Constant
{ readonly ERROR_MINING: "errorMining"; readonly MINER_DISCONNECTED: "disconnected"; readonly CONNECTING: "connecting"; readonly SLEEP: "sleep"; readonly LOW: "low"; readonly NORMAL: "normal"; readon…THRESHOLD_LEVEL
Constant
{ readonly ALERT: "alert"; readonly ALARM: "alarm"; readonly NORMAL: "normal"; readonly ALARM_LOW: "alarmLow"; readonly ALARM_HIGH: "alarmHigh"; readonly CRITICAL_LOW: "criticalLow"; readonly CRITICA…THRESHOLD_TYPE
Constant
{ readonly TANK_PRESSURE: "tankPressure"; readonly OIL_TEMPERATURE: "oilTemperature"; readonly WATER_TEMPERATURE: "waterTemperature"; readonly SUPPLY_LIQUID_PRESSURE: "supplyLiquidPressure"; }USER_ROLE
Constant
{ readonly ADMIN: "admin"; readonly READ_ONLY: "read_only_user"; readonly SITE_MANAGER: "site_manager"; readonly SITE_OPERATOR: "site_operator"; readonly FIELD_OPERATOR: "field_operator"; readonly RE…validateSettingsJson
Function
(data: unknown) => data is SettingsExportDataVOTING_SUBMISSION_TYPE
Submission type for the voting/approval workflow.
Constant
"voting"