Skip to content

Reference

Dashboard SDK

Every function and type of @thinger-io/dashboard-sdk, the package for dashboards built as web apps, plus how to start, publish and share them.

Reference19 min read

@thinger-io/dashboard-sdk is the package for dashboards built as web apps (React, Angular, Vue or plain TypeScript). The app runs inside a dashboard of the console with the session of the person viewing it, or on its own with a link that carries a token. The function reference on this page is generated from the type declarations of the package.

PackageInstalled fromVersionSource code
@thinger-io/dashboard-sdknpm0.3.1thinger-io/dashboard-sdk

The oldest server the SDK supports is Thinger.io 7.4, and every function of this version works on it.

Versions 0.x

While the SDK is in 0.x versions, its contract with the console can still change between minor versions. Check the changelog before you upgrade.

Get started ​

Create a project from a template of the SDK with the CLI, or add the package to an existing app:

bash
npm install @thinger-io/dashboard-sdk

The package exports Thinger, a client that starts when the module is imported. Wait for Thinger.ready() and then call the modules:

ts
import { Thinger, type BucketRecord } from '@thinger-io/dashboard-sdk';

await Thinger.ready();

// Devices of the account, or of the project the dashboard runs in
const devices = await Thinger.devices.list();
console.log(devices.map((device) => device.device));

// The last 6 hours of a Data Bucket, kept current as new data arrives
const stop = Thinger.buckets.subscribe('climate', { from: '6h', items: 500 }, (data, err) => {
    if (err) return console.error(err);
    const records: BucketRecord[] = data ?? [];
    console.log(records.length);
});

// Stop the live updates when the view goes away
stop();

climate stands for the ID of one of your Data Buckets. ready() rejects with code: 'no-session' when the page is opened outside the console without a standalone link.

Inside the console ​

