Skip to main content
Version: 3.0
Beta

App Studio is in release 3.0 as Beta: a paid add-on that no edition includes by default. A licence or a trial licence that includes the app_studio feature switches it on. The module is on by default, so the licence decides. This reference may change while App Studio is in Beta; the SDK changelog records each change.

Generated

Generated from the SDK sources by scripts/appstudio-sdk-docs.cjs for runtime-v1. Do not edit; run npm run appstudio:docs:sdk.

@maestrohub/sdk

Beta: look up the App Studio SDK calls an app uses to read live topics and the plant, write through declared actions and keep its own storage.

Runtime
runtime-v1
Exports
244 (103 values, 141 types)

Runtime, data, live-topic, action and storage APIs available to App Studio apps (Beta in 3.0).

Runtime: runtime-v1. 244 exports (103 values, 141 types). Import with:

import { ... } from '@maestrohub/sdk';

Hooks​

useActionPermission​

function useActionPermission(action: string): { granted: boolean; reason?: string; }

useActionPermission answers one of the manifest's declared actions for the viewer: the scope its door asks AND the viewer's own right on the bound resource (an OPC UA write the viewer may not run, a topic they may not publish to). Render the control disabled with reason from it; never hide it. Fail-closed: an action the manifest does not declare, or a shell that did not answer, is not granted. The server still checks every write; this is what the viewer is told before they press.

useAggregate​

function useAggregate(topic: string, options: AggregateOptions): ReadState<AggregateResult>

useAggregate reads a topic's values folded into time buckets (data.aggregate); needs uns:read.

useAlerts​

function useAlerts(limit?: number): AlertsState

useAlerts renders the workspace's alarm transitions as they happen (fires and clears), newest first, at most limit (default 200). Pair it with alerts.recent() for the alarms that were already active when the app opened. Needs the uns:read scope.

Example

const a = useAlerts();
return a.error ? <ErrorNotice error={a.error} /> : <Timeline items={a.events.map(e => ({ at: e.firedAt, title: e.topicPath, tone: e.cleared ? 'ok' : 'critical' }))} />;

useAppContext​

function useAppContext(): AppContextState

useAppContext returns user/workspace/theme (throws outside AppProvider).

useAttachmentUrl​

function useAttachmentUrl(collection: Collection, key: string, id: string | null): string | null

useAttachmentUrl fetches one attached photo and returns a URL an <img> can show (null while loading or for a missing file). The URL is released when the component unmounts or the file changes.

useAttachments​

function useAttachments(collection: Collection, key: string | null): AttachmentsState

useAttachments lists one stored record's files (photos, PDFs) and adds or removes them. Pass key: null while the record is not saved yet: files can only hang off a record that exists. Failures (wrong type, a file over the limit, the app's total reached) reject from add with an ApiError whose message says why; show it.

useClock​

function useClock(): AppClock

useClock is the clock the app shows: the workspace's time zone (or the viewer's own when the workspace sets none, timeZoneSource: "viewer") and the viewer's locale. Times are stored in UTC; this is how they are read. formatDateTime, dayWindow and sinceClock use the same clock.

Example

const clock = useClock();
<Text>Plant time ({clock.timeZone})</Text>

useConnection​

function useConnection(): ConnectionState

useConnection is the live connection as a whole: "live", or "reconnecting" since the moment it dropped. A kiosk shows it, so a value on the wall is never mistaken for a live one (see ConnectionNotice in @maestrohub/app-ui, and stale on useTopic).

useContract​

function useContract(topic: string): ReadState<TopicContract | null>

useContract reads a topic's contract by path (data.contract): its type, unit and bounds, answered from the topic's meaning; data is null for an untyped topic. Needs uns:read.

useEventCount​

function useEventCount(topic: string, options: EventCountOptions): ReadState<EventCountResult>

useEventCount reads how many times a condition held or began, per bucket (data.eventCount).

useExecutionStream​

function useExecutionStream(pipelineId: string, limit?: number): ExecutionStreamState

useExecutionStream renders one pipeline's live run events as they happen: execution start and finish plus per-node progress, newest first, at most limit (default 200). Needs pipelines:read (pipelines:execute carries it). Pair it with the executions read API for history: only manual and API-submitted runs stream live; scheduled and message-triggered runs don't emit these events. An empty pipelineId renders an idle stream ('closed', no error) so a not-yet-bound template stays honest.

Example

const run = useExecutionStream(pipelineId);
return run.error ? <ErrorNotice error={run.error} /> : <Timeline items={run.events.map((e) => ({ at: e.endedAt ?? e.startedAt ?? '', title: e.type, tone: e.type === 'execution.failed' ? 'critical' : 'ok' }))} />;

useFunction​

function useFunction(action: string, target: { connectionId: string; functionId: string; }): FunctionState

useFunction runs one declared connector-function action from a component: action is its manifest "actions" name (what may this viewer do, and why not), target the bound function. A failed call is an error like any refusal: render it with <ErrorNotice error={fn.error} />.

useHistory​

function useHistory(topic: string, options: HistoryOptions): ReadState<RangeResult>

useHistory reads a topic's stored values over a window (data.range); needs uns:read. For live values use useTopic.

usePendingWrites​

function usePendingWrites(): PendingWrites

usePendingWrites lists the records waiting to be sent while the connection is down, oldest first. Show the count: a record that waits has not reached MaestroHub yet.

Example

const pending = usePendingWrites();
{pending.count > 0 && <Badge tone="warn">{pending.count} waiting to send</Badge>}

usePeople​

function usePeople(options?: PeopleSearch): ReadState<PeoplePage>

usePeople lists who can open this app (people.search), re-read when the search changes. Debounce a typed search before passing it in.

usePermission​

function usePermission(scope: string): { granted: boolean; reason?: string; }

usePermission reports whether the current VIEWER holds a scope the app's manifest requested, the FR-29/42 data every bound actionable control renders its state from. Unknown scope → not granted, with a reason (fail closed, and the UI still explains itself).

usePersonPicture​

function usePersonPicture(person: Pick<Person, "kind" | "id" | "has_picture"> | null | undefined): string | null

usePersonPicture returns a URL an <img> can show for a person's picture, or null (no picture, a group, or still loading); show initialsOf(person) then. The URL is released on unmount or when the person changes.

usePipelineRun​

function usePipelineRun(action: string, target: { pipelineId: string; nodeId: string; cancelAction?: string; }): PipelineRunState

usePipelineRun runs one declared pipelines.submit action from a component and waits for the run: action is its manifest "actions" name, target the bound pipeline's manual-trigger node. The sibling of useFunction: render the outcome with <ErrorNotice error={run.error} />.

useRatio​

function useRatio(options: RatioOptions): ReadState<RatioResult>

useRatio reads one topic folded over another per bucket (data.ratio): yield, availability, any good/total KPI.

useStateDuration​

function useStateDuration(topic: string, options: StateDurationOptions): ReadState<StateDurationResult>

useStateDuration reads how long a state topic spent in each state (data.stateDuration).

useTopic​

function useTopic(topic: string): TopicState

useTopic renders the latest value on a topic; status/error explain the gaps.

Example

const t = useTopic('plant/line1/oee');
return t.error ? <ErrorNotice error={t.error} /> : <MetricCard label="OEE" value={t.value ?? '—'} />;

useTopics​

function useTopics(paths: string[]): TopicsState

useTopics is useTopic for many topics at once, on the same single socket: a scene of six stations with four signals each binds 24 topics, and hooks cannot be called in a loop whose length changes. Returns a state per path (missing paths read as connecting). A new array with the same paths, in any order, changes nothing; a changed set subscribes and unsubscribes only the difference. A burst of messages renders once per frame (about 16 ms), not once per message.

Example

const t = useTopics(stations.map((s) => s.stateTopic));
const state = t[stations[0].stateTopic]?.value;

Components​

AppProvider​

function AppProvider({ children }: { children: ReactNode; }): JSX.Element

AppProvider connects the React tree to the bridge state. When the shell disables the app mid-session (kill switch, FR-21) it also covers the whole frame: a read-only wall dashboard must not keep showing stale numbers behind a token that no longer exists. Plain inline styles: the SDK does not depend on @maestrohub/app-ui.

Functions​

ago​

function ago(iso?: string | null): string

ago renders how long ago an ISO-8601 instant was ("12s ago", "3m ago", "2h ago") and "—" when there is no instant.

apiFetch​

function apiFetch<T = unknown>(path: string, init?: RequestInit): Promise<T>

apiFetch calls a platform API path (e.g. "/api/v1/uns/topics") with the current app token. Throws ApiError on refusals, including the case the UI should treat as "render disabled-with-reason", a 403 INSUFFICIENT_SCOPE.

apiFetchBlob​

function apiFetchBlob(path: string, init?: RequestInit): Promise<Blob>

apiFetchBlob is apiFetch for a binary answer (an attachment download): the same token, headers and refusals, and the body comes back as a Blob.

clockFor​

function clockFor(workspaceZone?: string): AppClock

clockFor is the one rule for an app's clock, used by the shell that hands it over and by the SDK when no shell did: the workspace's zone when it sets one, else the viewer's browser zone; the viewer's browser language for numbers and dates.

dayWindow​

function dayWindow(daysAgo?: number, timeZone?: string): ClockWindow

dayWindow is a calendar day in the app's clock as UTC instants: "today" in Istanbul starts at 21:00Z the day before. daysAgo 0 is today, 1 yesterday. Today's window ends now.

Example

const { start, end } = dayWindow();          // today, plant time
data.range({ topic, start, end });

fmt​

function fmt(n: unknown, digits?: number): string

fmt renders a number for a tile or a cell: integers as they are, anything else with digits decimals (default 1), and "—" for anything that is not a finite number.

formatDateTime​

function formatDateTime(at: When | null | undefined, options?: FormatDateTimeOptions): string

formatDateTime writes an instant in the app's clock and locale: "15.10.2026 08:00" for a Turkish viewer of an Istanbul workspace, the same instant a UTC kiosk would otherwise show as 05:00. "—" when there is no instant.

Example

formatDateTime(entry.event.at)            // "15.10.2026 08:00"
formatDateTime(row.ts, { show: 'time' }) // "08:00"

formatNumber​

function formatNumber(n: unknown, digits?: number, options?: FormatNumberOptions): string

formatNumber writes a number in the viewer's locale ("1.234,5" for a Turkish or German viewer) with digits decimals at most (default 1), exactly digits with pad, as a percentage of a ratio with percent; "—" for anything that is not a finite number.

formatNumberish​

function formatNumberish(value: Numberish, options?: FormatNumberishOptions): string

