@hyperfrontend/features/host

Host

Host-side SDK for embedding hyperfrontend features — shell factory, display modes, iframe utilities, and lifecycle.

import { builtInDisplayModes, createShell, DisplayMode } from '@hyperfrontend/features/host'

const shell = createShell({
  modes: builtInDisplayModes,
  url: 'https://features.example.com/clock',
  container: '#clock-slot',
  displayMode: DisplayMode.Embedded,
})

shell.on('open', () => console.log('feature connected'))
shell.on('tick', (time) => console.log('feature said', time))

shell.open()
shell.send('set-timezone', { tz: 'UTC' })

API

ExportPurpose
createShellBuild a shell handle from an explicit modes map — only the mounts you pass ship.
builtInDisplayModesThe all-modes map, for hosts that want every mode available.
mountEmbeddedThe four mount functions (mountEmbedded, mountDialog, mountPopup, mountStandalone) for the modes map.
DisplayModeThe four built-in modes: Embedded, Dialog, Popup, Standalone.
ShellHandleType of the handle returned by createShell.
CreateShellOptionsOptions accepted by createShell (ShellOptions plus the modes map).
ExperiencePluginOpt-in extension point for layering transitions/animations onto display modes.

The modes map is how unused mode code stays out of bundles: a generated shell passes exactly the modes its feature declared, and a hand-written host that only ever embeds can pass { embedded: mountEmbedded } and ship one mode. Opening a mode outside the map throws, naming the supported set.

The shell wraps a @hyperfrontend/nexus broker: send emits a contract action to the feature, and on subscribes to feature messages and the open/closing/close/error/status/dirty-state/dismiss lifecycle events. close disconnects the channel politely (the feature gets a closing flush window, and isDirty reports declared unsaved work first); destroy also releases the DOM.

Opening is asynchronous: isOpen stays false and sends queue until the wire handshake with the feature completes, flushing on the open event. If the feature never completes the handshake within openTimeoutMs (default 10 s), the shell tears the mount down and emits error with reason: 'open-timeout'.

A feature that reloads itself (a refresh, an in-frame navigation, a dev-server rebuild) ends its session but keeps its mount: close fires with { reason: 'peer-reload' }, then open fires again once the new document completes its own handshake, and the shell re-announces the presentation to it. Treat the pair as a session boundary — pending requests reject, isDirty resets, and anything you sent the previous document needs sending again. To refuse the reload instead, destroy() on that reason.

Display modes and sizing

