@overvis/hmi-shared
Цей контент ще не доступний вашою мовою.
This package is for dashboard, CLI, and integration developers. For network operations, start with the API reference.
Cross-cutting TypeBox schemas, Standard Schema validators, value codecs, and small pure
utilities shared by API clients, CLI, and UI. No I/O, no DB, no node:* builtins. The main
export is loaded by the browser.
Requirements
Section titled “Requirements”Install with pnpm add @overvis/hmi-shared (or npm or Yarn). Node.js consumers need Node.js 22 or
later; browsers load it through a bundler. @overvis/hmi-shared/app-router contains only types and
needs @trpc/server 11 as a peer; the other entries do not. Keep @overvis/hmi-shared on the same
version as the other HMI packages; see Versions and updates.
The installed package includes TypeScript declarations for every exported schema and helper,
including fields this chapter does not list. The generated PublicAppRouter declaration provides
procedure inputs and outputs.
Import paths
Section titled “Import paths”| Import | Purpose |
|---|---|
@overvis/hmi-shared | Core: schema, API errors, localized strings, locales, date formatting |
@overvis/hmi-shared/workspace | Workspaces, members, uploads, branding, audit, maps, jobs, support |
@overvis/hmi-shared/setup | Pull, push, setup database, parameter graph, templates |
@overvis/hmi-shared/parameter | Parameter sources, value types, live values, readings |
@overvis/hmi-shared/endpoint | Endpoints, connection status, device discovery |
@overvis/hmi-shared/dashboard | Dashboard configuration, host props, host externals, build manifest, and fleet schemas |
@overvis/hmi-shared/report | Report presets, representations, comments |
@overvis/hmi-shared/graphics | Drawings, symbols, and connectors |
@overvis/hmi-shared/parameter-engine | Value codecs, formula evaluation, and formula validation |
@overvis/hmi-shared/taskfile | MC252 taskfile diagnostics, definitions, and logging-target mappings |
@overvis/hmi-shared/expression | The formula language: compile, type-check, and evaluate formulas |
@overvis/hmi-shared/automation | Automation and alarm rule schemas, setup payloads, limits, the validator, and the language service |
@overvis/hmi-shared/device-api | Device API manifests: schema, validator, path blocking, roles, redaction |
@overvis/hmi-shared/billing | Billed cost types and their units, the published price list, and cost estimates (estimateCost) |
@overvis/hmi-shared/starter | Edge program starters: placeholder schemas and value checks |
@overvis/hmi-shared/document | Documents: schema, validator, and formula evaluation |
@overvis/hmi-shared/api-errors | Error code → status tables and the client version header |
@overvis/hmi-shared/translation | Locale and catalog helpers without other domain schemas |
@overvis/hmi-shared/app-router | Generated PublicAppRouter declaration for typed tRPC clients |
Each name is exported from one entry; only the locale helpers are also in ./translation. The
package has no side effects, so bundlers keep only what a program imports.
import type { PublicAppRouter } from "@overvis/hmi-shared/app-router";import { formatAppDateTime, parseAppDateTime } from "@overvis/hmi-shared";import { endpointStatusOutputSchema } from "@overvis/hmi-shared/endpoint";import { parameterSetupPayloadSchema } from "@overvis/hmi-shared/parameter";import { canWriteSetup } from "@overvis/hmi-shared/workspace";The published declaration is @overvis/hmi-shared/app-router. PublicAppRouter declares every
public API procedure. Each procedure has a comment with the dotted path and a one-line description
next to the input type. Types this package exports are imported from their entry (for example
@overvis/hmi-shared/parameter) rather than repeated.
Types come from Static<typeof …Type>, or from exported aliases next to each schema. Accepted
values are exported as string literal unions.
Validation (schema)
Section titled “Validation (schema)”schema(type) wraps TypeBox compile as a Standard Schema object
(~standard.validate).
Compilation happens on the first validation call, not when importing or wrapping a schema. Plain and defaulting wrappers share the compiled validator for the same TypeBox schema object, so a schema object changed after its first validation keeps the old compiled validator.
Use the exported validators at input boundaries: a TypeBox shape alone does not perform all domain
validation. In particular, use graphicsDocumentSchema for drawing references and grouping
constraints, and parameterSetupIssues from ./parameter-engine for formulas, Modbus byte
capacity, references, and cycles. Setup form …FormToInput functions return API input or
{ ok: false, field, problem }; problem IDs are stable and carry no user-facing text.
- Issues always include an English
messagefor logs and tooling.keywordandparamsare the structured fields that translation catalogs map to user-facing text. - Parameter runtime errors work the same way:
error.messageis debug text, andreasonandparamsare the structured fields. The TypeBox runtime-error union pairs each structured reason with its valid code and required context, so clients can distinguish valid error combinations. - tRPC wire: validation failures use stable message
input_invalidplusdata.issues(ApiValidationIssue:path/keyword/params). Domain failures keep a stable code inmessageand may attachdata.details.
Helpers:
| Helper | Use |
|---|---|
schema(type) | Compile + Standard Schema validate |
schemaWithDefaults / applySchemaDefaults | Fill TypeBox { default: … } before check (older push JSON omitting defaulted keys) |
parseDashboardConfiguration | Narrow host configuration to a dashboard’s TypeBox-derived type |
readerSchema(type) | Read a response from a newer API: unknown keys and changed string/array limits pass |
readerSchema keeps checking types, required keys, and literal values; it drops only
additionalProperties: false and string and array length, pattern, and format limits.
Client version header
Section titled “Client version header”@overvis/hmi-shared/api-errors exports HMI_CLIENT_HEADER (x-hmi-client),
formatHmiClient({ name, version }) (→ cli/0.1.0), and parseHmiClient(value). A client that
sends the header and is older than the API supports gets client_outdated (PRECONDITION_FAILED);
parseClientOutdatedDetails reads its { client, minimum } details.
Request body size
Section titled “Request body size”A request body larger than the API accepts for the called procedure fails with
REQUEST_BODY_TOO_LARGE_CODE (request_body_too_large, PAYLOAD_TOO_LARGE, HTTP 413).
parseRequestBodyTooLargeDetails reads its RequestBodyTooLargeDetails: { limitBytes }, the
largest body the procedure accepts. All three come from @overvis/hmi-shared/api-errors.
Domains
Section titled “Domains”Workspace access
Section titled “Workspace access”"view_only" | "operator" | "editor" | "admin" | "owner";The roles are listed from least to most access; each includes everything before it.
| Helper | Who |
|---|---|
canWriteSetup | editor, admin, owner |
canWriteParameterValues | operator, editor, admin, owner |
canManageWorkspace | admin, owner |
Schemas: workspace list/get/create/rename/updateSettings/delete I/O, from
@overvis/hmi-shared/workspace. List and get responses include disabledSince, an ISO timestamp
or null. workspaceWatchChangesInputSchema and workspaceChangeEventSchema
(WorkspaceChangeEvent) are the input and events of the workspace.watchChanges subscription.
Workspace get responses include an IANA timezone and nullable location ({ lat, lng }).
workspaceTimezoneType, workspaceLocationType, workspaceSettingsSchema, and
workspaceUpdateSettingsInputSchema validate those settings. workspaceSettingsFormSchema,
workspaceSettingsFormValues, and workspaceSettingsFormToInput support coordinate text fields.
Setup payloads also carry these fields; omission preserves existing server values on push, while
location: null clears a saved location.
Fleet and site configuration
Section titled “Fleet and site configuration”@overvis/hmi-shared/dashboard has the configuration building blocks of dashboards that watch many
sites; the matching components are in
@overvis/hmi-workspace-ui.
| Export | Use |
|---|---|
siteProperties | id, name, optional zoneId and position, spread into a site schema |
sitePositionType, isSiteGeoPosition | Fixed { lat, lng } or a geo parameter { parameterId } |
siteEquipmentProperties(category) | Readings, alarms, controls, and a maintenance due date parameter |
siteReadingType(category), siteAlarmType | A reading with its category (role) and unit; an alarm condition |
fleetBoardType(category), fleetZoneType | Cards or table, zone grouping, summary columns (categories); zones |
defineSiteRoles, siteRoleTypes | Named single slots: a reading, a condition, or a control |
equipmentParameterIds, equipmentEntityIds, controlEntityIds | Parameters to read (live) or everything bound (bound); owned item IDs |
saveFleetBoard, assertBaseline, assertUniqueEntityIds | Conflict-checked configuration updates |
saveFleetDrawnSite, deleteFleetDrawnSite | Save or delete a site together with its generated drawing |
reorderItems, moveItem, upsertItem, updateItem, starterEquipment | Ordering, adding or replacing by ID, merging an update into one item, and typical bindings for a new site |
evaluateSites | Evaluate every site once per render, such as its status, as a lookup by site |
saveEquipmentItem, removeEquipmentItem, reorderEquipmentList | Apply a binding editor’s save, delete or new order to one equipment list |
treeParameters, commonBranch, branchPaths, remapParameters, duplicateEquipment | Copy a site to identical equipment elsewhere in the parameter tree |
FleetConfigurationError | conflict, duplicate-id, drawing-limit, invalid-drawing, invalid-configuration |
siteStatuses, siteStatusType | Site states in overview order, from alarm to unconfigured |
dashboardPageSummaryType, dashboardSummaryListLimit | The page summary a fleet or site page publishes to the assistant; its list limit (20) |
saveFleetDrawnSite(config, baseline, site, dashboardId, sites) adds a site (baseline null) or
replaces it, creating its drawing in graphics or reconciling the stored one so an editor’s layout
survives. sites is a FleetDrawnSiteList: get and set for the site list, entityIds (the
IDs a site owns), an optional validate for rules the schema cannot express, createDrawing and
reconcileDrawing. It throws conflict when the site or its zone changed since baseline and
duplicate-id when an ID is used elsewhere. deleteFleetDrawnSite(config, baseline, sites)
removes a site and its drawing.
category is the dashboard’s own TypeBox union of reading categories (pressure, flow,
temperature…). defineSiteRoles({ running: siteRoleTypes.condition }) returns properties for the
entity schema, parameterIds, mapParameterIds (reports slots without a match), and
formValue/fromForm for form rows. Update helpers take the latest configuration and the baseline
the editor opened with, so inside a configuration mutation a concurrent change fails with
conflict instead of being overwritten.
upsertItem(items, item) replaces the item with the same ID or appends a new one, and
updateItem(items, id, update) merges what update returns into one item, such as new equipment
lists into one pump of a station. evaluateSites(sites, evaluate) evaluates each site once and
returns a lookup that evaluates a site outside the list on demand, in the shape of a block’s
stateOf.
Generated drawings
Section titled “Generated drawings”@overvis/hmi-shared/graphics has builders for drawings generated from a configuration. Each item
gets the default appearance, with the given appearance fields over it, and no bindings or action
unless given:
graphicsSymbolElement({ id, name, symbolId, x, y, width, height, ... })places a symbol, with optionalrotation,properties,propertyBindingsandaction.graphicsShapeElement({ id, name, kind, x, y, width, height, appearance })is a rectangle, ellipse, text, group or junction, such as a busbar or a label.graphicsConnector({ id, from, to, bends, arrow, route, appearance })is an unnamed line, routed orthogonally and without an arrow by default, such as a pipe or a cable.
Locale
Section titled “Locale”App locales: en | pl | de | uk | ru. Helpers: coerceAppLocale and appLocaleUiCode
from the root or @overvis/hmi-shared/translation, and isAppLocale from
@overvis/hmi-shared/translation only.
Localized content accepts two-letter language keys beyond the supported UI languages. Missing
translations fall back to English and then the first available key. Date display helpers use
YYYY-MM-DD HH:mm:ss in the browser’s timezone. parseExactAppDateTime accepts only that exact
format; appDateTimeToISOString converts it to an ISO wire timestamp.
Dashboards
Section titled “Dashboards”CRUD I/O, name/settings form schemas, enable/disable, Lucide icon id list,
dashboardEntrypointUrl(id) → /static/dashboard/<id>/index.js, dashboardStylesheetUrl(id) →
/static/dashboard/<id>/index.css.
wrapDashboardCss(css, { hostClassNames }) turns compiled Tailwind utilities into a dashboard
stylesheet: rules are scoped to the DASHBOARD_SCOPE_ATTR element and everything inside it
(DASHBOARD_SCOPE_PROPS spreads the attribute), plain classes go to the dashboard cascade layer,
and variant classes go to dashboard-variants unless hostClassNames contains them or they are
!important. cssClassNames(css) lists the unescaped class names that a stylesheet’s rules
select, for building hostClassNames. hmi build applies both.
dashboard.create accepts optional template (catalog id, default "empty") and optional
configuration. template is create-only; see
Dashboard procedures for how changes are checked.
applyJsonPatch(document, operations) applies JSON Patch (RFC 6902) operations, typed by
jsonPatchOperationType, to a copy; jsonPatchChangedPaths lists the paths a patch changes.
templates.dashboard.list is the picker (summaries, filterable by kind, parameterTemplate and
query); templates.dashboard.get returns one template’s details, including the configSchema of
its configuration.
DashboardRootProps are the host props of a dashboard’s default export; see the
dashboard host contract.
dashboardLocationType and dashboardHref scope paths, queries, and anchors to one dashboard.
Graphics actions use the same optional fields; omitting them targets the root.
Documents
Section titled “Documents”documentType is the schema of a document, and DocumentSpec
its type. validateDocument(document, context) checks one without network access and returns ok
and diagnostics (documentDiagnosticType), each with a code, a severity, a JSON pointer
path, args and, for a formula, a range; describeDocumentDiagnostic gives English text.
context lists the workspace’s parameters (documentParameterInfo builds an entry from a
parameter’s setup payload) and, when known, its endpoints with their device operations, alarm rules
and automations, and uploaded files. analyzeDocument also returns the compiled formulas by JSON
pointer, which evaluateDocumentValues, evaluateDocumentFormula, documentRepeatRows and
documentSourceInput evaluate. documentApiProcedureInfo lists the HMI API procedures a document
may read, with their input and answer schemas.
Counter periods
Section titled “Counter periods”Pure functions in @overvis/hmi-shared/dashboard for consumption totals of counters (energy, heat,
water, gas). @overvis/hmi-workspace-ui builds useCounterTotals on them.
counterPeriodIds (schema counterPeriodIdType, guard isCounterPeriodId). A dashboard’s time
zone setting for calendar periods is dashboardTimeZoneType: an IANA zone, or browser for each
viewer’s own (isValidDashboardTimeZone checks it; browserTimeZone() in
@overvis/hmi-shared/report is the viewer’s zone).
| Period | Window | Comparison window |
|---|---|---|
24h, 7d, 30d | Rolling, ending at the last closed minute | The preceding window of the same length |
yesterday, last-week, last-month | The previous calendar day, week or month | The calendar period before it |
today, this-week, this-month | Start of the calendar period to last closed minute | The previous period up to the same wall time |
resolveCounterPeriod(id, now, timeZone) returns { id, window, comparison, inProgress } with
half-open [from, to) windows in epoch ms. Calendar periods use the given IANA zone (invalid →
UTC) and weeks start on Monday. DST days are 23 or 25 hours long. A period in progress compares
with the same wall time, so “today until 14:37” compares with “yesterday until 14:37”. When the
previous month has no such day, the comparison is the whole previous month. A wall time skipped by
DST moves to the next valid minute. In the first minute of a period in progress, both windows are
empty. Local calendar boundaries are specified for zones whose UTC offset is a whole number of
hours, as for reports.
classifyCounterTotal({ window, delta, first, latest, min, extent, backgroundReadingPeriodMs, deviceLogCompleteThrough? })
takes readings.aggregate values for one window (null when the pair was left out) and the
counter’s reading time extent. It returns one of:
{ kind: "value", value }. The value is the server’sdelta, so it can be 0.{ kind: "no-data" }: the window has no readings.{ kind: "reset" }: a counter reset, flagged and never corrected. It is detected bydelta < 0,min < first, ordelta < latest − first. The last means the reading before the window was above the first reading in it.{ kind: "partial", value, since, until }: the first reading is more thancounterCoverageToleranceMs(backgroundReadingPeriodMs)(background period + 1 minute) after the window start (since), or the last is that far before its end (until). The other side is null. For a counter whose readings a device records and HMI imports later, pass the time through which they are imported asdeviceLogCompleteThrough(the parameter’sdeviceLog.completeThrough): a window ending after it is partial (untilis the last reading in the window, or else that time), unless background readings reach the window end. Its start is judged only with a background period. Counters with neither are never partial.
counterChangeRatio(current, previous) is (current − previous) / previous. It is null unless
both are value and previous is above zero.
Endpoints
Section titled “Endpoints”Settings defaults and normalization (normalizeEndpointHostname, normalizeEndpointSettingsInput,
default TCP port) and CRUD inputs and outputs support endpoint configuration.
MC252 edge programs have their own contracts in ./endpoint: the edgeProgram.* procedure inputs
and outputs, the setup payload, source paths, file name and source checks, edge settings with their
defaults (endpointEdgeSettings), and analyzeEdgeProgramSet. See
MC252 edge programs.
Live endpoint shapes from @overvis/hmi-shared/endpoint describe what endpoint.status,
endpoint.watchStatus, and endpoint.traffic return:
| Export | Shape |
|---|---|
EndpointStatus | state, remote address, connectedAt or lastError, updatedAt |
EndpointStatusItem, EndpointStatusOutput | { endpointId, status } per endpoint; status is null until reported |
EndpointStatusEvent | snapshot (every endpoint), then change (endpointId, status) |
EndpointTrafficChannel | tx, sent, rx, events (endpointTrafficChannels lists them) |
EndpointTrafficFrame | Frame bytes (data, lowercase hex, id, write) or an EndpointEvent |
Traffic channels:
tx— requests handed to the connector: Modbus RTU without CRC (unit id + PDU)sent/rx— full Modbus TCP ADUs written to and received from the deviceevents—EndpointEvent; error events carry the required machine-readablereason, whilemessageis debug text
The CLI prints both with hmi endpoint status and hmi endpoint traffic — see
HMI CLI reference.
./endpoint exports MC252 HTTP status schemas and freshMc252Status. HTTP and Modbus reachability
are independent; stale HTTP observations become unknown.
./taskfile exports analyzeTaskfile and analyzeTaskfiles (MC252 program diagnostics, outlines,
logging targets) and taskfileLanguageService (editor features over a device’s programs).
Parameters
Section titled “Parameters”@overvis/hmi-shared/parameter covers:
| Area | Concern |
|---|---|
| Value types | Discriminated valueType codecs / display strings |
| Sources | Discriminated source (const / calc / modbus-tcp, …) |
| Forms and API | Forms + tRPC I/O |
| Runtime | Runtime errors, write items, and write acknowledgements |
| Defaults | Defaults helpers |
| Zones | Display zones of a value, and zone bands across a range |
| Numbers | Decimal places, number formatting, numeric value types |
| Conditions | Numeric conditions on a parameter’s value |
| Entities | Row shapes + setup payloads |
parameterValueZone(valueType, value) returns green, orange, red or null for a value. For a
num parameter it compares the engineering value with the numeric zones: below lowOrangeBegins
red, from it orange, from greenBegins green, from highOrangeBegins orange, from highRedBegins
red; a boundary that is not set continues the band below it. For an int parameter it returns the
zone of the label that matches the value. parameterZoneBands(valueType, { min, max }) lays a
num parameter’s zones across a range as bands from 0 to 1, such as for a GaugeBar, and
rangeFraction(range, value) places a value on it, pinned to the ends.
parameterValueTypeHasZones(valueType) tells whether a value type has any zone to color by: a
numeric boundary, or a zone on an int label.
formatNumValue(value, decimalPlaces, multiplier) formats a num value as live readings show it:
with decimalPlaces when set (trailing zeros kept), else with the places of multiplier and
trailing zeros dropped, never in exponential notation. decimalPlacesFromMultiplier(multiplier)
returns those places, at most 15.
A parameter condition (parameterConditionType, ParameterCondition: parameterId, operator,
value) compares a parameter with a number. evaluateNumericCondition(value, condition) applies
one to a value, and negateParameterCondition(condition) returns the condition that holds exactly
when it does not, such as “supply available” from “supply lost”.
parameterFlagCondition(parameterId) is the condition of a flag or status code that holds while it
is set: nonzero, or true.
parameterDecimals(valueType) is the number of places a parameter’s readings show: its own, else
its multiplier’s; 0 for int, null for values that are not numbers.
formatParameterNumber(value, valueType, places?) formats a number that way, with places
overriding the parameter’s. isNumericValueType is true for values a chart or gauge plots (num,
and int without labels); isComparableValueType also accepts labelled int and bool, which
numeric conditions compare.
Live values are read and written with parameter.readValues, parameter.readValuesStream, and
parameter.writeValues; their types are in this entry. See
live value procedures.
Parameter writes return kind: "write-acknowledgement", sourceKind, writtenAt, and sent or
stored bytes. Only read observations, kind: "observation", belong in measured-value displays and
history.
executeParameterWriteSequence awaits each acknowledgement and stops at the first failed, missing,
or cancelled result. The result names the stopping step and distinguishes a reported error from an
unknown outcome. Cancellation prevents later steps; it cannot undo a sent write. Callers own
retries, intent confirmation, and permission checks.
Setup payloads (wire / setup.db)
Section titled “Setup payloads (wire / setup.db)”Payload-only types for pull/push and local SQLite rows live next to each entity (no self
workspaceId / timestamps; entity id is the row UUID or upsert key):
| Type | Local projection |
|---|---|
WorkspaceSetupPayload | setup.db workspace singleton |
ParameterSetupPayload | setup.db parameter rows |
ParameterBranchSetupPayload | setup.db parameter_tree_branch rows |
EndpointSetupPayload | setup.db endpoint rows |
EdgeProgramSetupPayload | setup.db edge_program rows |
DashboardSetupPayload | setup.db dashboard rows |
ReportPresetSetupPayload | setup.db report_preset rows |
ReportCommentSetupPayload | setup.db report_comment rows |
AlarmRuleSetupPayload | setup.db alarm_rule rows |
AutomationSetupPayload | setup.db automation rows |
SETUP_DB_DDL and SETUP_DB_SCHEMA_VERSION (from ./setup) describe the local SQLite checkout.
The CLI upgrades an older checkout to its schema version and refuses to open a newer one. Complex
values remain JSON columns; parameterSetupIssues (from ./parameter-engine) checks formulas,
references, and cycles that foreign keys cannot express. isMirroredWorkspaceSourcePath defines
which source files synchronize with the cloud. Unsupported paths fail with push_unknown_path.
Reports
Section titled “Reports”@overvis/hmi-shared/report exports ReportPreset and ReportComment with their setup payloads.
A comment payload is the comment without id. Comment times are product epochs in milliseconds and
must fit a JavaScript Date (isSafeProductEpochMs, PRODUCT_EPOCH_MS_MAX).
report.comment.list returns { reportComments, viewerAccountId, authors }. authors lists each
author’s accountId and name; a deleted user’s comments carry no account id, missing users are
left out, and names longer than reportCommentListAuthorNameMaxLength are truncated. The comment
helpers decide where a comment shows (reportCommentSessionWindow, reportCommentOnWidget,
reportCommentOnPlot, reportCommentInFooter) and whether the viewer may delete it
(canDeleteReportComment).
validateReportPresetRecipe checks what the schema cannot express: layout keys and that a Sankey
is acyclic. workspace.push, hmi check and hmi import all run it and fail with
recipe_invalid. Widget recipe types are exported from the same entry; readings I/O is in
@overvis/hmi-shared/parameter. planQuickReport(items, counters) picks a quick report’s
parameters in priority order up to REPORT_PRESET_TEMPORARY_MAX_PARAMETER_IDS, counting a repeated
parameter once, and lists the names of the items it leaves out.
Pull / push wire contracts
Section titled “Pull / push wire contracts”@overvis/hmi-shared/setup exports these contracts:
| Contract | Content |
|---|---|
| Pull | Mint/redeem token I/O, entity/tombstone deltas since a revision (since), file hashes |
| Push | Upserts / tombstones / file and dist references, pushId, per-entity and per-file bases |
| Blobs | { sha256, size } file references, workspace.missingBlobs I/O, blob route and limits |
| Push error details | Closed workspace.push data.details + formatPushErrorLines |
| Staged push | splitWorkspacePush / mergeWorkspacePushParts for staged pushes (workspace.pushStage) |
| Base revisions | baseRevision / setup_conflict for setup edits: parseSetupConflictDetails, types |
| File encoding | choosePushFileEncoding / binary-safe encodings |
setupEntityTypes includes report_preset and report_comment. Fail-fast push errors put the
code in tRPC message and a closed object in data.details. canonicalJsonString sorts object
keys at every nesting level for stable JSON (e.g. mirrored-file digests). Pull is incremental
(since); push is checked per entity and per file against bases (push_conflict) and is
idempotent per pushId. A push too large for one request is staged in parts and committed as one
push (workspace.pushStage, workspace.pushCommit).
WorkspaceCommitPlan describes what a push would change, as printed by hmi push --dry-run.
Workspace timezones are IANA names, such as Europe/Warsaw. Setup syncs timezone and nullable
{ lat, lng } location; omitted fields are kept.
Branding validators check reserved paths, one image per theme, file sizes, PNG checksums and
dimensions, and SVG XML. Display a branding image only when its metadata has valid: true. The
favicon is a separate 32 × 32 PNG at branding/favicon.png.
Background jobs
Section titled “Background jobs”The package exports jobs.wait input and output schemas, endpoint device-discovery API schemas,
and typed progress and result payloads. Clients consume these contracts through the authorized API.
Each jobs.wait output pairs its jobType with the correct payload. Modbus findings are UIDs
with baud rate and character format. See
Find devices on an MC252 RS-485 bus
for the product workflow.
Failed device-classification rows can include optional diagnostics with controller-reported
mbReqPassed, checksPassed, linesPassed, scriptTime, and scriptVersion. Counters are
non-negative safe integers; metadata is text of at most 128 characters or null. Absent fields stay
absent; out-of-bounds diagnostics are omitted without changing the classification outcome. Counters
describe execution progress, not guaranteed failing-line coordinates. An error with a null
classId and match leaves identification unresolved; it does not establish that a parameter
template is missing. jobs.wait also retains valid partial classification results when the overall
job fails.
Utilities
Section titled “Utilities”| Export | Behavior |
|---|---|
formatAppDateTime | Always YYYY-MM-DD HH:mm:ss in the viewer’s local timezone. Locale-independent. Accepts string | number | Date; invalid → original string or "". |
parseAppDateTime | Parse UI YYYY-MM-DD HH:mm:ss (or T separator) as local wall time, or ISO / other Date-parseable strings → Date | null. Setup editors use it to write datetime values back. |
parseExactAppDateTime | Parse only YYYY-MM-DD HH:mm:ss in local time; invalid dates, ISO strings and whitespace return null. |
appDateTimeToISOString | Convert the same strict local input to an ISO wire timestamp, or return null. |
formatReportDateTime | Same shape in an IANA report timezone (invalid zone → UTC). |
formatReportDateTimeMs | Same wall clock plus .SSS (epoch millisecond remainder) for precise CSV timestamps. |
parseReportDateTime | Parse YYYY-MM-DD HH:mm:ss as wall time in a report timezone → epoch ms or null (rejects non-existent civil times). |
resolveReportTimeRange | Resolve preset defaultTimeRange → { from, to, usedFullRangeFallback } (ISO weeks Monday-start; full-range-to-now uses optional extent). |
canonicalJsonString | Deterministic JSON (stable key order) for digests / tooling |
writeCanonicalJson | The same text as canonicalJsonString, passed to a callback in pieces, so a large value can be hashed without building it as one string |
isUuidV4 | UUID checks |
| Reserved display-name helpers | Guard push artifact naming prefixes |
Error codes pattern
Section titled “Error codes pattern”@overvis/hmi-shared/api-errors exports publicApiErrorStatus (every public error code → the tRPC
status it is always sent with), the same codes per domain in publicApiErrorStatusTables, and
isPublicApiErrorCode. workspace-ui shows API error code X as its catalog message error_X
(apiErrorMessage) and attaches it to the form field named by details.field
(mapTrpcToFormErrors).
Conventions
Section titled “Conventions”- Entity ids are UUIDs (
format: "uuid"). - Object schemas are usually closed (
additionalProperties: false), so unknown fields fail validation. Variants are discriminated unions. - The package has no user-facing text; translations live in the UI packages.
What this package is not
Section titled “What this package is not”- Database access or migrations
- Modbus encode/decode (
@overvis/modbus) - Network connections of any kind
- translation catalogs
Sibling packages (open)
Section titled “Sibling packages (open)”| Package | Relationship |
|---|---|
@overvis/hmi-workspace-ui | Dashboard kit, UI, and host shell; imports ./app-router |
@overvis/hmi-cli | Pull/push payloads, setup database, and dashboard builds |