Locale-format a number: toLocaleString(locale, options) for both kinds. The same rules apply to a 19-digit ExactNumber as to any number (the locale's grouping and decimal mark, the fraction rounded to maximumFractionDigits), but its digits never pass through a double: 1729600000000000001 reads 1,729,600,000,000,000,001 (see ExactNumber.toLocaleString).

fractionDigits​

function fractionDigits(digits: unknown, fallback?: number): number

fractionDigits is the decimals count every kit number formatter uses: digits as a whole number in Intl's and toFixed's common range (0 to 20). A numeric string from JSON config ("2") counts as its number; anything else unreadable is fallback (default 1). Clamped, never thrown: a bad digits must not take a Table down during render.

initialsOf​

function initialsOf(p: Pick<Person, "kind" | "name">): string

Up to two initials for an avatar without a picture ("?" when there is no name).

isConfirmationRequired​

function isConfirmationRequired(err: unknown): err is ApiError

isConfirmationRequired: the platform wants the viewer's confirmation first.

isExactNumber​

function isExactNumber(value: unknown): value is ExactNumber

True for an ExactNumber (a number a double cannot hold, kept with every digit), from any copy of this module. typeof cannot tell: it says 'object'.

isNumberish​

function isNumberish(value: unknown): value is Numberish

True for a number or an ExactNumber: every value JSON wrote as a number.

isRateLimited​

function isRateLimited(err: unknown): err is ApiError & { status: 429; }

isRateLimited: the platform refused because this app (all of its viewers together) exceeded its request budget. Back off for retryAfterSeconds; prefer useTopic/useTopics for live values instead of polling REST.

labelOf​

function labelOf(p: Pick<Person, "kind" | "name">): string

What a picker shows for an entry: its name, or a label when it has none.

mountApp​

function mountApp(App: React.ComponentType): void

mountApp is the boot contract: the served document loads boot.mjs, which imports the app's default component and calls this. The bridge handshake completes BEFORE first render, so hooks never see a half-connected state; uncaught errors report to the shell (NR-3/FR-8), and a render error shows AppCrashBoundary's panel, not a blank frame.

num​

function num(value: unknown, field?: string): number | null

num reads the numeric reading out of a topic value (a number, a numeric string, or an object carrying one under field (default "value"), the shapes a UNS record's value takes depending on how the connector published it. null when there is no number.

parseJson​

function parseJson<T = unknown>(text: string): T

JSON.parse that keeps every digit. Throws JSON.parse's SyntaxError on invalid input.

parsePayload​

function parsePayload(raw: string): Pick<TopicMessage, "value" | "timestamp" | "quality" | "source">

parsePayload mirrors the shell's data explorer: enriched envelope → value; JSON → parsed; else raw.

print​

function print(options?: PrintOptions): Promise<void>

print opens the browser's print dialog for this app (paper or Save as PDF). It resolves when the dialog closes. Call it from a click.

sinceClock​

function sinceClock(hhmm: string, timeZone?: string): ClockWindow

sinceClock is the last time the app's clock read hh:mm (today if it has passed, else yesterday), until now: the window of a shift that started at 06:00 plant time.

Example

const shift = sinceClock('06:00');

stringifyJson​

function stringifyJson(value: unknown, replacer?: Replacer | null, space?: string | number): string

JSON.stringify that writes an ExactNumber as a JSON number with every digit. Everything else (strings and their escaping, toJSON, undefined and functions dropped from objects and nulled in arrays, Dates, the replacer and indentation) is JSON.stringify's own: an ExactNumber is swapped for a placeholder string, which is then replaced by its digits.

subjectOf​

function subjectOf(p: Pick<Person, "kind" | "id">): string

The address notifications.notify({ to }) takes: "user:<id>" or "group:<id>".

subscribeTopic​

function subscribeTopic(topic: string, onMessage: (m: TopicMessage) => void, onError?: (e: LiveError) => void): () => void

subscribeTopic delivers the topic's last stored value (seeded), then every value published on topic, until the returned function is called. Refusals (missing scope, topic outside the viewer's access, app disabled) arrive on onError with a reason and a remediation, never as silence.

viewerClock​

function viewerClock(): AppClock

The viewer's browser zone and language: what is used when the shell says nothing.

Classes​

ApiError​

class ApiError extends Error
new ApiError(status: number, code: string, message: string, details?: unknown, retryAfterSeconds?: number, remediation?: string): ApiError

ApiError carries the platform's flat {code, message, details?} refusal shape. details is what a refusal hands back for the caller to act on (a storage 409 carries the winning document there).

Members

  • readonly code: string
  • readonly details?: unknown
  • readonly remediation?: string | undefined: The platform's own "what to do instead": every refusal body carries one (rule 36).
  • readonly retryAfterSeconds?: number | undefined: Seconds the platform asked us to wait (429 APP_RATE_LIMITED, Retry-After).
  • readonly status: number

ConflictError​

class ConflictError<T = unknown> extends Error
new ConflictError<T = unknown>(current: StoredDocument<T> | null): ConflictError<T>

Thrown when a CAS write cannot converge; carries the winner's document.

Members

  • readonly current: StoredDocument<T> | null

DownloadRefusedError​

class DownloadRefusedError extends Error
new DownloadRefusedError(reason: string): DownloadRefusedError

DownloadRefusedError is what bridge.download rejects with when the file could not be handed to the viewer, locally (over MAX_DOWNLOAD_CHARS) or by the shell (download_refused). .reason is the human-readable explanation the app should show (rule 36).

Members

  • readonly reason: string

ExactNumber​

class ExactNumber
new ExactNumber(text: string): ExactNumber

A JSON number a double cannot hold, with every digit: String(x) and x.text are the digits as received, Number(x) the nearest double, x.toFixed(n) / x.toLocaleString() format the digits, and arithmetic and comparisons use the nearest double. It is an object, so typeof x === 'number' and Number.isFinite(x) are false: detect one with isExactNumber(x) (or accept both kinds with isNumberish(x)), and take Number(x) where a plain number is needed.

Members

  • isInteger: () => boolean: Is the number whole (no non-zero fraction digit)? Number.isInteger for an ExactNumber.
  • static of: (text: string) => number | ExactNumber: Wrap a JSON number token. Throws on anything that is not one. Returns the token's double instead when the double holds it exactly, so callers never hold an ExactNumber for a number a plain number represents.
  • readonly text: string: The number as written in JSON: a valid JSON number token.
  • toFixed: (digits?: number) => string: Number.prototype.toFixed: rounded to digits fraction digits (half away from zero, as decimal arithmetic rounds), every integer digit kept, no grouping.
  • toJSON: () => string: Native JSON.stringify writes the digits as a string (see the header).
  • toLocaleString: (locales?: string | string[], options?: Intl.NumberFormatOptions) => string: Number.prototype.toLocaleString for the decimal style: minimumFractionDigits, maximumFractionDigits (default 3, as Intl's) and useGrouping are honoured exactly: the integer digits grouped by Intl.NumberFormat over a BigInt, so the locale's own grouping applies (12,34,567 in en-IN) and no digit passes through a double. Any other option (currency, percent, compact or significant digits) has no exact form here and formats the nearest double.
  • toNumber: () => number: The nearest double: what Number(x) returns.
  • toString: () => string: The digits as received.
  • valueOf: () => number

FunctionFailedError​

class FunctionFailedError extends ApiError
new FunctionFailedError(input: ExecuteFunctionInput, result: ExecuteFunctionResult): FunctionFailedError

FunctionFailedError is what connectors.run and useFunction throw or hold when the platform let the call through and the device or service answered with a failure (success: false: a PLC refusing a write, a query error). An ApiError, so <ErrorNotice> and existing catch blocks render it: .message is the device's error, .result the whole answer.

Members

  • readonly connectionId: string
  • readonly functionId: string
  • readonly result: ExecuteFunctionResult

Label​

class Label
new Label(opts: LabelOptions): Label

A label being built; every method returns the label, toString() the ZPL.

Members

  • barcode: (xMm: number, yMm: number, value: string, options?: BarcodeOptions) => Label: A Code 128 barcode.
  • box: (xMm: number, yMm: number, widthMm: number, heightMm: number, options?: BoxOptions) => Label: A rectangle outline (or a line when one side is 0).
  • copies: (n: number) => Label: Print this many copies (1 to 999, default 1).
  • qr: (xMm: number, yMm: number, value: string, options?: QrOptions) => Label: A QR code (error correction M).
  • text: (xMm: number, yMm: number, value: string, options?: TextOptions) => Label: A line (or wrapped block) of text in the printer's scalable font.
  • toString: () => string: The label as ZPL, from ^XA to ^XZ, UTF-8 (^CI28).

PipelineRunError​

class PipelineRunError extends ApiError
new PipelineRunError(code: string, executionId: string, message: string, remediation: string): PipelineRunError

PipelineRunError is what pipelines.run rejects with when the run it started failed, was cancelled, or outlasted the wait. An ApiError, so <ErrorNotice> renders it; .executionId names the run.

Members

  • readonly executionId: string

Constants​

ALERTS_FEED​

const ALERTS_FEED: "alerts"

The pseudo-topic the alarm feed reports under in LiveError.topic.

BASE_CSS​

const BASE_CSS: string

The base stylesheet (installed once, by mountApp).

CODE_ACTION_NOT_DECLARED​

const CODE_ACTION_NOT_DECLARED: "ACTION_NOT_DECLARED"

ApiError.code when an app-token request hits one of the three write doors (publish, connector execute, pipeline submit) without a matching declared action in the app's manifest. The fix is a manifest change and a republish, not a retry.

CODE_APPROVAL_REQUIRED​

const CODE_APPROVAL_REQUIRED: "APPROVAL_REQUIRED"

ApiError.code when the matched manifest action is on the "approval" rung: the write guard refuses direct calls to it, so such an action only runs through a pipeline with an approval gate.

CODE_CONFIRMATION_REQUIRED​

const CODE_CONFIRMATION_REQUIRED: "CONFIRMATION_REQUIRED"

ApiError.code when the platform's write guard requires the viewer's confirmation for a rung-"confirm" action and the request carried no confirmed-at assertion. Retry the same call with { confirmed: true } from the confirmed click; isConfirmationRequired checks for it.

CODE_FUNCTION_FAILED​

const CODE_FUNCTION_FAILED: "FUNCTION_FAILED"

The code a FunctionFailedError carries.

CODE_OFFLINE​

const CODE_OFFLINE: "OFFLINE"

ApiError.code when a write was not sent because the connection to MaestroHub is down. Nothing was done; the same action may be tried again once it is back.

CODE_PIPELINE_RUN_CANCELLED​

const CODE_PIPELINE_RUN_CANCELLED: "PIPELINE_RUN_CANCELLED"

... when the run was cancelled.

CODE_PIPELINE_RUN_FAILED​

const CODE_PIPELINE_RUN_FAILED: "PIPELINE_RUN_FAILED"

The code a PipelineRunError carries when the run failed.

CODE_PIPELINE_RUN_TIMEOUT​

const CODE_PIPELINE_RUN_TIMEOUT: "PIPELINE_RUN_TIMEOUT"

... when the run outlasted timeoutMs (it goes on running).

CODE_RATE_LIMITED​

const CODE_RATE_LIMITED: "APP_RATE_LIMITED"

CODE_RATE_LIMITED: the app's per-workspace fair-use budget is spent (429).

FALLBACK_COLOURS​

const FALLBACK_COLOURS: Record<"light" | "dark", FallbackColours>

The fallback colours per mode. The one copy: the UI kit's palette builds on these, so a plain element and a kit component agree when the shell sent no tokens.

Members

  • dark: FallbackColours
  • light: FallbackColours

MAX_DOWNLOAD_CHARS​

const MAX_DOWNLOAD_CHARS: 20000000

The size cap (in characters) on a download message's content. bridge.download / bridge.requestDownload refuse locally above it, and the shell (AppFrameHost) answers download_refused with the same limit for anything that slips through.

MAX_OPEN_FILE_BYTES​

const MAX_OPEN_FILE_BYTES: number

The size cap (in bytes) on an open_file message's data.

MAX_SCREEN_CHARS​

const MAX_SCREEN_CHARS: 8000

The cap (in characters) on a screen message's text; the server keeps the same (application.MaxScreenChars).

const PRINT_CSS: "\n.mh-print-only { display: none !important; }\n@media print {\n  @page { margin: 12mm; }\n  html, body { background: #fff !important; }\n  .mh-no-print { display: none !important; }\n  .mh-print-only { display: block !important; }\n  .mh-page-break { break-before: page; }\n  .mh-keep-together { break-inside: avoid; }\n}\n"

The print stylesheet (installed once, by mountApp and by print()).

PROTOCOL_VERSION​

const PROTOCOL_VERSION: 1

The bridge schema version stamped as v on every message in both directions. The app-side bridge ignores any shell message whose v differs, and the shell does the same for app messages.

SCOPE_ALERTS_ACK​

const SCOPE_ALERTS_ACK: "alerts:ack"

The scope alerts.ack needs; guard its button with usePermission(SCOPE_ALERTS_ACK).

SCOPE_APPROVALS_DECIDE​

const SCOPE_APPROVALS_DECIDE: "approvals:decide"

The scope approvals.approve / approvals.reject need; guard their buttons with it.

SCOPE_APPROVALS_READ​

const SCOPE_APPROVALS_READ: "approvals:read"

The scope the approvals inbox reads need (approvals:decide carries it too).

SCOPE_CONNECTORS_READ​

const SCOPE_CONNECTORS_READ: "connectors:read"

The scope connectors.catalog needs: the functions the viewer may read (never connection configs).

SCOPE_FUNCTIONS_DISCOVER​

const SCOPE_FUNCTIONS_DISCOVER: "functions:discover"

The scope connectors.execute needs for a discover-effect function (browse namespaces, enumerate operations).

SCOPE_FUNCTIONS_READ​

const SCOPE_FUNCTIONS_READ: "functions:read"

Per-effect function scopes: guard a button with the one matching the function's effect.

SCOPE_FUNCTIONS_STREAM​

const SCOPE_FUNCTIONS_STREAM: "functions:stream"

The scope connectors.execute needs for a stream-effect function (subscribe, tail, watch).

SCOPE_FUNCTIONS_WRITE​

const SCOPE_FUNCTIONS_WRITE: "functions:write"

The scope connectors.execute needs for a write-effect function (commands, tag writes, publishes).

SCOPE_PIPELINES_EXECUTE​

const SCOPE_PIPELINES_EXECUTE: "pipelines:execute"

The scope pipelines.submit needs; guard its button with usePermission(SCOPE_PIPELINES_EXECUTE).

SCOPE_PIPELINES_READ​

const SCOPE_PIPELINES_READ: "pipelines:read"

The scope the execution stream needs: pipelines:execute carries read, so an app that submits runs can also watch them land.

SCOPE_PLANT_DECIDE​

const SCOPE_PLANT_DECIDE: "proposals:decide"

The scope that lets facts land at once: with it, plant.update applies for a viewer who may decide proposals (unless the part is held to another person's approval); without it every update waits under Review.

SCOPE_PLANT_DECLARE​

const SCOPE_PLANT_DECLARE: "entities:declare"

The scope plant.declare needs.

SCOPE_PLANT_PROPOSE​

const SCOPE_PLANT_PROPOSE: "proposals:write"

The scope plant.update needs: facts are proposed as the viewer.

SCOPE_PLANT_READ​

const SCOPE_PLANT_READ: "entities:read"

The scope every plant.* read needs; guard plant panels with usePermission(SCOPE_PLANT_READ). The scope string stays entities:read, since manifests already declare it.

SCOPE_PLANT_RECORD​

const SCOPE_PLANT_RECORD: "entities:record"

The scope plant.record needs: events land in the plant's log at once.

SCOPE_UNS_PUBLISH​

const SCOPE_UNS_PUBLISH: "uns:publish"

Scope names the actions need, exported so apps guard with the same strings.

SCOPE_UNS_READ​

const SCOPE_UNS_READ: "uns:read"

The scope live subscriptions need. live.subscribe checks the viewer's grant for it before opening a socket and reports scope_missing on onError when it is absent; guard live panels with usePermission(SCOPE_UNS_READ).

alerts​

const alerts: { recent(options?: RecentAlertsOptions): Promise<AlertItem[]>; history(options?: AlertHistoryOptions): Promise<AlertHistoryItem[]>; subscribe: (sub: Parameters<typeof live.subscribeAlerts>[0]) => () => void; ack(input: AckAlertInput, options?: ActionOptions): Promise<AckAlertResult>; }

The alarm surface: recent and history read the platform's alert feed (needs uns:read, since alert visibility inherits topic read), subscribe streams transitions live (see useAlerts), and ack acknowledges one alarm through the write ladder (a declared alerts.ack action bound to an alerts binding, with its rung) and needs alerts:ack. The viewer's own alert:ack authority per topic still bounds it: an app never silences an alarm its viewer could not.

Members

  • ack: (input: AckAlertInput, options?: ActionOptions) => Promise<AckAlertResult>: Acknowledge one alarm with the viewer's authority. The answer says what it did: not_found when no active alarm carries that key.
  • history: (options?: AlertHistoryOptions) => Promise<AlertHistoryItem[]>: One topic's (or every topic's) transitions, newest first.
  • recent: (options?: RecentAlertsOptions) => Promise<AlertItem[]>: Alarms currently known to the platform (active, cleared-recently, shelved), newest first.
  • subscribe: (sub: Parameters<typeof live.subscribeAlerts>[0]) => () => void: Live transitions over the app's scoped socket (needs uns:read). See useAlerts.

approvals​

const approvals: { list(options?: ListApprovalsOptions): Promise<ListApprovalsResponse>; get(id: string): Promise<ApprovalDecision>; approve(input: DecideApprovalInput, options?: ActionOptions): Promise<ApprovalDecision>; reject(input: DecideApprovalInput, options?: ActionOptions): Promise<ApprovalDecision>; }

The approvals surface: the human decision inbox for pipeline gates. list / get read it (approvals:read; approvals:decide carries read); approve / reject decide one; the pipeline then continues with the held payload, or stops, through the write ladder (a declared approvals.decide action bound to an approvals binding, with its rung) and with the viewer's own approval:decide authority. There is no live stream for approvals; poll list gently (the inbox changes at human speed) or lean on the deadline the row carries.

Members

  • approve: (input: DecideApprovalInput, options?: ActionOptions) => Promise<ApprovalDecision>: Approve: the pipeline continues with the held payload, as the viewer.
  • get: (id: string) => Promise<ApprovalDecision>: One decision, with its payload.
  • list: (options?: ListApprovalsOptions) => Promise<ListApprovalsResponse>: The inbox, newest first; state defaults to "pending" server-side.
  • reject: (input: DecideApprovalInput, options?: ActionOptions) => Promise<ApprovalDecision>: Reject: the pipeline continues with decision=rejected, as the viewer.

bridge​

const bridge: Bridge

The module-singleton bridge: one iframe, one bridge.

Members

  • currentState: () => AppContextState | null
  • currentToken: () => string | null: currentToken returns the live bearer value or null (disabled/expired-out).
  • download: (name: string, mime: string, content: string) => Promise<void>: download is the promise form of requestDownload: it settles once the shell has had its say. Rejects with a DownloadRefusedError (carrying .reason) when the content is over MAX_DOWNLOAD_CHARS or the shell answers download_refused; resolves after DOWNLOAD_REFUSAL_WINDOW_MS without a refusal. Refusals are only received after start() has run (the listener is the handshake's); mountApp always does that.
  • openFile: (name: string, data: ArrayBuffer) => Promise<void>: openFile asks the shell to show the viewer a file (a stored photo or PDF): a new tab, or a download when the browser blocks the tab. Rejects with a DownloadRefusedError when the file is over MAX_OPEN_FILE_BYTES or the shell refuses it (it accepts JPEG, PNG, WebP and PDF, read from the bytes); resolves after the refusal window.
  • post: (msg: AppToShellMessage) => void
  • reportError: (message: string, stack?: string) => void: reportError sends an uncaught error to the shell (NR-3 / FR-8).
  • reportLiveError: (e: { code: string; reason: string; remediation?: string; topic?: string; }) => void: reportLiveError tells the shell a live subscription failed. The builder shows it next to the preview with the remediation; the Run and Kiosk hosts ignore it (the app's own UI already told the viewer).
  • reportTelemetry: (method: string, path: string, status: number, durationMs: number) => void: reportTelemetry sends one API call's timing to the shell (G7).
  • requestDownload: (name: string, mime: string, content: string) => boolean: requestDownload asks the shell to hand the viewer a file (the sandbox cannot start downloads itself). Text content only; refused (returns false) above MAX_DOWNLOAD_CHARS. Synchronous, fire-and-forget: a refusal the SHELL decides on later is logged, not returned; callers that need to react to it use download.
  • start: () => Promise<AppContextState>: start runs the handshake once; subsequent calls return the same promise.
  • subscribe: (fn: Listener) => () => void

connectors​

const connectors: { execute(input: ExecuteFunctionInput, options?: ActionOptions): Promise<ExecuteFunctionResult>; catalog(options?: CatalogOptions): Promise<CatalogFunction[]>; run(input: ExecuteFunctionInput, options?: ActionOptions): Promise<ExecuteFunctionResult>; }

The connector-function surface: execute runs a saved function on a connection with the viewer's authority (see the member docs). Rides the write ladder and needs the functions:<effect> scope of that function.

Members

  • catalog: (options?: CatalogOptions) => Promise<CatalogFunction[]>: The connector functions THIS viewer may read, for a picker (FR-41 dynamic bindings): searched in plant language, each with its effect, scope and params. Needs the connectors:read scope. Listing is not running: executing a picked function still needs a declared action.
  • execute: (input: ExecuteFunctionInput, options?: ActionOptions) => Promise<ExecuteFunctionResult>: Execute a saved connector function (an OPC UA write, a DB query, a command) with the viewer's authority. The platform resolves the function's effect and demands the matching functions:<effect> scope. Resolves with success: false when the device or service refused the call; check it. run throws instead.
  • run: (input: ExecuteFunctionInput, options?: ActionOptions) => Promise<ExecuteFunctionResult>

data​

const data: { subscribe: (topic: string, onMessage: (m: TopicMessage) => void, onError?: (e: LiveError) => void) => () => void; publish(input: PublishInput, options?: ActionOptions): Promise<PublishResult>; range(input: RangeInput): Promise<RangeResult>; aggregate(input: AggregateInput): Promise<AggregateResult>; ratio(input: RatioInput): Promise<RatioResult>; stateDuration(input: StateDurationInput): Promise<StateDurationResult>; contract(topic: string): Promise<TopicContract | null>; eventCount(input: EventCountInput): Promise<EventCountResult>; }

The UNS data surface: subscribe for live values (see subscribeTopic) and publish for one write to an existing topic (see the member docs). publish goes through the write ladder (declared action, idempotency key, in-flight lock) and needs uns:publish.

Members

  • aggregate: (input: AggregateInput) => Promise<AggregateResult>: A topic's values folded into time buckets (POST /uns/data/aggregated): one value per bucketWidth ("1m", "15m", "1h") by agg. Needs uns:read. Non-numeric samples are left out and counted (nonNumericInRange, with a remediation).
  • contract: (topic: string) => Promise<TopicContract | null>: A topic's contract, by its path (GET /uns/topics/contract): what it carries (type, unit, bounds, alert thresholds, enum values) and the shape its stored series has. Resolves null when the topic has no contract: it is untyped, or there is no such topic. Needs uns:read. Label axes and tiles with schema.unit, and draw bounds from it. Since 3.0 the contract is answered from the topic's meaning.
  • eventCount: (input: EventCountInput) => Promise<EventCountResult>
  • publish: (input: PublishInput, options?: ActionOptions) => Promise<PublishResult>: Publish one value to an existing UNS topic.
  • range: (input: RangeInput) => Promise<RangeResult>: A topic's stored values over a window, oldest first (POST /uns/data/range). Needs uns:read. Give since ("8h", "30m", "7d") or start (and end, default now). Ask for a bounded window and a limit: the platform caps the answer and says so (total vs totalInRange).
  • ratio: (input: RatioInput) => Promise<RatioResult>: One topic's fold over another's, per bucket (POST /uns/data/ratio): yield = good parts / all parts, availability = run time / planned time. Each side has its own agg. A bucket whose denominator is 0 says so (divZero). Needs uns:read.
  • stateDuration: (input: StateDurationInput) => Promise<StateDurationResult>: How long a state topic spent in each state (POST /uns/data/state-duration): mode "exact" per distinct value (run / idle / fault), "range" per labelled numeric band (ranges), "breakdown" per bucket. Needs uns:read.
  • subscribe: (topic: string, onMessage: (m: TopicMessage) => void, onError?: (e: LiveError) => void) => () => void: Live values on a topic over the app's scoped socket (needs uns:read). See subscribeTopic.

live​

const live: LiveConnection

The app's single live-data connection (one socket per runtime), shared by useTopic, subscribeTopic and data.subscribe. Call live.subscribe(topic, subscriber) directly only when you need the onStatus callback; see the LiveConnection member docs.

Members

  • alertSubscriberCount: () => number: Test seam: number of alarm-feed subscribers.
  • connection: () => ConnectionState: The connection as a whole now.
  • onConnection: (listener: (s: ConnectionState) => void) => () => void: Hear every change of the connection's state; returns the unsubscribe.
  • pipelineCount: () => number: Test seam: number of pipelines with live watchers.
  • subscribe: (topic: string, sub: TopicSubscriber) => () => void
  • subscribeAlerts: (sub: AlertSubscriber) => () => void: subscribeAlerts delivers every alarm transition in the workspace the viewer may see (alert visibility inherits topic read) until the returned function is called. Needs uns:read like a topic; refusals arrive on onError with a reason and a remediation.
  • subscribePipeline: (pipelineId: string, sub: PipelineSubscriber) => () => void: subscribePipeline delivers ONE pipeline's live execution events (execution.started/completed/failed/cancelled plus per-node progress) until the returned function is called. Gated exactly like the HTTP pipeline reads: the pipelines:read scope (pipelines:execute carries it) plus the viewer's own access to that pipeline; refusals arrive on onError with a reason and a remediation. Only manual and API-submitted runs emit events (mode 'live' | 'sandbox'); scheduled and message-triggered runs appear in the executions API.
  • topicCount: () => number: Test seam: number of topics with live subscribers.

notifications​

const notifications: { notify(input: NotifyInput, options?: ActionOptions): Promise<NotifyResult>; }

The notification surface: notify posts one notice to the person feed of THE APP'S OWN PEOPLE: its owner plus every viewer who has opened it, or, with to, the people and groups named (each one someone who can open the app; see people). The platform stamps the rest: the producer, the app-name prefix on the title, and the audience, so an app can neither impersonate the platform nor reach beyond its users. A declared manifest action (kind notifications.notify, a notifications binding, a rung), with no scope needed. Workspace channels (Slack, Teams) hear app notices only when an operator explicitly subscribes a channel to them.

Members

  • notify: (input: NotifyInput, options?: ActionOptions) => Promise<NotifyResult>: Post one notice to the app's people.

pendingWrites​

const pendingWrites: Outbox

The app's outbox; pendingWrites.flush() tries the queue now.

Members

  • current: () => PendingWrites
  • flush: () => void: Try the queue now: the connection is back, or the app asked.
  • send: <T>(label: string, run: () => Promise<T>) => Promise<T>: send runs a record write now; if it does not get through, keeps it and resolves once a later attempt does. Any other answer (a refusal, a conflict) settles the call as it is.
  • subscribe: (l: () => void) => (() => void)

people​

const people: { search(options?: PeopleSearch): Promise<PeoplePage>; picture(p: Pick<Person, "kind" | "id" | "has_picture">): Promise<Blob | null>; }

The app's people directory: search lists who can open this app (people first, then groups, by name; never an email), picture reads a person's avatar. Prefer usePeople / usePersonPicture in components.

Members

  • picture: (p: Pick<Person, "kind" | "id" | "has_picture">) => Promise<Blob | null>: Fetches a person's picture (null when they have none). The avatar route is public, like every <img> of a person on the platform; the app token is not sent.
  • search: (options?: PeopleSearch) => Promise<PeoplePage>: Lists who can open this app, people first, then groups, by name.

pipelines​

const pipelines: { submit(input: SubmitPipelineInput, options?: ActionOptions): Promise<SubmitPipelineResult>; run(input: SubmitPipelineInput, options?: RunPipelineOptions): Promise<PipelineRunResult>; cancel(executionId: string, options?: ActionOptions): Promise<CancelPipelineRunResult>; }

The pipeline surface: submit fires a pipeline's manual-trigger node with the viewer's authority (see the member docs). Rides the write ladder and needs pipelines:execute.

Members

  • cancel: (executionId: string, options?: ActionOptions) => Promise<CancelPipelineRunResult>: Ask the platform to stop a run THIS app started (by the execution id submit or run answered). Needs pipelines:execute and a declared pipelines.cancel action on the pipeline's binding. Cancelling is cooperative: the run stops at its next checkpoint, and run rejects with PIPELINE_RUN_CANCELLED when it has. A run another app, a person or a schedule started is refused (APP_RUN_NOT_STARTED_BY_APP).
  • run: (input: SubmitPipelineInput, options?: RunPipelineOptions) => Promise<PipelineRunResult>: Fire a pipeline's manual trigger and wait for the run it started: resolves when it completes, with each node's output; rejects with a PipelineRunError when it fails, is cancelled, or outlasts timeoutMs (the run itself goes on). onProgress gets the run's live events as they happen. Needs pipelines:execute, and the same declared action as submit.
  • submit: (input: SubmitPipelineInput, options?: ActionOptions) => Promise<SubmitPipelineResult>: Fire a pipeline's manual trigger with the viewer's authority.

plant​

const plant: { whatCanIAsk(): Promise<Envelope<Vocabulary>>; find(options: FindOptions): Promise<Envelope<Candidate[]>>; describe(thing: string, options?: DescribeOptions): Promise<Envelope<Described>>; walk(options: WalkOptions): Promise<Envelope<WalkedThing[]>>; numbers<T = unknown>(options: NumbersOptions): Promise<Envelope<T>>; timeline(options: TimelineOptions): Promise<Envelope<TimelineEntry[]>>; record(input: RecordEventsInput, options?: ActionOptions): Promise<Envelope<Recorded>>; update(input: UpdateFactsInput, options?: ActionOptions): Promise<Envelope<Recorded>>; declare(thing: string, mode: DeclaredMode, options?: ActionOptions & { note?: string; }): Promise<Envelope<Declared>>; }

The plant. The reads need the entities:read scope (SCOPE_PLANT_READ); the viewer's own access bounds every row, as always. Each read is one of the knowledge module's tools, answered as an Envelope: read result, and say what coverage and hidden say. Key per-machine app state by the thing's id, because a topic path renames.

Three writes, each a declared manifest action on a plant binding, with the viewer's own authority. record (events in the log, under entities:record) is an observation: it lands at once for a viewer who may record. update (facts on things, under proposals:write) changes what the model says a thing is: a change set proposed as the viewer and applied in the same call only where the app carries proposals:decide and the viewer may decide proposals; otherwise it waits under Review and the answer says why. declare (under entities:declare) says what a thing is doing (maintenance keeps its alarms quiet) and applies at once. A part held to another person's approval holds every write for them.

Members

  • declare: (thing: string, mode: DeclaredMode, options?: ActionOptions & { note?: string; }) => Promise<Envelope<Declared>>: Declare what a thing is doing (a declared plant.declare action; needs entities:declare); everything under it follows.
  • describe: (thing: string, options?: DescribeOptions) => Promise<Envelope<Described>>: One thing in full: its facts, places, identities, bindings (the topics), and with "values" what it reads now.
  • find: (options: FindOptions) => Promise<Envelope<Candidate[]>>: Things by name, by a number another system issued, or by the topic(s) they are readings of.
  • numbers: <T = unknown>(options: NumbersOptions) => Promise<Envelope<T>>: A figure for one thing or hundreds at once (the latest value, an average, time in a state, OEE), ordered when order is set: the "N machines, worst first" question. The result's shape follows the measure.
  • record: (input: RecordEventsInput, options?: ActionOptions) => Promise<Envelope<Recorded>>: Record events in the plant's log (a declared plant.record action; needs entities:record). In the log at once, or proposed where a part is held: read result.state.
  • timeline: (options: TimelineOptions) => Promise<Envelope<TimelineEntry[]>>: What happened to a thing, or what is happening now under a place: alarms, trips, work orders, shifts, calibrations.
  • update: (input: UpdateFactsInput, options?: ActionOptions) => Promise<Envelope<Recorded>>: Set facts on things (a declared plant.update action; needs proposals:write). Applied at once or proposed: read result.state.
  • walk: (options: WalkOptions) => Promise<Envelope<WalkedThing[]>>: Everything reached from a thing, down a tree (the machines under a line) or along links (what a pump feeds), with their readings when values is set.
  • whatCanIAsk: () => Promise<Envelope<Vocabulary>>: The plant's vocabulary: its sites (the roots of every tree), the trees it keeps, its types, what it measures. Ask it first.

storage​

const storage: { shared: { collection: <T>(name: string) => Collection<T>; }; user: { collection: <T>(name: string) => Collection<T>; }; }

The app's own document store: shared (one copy per workspace, CAS by default) and user (one copy per viewer), and both expose collection(name) returning a Collection. Not for plant data; see the Collection member docs for get/put/delete/list/usage.

Example

const prefs = storage.user.collection<{ unit: string }>('prefs');
await prefs.put('display', { unit: 'bar' }, (current, mine) => ({ ...current, ...mine }));

Members

  • shared: { collection: <T>(name: string) => Collection<T>; }: App-wide documents (the manifest's scope: "shared" collections).
  • user: { collection: <T>(name: string) => Collection<T>; }: Per-viewer documents (the manifest's scope: "user" collections).

zpl​

const zpl: { label(options: LabelOptions): Label; escapeField: (data: string) => string; }

The ZPL builder: zpl.label({ widthMm, heightMm, dpi? }) starts a Zebra label; send toString() to the printer through a TCP connector function (port 9100, utf8 encoding).

Members

  • escapeField: (data: string) => string
  • label: (options: LabelOptions) => Label: Starts a label of this size.

Types​

AckAlertInput​

interface AckAlertInput

Input to alerts.ack: the alarm's identity as the feed returns it (topicId + level, plus propertyId / direction when the feed carries them). The property is named by id: the platform keys an incident by id so a rename never splits it, and a name is not a key. Mirrors uns AcknowledgeAlertRequest verbatim.

Members

  • direction?: string | undefined
  • level: string
  • propertyId?: string | undefined
  • topicId: string

ActionOptions​

interface ActionOptions

Options every write action accepts.

Members

  • confirmed?: boolean | undefined: The viewer confirmed this specific invocation (rung "confirm").
  • idempotencyKey?: string | undefined: Reuse a key to retry the SAME request; omit for a fresh invocation.

ActionPermission​

interface ActionPermission

One action's answer for the viewer.

Members

  • granted: boolean
  • reason?: string | undefined

AggregateBucket​

interface AggregateBucket

One bucket (AggregatedBucketResponse).

Members

  • bucketStart: string: RFC 3339 start of the bucket.
  • count: number: Samples folded into it.
  • quality?: number | undefined
  • value: number

AggregateFn​

type AggregateFn = 'avg' | 'min' | 'max' | 'sum' | 'count' | 'avg_tw';

The fold data.aggregate applies per bucket; avg_tw is the time-weighted average.

AggregateInput​

interface AggregateInput extends ReadWindow

Input to data.aggregate.

Members

  • agg: AggregateFn
  • attribute?: string | undefined
  • bucketWidth: string: A duration: "1m", "15m", "1h".
  • end?: string | Date | undefined
  • since?: string | undefined: How far back from now: a number and a unit, s m h or d ("90s", "30m", "8h", "7d").
  • start?: string | Date | undefined
  • topic: string

AggregateOptions​

type AggregateOptions = Omit<AggregateInput, 'topic'> & {
refreshMs?: number;
};

Options for useAggregate: data.aggregate's input without the topic, plus an optional re-read period (at least 5 s).

AggregateResult​

interface AggregateResult

What data.aggregate answers (AggregatedResponse).

Members

  • agg: string
  • bucketWidth: string
  • buckets: AggregateBucket[]
  • nonNumericInRange: number: Samples left out because they are not numbers.
  • remediation?: string | undefined: How to have those samples aggregated, when some were left out.
  • topic: string
  • total: number
  • totalInRange: number

AlarmState​

interface AlarmState

A live alarm's state, as plant.timeline reports it with state set.

Members

  • acknowledged: boolean
  • acknowledged_at?: string | undefined
  • acknowledged_by_name?: string | undefined
  • active: boolean
  • active_hours: number
  • shelved: boolean
  • shelved_until?: string | undefined
  • standing: boolean
  • to_act_on: boolean

AlertEvent​

interface AlertEvent

One alarm transition from the platform's rule engine; mirrors the uns contract SchemaAlertFiredEvent (shared/contracts/uns) the socket relays as an alert.fired frame. cleared false = the alarm fired, true = it cleared.

An attribute holds one alarm at a time. A fire is the attribute's alarm from then on: when it replaces another level (critical easing to warning, warning escalating to critical, or a crossing to the other side of normal), previousLevel / previousDirection name the alarm it replaced, which has ended. A clear ends the attribute's alarm whatever its level. For the alarms open right now, read alerts.recent().

Members

  • attributePath?: string | undefined: The property's name at the transition: a label, never a key.
  • cleared: boolean
  • direction: string: "low" | "high".
  • firedAt: string: RFC3339.
  • level: string: "warning" | "critical": the threshold that tripped.
  • message?: string | undefined
  • previousDirection?: string | undefined: On a fire: the side of normal of the alarm it replaced.
  • previousLevel?: string | undefined: On a fire: the level of the alarm it replaced (now ended). Absent on a first fire and on a clear.
  • previousSeverity?: string | undefined: On a fire: the replaced alarm's operator-facing severity.
  • propertyId?: string | undefined: The alarm key's property, by id. Empty for value schemas.
  • receivedAt: number
  • recordTimestamp: string
  • schemaId: string
  • schemaName: string
  • severity: string: Operator-facing "warning" | "critical": the level's own severity, raised to "critical" when the schema marks warnings urgent. Routing and escalation read this; level says which threshold was crossed.
  • stateRevision?: number | undefined: The order of this attribute's transitions: higher is later. A topic can take data from several sources, so events can arrive out of order: sort or discard by this, not by arrival. Absent on events from older platform versions.
  • threshold: number
  • topicId: string
  • topicPath: string
  • unit?: string | undefined
  • value: number

AlertHistoryOptions​

interface AlertHistoryOptions

Options for alerts.history: one topic's transitions, newest first, before an instant.

Members

  • before?: string | undefined: RFC3339: only events before this instant.
  • limit?: number | undefined
  • topicId?: string | undefined

AlertItem​

interface AlertItem

One alarm as the platform's feed returns it; mirrors uns CurrentAlertDTO verbatim.

Members

  • acknowledgedAt?: string | undefined
  • attributePath?: string | undefined: The property's name at the last fire: a label, never a key.
  • clearedAt?: string | undefined
  • direction?: string | undefined: "low" | "high".
  • fireCount: number
  • firstFiredAt: string: RFC3339.
  • lastClearedAt?: string | undefined
  • lastFiredAt: string
  • lastRecordTs?: string | undefined
  • level: string: "warning" | "critical": the threshold that tripped.
  • message?: string | undefined
  • propertyId?: string | undefined: The alarm key's property, by id (empty for a value schema).
  • schemaId: string
  • schemaMajor: number
  • schemaMinor: number
  • schemaName: string
  • severity: string: Operator-facing "info" | "warning" | "critical".
  • shelvedAt?: string | undefined
  • shelvedBy?: string | undefined
  • shelvedUntil?: string | undefined
  • threshold: number
  • topicId: string
  • topicPath: string
  • unit?: string | undefined
  • value: number
  • workspaceId: string

AlertSubscriber​

interface AlertSubscriber

Callbacks handed to live.subscribeAlerts; useAlerts builds one for you.

Members

  • onError?: ((e: LiveError) => void) | undefined
  • onEvent: (e: AlertEvent) => void
  • onStatus?: ((s: LiveStatus) => void) | undefined

AlertsState​

interface AlertsState

What useAlerts returns: the latest transitions (newest first) plus the feed's status.

Members

  • error: LiveError | null
  • events: AlertEvent[]
  • status: LiveStatus

AppClock​

interface AppClock

The clock an app shows: the zone, where it came from, and the locale numbers and dates are written in.

Members

  • locale: string: A BCP 47 tag, such as "tr-TR" or "en-US": the viewer's browser language.
  • timeZone: string: An IANA zone name, such as "Europe/Istanbul".
  • timeZoneSource: "workspace" | "viewer": "workspace": the workspace's own clock. "viewer": none is set, so the viewer's browser zone is used.

AppContextState​

interface AppContextState

What the shell told the app about its viewer, as read by useAppContext and bridge.currentState. Built from the context message; theme follows later theme pushes and disabled is set by a disable push.

Members

  • actions?: Record<string, ActionPermission> | undefined: Per declared action: may this viewer do it; useActionPermission reads these. Undefined on a shell that predates it.
  • canEditApp: boolean: The viewer may edit this app: gate curation UI on it (writers: "editors" collections).
  • clock?: AppClock | undefined: The clock the shell handed over; absent on an older shell (read it through useClock, which falls back to the viewer's).
  • disabled?: string | undefined: Set once the shell disabled the app; carries the notice to show. The token is dropped at the same time.
  • permissions: Record<string, { granted: boolean; reason?: string; }>: Per-scope grant results; usePermission reads these.
  • theme: ThemeState: The shell's current theme mode.
  • user: { id: string; displayName: string; }: The viewer's id and display name.
  • workspace: { id: string; slug: string; }: The workspace the app runs in.

AppToShellMessage​

type AppToShellMessage = HelloMessage | ReadyMessage | ErrorMessage | TelemetryMessage | DownloadMessage | OpenFileMessage | LiveErrorMessage | ScreenMessage;

Every message the app posts to the shell: hello (handshake start), ready (handshake done), error (uncaught error), telemetry (one API call's timing), download (hand the viewer a file), open_file (show the viewer a stored attachment), live_error (a live-data subscription failed, for the builder) and screen (what the app shows, for the builder). Discriminated on type.

ApprovalDecision​

interface ApprovalDecision

One pending or decided approval; mirrors the engine's DecisionResponse verbatim.

Members

  • createdAt: string
  • deadline: string: RFC3339: the gate expires by itself after this.
  • decidedAt?: string | undefined
  • decidedBy?: string | undefined
  • decisionNote?: string | undefined
  • freshUntil?: string | undefined
  • id: string
  • kind: string: Apps see "pipeline_gate" only; the agent-writes surface is not exposed.
  • nodeId: string
  • payload?: unknown: The held upstream data: exactly what continues on approve.
  • pipelineId: string
  • pipelineName?: string | undefined
  • reason?: string | undefined
  • requestedBy?: string | undefined
  • signature: string
  • sourceExecutionId?: string | undefined
  • state: string: "pending" | "approved" | "rejected" | "expired" | "executed".
  • title: string
  • verdictOutcome?: string | undefined: "queued" once the scheduler has the run; "run_failed" when that run never started, "undeliverable" when it never can be (verdictWaiting says why).
  • verdictPending?: boolean | undefined: The verdict is recorded but not yet confirmed queued to the pipeline.
  • verdictWaiting?: string | undefined: Why a pending verdict is not moving, when it is not (e.g. no scheduler serving).

Attachment​

interface Attachment

One file attached to a stored record, as the attachments API returns it.

Members

  • content_type: string: Read from the bytes: image/jpeg, image/png, image/webp, application/pdf, or model/gltf-binary for a .glb 3D model.
  • created_at: string: RFC3339 instant it was attached.
  • created_by: string: The user who attached it.
  • id: string: The file's id; pass it to blob, open and remove.
  • name: string: The file name the app sent, without any folder part.
  • size_bytes: number: Size in bytes.

AttachmentUsageInfo​

interface AttachmentUsageInfo

What Collection.attachmentUsage returns: the app's attachment total across every record.

Members

  • cap_bytes: number: The app's total; an upload that would exceed it is refused with a 413 ATTACHMENT_QUOTA_EXCEEDED.
  • file_count: number: Number of files the app stores.
  • max_file_bytes: number: The largest single photo or PDF; a bigger one is refused with a 413 ATTACHMENT_TOO_LARGE.
  • max_model_bytes: number: The largest single 3D model (.glb); a bigger one is refused with a 413 ATTACHMENT_TOO_LARGE.
  • total_bytes: number: Bytes used by them.

Attachments​

interface Attachments

The files of one stored record, from collection.attachments(key). Save the record first: attaching to a key with no document is a 404 ATTACHMENT_RECORD_MISSING. Deleting the record deletes its files. Accepted, read from the bytes: JPEG, PNG, WebP, PDF, and binary glTF 2.0 models (.glb, uncompressed); anything else is a 415 ATTACHMENT_TYPE_NOT_ALLOWED. At most 50 per record.

Members

  • add: (file: Blob, name?: string) => Promise<Attachment>: Attaches a file (a File from an input, or any Blob); name defaults to the File's name.
  • blob: (id: string) => Promise<Blob>: The file's bytes; URL.createObjectURL on it renders a photo in an <img>.
  • list: () => Promise<Attachment[]>: The record's files, oldest first (metadata only).
  • open: (id: string, name?: string) => Promise<void>: Shows the viewer the file in a new tab (a download when the browser blocks the tab).
  • remove: (id: string) => Promise<void>: Removes one file; resolves even if it was already gone.

AttachmentsState​

interface AttachmentsState extends ReadState<Attachment[]>

What useAttachments holds: the record's files, plus add/remove/open that re-read the list.

Members

  • add: (file: Blob, name?: string) => Promise<Attachment>: Attaches a file (e.g. from <input type="file" accept="image/*,application/pdf" capture>), then re-reads.
  • busy: boolean: True while an add or remove is in flight.
  • data?: Attachment[] | undefined
  • error?: unknown
  • loading: boolean
  • open: (id: string, name?: string) => Promise<void>: Shows the viewer one file in a new tab.
  • refresh: () => void: Read again now (the window is recomputed: a since window moves to now).
  • remove: (id: string) => Promise<void>: Removes one file, then re-reads.

BarcodeOptions​

interface BarcodeOptions

Options for Label.barcode (Code 128).

Members

  • heightMm?: number | undefined: Bar height (default 12 mm).
  • humanReadable?: boolean | undefined: Print the value under the bars (default true).
  • moduleDots?: number | undefined: Narrow bar width in dots, 1 to 10 (default 2).

Binding​

interface Binding

A binding: which series carries one property of a thing.

Members

  • id: string
  • property_id: string
  • series: { kind: string; ref: string; workspace_id?: string; }: kind "uns" and ref the topic path, THE way from a thing to its live data.
  • thing_id: string
  • unit?: string | undefined

BoxOptions​

interface BoxOptions

Options for Label.box.

Members

  • thicknessMm?: number | undefined: Line thickness (default 0.5 mm).

CancelPipelineRunResult​

interface CancelPipelineRunResult

What the engine answers a cancel with (cancelExecutionResponse): the stop is requested, not yet done.

Members

  • executionId: string
  • message: string
  • status: string: 'cancel_requested': the run stops at its next checkpoint.

Candidate​

interface Candidate

plant.find: one thing that answers.

Members

  • name: string
  • physical_place?: string | undefined: Where it sits in the physical tree, in words.
  • property?: string | undefined
  • reading?: Reading | undefined
  • site: string
  • thing: string
  • topic?: string | undefined: With topic / topics: the topic the row answers for, and the property it is bound to.
  • type?: string | undefined

CatalogFunction​

interface CatalogFunction

One connector function the viewer may read (GET /appstudio/catalog/functions, application.FunctionMatch; field names as the server sends them).

Members

  • connection_id: string
  • connection_name: string
  • connection_type: string
  • description?: string | undefined
  • effect: string: read | write | stream | discover; '' = unclassified, which no app may execute.
  • function_type: string
  • id: string
  • name: string
  • params_schema?: Record<string, unknown> | undefined: JSON schema of the params connectors.execute takes for it.
  • scope: string: The manifest scope executing it needs (functions:<effect>); '' when none can.

CatalogOptions​

interface CatalogOptions

Input to connectors.catalog.

Members

  • limit?: number | undefined: Default 20, at most 50.
  • query?: string | undefined: Plant-language words ("furnace line 3"); empty lists all.

ClockWindow​

interface ClockWindow

A period as two UTC instants, ready for a read (data.range, plant.timeline).

Members

  • end: string: RFC 3339, UTC.
  • start: string: RFC 3339, UTC.

Collection​

interface Collection<T = unknown>

A handle on one declared storage collection, from storage.shared.collection(name) or storage.user.collection(name). Every method is one or more apiFetch calls to /api/v1/appstudio/storage/<collection>; an undeclared collection is a 404.

Members

  • attachmentUsage: () => Promise<AttachmentUsageInfo>: The app's attachment total, its cap, and the largest file allowed.
  • attachments: (key: string) => Attachments: The files (photos, PDFs) of one stored record; see Attachments.
  • delete: (key: string) => Promise<void>: Removes a document; resolves even if it was already gone.
  • get: (key: string) => Promise<StoredDocument<T> | null>: Returns null when absent.
  • list: (opts?: ListOptions) => Promise<ListPage<T>>: One page of documents; follow next_cursor for more.
  • readonly name: string: The collection name the handle was made for.
  • put: (key: string, value: T, merge?: (current: T | null, mine: T) => T) => Promise<StoredDocument<T>>: Writes a value. On a CAS collection: merges onto the current document via merge (default: replace) and retries until it lands or MAX_CAS_ATTEMPTS is hit. On a last-write-wins collection: one write.
  • usage: () => Promise<UsageInfo>: Document count, bytes used and the cap for this collection's scope.

ConnectionState​

interface ConnectionState

The app's live connection as a whole (D7), for a kiosk that must say when what it shows stopped being live. since is when it entered the state (ms since epoch): for "reconnecting", when the connection dropped, so "values as of 08:03" is honest.

Members

  • since: number
  • state: "connecting" | "live" | "idle" | "reconnecting" | "disabled": idle: nothing subscribed. connecting: the first connect. live: values arrive. reconnecting: dropped, being retried. disabled: the shell disabled the app.

ContextMessage​

interface ContextMessage

Shell → app: identity, per-scope grant results, theme, and the token.

Members

  • actions?: Record<string, ActionPermission> | undefined: Per declared action (manifest "actions"): may this viewer do it, and if not why: the scope AND the viewer's own right on the bound resource (FR-42 b). What useActionPermission renders from. Every declared action is answered; absent on a shell that predates it.
  • canEditApp?: boolean | undefined: The viewer holds app:update on this app (a "keeper": App Data Authority R1): editor-only affordances render enabled from it. The platform re-checks server-side on every write.
  • clock?: AppClock | undefined: The clock the app shows (D6): the workspace's time zone, or the viewer's own when the workspace sets none, and the viewer's locale. Absent on a shell that predates it; the SDK then uses the viewer's.
  • permissions: Record<string, { granted: boolean; reason?: string; }>: Per-scope grant results from the token exchange (granted + denied_scopes), which is what usePermission renders disabled-with-reason from (FR-29/42).
  • reportScreen?: boolean | undefined: The builder asks for screen reports: the preview's visible text, which an AI client building the app reads through run_report. Set by the builder's preview only; a published app never sends them.
  • theme: ThemeState
  • token: TokenPayload
  • type: "context"
  • user: { id: string; displayName: string; }
  • v: 1
  • workspace: { id: string; slug: string; }

DataRecord​

interface DataRecord

One stored value (DataRecordResponse).

Members

  • id: string
  • quality?: number | undefined: OPC-style quality; absent when good.
  • qualityReason?: string | undefined
  • retain: boolean
  • timestamp: string: RFC 3339.
  • value: unknown

DecideApprovalInput​

interface DecideApprovalInput

Input to approvals.approve / approvals.reject.

Members

  • id: string: The decision's id, from the inbox.
  • note?: string | undefined: Recorded beside the verdict; the decider is always the viewer.

Declared​

interface Declared

What plant.declare did: the declaration, and how far it reaches.

Members

  • by: string
  • cleared?: { id: string; thing: string; mode: string; since: string; until?: string; by?: string; note?: string; } | undefined: The declaration this one replaced on the thing.
  • covers: number: How many things it reaches, itself included.
  • mode: DeclaredMode
  • name: string
  • note?: string | undefined
  • overridden?: number | undefined
  • since: string
  • thing: string
  • topics: number: How many uns topics bound to them fall quiet (or wake, for running).

DeclaredMode​

type DeclaredMode = 'running' | 'maintenance' | 'changeover' | 'stopped';

The modes plant.declare names: running clears a declaration.

DescribeOptions​

interface DescribeOptions

What plant.describe may bring beyond the thing itself.

Members

  • as_of?: string | undefined: The thing as it was at an instant, RFC3339.
  • include?: ("running" | "values" | "links" | "ended" | "missing" | "brief")[] | undefined: "values" for what it reads now, "links" for its links, "missing" for recorded absences.
  • property?: string | undefined: Narrow the readings to one property.

Described​

interface Described

plant.describe: one thing in full.

Members

  • bindings?: Binding[] | undefined: The series bound to it: series.ref is the topic path for live values.
  • declared?: InForce | undefined
  • documents?: string[] | undefined
  • facts?: Record<string, FactValue> | undefined
  • identities?: Identity[] | undefined
  • links?: DescribedLink[] | undefined
  • parts?: string[] | undefined
  • places?: Record<string, string> | undefined: Where it sits, in every tree that holds it, keyed by the tree kind (physical, location, floc, …).
  • readings?: Reading[] | undefined: With include "values": what it reads now.
  • thing: Thing
  • type_chain?: string[] | undefined: Its type and every type it extends, nearest first.
interface DescribedLink

A link on a thing, named from the thing's side.

Members

  • link: string
  • name: string
  • other: string
  • other_name: string
  • other_site?: string | undefined
  • since: string
  • until?: string | undefined

DisableMessage​

interface DisableMessage

Shell → app: kill switch / unshare: drop the token, show the notice.

Members

  • message: string
  • type: "disable"
  • v: 1

DownloadMessage​

interface DownloadMessage

App → shell: hand the viewer a file (G1 export). The sandbox has no allow-downloads, so a download started inside the iframe is inert; the shell materialises it. Text content only (CSV/JSON/text), size-capped.

Members

  • content: string
  • id?: string | undefined: Correlates a download_refused reply with the request that caused it.
  • mime: string
  • name: string
  • type: "download"
  • v: 1

DownloadRefusedMessage​

interface DownloadRefusedMessage

Shell → app: the shell refused a download (over MAX_DOWNLOAD_CHARS, non-text content). id echoes the request's id so the SDK can settle the right caller's promise; a refusal is never silent (rule 36).

Members

  • id?: string | undefined
  • reason: string
  • type: "download_refused"
  • v: 1

Envelope​

interface Envelope<T>

Every plant answer: the result, and what the planner says about it: what it could not read (coverage), how many rows the viewer may not see (hidden), the sentence it computed, and the calls that would say more.

Members

  • ambiguous?: boolean | undefined: More than one thing answered to the name asked.
  • computed?: string | undefined: The answer's own sentence, in words.
  • coverage?: { missing?: string[]; without_reading?: string[]; } | undefined: What the answer needed and the plant does not record, or did not read.
  • cut_short?: { limit: string; } | undefined: The answer was cut short at this limit.
  • hidden?: number | undefined: Rows the viewer's access hides, counted, never shown.
  • next?: { tool: string; why: string; }[] | undefined: What to ask next, and why.
  • readings_as_of?: string | undefined: The instant the readings in the answer are as of, RFC3339.
  • result: T

ErrorMessage​

interface ErrorMessage

App → shell: an uncaught error (NR-3 + FR-8's send-to-agent hook).

Members

  • message: string
  • stack?: string | undefined
  • type: "error"
  • v: 1

EventCountInput​

interface EventCountInput extends ReadWindow

Input to data.eventCount: the condition is value <op> value, with a plain number, boolean or string.

Members

  • bucketWidth: string
  • end?: string | Date | undefined
  • mode: "sample" | "transition"
  • op: "eq" | "neq" | "gt" | "gte" | "lt" | "lte"
  • since?: string | undefined: How far back from now: a number and a unit, s m h or d ("90s", "30m", "8h", "7d").
  • start?: string | Date | undefined
  • topic: string
  • value: string | number | boolean

EventCountOptions​

type EventCountOptions = Omit<EventCountInput, 'topic'> & {
refreshMs?: number;
};

Options for useEventCount: data.eventCount's input without the topic, plus refreshMs.

EventCountResult​

interface EventCountResult

What data.eventCount answers (EventCountResponse).

Members

  • bucketWidth: string
  • buckets: { bucketStart: string; count: number; }[]
  • mode: string
  • topic: string
  • total: number

ExecuteFunctionInput​

interface ExecuteFunctionInput

Input to connectors.execute.

Members

  • connectionId: string: The connection the saved function belongs to.
  • functionId: string: A SAVED function on that connection (apps cannot run ad-hoc function bodies).
  • params?: Record<string, unknown> | undefined: Function parameters; sent as {} when omitted.

ExecuteFunctionResult​

interface ExecuteFunctionResult

Mirrors the platform's FunctionResultResponse.

Members

  • data?: Record<string, unknown> | undefined
  • durationMs: number
  • error?: string | undefined
  • metadata?: Record<string, unknown> | undefined
  • success: boolean
  • timestamp: string

ExecutionEvent​

interface ExecutionEvent

One live event from a pipeline's execution stream: the platform's unified live-exec family (shared/contracts/pipeline live_events.go), delivered as WS frames typed execution.* / node.*. Field names mirror the contract's json tags verbatim (camelCase); a full-boot Go test pins them. Only manual and API-submitted runs emit these events (mode separates real runs from sandbox test runs); scheduled and message-triggered runs do not; read those from the executions API.

Members

  • data: Record<string, unknown>: The frame's full payload, verbatim, for fields not lifted above.
  • durationMs?: number | undefined
  • endedAt?: string | undefined
  • error?: string | undefined: A node event's error, or execution.failed's errorSummary.
  • executionId: string
  • mode: string: 'live' for a real run, 'sandbox' for a test run.
  • nodeId?: string | undefined: Node events only.
  • nodeName?: string | undefined
  • nodeType?: string | undefined
  • pipelineId: string
  • receivedAt: number
  • startedAt?: string | undefined
  • type: string: 'execution.started' | 'execution.completed' | 'execution.failed' | 'execution.cancelled' | 'node.started' | 'node.progress' | 'node.completed' | 'node.failed' | 'node.skipped' | 'node.recovered' | 'node.prompt'. node.progress is a loop body node's coalesced progress: cumulative completed / failed counts and the latest iteration's output.

ExecutionStreamState​

interface ExecutionStreamState

What useExecutionStream returns: the run events (newest first) plus the stream's status.

Members

  • error: LiveError | null
  • events: ExecutionEvent[]
  • status: LiveStatus

FactInput​

interface FactInput

A fact's value, with its unit when the property has one; value: null removes the fact.

Members

  • unit?: string | undefined
  • value: string | number | boolean | null

FactValue​

interface FactValue

A fact a thing carries, with its unit when it has one.

Members

  • unit?: string | undefined
  • value: unknown

FallbackColours​

interface FallbackColours

One mode's fallback colours: what an app shows when the shell sent no tokens.

Members

  • background: string: Page background.
  • border: string: Borders and rules.
  • danger: string: Destructive fill.
  • ink: string: Primary text.
  • muted: string: Secondary text.
  • primary: string: Accent: primary buttons, links, focus ring.
  • primaryInk: string: Text on the accent.
  • subtle: string: Subtle fill: table header, neutral button, track.
  • surface: string: Card / control background.

FindOptions​

interface FindOptions

What plant.find takes: a name, a number another system issued, a topic, or many topics at once.

Members

  • as_of?: string | undefined: The plant as it was at an instant, RFC3339.
  • identifier?: string | undefined: A number another system issued, with system saying which.
  • name?: string | undefined: A name or part of one, in any language the plant records.
  • system?: string | undefined
  • topic?: string | undefined: A uns topic path: answered with the thing it is a reading of and the property.
  • topics?: string[] | undefined: Many topic paths in one call: a screen's whole list; never topic in a loop.

FormatDateTimeOptions​

interface FormatDateTimeOptions

Options for formatDateTime.

Members

  • seconds?: boolean | undefined: Show seconds with the time.
  • show?: "datetime" | "date" | "time" | undefined: What to show: "datetime" (default), "date" or "time".
  • timeZone?: string | undefined: Overrides the app's zone, for a site that keeps another clock.

FormatNumberOptions​

interface FormatNumberOptions

Options for formatNumber.

Members

  • pad?: boolean | undefined: Always write digits decimals (2.00, not 2): a column of figures that must line up.
  • percent?: boolean | undefined: n is a ratio, written as a percentage in the locale's own form (0.088 → 8.8%, 8,8 %, %8,8).

FunctionState​

interface FunctionState

What useFunction holds and returns.

Members

  • error?: unknown: The last call's failure, cleared when the next one starts.
  • granted: boolean: useActionPermission(action): render the control disabled with reason when false.
  • loading: boolean: A call is in flight.
  • reason?: string | undefined
  • result?: ExecuteFunctionResult | undefined: The last successful result.
  • run: (params?: Record<string, unknown>, options?: ActionOptions) => Promise<ExecuteFunctionResult | undefined>: Runs the function once. Never rejects: a refusal or a failed call lands in error (a FunctionFailedError for success:false) and run resolves undefined; a success lands in result and is returned.

HelloMessage​

interface HelloMessage

App → shell: announce readiness to receive context.

Members

  • app: { slug: string; }
  • type: "hello"
  • v: 1

HistoryOptions​

type HistoryOptions = Omit<RangeInput, 'topic'> & {
refreshMs?: number;
};

Options for useHistory: data.range's input without the topic, plus an optional re-read period (at least 5 s).

HostPalette​

interface HostPalette

The host's design tokens, resolved by the shell to plain CSS colours (hsl(220 14% 10%), #fff) so an app renders in the shell's exact theme: every variant, not a hard-coded light/dark pair. Optional in every message: a shell that cannot resolve them (no stylesheet yet) omits the field and the UI kit falls back to its own palette.

Members

  • background: string: Page background (--background).
  • border: string: Borders and rules (--border).
  • danger: string: Destructive fill: a danger button's background (--destructive). Not a text colour.
  • dangerInk?: string | undefined: Text on the destructive fill (--destructive-foreground). Optional: a shell that sends none gets the readable one of white / near-black computed against danger.
  • font: string: The shell's font stack (--font-sans).
  • ink: string: Primary text (--foreground).
  • muted: string: Secondary text (--muted-foreground).
  • primary: string: Accent: primary buttons, active tab, default chart series (--primary).
  • primaryInk: string: Text on the accent (--primary-foreground).
  • radius: string: The shell's corner radius (--radius), a CSS length.
  • subtle: string: Subtle fill: table header, neutral button (--muted).
  • surface: string: Card / control surface (--card).

Identity​

interface Identity

A number another system knows the thing by: the SAP equipment, the functional location, the OPC UA node.

Members

  • id: string
  • identifier: string
  • kind?: string | undefined
  • system: string

InForce​

interface InForce

A declaration in force on a thing, its own or the nearest above it: maintenance, decommissioned, …

Members

  • by?: string | undefined
  • mode: string
  • note?: string | undefined
  • on: string: The thing the declaration was made on.
  • on_name?: string | undefined
  • since: string

LabelOptions​

interface LabelOptions

Size and resolution of the label.

Members

  • dpi?: 203 | 300 | 600 | undefined: Printer resolution: 203 (default), 300 or 600 dpi.
  • heightMm: number
  • widthMm: number

ListApprovalsOptions​

interface ListApprovalsOptions

Filters for approvals.list; mirrors the engine's query names verbatim.

Members

  • limit?: number | undefined
  • offset?: number | undefined
  • pipelineId?: string | undefined
  • state?: string | undefined: "pending" (the default) | "approved" | "rejected" | "expired" | "executed" | "all".

ListApprovalsResponse​

interface ListApprovalsResponse

The inbox page shape.

Members

  • items: ApprovalDecision[]
  • total: number

ListOptions​

interface ListOptions

Query options for Collection.list; each one becomes a query parameter only when set.

Members

  • cursor?: string | undefined: The next_cursor of the previous page.
  • limit?: number | undefined: Maximum documents per page.
  • since?: string | undefined: RFC3339: only documents updated at or after this instant.

ListPage​

interface ListPage<T = unknown>

One page of Collection.list.

Members

  • items: StoredDocument<T>[]: The documents on this page.
  • next_cursor?: string | undefined: Pass as ListOptions.cursor to fetch the next page; absent on the last page.

LiveError​

interface LiveError

A refusal or failure on the live path: always carries a next step.

Members

  • code: string
  • reason: string
  • remediation: string
  • topic?: string | undefined

LiveErrorMessage​

interface LiveErrorMessage

App → shell: a live-data subscription was refused or failed (a missing scope, a topic the platform would not serve, an auth failure). The SDK already tells the app's own code through onError; this copy is for the BUILDER, which otherwise sees only "Status: error" inside the preview and cannot say why. Carries the same code / reason / remediation the app got, so the builder can teach the fix.

Members

  • code: string
  • reason: string
  • remediation?: string | undefined
  • topic?: string | undefined
  • type: "live_error"
  • v: 1

LiveStatus​

type LiveStatus = 'connecting' | 'live' | 'error' | 'closed';

Connection state a subscriber sees: connecting until the server acks the subscription (also while reconnecting), live once it has, error after a refusal or failure. closed is part of the type but the current LiveConnection never emits it.

Numberish​

type Numberish = number | ExactNumber;

A number as JSON carries it: a plain number, or an ExactNumber past what a double holds.

NumbersOptions​

interface NumbersOptions

What plant.numbers takes: a set of things, a property, a measure, a window.

Members

  • as_of?: string | undefined: The plant and its readings as they were at an instant, RFC3339.
  • measure?: string | undefined: Which number: "latest", "avg", "sum", "min", "max", "delta", "count", "time_in_state", "oee", …
  • order?: "asc" | "desc" | undefined: Order the rows: "asc" or "desc".
  • property?: string | undefined: The property to read or rank, e.g. "mh:vibration".
  • set: SetOptions
  • top?: number | undefined: How many rows to keep; the rest are counted, not dropped.
  • window?: string | undefined: The period: "now", "current_shift", "yesterday", "last_7d", "this_month", a date, a month.

OpenFileMessage​

interface OpenFileMessage

App → shell: show the viewer a stored attachment (D3), a photo or PDF the app fetched with its token. The sandbox can neither open a tab nor download, so the shell does it: it reads the type from the bytes itself (JPEG, PNG, WebP or PDF only), opens the file in a new tab, and falls back to a download when the browser blocks the tab. A refusal comes back as download_refused with the same id.

Members

  • data: ArrayBuffer: The file's bytes.
  • id?: string | undefined: Correlates a download_refused reply with the request that caused it.
  • name: string
  • type: "open_file"
  • v: 1

PendingWrite​

interface PendingWrite

One record waiting to be sent.

Members

  • attempts: number: Send attempts since it was queued.
  • id: number
  • label: string: What it is, in words: "save notes/shift-2", "record 2 events", "notice".
  • queuedAt: number: When it was made, ms since epoch.

PendingWrites​

interface PendingWrites

What usePendingWrites returns.

Members

  • count: number
  • items: PendingWrite[]

PeoplePage​

interface PeoplePage

A page of the directory.

Members

  • items: Person[]
  • truncated: boolean: More matched than limit: narrow the search.

PeopleSearch​

interface PeopleSearch

Filters for people.search.

Members

  • kind?: "user" | "group" | undefined: Only people ('user') or only groups ('group').
  • limit?: number | undefined: At most this many (default 50, at most 200).
  • search?: string | undefined: Part of a name, any case.

Person​

interface Person

One entry of the directory: a person or a group.

Members

  • has_picture: boolean: People only: a stored picture exists (people.picture fetches it).
  • id: string
  • kind: "user" | "group"
  • name: string: Display name; '' for a person who never set one (show "Unnamed person").

PipelineRunResult​

interface PipelineRunResult

What pipelines.run resolves with: a run that finished.

Members

  • durationMs?: number | undefined
  • error?: string | undefined: The run's error summary, when it completed with errors.
  • executionId: string
  • outputs: Record<string, Record<string, unknown>>: Each node's output, by node id: from the stored run when it has them, else from the run's live events.
  • status: string: 'completed', or 'completed_with_errors' when some nodes failed but the pipeline was set to carry on.

PipelineRunState​

interface PipelineRunState

What usePipelineRun holds and returns.

Members

  • canCancel?: { granted: boolean; reason?: string; } | undefined: useActionPermission(cancelAction), when one was given.
  • cancel?: (() => Promise<void>) | undefined: Ask the platform to stop the run in flight, through the manifest's cancelAction (a declared pipelines.cancel action). Never rejects: a refusal lands in error; once the run has stopped, error holds its PIPELINE_RUN_CANCELLED. Undefined when no cancelAction was given.
  • error?: unknown: The last run's failure, cleared when the next one starts.
  • granted: boolean: useActionPermission(action): render the control disabled with reason when false.
  • loading: boolean: A run is in flight.
  • progress?: ExecutionEvent | undefined: The latest live event of the run in flight (a node started or finished): render progress from it.
  • reason?: string | undefined
  • result?: PipelineRunResult | undefined: The last finished run.
  • run: (data?: Record<string, unknown>, options?: RunPipelineOptions) => Promise<PipelineRunResult | undefined>: Fires the pipeline and waits for the run. Never rejects: a refusal, a failed or cancelled run, or a timeout lands in error (a PipelineRunError for the run's own outcome) and run resolves undefined; a finished run lands in result and is returned.

PipelineSubscriber​

interface PipelineSubscriber

Callbacks handed to live.subscribePipeline; useExecutionStream builds one for you.

Members

  • onError?: ((e: LiveError) => void) | undefined
  • onEvent: (e: ExecutionEvent) => void
  • onStatus?: ((s: LiveStatus) => void) | undefined

PlantEvent​

interface PlantEvent

An event the plant recorded or worked out: alarm, trip, work_order, mode_change, …

Members

  • at: string
  • cleared_at?: string | undefined
  • id: string
  • kind: string
  • name?: string | undefined
  • payload?: Record<string, unknown> | undefined
  • severity?: "info" | "warning" | "critical" | undefined
  • site_id: string
  • source?: string | undefined
  • thing_id: string

PrintOptions​

interface PrintOptions

Options for print().

Members

  • keepTheme?: boolean | undefined: Keep the current theme (dark) instead of printing in light colours.
  • title?: string | undefined: The title the print dialog shows and the PDF file name, e.g. "Shift report, Line 2, 2026-10-15".

PublishInput​

interface PublishInput

Input to data.publish.

Members

  • source?: string | undefined: Optional source label recorded with the point.
  • topic: string: Existing UNS topic path, e.g. "factory/line1/reset".
  • value: unknown: JSON-serialisable value the topic's schema accepts.

PublishResult​

interface PublishResult

What POST /api/v1/uns/data/publish returns on success.

Members

  • message: string: The platform's human-readable acknowledgement.

QrOptions​

interface QrOptions

Options for Label.qr.

Members

  • magnification?: number | undefined: Cell size, 1 to 10 (default 4).

RangeInput​

interface RangeInput extends ReadWindow

Input to data.range.

Members

  • attribute?: string | undefined: One attribute of an object topic, by its path.
  • end?: string | Date | undefined
  • limit?: number | undefined: At most this many records.
  • since?: string | undefined: How far back from now: a number and a unit, s m h or d ("90s", "30m", "8h", "7d").
  • start?: string | Date | undefined
  • topic: string: The topic's full path (mHv1.0/...).

RangeResult​

interface RangeResult

What data.range answers (DataRecordsResponse).

Members

  • records: DataRecord[]
  • total: number: Records in this answer.
  • totalInRange?: number | undefined: Records the window holds, when the answer was capped.

RatioBucket​

interface RatioBucket

One ratio bucket (RatioBucketResponse).

Members

  • bucketStart: string
  • count: number
  • denValue: number
  • divZero: boolean
  • numValue: number
  • quality?: number | undefined
  • value: number: numValue / denValue; 0 with divZero true when the denominator is 0.

RatioInput​

interface RatioInput extends ReadWindow

Input to data.ratio.

Members

  • bucketWidth: string
  • denominator: RatioSide
  • end?: string | Date | undefined
  • numerator: RatioSide
  • since?: string | undefined: How far back from now: a number and a unit, s m h or d ("90s", "30m", "8h", "7d").
  • start?: string | Date | undefined

RatioOptions​

type RatioOptions = RatioInput & {
refreshMs?: number;
};

Options for useRatio: data.ratio's input plus an optional re-read period (at least 5 s).

RatioResult​

interface RatioResult

What data.ratio answers (RatioResponse).

Members

  • bucketWidth: string
  • buckets: RatioBucket[]
  • denominatorAgg: string
  • denominatorNonNumeric: number
  • denominatorTopic: string
  • numeratorAgg: string
  • numeratorNonNumeric: number
  • numeratorTopic: string
  • remediation?: string | undefined
  • total: number

RatioSide​

interface RatioSide

One side of a ratio: a topic and how its bucket is folded.

Members

  • agg: AggregateFn
  • topic: string

ReadState​

interface ReadState<T>

What a read hook holds: the last answer, whether a read is in flight, and its failure.

Members

  • data?: T | undefined
  • error?: unknown
  • loading: boolean
  • refresh: () => void: Read again now (the window is recomputed: a since window moves to now).

ReadWindow​

interface ReadWindow

A read window: since back from now, or start (and optional end, default now). Dates or ISO strings.

Members

  • end?: string | Date | undefined
  • since?: string | undefined: How far back from now: a number and a unit, s m h or d ("90s", "30m", "8h", "7d").
  • start?: string | Date | undefined

Reading​

interface Reading

A reading of a thing now, as the planner words it: the value, when, how old, how far it can be trusted.

Members

  • age: string: How old it is, in words.
  • at: string: When it was read, RFC3339.
  • flat?: boolean | undefined
  • name?: string | undefined
  • property: string: The property id, e.g. "mh:vibration".
  • quality: "good" | "uncertain" | "bad"
  • ref: string: The series it comes from; for kind "uns", the topic path: what useTopic takes.
  • source?: string | undefined
  • stale?: boolean | undefined
  • text?: string | undefined
  • unit?: string | undefined
  • value?: number | undefined

ReadyMessage​

interface ReadyMessage

App → shell: handshake complete.

Members

  • type: "ready"
  • v: 1

RecentAlertsOptions​

interface RecentAlertsOptions

Options for alerts.recent: activeOnly keeps only alarms still firing; shelved only shelved ones.

Members

  • activeOnly?: boolean | undefined
  • limit?: number | undefined
  • shelved?: boolean | undefined

RecordEvent​

interface RecordEvent

One event to record on a thing.

Members

  • at?: string | undefined: When it happened, RFC3339; the plant's now when left out. Not ahead of the plant's clock.
  • cleared_at?: string | undefined: When an event that lasts ended (a changeover), RFC3339; not before at.
  • kind: RecordableKind
  • name?: string | undefined: What it was: "short fill", "BRIX", a work order's title. At most 128 characters.
  • payload?: Record<string, unknown> | undefined: What else to keep with it: a count, a result, a reason code. At most 16 KB as JSON.
  • severity?: "info" | "warning" | "critical" | undefined
  • thing: string: The thing's id (key app state by id, never by a topic path).

RecordEventsInput​

interface RecordEventsInput

Input to plant.record: events landing together or not at all, at most 100.

Members

  • events: RecordEvent[]
  • note?: string | undefined: Why: required where a part asks a reason for every change.

RecordableKind​

type RecordableKind = 'reject' | 'lab_result' | 'fill' | 'changeover' | 'work_order' | 'calibration' | 'proof_test' | 'shift';

The event kinds a person may record; what a machine signals or the readings show is not recorded by hand.

Recorded​

interface Recorded

What became of a record. state is "applied" (in the plant now) or "proposed" (waiting under Review; waiting says why: the viewer may not decide, the app lacks proposals:decide, or the part is held to another person's approval). Events land at once unless a part is held; facts wait unless the viewer may decide. Show the difference: a proposed record has not happened in the plant yet.

Members

  • applied?: string | undefined
  • change_set: string
  • events?: string[] | undefined: The recorded events' ids, in the order given.
  • pieces: RecordedPiece[]
  • state: "applied" | "proposed"
  • waiting?: string | undefined

RecordedPiece​

interface RecordedPiece

One piece of a record and what the plant made of it.

Members

  • describes: string
  • index: number
  • reported?: string[] | undefined
  • would_fail: boolean

RunPipelineOptions​

interface RunPipelineOptions extends ActionOptions

Options for pipelines.run: the write options, plus how long to wait and who hears progress.

Members

  • confirmed?: boolean | undefined: The viewer confirmed this specific invocation (rung "confirm").
  • idempotencyKey?: string | undefined: Reuse a key to retry the SAME request; omit for a fresh invocation.
  • onProgress?: ((event: ExecutionEvent) => void) | undefined: Each live event of THIS run (node started/completed, execution finished), as it happens.
  • onStarted?: ((executionId: string) => void) | undefined: Called once the platform has named the run: the id pipelines.cancel takes.
  • timeoutMs?: number | undefined: How long to wait for the run to finish; default 60 000 ms. Past it the promise rejects; the run goes on.

ScreenMessage​

interface ScreenMessage

App → shell: what the app shows, as text (its visible text in reading order), sent while the shell asked for it (reportScreen), a moment after the screen settles and only when it changed. The builder passes it to the server for run_report.

Members

  • text: string
  • type: "screen"
  • v: 1

SetFacts​

interface SetFacts

Facts to set on one thing, by property id.

Members

  • facts: Record<string, FactInput>
  • thing: string

SetOptions​

interface SetOptions

Which things a plant.numbers or plant.timeline set covers, in match's words, or a plain list of ids.

Members

  • include_subtypes?: boolean | undefined
  • things?: string[] | undefined
  • type?: string | undefined
  • under?: string | undefined: Everything below this thing in the physical tree.

ShellToAppMessage​

type ShellToAppMessage = ContextMessage | TokenMessage | ThemeMessage | DisableMessage | DownloadRefusedMessage;

Every message the shell may post into the app iframe: the initial context, token rotations, theme flips, disable (kill switch / unshare) and download_refused. Discriminated on type.

SiteClock​

interface SiteClock

A site's clock.

Members

  • name: string
  • now: string
  • site: string
  • zone: string

StateDurationEntry​

interface StateDurationEntry

Time in one state (StateDurationEntryResponse); durationNanos / 1e9 is seconds.

Members

  • count: number
  • durationNanos: number
  • state: string

StateDurationInput​

interface StateDurationInput extends ReadWindow

Input to data.stateDuration.

Members

  • bucketWidth?: string | undefined
  • end?: string | Date | undefined
  • mode: "exact" | "range" | "breakdown"
  • ranges?: StateRange[] | undefined
  • since?: string | undefined: How far back from now: a number and a unit, s m h or d ("90s", "30m", "8h", "7d").
  • start?: string | Date | undefined
  • topic: string

StateDurationOptions​

type StateDurationOptions = Omit<StateDurationInput, 'topic'> & {
refreshMs?: number;
};

Options for useStateDuration: data.stateDuration's input without the topic, plus refreshMs.

StateDurationResult​

interface StateDurationResult

What data.stateDuration answers (StateDurationResponse).

Members

  • buckets: { bucketStart: string; entries: StateDurationEntry[]; }[]
  • mode: string
  • topic: string
  • total: number

StateRange​

interface StateRange

A labelled numeric band for state-duration mode "range" (RangeSpecRequest).

Members

  • label: string
  • max: number
  • min: number

StoredDocument​

interface StoredDocument<T = unknown>

One document as the storage API returns it.

Members

  • key: string: The document key within its collection.
  • revision: number: Server-assigned revision; put sends it back for compare-and-set writes.
  • updated_at: string: RFC3339 instant of the last write.
  • updated_by: string: The user who last wrote the document.
  • value: T: The stored JSON value.

SubmitPipelineInput​

interface SubmitPipelineInput

Input to pipelines.submit.

Members

  • data?: Record<string, unknown> | undefined: Payload delivered to the run as its trigger data.
  • nodeId: string: The manual-trigger node's id inside that pipeline.
  • pipelineId: string: The pipeline that owns the manual-trigger node.

SubmitPipelineResult​

interface SubmitPipelineResult

What the scheduler's trigger endpoint returns on success.

Members

  • execution_id?: string | undefined: The run the trigger started (scheduler TriggerResponse.execution_id): follow it with useExecutionStream, read it at GET /engine/executions/:id.
  • status: string: The scheduler's status word for the accepted trigger.

TelemetryMessage​

interface TelemetryMessage

App → shell: one API call's timing (G7). The builder aggregates these into "slow data sources" so latency is a build-time signal, not a production surprise. Sent for every apiFetch; cheap, fire-and-forget.

Members

  • durationMs: number
  • method: string
  • path: string
  • status: number
  • type: "telemetry"
  • v: 1

TextOptions​

interface TextOptions

Options for Label.text: size, and an optional wrapping block.

Members

  • align?: "left" | "center" | "right" | undefined
  • heightMm?: number | undefined: Character height (default 4 mm).
  • maxLines?: number | undefined
  • widthMm?: number | undefined: Wrap within this width, up to maxLines lines.

ThemeMessage​

interface ThemeMessage

Shell → app: a live theme switch (FR-17). The context message carries the initial mode; this one follows every flip the viewer makes in the shell, so an app never has to reload to match its host.

Members

  • theme: ThemeState
  • type: "theme"
  • v: 1

ThemeState​

interface ThemeState

The theme as the shell sends it: the mode, and the host tokens when the shell could resolve them.

Members

  • mode: "light" | "dark"
  • palette?: HostPalette | undefined

Thing​

interface Thing

One thing the plant knows: a machine, a line, an area, a site.

Members

  • facts?: Record<string, FactValue> | undefined
  • id: string
  • labels?: Record<string, string> | undefined
  • name: string
  • site_id: string
  • type_id?: string | undefined: Its type, e.g. "company:centrifugal_pump".
  • validity?: { valid_from?: string; valid_to?: string; } | undefined
  • workspace_id?: string | undefined

TimelineEntry​

interface TimelineEntry

One entry of plant.timeline: the event and the thing it happened to.

Members

  • alarm?: AlarmState | undefined
  • event: PlantEvent
  • site_name?: string | undefined
  • thing_name: string
  • why?: string | undefined: With rank: why it comes first.

TimelineOptions​

interface TimelineOptions

What plant.timeline takes: whose events, of which kinds, over which period or state.

Members

  • as_of?: string | undefined: The model as it was at an instant, RFC3339.
  • kinds?: string[] | undefined: Which kinds of event: "alarm", "trip", "work_order", "mode_change", "due", …; leave it out for all.
  • limit?: number | undefined
  • rank?: boolean | undefined: Order by what to look at first (severity, then how much sits downstream) rather than by time.
  • state?: "active" | "to_act_on" | "acknowledged" | "shelved" | "standing" | undefined: Live alarms ("active"), or only those to act on, acknowledged, shelved, standing.
  • things?: string[] | undefined: The things to ask about, by id or by name.
  • under?: string | undefined: Everything below this thing in the physical tree.
  • window?: string | undefined: The period: "now", "current_shift", "yesterday", "last_7d", "last_24h", a date, a month.

TokenMessage​

interface TokenMessage

Shell → app: a rotated token (silent re-issue, DS4).

Members

  • actions?: Record<string, ActionPermission> | undefined: The re-issue's per-action answers: a right granted or taken away mid-session shows here.
  • token: TokenPayload
  • type: "token"
  • v: 1

TokenPayload​

interface TokenPayload

The scoped app token the shell hands over in context and re-issues in token pushes.

Members

  • expiresAt: string: RFC3339: the shell re-issues before this; the app never refreshes itself.
  • value: string: The bearer value apiFetch and the live socket authenticate with.

TopicContract​

interface TopicContract

What data.contract answers (TopicContractResponse).

Members

  • binding: Record<string, unknown> | null: The topic's binding to its schema.
  • schema: TopicSchema | null
  • series?: { data_type: string; unit?: string; mismatch?: Record<string, unknown>; } | undefined: The shape the stored series has; absent before the first publish.

TopicMessage​

interface TopicMessage

One value delivered on a topic.

Members

  • quality?: number | undefined
  • raw: string: The payload exactly as the server sent it.
  • receivedAt: number
  • retain: boolean
  • seeded?: boolean | undefined: True for the topic's last stored value, delivered as the subscription starts so a topic that publishes rarely is not blank until its next publish. Every later message is a newly published one.
  • source?: string | undefined
  • timestamp?: string | undefined: Server-side fields of the enriched envelope (application.MQTTPayload) when present.
  • topic: string
  • value: unknown: The parsed value: the enriched envelope's value, else parsed JSON, else the raw string.

TopicSchema​

interface TopicSchema

What a topic carries, as its schema says (TopicContractResponse.schema; DataSchema on the wire).

Members

  • alert?: Record<string, unknown> | undefined: The alert thresholds the platform fires on.
  • attributes?: Record<string, unknown>[] | undefined: An object's attributes, each with its own type and unit.
  • display_name?: string | undefined
  • enum_values?: { value: string; display?: string; semantic_id?: string; }[] | undefined: An enum's closed set.
  • id: string
  • kind: number: 1 one value, 2 an object with attributes, 3 an enum.
  • major_version: number
  • max?: number | undefined
  • min?: number | undefined
  • minor_version: number
  • name: string
  • unit?: string | undefined
  • value_type?: { [key: string]: unknown; kind: string; primitive?: string; } | undefined: For a value: {kind: "primitive", primitive: "float64" | "int64" | "bool" | "string" | ...}.

TopicState​

interface TopicState

What useTopic returns; status and error explain why value may be null.

Members

  • error: LiveError | null: The last refusal or failure; cleared by the next message.
  • message: TopicMessage | null: The full last message (raw payload, retain flag, envelope fields; seeded on the stored one), or null before the first.
  • stale: boolean: The value shown is the last one received and is not live now (the connection dropped or the topic was refused after it arrived). Show it as such: message.receivedAt says when it came.
  • status: LiveStatus: Current connection state for this topic.
  • value: unknown: The latest value (the enriched envelope's value): the topic's last stored value as soon as the subscription starts, then each newly published one. Null only for a topic that has never published.

TopicSubscriber​

interface TopicSubscriber

Callbacks handed to live.subscribe; useTopic and subscribeTopic build one for you.

Members

  • onError?: ((e: LiveError) => void) | undefined: Refusals and failures (missing scope, refused topic, auth error, reconnecting, app disabled).
  • onMessage: (m: TopicMessage) => void: Every value delivered on the topic.
  • onStatus?: ((s: LiveStatus) => void) | undefined: Connection-state transitions for this subscription.

TopicsState​

type TopicsState = Record<string, TopicState>;

What useTopics returns: one TopicState per path asked for.

TreeView​

interface TreeView

A tree the plant keeps: a legal value of plant.walk's tree.

Members

  • default?: boolean | undefined
  • id: string
  • link_types?: string[] | undefined
  • name: string
  • tree_kind: string

TypeCount​

interface TypeCount

How many things are of a type.

Members

  • subtypes?: string[] | undefined
  • things: number
  • type: string
  • with_subtypes?: number | undefined

UpdateFactsInput​

interface UpdateFactsInput

Input to plant.update: facts on one or more things, landing together or not at all.

Members

  • facts: SetFacts[]
  • note?: string | undefined: Why: required where a part asks a reason for every change.

UsageInfo​

interface UsageInfo

What Collection.usage returns: how full the collection's scope is.

Members

  • cap_bytes: number: The quota; a write that would exceed it is refused with a 413.
  • doc_count: number: Number of documents stored.
  • total_bytes: number: Bytes used.

Vocabulary​

interface Vocabulary

plant.whatCanIAsk: the plant's vocabulary: its sites, trees, types, and what it measures.

Members

  • event_kinds?: string[] | undefined
  • link_types?: string[] | undefined
  • measured_properties: string[]
  • now: string
  • sites: SiteClock[]
  • trees: TreeView[]
  • types: TypeCount[]

WalkOptions​

interface WalkOptions

What plant.walk takes: a start, and either a tree or the link types to follow.

Members

  • as_of?: string | undefined: The plant as it was at an instant, RFC3339.
  • depth?: number | undefined: How many hops; leave it out to go as far as it goes.
  • direction?: "downstream" | "upstream" | "both" | "up" | "down" | undefined: Along links: "upstream" / "downstream" / "both"; in a tree: "up" / "down".
  • from: string: The thing to start at, by id or by name.
  • tree?: string | undefined: Follow a whole tree: "physical", "location", "floc", "electrical", "cost_centre"; whatCanIAsk lists this plant's.
  • type?: string[] | undefined: Return only these types, having walked through the rest.
  • values?: string[] | undefined: Properties to read for everything reached, in one read: the fleet's values, ranked by you.
  • via?: string[] | undefined: The link types to follow instead of a tree, e.g. ["feeds"].

WalkedThing​

interface WalkedThing

One thing a plant.walk reached.

Members

  • depth: number
  • name?: string | undefined
  • readings?: Reading[] | undefined: With values: the properties asked, read now.
  • site: string
  • stub?: boolean | undefined
  • thing: string
  • type?: string | undefined
  • via?: string[] | undefined: The link types followed to reach it.