The host owns presentation. It picks the display mode (from the set the feature's contract declares), announces it to the feature once per mount — the announcement already carries the frame's initial dimensions, so the feature lays itself out without waiting for a second message — and is the single authority on frame geometry: every dimension crosses the boundary as an exact pixel value, host to feature, never the other way.

Mounted is not displayed: the frame mounts hidden and is revealed only once the session opens, so the user never sees (or clicks into) a frame whose feature is not ready. A dialog pane cannot intercept the page while it is still connecting; an embedded frame reserves its box without painting.

Embedded mounts the frame inline in your container and the frame fills the container's content box — measured before the frame is inserted, then observed with a ResizeObserver; every later change is reported to the feature. While the container has no measurable size (hidden, not yet laid out, or nothing gives it a height), the SDK applies a dynamic viewport-derived fallback so the embed is never invisible by accident; the fallback retires as soon as your layout takes over. A feature with intrinsic dimensions can bake fixed embedWidth/embedHeight instead (or you can pass them) — then the frame gets exactly those pixels and you place the container somewhere they fit; the SDK never distorts a fixed agreement.

Dialog is a full-viewport transparent pane layered above your page. The feature draws its dialog box (and any backdrop paint) inside the pane; dialogWidth/dialogHeight set the inner box (viewport-derived when unset) and dialogPosition places it — center by default, or any edge/corner (top-leftbottom-right). The feature detects backdrop clicks and in-frame Escape presses and reports them as a dismiss signal; dialogBackdrop decides what the shell does — close (default) starts the polite teardown, event emits a dismiss event for you to handle, none ignores it. closeOnEscape covers Escape from both documents.

shell.open({ displayMode: DisplayMode.Dialog, dialogWidth: 480, dialogPosition: 'top-center', dialogBackdrop: 'event' })
shell.on('dismiss', ({ source }) => console.log('backdrop interaction', source))

Popup opens a separate window at popupWidth/popupHeight (viewport-derived when unset), placed on the screen per popupPosition (center by default, or any edge/corner). After that the window belongs to the browser and the user: they move and resize it freely, and no frame geometry crosses the boundary. The window's title and chrome are not the host's to set — the title comes from the loaded document (the feature sets its own document.title), and browsers ignore chrome flags like resizability for window.open. Standalone is a plain new tab — the simplest mode, deliberately free of presentation coordination.

Transparency is on by default in both iframe modes (allowtransparency plus a matched color-scheme pin on both sides — a mismatch would force an opaque canvas), so features can render non-rectangular designs, blend with your UI, and paint dialog backdrops. Want an opaque embed? Give your container a background.

What the SDK deliberately does not do

  • Content-driven growth (the embed grows with its content) is not built in — it would hand geometry authority to the feature, which is the inversion this design exists to avoid. The recipe is one contract action: have the feature emit its content height as product data, and set it on the container you own (shell.on('contentHeight', (px) => setContainerHeight(px))); the SDK's container observation propagates the change back down.
  • Clipping and scrolling are not managed. The feature owns its document's overflow behaviour; the host owns the container's. Neither needs a protocol.
  • Draggable/resizable dialog boxes are not built in — but the full-viewport pane makes them a pure feature-side concern: the pane never moves, so the feature can drag or resize its inner box with ordinary CSS/pointer code and nothing needs to cross the boundary. If your host UI needs to know, carry position as an ordinary contract action.

Browser capabilities

Capability is one of the two axes in the Security Model — read it for where these options sit relative to what the browser enforces and what stays the operator's job.

Two ShellOptions fields govern what the feature frame may do with the browser around it, both applied before the frame loads (the only moment they take effect) and both scoped to the iframe modes — popup and standalone open top-level windows, which ask the user for permissions directly.

permissions delegates Permissions-Policy features (camera, fullscreen, clipboard, …) to the frame via the iframe allow attribute. Browsers deny these to cross-origin frames by default, so a feature that needs one only works when the host delegates it. A generated shell bakes the needs the feature declared at build time (also disclosed in its README and metadata.json); a host-supplied list replaces the baked one entirely.

sandbox is the host's containment lever and is never baked by a build. true (or an opt-in object) starts the frame from the browser's deny-all sandbox; the SDK manages the two hazardous tokens itself — allow-scripts is always granted (the feature runtime is JavaScript), and allow-same-origin is granted only to cross-origin feature URLs, since a same-origin frame holding both tokens could remove its own sandbox. A sandboxed same-origin feature therefore runs with an opaque origin (no cookies or storage) while the messaging protocol still connects. Everything else — forms, popups, modals, downloads, topNavigationByUserActivation — is denied unless opted in. Requesting a sandbox on popup or standalone throws, because no containment can apply to a top-level window.

shell.open({
  permissions: ['fullscreen', 'clipboard-write'],
  sandbox: { downloads: true },
})

API Reference

ƒ Functions

§function

createShell(options: CreateShellOptions): ShellHandle

Creates a host-side shell for embedding a feature.
Provisions a nexus broker and returns a handle whose open mounts the feature in the requested display mode. The shell is built from an explicit modes map — pass the mounts this host supports (which is how generated shells exclude undeclared modes from their bundles) or builtInDisplayModes for all of them; opening a mode outside the map throws, naming the supported set. The contract option takes the feature's contract exactly as the feature authored it; the shell derives the host-side orientation itself, so the handle sends what the feature accepts and receives what the feature emits.

Parameters

NameTypeDescription
§options
CreateShellOptions
Create-time options including the modes map; overridable per open call.

Returns

ShellHandle
A handle exposing open, close, destroy, send, on, and isOpen.

Example

Embedding a clock feature with every built-in mode available

const clock = createShell({ modes: builtInDisplayModes, container: '#clock', url: 'https://clock.example.com' })
clock.open({ displayMode: DisplayMode.Dialog, dialogWidth: 530 })
clock.on('timeUpdated', (data) => console.log(data))

Interfaces

§interface

CreateShellOptions

Options accepted by createShell: the shell options plus the display modes this shell is built from.

Properties

§closeOnEscape?:boolean
Whether Escape closes the dialog; defaults to true. Enforced on both sides of the boundary: the host listens in its own document, and the feature reports an Escape pressed inside its frame as a dismiss signal the host acts on (dialog mode only).
§container?:string | HTMLElement
Anchor element (or CSS selector) the embedded feature mounts into; required by (and only meaningful for) embedded mode.
§contract?:FeatureContract
The feature's contract exactly as the feature authored it (emitted = what the feature sends, accepted = what the feature handles). The shell derives the host-side orientation itself — hand it the feature's contract, never a pre-swapped copy. Replaces the generic default when provided.
§dialogBackdrop?:BackdropBehavior
How the host reacts to a pointer interaction on the dialog backdrop — the transparent area around the feature's dialog box; defaults to close. See BackdropBehavior.
§dialogHeight?:number
Height in pixels of the feature's inner dialog box; see ShellOptions.dialogWidth.
§dialogPosition?:BoxPosition
Where the inner dialog box sits inside the pane (dialog mode only); defaults to center.
§dialogWidth?:number
Width in pixels of the feature's inner dialog box (dialog mode only). Crosses the boundary at open and is applied by the hostee SDK inside the full-viewport dialog pane; when absent, the hostee derives a size from the viewport and its aspect ratio.
§displayMode?:DisplayMode
How the feature should be surfaced; defaults to DisplayMode.Embedded.
§embedHeight?:number
Fixed embedded height in pixels; see ShellOptions.embedWidth.
§embedWidth?:number
Fixed embedded width in pixels. When both embedWidth and embedHeight are set, the embedded iframe receives exactly those dimensions instead of filling its container, and the host application is responsible for placing the container somewhere the feature fits — the SDK never distorts or reinterprets fixed dimensions. Setting only one of the pair throws.
§modes:DisplayModeMap
The display modes this shell supports, mode name to mount function.
§name?:string
Stable identifier for the feature; seeds the broker name surfaced in debug logs.
§onUnresponsive?:UnresponsivePolicy
How the host reacts when the feature stops responding; defaults to emit.
§openTimeoutMs?:number
Milliseconds the shell waits for the feature to complete the connection handshake before emitting an error with reason: 'open-timeout' and tearing the mount down; defaults to 10000.
Opening is asynchronous: isOpen stays false and the open event fires only once the wire handshake completes. send/request calls issued in between queue on the channel and flush on open.
§permissions?:unknown
Permissions-Policy features delegated to the feature frame, applied as the iframe allow attribute scoped to the frame's own origin. Shell builds bake the feature's declared needs here; a host-supplied list replaces the baked one entirely. Only the iframe modes (embedded, dialog) apply it — popup and standalone open top-level windows, which request these permissions from the user directly.
§plugins?:unknown
Experience plugins wrapped around each mount/unmount; onMount runs in registration order, onUnmount in reverse.
§popupHeight?:number
Popup window height in pixels (popup mode only); when absent, derived from the viewport.
§popupPosition?:BoxPosition
Where the popup window sits on the screen (popup mode only); defaults to center.
§popupWidth?:number
Popup window width in pixels (popup mode only); when absent, derived from the viewport.
§protocol?:SecurityProtocol
Security envelope to negotiate; defaults to none.
§sandbox?:boolean | SandboxOptions
Containment posture for the feature frame. true (or an opt-in object) starts the frame from the browser's deny-all sandbox; the SDK always returns allow-scripts, grants allow-same-origin only to cross-origin feature URLs, and denies everything else unless opted in — see SandboxOptions for the managed tokens and why. Host-decreed and never baked by a shell build. Only meaningful for the iframe modes: opening popup or standalone with a sandbox set throws, because no containment can apply to a top-level window.
§sharedKey?:string
Pre-shared key used by the v2 protocol.
§url?:string
URL of the feature app to load.
§interface

HeartbeatStatus

Snapshot of the watchdog's judgement.

Properties

§lastBeatAt:number
Timestamp of the last received beat, or null if none arrived.
§missedBeats:number
Consecutive watchdog ticks without a beat.
§state:HeartbeatState
Current liveness state.
§interface

MountContext

Context handed to a display-mode mount function.

Properties

§options:ShellOptions
The fully merged shell options for this open.
§interface

MountResult

Outcome of mounting a display mode: the window to message plus a teardown hook.

Properties

§element?:HTMLElement
In-document root the mode mounted (the feature iframe); unset when the feature opens in a separate window.
§present:PresentPayload
Presentation announcement the shell sends the feature once per mount: the mode, the frame's initial dimensions, and any agreed dialog box geometry.
§target:Window
Window the host messages, or null when a popup/standalone was blocked.
§viewport?:ViewportReporter
Reporter of the frame's exact pixel space, when the mode observes an iframe; the shell forwards its change reports once the channel opens.
§interface

ShellHandle

Public handle returned by createShell.

Properties

§readonly isDirty:boolean
Whether the feature has declared unsaved work (true between setDirty(true) and setDirty(false); resets when the channel closes).
§readonly isOpen:boolean
Whether the feature channel is currently open (true while connected).
§interface

ViewportReporter

Reports the exact pixel dimensions of the space a feature frame occupies.
Created by a display-mode mount seeded with a synchronous initial measurement: current() feeds the presentation announcement, and once the shell calls start, only changes relative to what was already announced are forwarded — the initial size never crosses twice.

Properties

§interface

ActionDescription

Description of a single action a feature can emit or accept.
Structurally compatible with nexus's channel contract action shape so the same contract can drive both messaging and the shell type generator.

Properties

§description?:string
Human-readable explanation of the action, surfaced in tooling.
§required?:boolean
Marks an accepted action as essential for correct operation: the connection is denied at handshake time unless the counterpart emits this type. Only meaningful on accepted entries. Unflagged actions never gate the connection, so additive contract evolution stays non-breaking.
§respondsWith?:string
When this action is used as a request, the type of the action in the other direction that answers it.
§schema?:object
Optional JSON-schema-like shape describing the action payload.
§type:string
Wire type string that identifies the action.
§interface

ExperiencePlugin

Opt-in extension that decorates a feature's mount lifecycle (e.g. transitions, animations).
Register plugins through ShellOptions.plugins. After each successful mount the shell calls onMount on every plugin in registration order; before each unmount it calls onUnmount one plugin at a time in reverse registration order, awaiting any returned promise, then runs the teardowns returned by onMount (also in reverse registration order) and finally removes the feature. The SDK ships no built-in plugins.

Properties

§name:string
Unique plugin name, surfaced in debug logs.
§interface

ExperiencePluginContext

Context handed to an ExperiencePlugin around a feature's mount lifecycle.

Properties

§displayMode:DisplayMode
The display mode the feature was surfaced in.
§element:HTMLElement
The in-document root the display mode mounted: the iframe for embedded, the dialog container for dialog, and null for popup and standalone, which open a separate window with no in-document element.
§interface

FeatureContract

The set of actions a feature emits to, and accepts from, its counterpart.
This is the same shape the on-disk *.contract.json files and the shell generator consume.

Properties

§accepted:ActionDescription[]
Actions this side handles from the other side.
§emitted:ActionDescription[]
Actions this side sends to the other side.
§version?:string
Optional semver version announcing the contract cut this side holds. Builds canonicalize and bake it into the generated shell; the two sides compare their announcements during the connection handshake and incompatible cuts are denied before the channel opens. Absent on either side, the check passes, so unversioned peers keep connecting.
§interface

PresentPayload

Payload of the reserved present control message the host sends once per mount: the display mode this mount uses, the frame's initial dimensions, and the agreed inner dialog box geometry when the mode is dialog.

Properties

§dialog?:DialogBoxSize
Agreed inner dialog box geometry (dialog mode only).
§mode:DisplayMode
The display mode the host mounted the feature in.
§viewport?:ViewportPayload
The frame's usable space at mount time, in exact pixels (iframe modes only), so the feature can lay itself out without waiting for the first viewport report — later changes arrive as viewport reports.
§interface

RequestOptions

Per-request settings accepted by request.

Properties

§timeoutMs?:number
Milliseconds to wait for the response before rejecting; defaults to 30000.
§interface

SandboxOptions

Containment opt-ins for a sandboxed feature frame.
Enabling ShellOptions.sandbox starts the frame from the browser's deny-all sandbox and returns capabilities selectively. Two tokens are managed by the SDK and are not configurable: allow-scripts is always present (the feature runtime is JavaScript, so a script-less frame can never connect), and allow-same-origin is granted only when the feature URL resolves to a different origin than the host page — a same-origin frame holding both tokens could remove its own sandbox, so that pairing cannot be expressed. A sandboxed same-origin feature therefore runs with an opaque origin (no cookies or storage); the messaging protocol still connects. Every opt-in below defaults to false (denied).

Properties

§downloads?:boolean
Allow the feature to trigger file downloads; defaults to false.
§forms?:boolean
Allow the feature to submit forms; defaults to false.
§modals?:boolean
Allow the feature to open modal dialogs (alert, confirm, print); defaults to false.
§popups?:boolean
Allow the feature to open popup windows; defaults to false.
§topNavigationByUserActivation?:boolean
Allow the feature to navigate the top-level page in response to a user activation (e.g. a clicked link targeting _top); defaults to false. Unrestricted top-level navigation is deliberately not offered — it enables an entire class of takeover incidents that user-activation gating avoids.
§interface

ShellOptions

Options accepted by the host-side FeatureContract consumer when creating or opening a shell.

Properties

§closeOnEscape?:boolean
Whether Escape closes the dialog; defaults to true. Enforced on both sides of the boundary: the host listens in its own document, and the feature reports an Escape pressed inside its frame as a dismiss signal the host acts on (dialog mode only).
§container?:string | HTMLElement
Anchor element (or CSS selector) the embedded feature mounts into; required by (and only meaningful for) embedded mode.
§contract?:FeatureContract
The feature's contract exactly as the feature authored it (emitted = what the feature sends, accepted = what the feature handles). The shell derives the host-side orientation itself — hand it the feature's contract, never a pre-swapped copy. Replaces the generic default when provided.
§dialogBackdrop?:BackdropBehavior
How the host reacts to a pointer interaction on the dialog backdrop — the transparent area around the feature's dialog box; defaults to close. See BackdropBehavior.
§dialogHeight?:number
Height in pixels of the feature's inner dialog box; see ShellOptions.dialogWidth.
§dialogPosition?:BoxPosition
Where the inner dialog box sits inside the pane (dialog mode only); defaults to center.
§dialogWidth?:number
Width in pixels of the feature's inner dialog box (dialog mode only). Crosses the boundary at open and is applied by the hostee SDK inside the full-viewport dialog pane; when absent, the hostee derives a size from the viewport and its aspect ratio.
§displayMode?:DisplayMode
How the feature should be surfaced; defaults to DisplayMode.Embedded.
§embedHeight?:number
Fixed embedded height in pixels; see ShellOptions.embedWidth.
§embedWidth?:number
Fixed embedded width in pixels. When both embedWidth and embedHeight are set, the embedded iframe receives exactly those dimensions instead of filling its container, and the host application is responsible for placing the container somewhere the feature fits — the SDK never distorts or reinterprets fixed dimensions. Setting only one of the pair throws.
§name?:string
Stable identifier for the feature; seeds the broker name surfaced in debug logs.
§onUnresponsive?:UnresponsivePolicy
How the host reacts when the feature stops responding; defaults to emit.
§openTimeoutMs?:number
Milliseconds the shell waits for the feature to complete the connection handshake before emitting an error with reason: 'open-timeout' and tearing the mount down; defaults to 10000.
Opening is asynchronous: isOpen stays false and the open event fires only once the wire handshake completes. send/request calls issued in between queue on the channel and flush on open.
§permissions?:unknown
Permissions-Policy features delegated to the feature frame, applied as the iframe allow attribute scoped to the frame's own origin. Shell builds bake the feature's declared needs here; a host-supplied list replaces the baked one entirely. Only the iframe modes (embedded, dialog) apply it — popup and standalone open top-level windows, which request these permissions from the user directly.
§plugins?:unknown
Experience plugins wrapped around each mount/unmount; onMount runs in registration order, onUnmount in reverse.
§popupHeight?:number
Popup window height in pixels (popup mode only); when absent, derived from the viewport.
§popupPosition?:BoxPosition
Where the popup window sits on the screen (popup mode only); defaults to center.
§popupWidth?:number
Popup window width in pixels (popup mode only); when absent, derived from the viewport.
§protocol?:SecurityProtocol
Security envelope to negotiate; defaults to none.
§sandbox?:boolean | SandboxOptions
Containment posture for the feature frame. true (or an opt-in object) starts the frame from the browser's deny-all sandbox; the SDK always returns allow-scripts, grants allow-same-origin only to cross-origin feature URLs, and denies everything else unless opted in — see SandboxOptions for the managed tokens and why. Host-decreed and never baked by a shell build. Only meaningful for the iframe modes: opening popup or standalone with a sandbox set throws, because no containment can apply to a top-level window.
§sharedKey?:string
Pre-shared key used by the v2 protocol.
§url?:string
URL of the feature app to load.
§interface

UnresponsiveInfo

Context passed to an UnresponsivePolicy callback when a feature stops beating.

Properties

§displayMode:DisplayMode
The display mode the unresponsive feature was using.
§lastBeatAt:number
Timestamp (ms) of the last beat received, or null if none ever arrived.
§missedBeats:number
Consecutive missed beats that tripped the watchdog.
§interface

ViewportPayload

Payload of the reserved viewport control message: the exact pixel dimensions of the space the feature's frame occupies, reported by the host whenever the measured space changes (iframe modes only).

Properties

§height:number
Usable height in pixels.
§width:number
Usable width in pixels.

Types

§type

DisplayModeMap

The display modes a shell is created from: mode name to mount function.
Only the mount functions handed in are reachable, so a shell that passes the modes its feature contract declares (as generated shells do) ships no code for the others. Pass builtInDisplayModes to support every mode.
type DisplayModeMap = Partial<Record<DisplayMode, DisplayModeMount>>
§type

DisplayModeMount

Mounts a feature for a single display mode and returns its MountResult.
type DisplayModeMount = (context: MountContext) => MountResult
§type

HeartbeatState

Liveness state of the connected feature, as judged by the watchdog.
  • healthy — beats are arriving within the expected budget.
  • unobservable — the host page or the feature page is hidden, so browser
timer throttling makes silence weak evidence; the watchdog pauses.
  • suspect — the pages are visible and the miss budget is exhausted; the
feature is probably unhealthy.
  • gone — the session is closed or destroyed (or not yet open).
type HeartbeatState = "healthy" | "unobservable" | "suspect" | "gone"
§type

BackdropBehavior

How the host reacts when the feature reports a pointer interaction on the dialog backdrop (the transparent area outside the feature's dialog box).
close (the default) treats the interaction as a close request and starts the polite teardown; event surfaces it as a dismiss event for the host consumer to handle; none ignores it.
type BackdropBehavior = "close" | "event" | "none"
§type

BoxPosition

Where a positioned box sits inside its available area: the dialog inner box within the full-viewport pane, or the popup window on the screen.
center (the default) centers on both axes; the compound values anchor to an edge or corner of the area.
type BoxPosition = "center" | "top-left" | "top-center" | "top-right" | "center-left" | "center-right" | "bottom-left" | "bottom-center" | "bottom-right"
§type

DismissSource

Where a hostee dismiss signal originated: a pointer interaction on the dialog backdrop, or the Escape key pressed inside the feature's document.
type DismissSource = "backdrop" | "escape"
§type

EventHandler

Handler invoked when a subscribed event fires.
type EventHandler = (data: unknown) => void
§type

FeaturePermission

A Permissions-Policy feature name the host can delegate to the feature frame.
Browsers deny powerful features (camera, fullscreen, clipboard, …) to cross-origin frames by default, so a feature that needs one only works when the host delegates it. The union lists the common names for editor completion; any string the browser understands is accepted.
type FeaturePermission = "accelerometer" | "autoplay" | "camera" | "clipboard-read" | "clipboard-write" | "display-capture" | "encrypted-media" | "fullscreen" | "gamepad" | "geolocation" | "gyroscope" | "magnetometer" | "microphone" | "midi" | "payment" | "picture-in-picture" | "publickey-credentials-get" | "screen-wake-lock" | "usb" | "web-share" | "xr-spatial-tracking" | string & { }
§type

RequestHandler

Answers one request type; may return the response value directly or a promise of it.
type RequestHandler = (data: unknown) => unknown
§type

SecurityProtocol

Union of the supported security envelope selectors.
none is the local default (opt-in security); production builds must pick v1 or v2.
type SecurityProtocol = "none" | "v1" | "v2"
§type

UnresponsivePolicy

What the host does when a feature misses too many heartbeats while visible.
emit (the default) emits an error; unmount also tears the feature down; a callback takes over handling entirely with the UnresponsiveInfo. The policy runs once per suspect episode: a recovering beat returns the feature to healthy and re-arms it. While either page is hidden the watchdog pauses instead (unobservable) — throttled timers make silence weak evidence.
type UnresponsivePolicy = "emit" | "unmount" | (info: UnresponsiveInfo) => void

Variables

§type

builtInDisplayModes

Every built-in display mode, mode name to mount function.
createShell composes a shell from this full map; generated shells import the individual mounts and compose only the modes their feature declared, so this map (and the modes it would drag in) stays out of their bundles.
§type

mountDialog

Mounts a feature as a full-viewport dialog pane layered above the host UI.
The pane is a single transparent iframe spanning the host viewport; the feature renders its dialog box inside it and the transparent remainder is the backdrop. It mounts hidden — inert to the user and the page — and is revealed once the session opens. Backdrop and in-frame Escape interactions are detected by the feature side and cross as dismiss signals the shell acts on per dialogBackdrop/closeOnEscape; an Escape pressed while the host document holds focus is handled here directly.
§type

mountEmbedded

Mounts a feature inline inside the host-provided container element.
By default the iframe fills the container's content box — measured before the iframe is inserted, so the announcement carries the container's own dimensions — and a reporter forwards every later change (with viewport-derived fallback dimensions while the container has none). When the merged options agree a fixed embedWidth/embedHeight, the iframe receives exactly those dimensions and the host application places the container so the feature fits. The frame mounts hidden and is revealed once the session opens.
§type

mountPopup

Mounts a feature in a separate, sized browser popup window.
The window opens at the agreed popupWidth/popupHeight (falling back to a viewport-derived size), placed on the screen per popupPosition — centered by default. Once open, the window is the browser's: the user may move and resize it freely, the feature's own window is its viewport (no viewport reports cross the boundary), and no sandbox or permissions delegation can apply to a top-level window. The window's title and chrome belong to the loaded document and the browser — the feature sets document.title; the host cannot.
§type

mountStandalone

Mounts a feature in a full standalone browser tab/window.
The simplest mode: the browser's normal new-tab behavior is sufficient, so no sizing or presentation coordination applies — only the ordinary session lifecycle over the opener relationship.
§type

DisplayMode

Supported ways a host can surface an embedded feature.
The host selects the mode; a feature declares which modes it supports in its feature.config.* display.modes, and the generated shell composes exactly those.