Standalone operation

Standalone is what the dashlet becomes when it runs outside any enaio environment — a plain browser tab, a dev server, or any non-enaio embed: no bridge, no events. It is a first-class state, not a failure.

1. How standalone is reached

There is no explicit flag. The detection state machine (see Environments and detection) simply times out: when no rich-client bridge and no accepted webclient event arrive within the detection cap (detectionTimeoutMs, default 5000 ms), the dashlet settles as standalone. It is never a hang — the state is reached in bounded time, and it is observable through the normal init promise.

Two further corners arrive at the same state:

  • Top-level window, no configured origin: origin learning only works inside an iframe. A top-level window that has no configured origin never learns and degrades to standalone after the detection cap (see Origin configuration).

  • Foreign-origin host: a webclient-style onInit posted from an origin that fails validation is rejected; nothing initializes, and the dashlet degrades to standalone within the same bounded cap.

2. What a standalone dashlet does

Surface Behavior

dashlet.init

Resolves exactly once and never rejects, with environment: 'standalone' and an empty/absent selection — the degraded state is an observable fallback, not an error

onInit / onUpdate listeners

Registered normally; they replay the standalone init and never fire updates

call(method, params)

Rejects with the bounded TimeoutError (no host reply path exists)

All seven portable facade methods

Same as call(): each rejects with the bounded TimeoutError

The rule for dashlet code: render a fallback instead of waiting. The init promise is the place to branch — if ctx.environment === 'standalone', show your offline/degraded UI and don’t await any host call.

3. The timeout mechanics

Every host interaction that awaits a reply is bounded: the init wait by the detection cap (detectionTimeoutMs, default 5000 ms) plus a 250 ms safety net, every method call by the response timeout (timeoutMs, default 5000 ms). A timeout rejects with the distinct TimeoutError (error name DashletTimeoutError, carrying the operation and the timeout it hit), so dashlet code can distinguish "host never answered" from any other failure:

import { TimeoutError } from 'ecmind-blue-dashlet';

await dashlet.openIndexData({ inNewTab: false, mode: 'view', objectId: '1024' })
    .catch((e) => {
        if (e instanceof TimeoutError) {
            showFallback(); // standalone or a dead host — no retry loop
        }
        throw e;
    });

The enaio contract defines no response guarantee; the bound is what makes "no response" an observable state.

4. Tuning the knobs

Option Default Standalone-relevant meaning

detectionTimeoutMs

5000

Detection cap: how long the dashlet probes for a bridge / waits for an onInit before reporting standalone

timeoutMs

5000

Response timeout for every method call — in standalone, this is how quickly each facade call rejects with TimeoutError

pollIntervalMs

50

Rich-client bridge poll interval (no effect on standalone, but part of the same tuning story: a late bridge is caught by polling within the detection cap)