- Events: pushed from the host, no response expected
(
config.changed,theme.changed,telemetry.<topic>). - Responses: returned by the host in reply to a plugin request.
Events the host pushes
Subscribe via
ctx.client.on("config.changed", handler) or the typed
wrappers ctx.config.onChange, ctx.theme.onChange, and
ctx.telemetry.subscribe. For any other host-pushed topic (for example
the video.overlay host props the host forwards to a video overlay
iframe, or an agent plugin’s state read-back), use the generic
ctx.events.subscribe(topic, handler), which returns an unsubscribe
function and does no request/response round-trip.
Requests the plugin can send
The SDK context exposes these high-level wrappers. Each delegates to a singlePluginClient; drop to ctx.client.request(method, capability, args) for anything else.
The host registry also recognizes
telemetry.unsubscribe, recording.start
and recording.stop (capability recording.write), events.subscribe and
events.publish (event.subscribe / event.publish, both require a
topic arg), cloud.read and cloud.write, plus three always-allowed
methods that need no capability: ping, notify, and i18n.t. A method
that is not in the registry is rejected with method_unknown.
The host re-resolves the required capability from the method (and, for
telemetry, from the topic) and checks the granted set. The plugin never
computes the capability id itself.
Wire shape
PluginClient generates
the id, attaches the protocol version, and waits for the correlated
response.
Error envelopes
When the host rejects a request it returns a response witherror: { code, message }. The SDK throws a HostError whose code
field carries the machine-readable code:
Branch on
code, not on message. Messages are for log lines.
There is also an
origin_mismatch error, but the host never sends it to
the plugin. When a message arrives from a window that is not the trusted
iframe, the bridge drops it and records a security event host-side rather
than replying. A plugin will never see it on the wire.Theming
theme.changed arrives once on mount and again on every theme toggle.
The payload is a Record<string, string> of CSS variables. Apply them by
walking the entries:
i18n
Plugin authors ship a locale bundle in their archive; the host streams the active bundle to the plugin on mount. The SDK formats keys withctx.i18n.t(key, params):
{name} placeholder so it is visible in QA.