A dashboard of the console can show your app instead of widgets. The console loads it in a sandboxed frame and hands it the session of the person viewing it: the app never handles credentials, and API calls run with that person's permissions and in their current project. Build the app with these rules:

  • Use hash routing (#/devices). The console keeps the route in its own URL, so reloading or sharing the console link reopens the same screen.
  • Use relative asset URLs (base: './' in Vite) and no <base> tag.
  • Reload with Thinger.reload(), not location.reload(): a plain reload gets no session.
  • Do not use localStorage, sessionStorage or cookies; the frame has no storage of its own. Keep settings in properties.
  • Open other screens of the console with Thinger.navigate().
  • The app fills the content area of the console and scrolls inside it: design for that height instead of a fixed one.
  • Files of a private file storage need Thinger.storages.url(); a plain <img src> to them fails.
  • People who open a shared dashboard may lack some permissions: handle status: 403 errors.

Publish an app ​

The console loads the app from a file storage of your account:

  1. Upload the build folder to a public file storage with index.html as its index. The frame cannot send an authorization header when it loads files, so a private storage does not work.
  2. Point the dashboard at the storage folder, with the trailing slash: /v1/users/YOUR_USER/storages/<storage>/files/. Without the slash the server answers with the file list.
  3. For per-device or per-product dashboards, set the same source on the dashboard property of that device or product.

thinger dashboard publish does the three steps from the build folder; see the CLI reference. Publishing again replaces the files; with --bump, consoles that have the app open reload it at once.

An app published to a public storage also works outside the console, for example embedded in another website. Pass the session in the fragment of the URL:

text
https://YOUR_SERVER/v1/users/YOUR_USER/storages/<storage>/files/#/<route>&thinger_token=YOUR_TOKEN&thinger_project=<project>
ParameterContent
thinger_tokenRequired. An access token (JWT); the SDK takes the user from it. Here YOUR_TOKEN is an access token of your account.
thinger_apiServer address, URL-encoded, when the app is not served by the Thinger.io server: https://host[:port], optionally with a path. Without it, the page's own origin.
thinger_projectProject the app runs in; API calls are scoped to it.
thinger_device, thinger_product, thinger_type, thinger_groupFill Thinger.context, as a device, product, asset type or asset group dashboard would.

The fragment never reaches the server. The SDK reads the thinger_* parameters, removes them from the address bar and keeps them for the browser tab, so a reload keeps the session. There is no token renewal: when the token expires, calls fail with status: 401 and the app needs a new link. thinger dashboard publish --preview prints such links with a read-only token.

Permissions for a read-only token ​

A standalone link carries a token; give it only what the app needs. For a read-only app, create the token in the project of the dashboard and allow:

ResourceActions
DeviceListDevices, ReadDeviceConfig, ReadDeviceStatus, ListDeviceProperties, ReadDeviceProperty, ReadDeviceBucket
BucketListBuckets, ReadBucket, ListBucketTags
Product, Type, Group, ProjectList…, Read…Config, List…Properties, Read…Property of each one the app reads
AlarmListAlarmRules, ReadAlarmRuleConfig, ListAlarmInstances
StorageReadStorageFiles, for files of private storages

Add actions such as AccessDeviceResources, SetDeviceProperty or UpdateAlarmInstance only if the app calls device resources, writes properties or changes alarms.

The live functions (buckets.subscribe, devices.subscribeProperty, devices.subscribeState, alarms.subscribe, alarms.rules.subscribe and events.subscribe) receive events over a WebSocket. An access token can subscribe only to the events of the permissions table, each with its read permission: ReadBucket or ReadDeviceBucket for bucket writes, ReadDeviceProperty for property updates, ReadDeviceConfig for device state, and ListAlarmInstances or ListAlarmRules on all alarms for alarm events. When the server refuses a subscription, reads still work, the data does not update live, and the SDK logs a warning in the browser console.

Errors ​

Every call rejects with a ThingerError. Its code says why; subscriptions pass the error to their callback instead.

codeMeaningExtra field
httpThe server answered with an error status. The message reads HTTP <status> <reason>.status
unsupportedThe server is older than the function needs.requires: the minimum server version
no-sessionNo session yet: called before ready(), or the page was opened without one.
invalid-argumentThe call itself is wrong, for example device: true without a context device.
unexpected-responseThe server answered something the SDK cannot use.
ts
import { Thinger, ThingerError } from '@thinger-io/dashboard-sdk';

try {
    await Thinger.devices.get('YOUR_DEVICE');
} catch (err) {
    if (err instanceof ThingerError && err.code === 'http' && err.status === 404) {
        console.log('No such device');
    }
}

Time values ​

Options such as from and to take a time value:

ValueMeaning
A numberMilliseconds since the epoch.
A DateThat instant.
'now'The current time.
'<n><unit>'That long before now. Units: s seconds, m minutes, h hours, d days, w weeks, M months (30 days), y years (365 days). Examples: '30m', '6h', '7d', '1M'.

Units are case-sensitive (m is minutes, M is months), and combined values such as '1h30m' are not accepted: they fail with code: 'invalid-argument'. Without from and to, a query has no time bound.

Script build ​

Deprecated

The script build thinger-dashboard.min.js, which defines a global Thinger for pages without a bundler, is deprecated and logs a warning. Install the package from npm and import { Thinger } from '@thinger-io/dashboard-sdk' in every module instead; the migration notes are in the changelog.

Thinger ​

Thinger is the client the package exports, an instance of ThingerClient. Its modules are listed under Modules.

Thinger.version ​

ts
readonly version: string;

SDK version (semver).

new ThingerClient ​

ts
constructor(options?: ClientOptions);

Thinger.apiBase ​

ts
get apiBase(): string;

Base URL of API calls ('' = the page's origin).

Thinger.apiHost ​

ts
get apiHost(): string;

Informational: the absolute API host the console reported.

Thinger.token ​

ts
get token(): string | null;

Viewer's access token.

Thinger.user ​

ts
get user(): User | null;

{ id } of the viewer.

Thinger.project ​

ts
get project(): Project | null;

Project the dashboard runs in; API calls are scoped to it (?project=).

Thinger.context ​

ts
get context(): Context;

The resource whose dashboard property is shown: { device, product, type, group, project }.

Thinger.dashboard ​

ts
get dashboard(): DashboardRef | null;

{ id, name } of the dashboard (inside the console).

Thinger.serverVersion ​

ts
get serverVersion(): string | null;

Server version (e.g. "7.5.0"), known after ready(); null when it could not be read.

Thinger.ready ​

ts
ready(): Promise<ThingerClient>;

Resolves once the session is there: the console handshake, or the standalone link. It also waits (up to 3 s) for the server version, so supports() is accurate afterwards. Rejects when the page has no session at all.

Thinger.onInit ​

ts
onInit(fn: (sdk: ThingerClient) => void): void;

Call fn(Thinger) on every init (and now, when already initialized).

Thinger.supports ​

ts
supports(name: string): boolean;

Is a function available on this server? name is its path from Thinger ('devices.list', 'alarms.rules.get'). Functions that need a newer server than this one answer false; the rest true. Accurate after ready(); before it, or when the server version cannot be read, only unknown names answer false.

Thinger.request ​

ts
request<T = any>(path: string, opts?: RequestOptions): Promise<T>;

API call: fetch() plus error handling and body parsing. opts.body: any JSON value, or a string, Blob, FormData or ArrayBuffer sent as is. opts.as forces the response type ('json', 'text', 'blob', 'arrayBuffer'); by default parsed JSON for JSON responses, text otherwise, null when empty. opts.project: false skips the project scoping. Throws a ThingerError HTTP <status> <reason> with status.

Thinger.fetch ​

ts
fetch(path: string, options?: FetchOptions): Promise<Response>;

Authenticated fetch(): adds Authorization: Bearer <token> and, in a project, ?project= (the server maps the URL's user to the project owner, so callers never need to know it). Inside the console, a 401 asks it for a new token and retries once. An absolute URL of another server goes out as a plain fetch: the token only travels to the Thinger server.

Thinger.navigate ​

ts
navigate(target: NavigateTarget): void;

Navigate the console: a path or URL, or one of { device }, { product }, { project }, { dashboard }, { url }. Standalone pages go to the URL themselves.

Thinger.reload ​

ts
reload(): void;

Reload the app. Use it instead of location.reload(): inside the console it keeps the key of the frame load, without which the reloaded page gets no token.

Modules ​

ModuleDescription
Thinger.eventsServer events (bucket writes, property updates, alarms…) over one WebSocket shared by every subscription, /v2/users/{user}/events. It reconnects with backoff, refreshing the token first when it has expired.
Thinger.bucketsBucket data: read, write, live reads and tags.
Thinger.devicesDevices: documents, properties, resources (read, call, poll, stream) and their events.
Thinger.alarmsAlarm instances: list, live list, state changes.
Thinger.alarms.rulesAlarm rules and their executions.
Thinger.resourcesAny kind of resource, listed or read by id.
Thinger.propertiesProperties of devices, products, projects, groups and types. Also a place for the dashboard's own settings (e.g. a project or product property).
Thinger.productsProducts and their API.
Thinger.endpointsEndpoints: email, webhooks, notifications…
Thinger.storagesFiles in file storages. Every call carries the viewer's token, so private storages work too. A plain <img src> to a private file goes without the token: use url().
Thinger.projectsProjects the viewer can open. Not scoped to the console's current project.
Thinger.statsAccount and traffic statistics.

Thinger.events ​

Server events (bucket writes, property updates, alarms…) over one WebSocket shared by every subscription, /v2/users/{user}/events. It reconnects with backoff, refreshing the token first when it has expired.

events.subscribe ​

ts
subscribe<E extends ServerEvent = ServerEvent>(filter: EventFilter, cb: (event: E) => void, onReconnect?: () => void): Unsubscribe;

Subscribe to server events. filter is { event, ...filters }, e.g. { event: 'bucket_write', bucket: 'b' }. Events sent while the socket is down are lost: onReconnect() runs each time it comes back after a drop.

Thinger.buckets ​

Bucket data: read, write, live reads and tags.

buckets.read ​

ts
read<T = BucketRecord>(bucketId: string, opts?: BucketQuery): Promise<T[]>;

Records { ts, ...fields }. opts.device reads the device-scoped view of a product bucket (a device id, or true for the context device): it only needs access to the device.

buckets.write ​

ts
write(bucketId: string, value: unknown): Promise<unknown>;

Write a record to a bucket (one whose data source is the API).

buckets.tags ​

ts
tags(bucketId: string, opts?: {
    device?: string | true | null;
}): Promise<any>;
tags(bucketId: string, tag: string, opts?: {
    device?: string | true | null;
}): Promise<any>;

Tags of a bucket, or the values seen for one tag (to build filters).

buckets.subscribe ​

ts
subscribe<T = BucketRecord>(bucketId: string, cb: BucketCallback<T>): Unsubscribe;
subscribe<T = BucketRecord>(bucketId: string, opts: BucketSubscribeOptions, cb: BucketCallback<T>): Unsubscribe;

read(bucketId, opts), then the same read kept current as the bucket is written (debounced by opts.debounceMs, 500 ms by default). Only what a write changes is read again; opts.refetch: true re-runs the whole read instead. cb(data, err, { added, reset }).

Thinger.devices ​

Devices: documents, properties, resources (read, call, poll, stream) and their events.

devices.list ​

ts
list(query?: DeviceQuery): Promise<Device[]>;

Devices, all pages (the API returns 50 per page). query filters: product, asset_type, asset_group, type, name, sort, order, labels ({ key: value }, or [key] for "has label"), limit.

devices.get ​

ts
get(deviceId: string): Promise<Device>;

One device, with its connection status.

devices.locations ​

ts
locations(opts?: LocationsQuery): Promise<any[]>;

Device locations for maps. Without options: every asset with a location. { group } / { type } narrow it to an asset group / type; { connected: true } returns only connected devices.

devices.stats ​

ts
stats(deviceId: string): Promise<any>;

Traffic usage of one device over the last 30 days.

devices.listProperties ​

ts
listProperties(deviceId: string, query?: PropertyQuery): Promise<Property[]>;

Properties of a device, inherited ones included: those carry source (type, group or product). query.id accepts a pattern ('temp*').

devices.getProperty ​

ts
getProperty<T = any>(deviceId: string, propertyId: string): Promise<Property<T>>;

One property: { property, value, source, created, modified, … }.

devices.setProperty ​

ts
setProperty(deviceId: string, propertyId: string, value: unknown): Promise<any>;

Create or update a property.

devices.deleteProperty ​

ts
deleteProperty(deviceId: string, propertyId: string): Promise<boolean>;

Remove a property (true also when it did not exist).

devices.getResource ​

ts
getResource<T = any>(deviceId: string, resource: string, opts?: {
    shadow?: boolean;
}): Promise<T>;

Read a device resource. shadow: true returns the last value saved when the device disconnected.

devices.callResource ​

ts
callResource<T = any>(deviceId: string, resource: string, input?: unknown): Promise<T>;

Call a device resource (actuation / RPC) with input as its JSON body: any serializable value. Returns the device's response, or null when it sends none.

devices.pollResource ​

ts
pollResource<T = any>(deviceId: string, resource: string, intervalMs: number, cb: (data: T | null, err: Error | null) => void): Unsubscribe;

Read a resource every intervalMs. cb(data, err) per read.

devices.subscribeProperty ​

ts
subscribeProperty(deviceId: string, propertyId: string, cb: (event: PropertyUpdateEvent) => void): Unsubscribe;

Property update events of one property.

devices.subscribeState ​

ts
subscribeState(deviceId: string, cb: (event: DeviceStateEvent) => void): Unsubscribe;

Connection events; event.state is connected, disconnected, resumed, awake or asleep.

devices.streamResource ​

ts
streamResource<T = any>(deviceId: string, resource: string, cb: (payload: T | null, err: Error | null, frame: StreamFrame) => void): Unsubscribe;
streamResource<T = any>(deviceId: string, resource: string, intervalMs: number, cb: (payload: T | null, err: Error | null, frame: StreamFrame) => void): Unsubscribe;

The device pushes the resource every intervalMs (0 or omitted: when it changes), over the device's resources WebSocket. Intervals go to the device in whole seconds. Subscribers of one resource share its stream, at the GCD of their intervals. When the device is offline, cb gets the error and then the last known value (frame.signal === 'shadow'). Reconnects with backoff.

Thinger.alarms ​

Alarm instances: list, live list, state changes.

alarms.STATE ​

ts
readonly STATE: Readonly<{
    readonly NONE: 0;
    readonly ACTIVATED: 1;
    readonly ACKNOWLEDGED: 2;
    readonly LATCHED: 3;
    readonly SHELVED: 4;
    readonly CLEARED: 5;
}>;

Same as Alarms.STATE, reachable as Thinger.alarms.STATE.

alarms.SEVERITY ​

ts
readonly SEVERITY: Readonly<{
    readonly NONE: 0;
    readonly LOW: 1;
    readonly MEDIUM: 2;
    readonly HIGH: 3;
    readonly CRITICAL: 4;
}>;

Same as Alarms.SEVERITY, reachable as Thinger.alarms.SEVERITY.

alarms.list ​

ts
list(query?: AlarmQuery): Promise<AlarmInstance[]>;

Alarm instances. query is sent as query params: exact values, nested fields with dots, an array matching any of its values ({ state: 1 }, { 'alarm.rule': 'r1', 'origin.id': ['d1', 'd2'] }).

alarms.get ​

ts
get(instanceId: string): Promise<AlarmInstance>;

alarms.stats ​

ts
stats(): Promise<any>;

Counts per state / severity.

alarms.subscribe ​

ts
subscribe(cb: (instances: AlarmInstance[] | null, err: Error | null) => void): Unsubscribe;
subscribe(query: AlarmSubscribeQuery, cb: (instances: AlarmInstance[] | null, err: Error | null) => void): Unsubscribe;

list(query) now, and again (debounced by query.debounceMs, 500 ms by default) whenever an instance is activated, normalized, updated (acknowledge, shelve, latch, clear, annotation; from this app or anywhere else), created or deleted. cb(instances, err).

alarms.onActivate ​

ts
onActivate(cb: (event: ServerEvent) => void): Unsubscribe;

Raw alarm_instance_activate events.

alarms.onNormalize ​

ts
onNormalize(cb: (event: ServerEvent) => void): Unsubscribe;

Raw alarm_instance_normalize events.

alarms.onUpdate ​

ts
onUpdate(cb: (event: ServerEvent) => void): Unsubscribe;

Raw alarm_instance_update events (state, annotation… changed).

alarms.update ​

ts
update(instanceId: string, body: Record<string, unknown>): Promise<any>;

Update an instance: usually its state (see STATE), with annotation / reactivation. The server validates transitions (a CLEARED alarm cannot be reactivated). The helpers below only differ in the state they set.

alarms.acknowledge ​

ts
acknowledge(instanceId: string, opts?: AlarmUpdateOptions): Promise<any>;

alarms.shelve ​

ts
shelve(instanceId: string, opts?: AlarmUpdateOptions): Promise<any>;

Shelve (usually with a reactivation timespan).

alarms.latch ​

ts
latch(instanceId: string, opts?: AlarmUpdateOptions): Promise<any>;

Latch (fires again after the configured timeout).

alarms.clear ​

ts
clear(instanceId: string, opts?: AlarmUpdateOptions): Promise<any>;

Clear (resolve). A cleared instance cannot be reactivated.

Thinger.alarms.rules ​

Alarm rules and their executions.

alarms.rules.list ​

ts
list(query?: Record<string, unknown>): Promise<any[]>;

alarms.rules.get ​

ts
get(ruleId: string): Promise<any>;

alarms.rules.subscribe ​

ts
subscribe(cb: (event: ServerEvent) => void): Unsubscribe;

alarm_rule_execute events (needs the account owner).

alarms.rules.onExecute ​

ts
onExecute(cb: (event: ServerEvent) => void): Unsubscribe;

Same as subscribe(cb).

Thinger.resources ​

Any kind of resource, listed or read by id.

resources.list ​

ts
list<T = any>(kind: ResourceKind, query?: ListQuery): Promise<T[]>;

Resources of a kind, following pagination. query is sent as filters (labels as in devices.list); query.limit caps how many are returned.

resources.get ​

ts
get<T = any>(kind: ResourceKind, id: string): Promise<T>;

One resource document.

Thinger.properties ​

Properties of devices, products, projects, groups and types. Also a place for the dashboard's own settings (e.g. a project or product property).

properties.list ​

ts
list(kind: PropertyKind, id: string, query?: PropertyQuery): Promise<Property[]>;

query.id accepts a pattern matching several properties ('temp*').

properties.get ​

ts
get<T = any>(kind: PropertyKind, id: string, propertyId: string): Promise<Property<T>>;

The full document { property, value, created, modified, … }.

properties.set ​

ts
set(kind: PropertyKind, id: string, propertyId: string, value: unknown): Promise<any>;

Create or update a property.

properties.delete ​

ts
delete(kind: PropertyKind, id: string, propertyId: string): Promise<boolean>;

Remove a property (true also when it did not exist).

Thinger.products ​

Products and their API.

products.list ​

ts
list(query?: ListQuery): Promise<Product[]>;

products.get ​

ts
get(productId: string): Promise<Product>;

products.call ​

ts
call<T = any>(productId: string, resource: string, input?: unknown): Promise<T>;

Call a resource of the product API (the functions of the product profile) with input as its JSON body. It reaches a device only if the resource defines a device_id_resolver.

Thinger.endpoints ​

Endpoints: email, webhooks, notifications…

endpoints.call ​

ts
call<T = any>(endpointId: string, payload?: unknown): Promise<T>;

Trigger an endpoint with an optional JSON payload.

Thinger.storages ​

Files in file storages. Every call carries the viewer's token, so private storages work too. A plain <img src> to a private file goes without the token: use url().

storages.list ​

ts
list(storageId: string, path?: string): Promise<StorageFile[]>;

Files of a storage, optionally inside path.

storages.read ​

ts
read(storageId: string, path: string, opts: {
    as: 'blob';
}): Promise<Blob>;
read(storageId: string, path: string, opts: {
    as: 'arrayBuffer';
}): Promise<ArrayBuffer>;
read(storageId: string, path: string, opts: {
    as: 'text';
}): Promise<string>;
read<T = any>(storageId: string, path: string, opts?: {
    as?: 'json';
}): Promise<T>;

File contents. opts.as: 'json', 'text', 'blob' or 'arrayBuffer'; by default JSON when the server says so and text otherwise. Use 'blob' / 'arrayBuffer' for binary files (PDF, images…).

storages.url ​

ts
url(storageId: string, path: string): Promise<string>;

A temporary blob: URL with the file, for <img>, <video>, <a href>… Revoke it with URL.revokeObjectURL(url) when no longer needed.

storages.download ​

ts
download(storageId: string, path: string, filename?: string): Promise<void>;

Save the file on the viewer's computer (filename defaults to the file's name).

storages.write ​

ts
write(storageId: string, path: string, data: unknown): Promise<any>;

Create or overwrite a file; folders on the path are created. data: a string, a Blob / File (e.g. from <input type="file">), an ArrayBuffer / typed array, or any other value, stored as JSON.

storages.open ​

ts
open(storageId: string, path: string): Promise<void>;

Open the file in a new browser tab (PDFs, images…), through the console: the sandboxed frame can neither open tabs nor show the browser's PDF viewer. Call it from a click handler, so the browser does not block the new tab.

storages.remove ​

ts
remove(storageId: string, path: string): Promise<any>;

Delete a file, or a folder with everything in it.

storages.publicUrl ​

ts
publicUrl(storageId: string, path: string): string;

Direct URL of a file in a PUBLIC storage, for <img src> or links without the SDK. Private storages need url().

Thinger.projects ​

Projects the viewer can open. Not scoped to the console's current project.

projects.list ​

ts
list(): Promise<ProjectRef[]>;

The viewer's own projects and the ones shared with them (those carry owner).

projects.get ​

ts
get(projectId: string): Promise<ProjectRef>;

Thinger.stats ​

Account and traffic statistics.

stats.account ​

ts
account(): Promise<any>;

Account statistics.

stats.usage ​

ts
usage(deviceId?: string): Promise<any>;

Traffic usage over the last 30 days: all devices, or one with deviceId.

Errors and values ​

ThingerError ​

ts
declare class ThingerError extends Error { … }

Error of every SDK call. API errors read HTTP <status> <reason>, with status set.

ThingerError.code ​

ts
readonly code: ThingerErrorCode;

ThingerError.status ​

ts
readonly status?: number;

HTTP status, for code: 'http'.

ThingerError.requires ​

ts
readonly requires?: string;

Minimum server version, for code: 'unsupported' (e.g. "7.6").

ThingerErrorCode ​

ts
type ThingerErrorCode = 'http' | 'unsupported' | 'no-session' | 'invalid-argument' | 'unexpected-response';

Why a call failed:

  • http: the server answered with an error status (status set).
  • unsupported: the server is older than the function needs (requires set).
  • no-session: no user or token yet (before ready(), or opened without a session).
  • invalid-argument: the call itself is wrong (e.g. device: true without a context device).
  • unexpected-response: the server answered something the SDK cannot use.

ALARM_INSTANCE_EVENTS ​

ts
declare const ALARM_INSTANCE_EVENTS: readonly ["alarm_instance_activate", "alarm_instance_normalize", "alarm_instance_create", "alarm_instance_update", "alarm_instance_delete"];

Server events that change the alarm instance list.

ALARM_SEVERITY ​

ts
declare const ALARM_SEVERITY: Readonly<{
    readonly NONE: 0;
    readonly LOW: 1;
    readonly MEDIUM: 2;
    readonly HIGH: 3;
    readonly CRITICAL: 4;
}>;

Numeric severity values of the backend ALARM_SEVERITY enum.

ALARM_STATE ​

ts
declare const ALARM_STATE: Readonly<{
    readonly NONE: 0;
    readonly ACTIVATED: 1;
    readonly ACKNOWLEDGED: 2;
    readonly LATCHED: 3;
    readonly SHELVED: 4;
    readonly CLEARED: 5;
}>;

Numeric state values of the backend ALARM_STATE enum.

BASE_SERVER_VERSION ​

ts
declare const BASE_SERVER_VERSION = "7.4";

Oldest server the SDK supports: everything without a declaration works there.

SDK_VERSION ​

ts
declare const SDK_VERSION = "0.3.1";

Thinger ​

ts
declare const Thinger: ThingerClient;

The SDK, ready to use after await Thinger.ready().

parseTime ​

ts
declare function parseTime(value: Time | null | undefined): number | undefined;

A time value as a milliseconds timestamp; durations count back from now.

Types ​

AlarmInstance ​

ts
interface AlarmInstance {
    instance: string;
    name?: string;
    severity: AlarmSeverity;
    state: AlarmState;
    /** alarm.rule is the rule id. */
    alarm: {
        rule: string;
        [key: string]: unknown;
    };
    /** origin.id is the device. */
    origin: {
        source: 'device';
        id: string;
        name?: string;
    };
    asset_type?: string;
    asset_group?: string;
    project?: string[];
    /** Timestamps in ms. */
    activation?: {
        detections?: number;
        initiated?: number;
        completed?: number;
    };
    normalization?: {
        detections?: number;
        initiated?: number;
        completed?: number;
    };
    /** Values that triggered it: { "<source>.<field>": value }. */
    evaluation?: {
        last_values?: Record<string, unknown>;
        [key: string]: unknown;
    };
    annotation?: string;
    [key: string]: any;
}

AlarmQuery ​

ts
type AlarmQuery = Record<string, unknown>;

Query of alarm instances: exact values, nested fields with dots, an array matching any.

AlarmSeverity ​

ts
type AlarmSeverity = 0 | 1 | 2 | 3 | 4;

AlarmState ​

ts
type AlarmState = 0 | 1 | 2 | 3 | 4 | 5;

AlarmSubscribeQuery ​

ts
interface AlarmSubscribeQuery extends AlarmQuery {
    /** Wait for changes to settle before listing again (default 500 ms). */
    debounceMs?: number;
}

AlarmUpdateOptions ​

ts
interface AlarmUpdateOptions {
    annotation?: string;
    reactivation?: {
        type: 'timespan';
        timespan: {
            value: number;
            magnitude: 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
        };
    };
}

BucketCallback ​

ts
type BucketCallback<T = BucketRecord> = (data: T[] | null, err: Error | null, change?: BucketChange<T>) => void;

BucketChange ​

ts
interface BucketChange<T = BucketRecord> {
    /** Records new or updated in this call (aggregation windows replace the old one), in `data` order. */
    added: T[];
    /** `data` comes from a full read: the first call, refetch, or after an error. */
    reset: boolean;
}

Third argument of the buckets.subscribe callback.

BucketQuery ​

ts
interface BucketQuery {
    /** Device id, or `true` for the device of the dashboard context. */
    device?: string | true | null;
    from?: Time;
    to?: Time;
    /** Max 1000 per call; the server returns 50 when not set. */
    items?: number;
    /** 'desc' (default) or 'asc'. */
    sort?: 'asc' | 'desc';
    /** Aggregation period: '5m', '1h', '1d', '1w', '1mo', '1y'… */
    aggregation?: string;
    /** Aggregation function: 'mean', 'max', 'min', 'sum', 'count', 'first', 'last', 'mode'… */
    aggregator?: string;
    transform?: string;
    /** Fields to return, e.g. ['temperature']. */
    fields?: string | string[];
    /** Group results, e.g. 'device'. */
    groupBy?: string | string[];
    /** IANA zone where aggregation windows start (default: the viewer's browser zone). */
    timeZone?: string;
    /** Tag filters: one value, or any of several. */
    tags?: Record<string, string | number | Array<string | number>>;
}

BucketRecord ​

ts
interface BucketRecord {
    ts: number;
    [field: string]: any;
}

A bucket record: ts (ms) plus the stored fields.

BucketSubscribeOptions ​

ts
interface BucketSubscribeOptions extends BucketQuery {
    /** Wait for writes to settle before updating (default 500 ms). */
    debounceMs?: number;
    /** Re-run the whole read on each write instead of reading only what changed. */
    refetch?: boolean;
}

ClientOptions ​

ts
interface ClientOptions {
    /** The page window; none (server-side rendering) leaves the SDK idle. */
    window?: Window | null;
    fetch?: typeof fetch;
    WebSocket?: typeof WebSocket;
    /** Wait at most this long for the server version before `ready()` resolves (ms, default 3000). */
    versionTimeoutMs?: number;
    /** Inside a frame, reject `ready()` when no `thinger:init` arrives in this time (ms, default 10000). */
    handshakeTimeoutMs?: number;
}

What the SDK takes from its environment. Defaults: the page's own globals.

Context ​

ts
interface Context {
    device?: string | null;
    product?: string | null;
    type?: string | null;
    group?: string | null;
    project?: string | null;
}

The resource whose dashboard property is being shown (null or missing when not set).

DashboardRef ​

ts
interface DashboardRef {
    id: string;
    name?: string;
}

The dashboard being shown.

Device ​

ts
interface Device {
    device: string;
    name?: string;
    description?: string;
    type?: string;
    product?: string;
    asset_type?: string;
    asset_group?: string;
    labels?: Record<string, string>;
    enabled?: boolean;
    connection?: DeviceConnection;
    [key: string]: any;
}

DeviceConnection ​

ts
interface DeviceConnection {
    active?: boolean;
    ts?: number;
    location?: {
        lat?: number;
        lon?: number;
        [key: string]: unknown;
    };
    [key: string]: any;
}

DeviceQuery ​

ts
interface DeviceQuery extends ListQuery {
    product?: string;
    asset_type?: string;
    asset_group?: string;
    type?: string;
    /** `{ key: value }` for exact matches, or `[key]` for devices that have the label. */
    labels?: Record<string, string> | string[];
}

DeviceState ​

ts
type DeviceState = 'connected' | 'disconnected' | 'resumed' | 'awake' | 'asleep';

DeviceStateEvent ​

ts
interface DeviceStateEvent {
    event: 'device_state_change';
    device: string;
    product?: string;
    state: DeviceState;
    ts?: number;
    [key: string]: any;
}

EventFilter ​

ts
interface EventFilter {
    event?: string;
    [key: string]: any;
}

{ event, ...filters }, e.g. { event: 'bucket_write', bucket: 'b' }.

FetchOptions ​

ts
interface FetchOptions extends RequestInit {
    /** false: do not add the console's current `?project=` to this call. */
    project?: false;
}

Options of fetch().

ListQuery ​

ts
interface ListQuery {
    name?: string;
    sort?: string;
    order?: 'asc' | 'desc';
    /** Maximum number of items; all pages are fetched otherwise. */
    limit?: number;
    [filter: string]: unknown;
}

LocationsQuery ​

ts
interface LocationsQuery {
    group?: string;
    type?: string;
    connected?: boolean;
}
ts
type NavigateTarget = string | {
    device: string;
} | {
    product: string;
} | {
    project: string;
} | {
    dashboard: string;
} | {
    url: string;
};

Where navigate() asks the console to go: a path or URL, or one resource.

Product ​

ts
interface Product {
    product: string;
    name?: string;
    description?: string;
    enabled?: boolean;
    config?: Record<string, unknown>;
    profile?: Record<string, unknown>;
    [key: string]: any;
}

Project ​

ts
interface Project {
    id: string;
    owner?: string;
    name?: string;
}

Project the dashboard runs in.

ProjectRef ​

ts
interface ProjectRef {
    project: string;
    name?: string;
    description?: string;
    /** Set on projects shared with the viewer: the account that owns them. */
    owner?: string;
    [key: string]: any;
}

Property ​

ts
interface Property<T = unknown> {
    property: string;
    name?: string;
    description?: string;
    value: T;
    /**
     * Device properties only: the level the value comes from, the first that defines it
     * (device → asset type → asset group → product). `listProperties` leaves it out for the
     * device's own properties.
     */
    source?: PropertySource;
    created?: string;
    modified?: string;
    [key: string]: any;
}

PropertyKind ​

ts
type PropertyKind = 'device' | 'product' | 'project' | 'group' | 'type';

PropertyQuery ​

ts
interface PropertyQuery {
    /** Property id, or a pattern matching several ('temp*'). */
    id?: string;
}

PropertySource ​

ts
type PropertySource = 'device' | 'type' | 'group' | 'product';

Level a device property's value comes from: the first that defines it.

PropertyUpdateEvent ​

ts
interface PropertyUpdateEvent {
    event: 'device_property_update';
    device: string;
    property: string;
    value?: unknown;
    ts?: number;
    [key: string]: any;
}

RequestOptions ​

ts
interface RequestOptions extends Omit<RequestInit, 'body'> {
    /** Any JSON value (serialized automatically), or a string / Blob / FormData / ArrayBuffer sent as is. */
    body?: unknown;
    /** Force the response type. Default: parsed JSON for JSON responses, text otherwise, null when empty. */
    as?: 'json' | 'text' | 'blob' | 'arrayBuffer';
    /** false: do not add the console's current `?project=` to this call. */
    project?: false;
}

Options of request().

ResourceKind ​

ts
type ResourceKind = 'device' | 'product' | 'bucket' | 'group' | 'type' | 'project' | 'dashboard' | 'endpoint' | 'storage' | 'alarm_rule';

ServerEvent ​

ts
interface ServerEvent {
    event?: string;
    [key: string]: any;
}

A server event (bucket_write, alarm_instance_update…): event plus its fields.

StandaloneParams ​

ts
type StandaloneParams = Partial<Record<StandaloneParam, string>>;

Values of a standalone link.

StorageFile ​

ts
interface StorageFile {
    name: string;
    path: string;
    size: number;
    type: 'file' | 'directory';
    [key: string]: any;
}

StreamFrame ​

ts
interface StreamFrame {
    /** 'shadow': the last value saved when the device disconnected, sent once while it is offline. */
    signal: 'data' | 'error' | 'shadow';
    resource?: string;
    ts?: number;
    error?: string;
    payload?: any;
    [key: string]: any;
}

Envelope of a value delivered by streamResource.

Time ​

ts
type Time = number | Date | string;

Milliseconds timestamp, Date, 'now', or a duration before now ('30m', '6h', '7d', '1M'…).

Unsubscribe ​

ts
type Unsubscribe = () => void;

Returned by every subscribe / poll / stream call: stop it.

User ​

ts
interface User {
    id: string;
}

The viewer.

See also ​