Message Protocol
Canvas themes run in an opaque-origin sandbox iframe. The host sends sanitized public data through postMessage; the theme declares readiness, requests height changes and reads whitelisted public resources with fixed message types. The plugin runtime is not open.
Protocol Table
| Direction | Type | Purpose |
|---|---|---|
| Canvas to host | nie-sla:ready | Ask the host to send the current status |
| Host to Canvas | nie-sla:status | Full public status snapshot |
| Canvas to host | nie-sla:resize | Request an iframe height change |
| Canvas to host | nie-sla:request | Request a whitelisted public resource |
| Host to Canvas | nie-sla:response | Return the result or an error |
Type names and the Manifest schema nie-sla-theme-v1 are the current protocol constants; use them literally.
Ready
parent.postMessage({ type: 'nie-sla:ready' }, '*')Send it after the message listener is registered. The host also attempts one status send on iframe load, so themes must accept duplicate snapshots.
Status Snapshot
{
type: 'nie-sla:status',
api_version: 'v1',
payload: { /* same shape as GET /api/v1/status */ }
}Receiver-side validation:
window.addEventListener('message', event => {
if (event.source !== parent) return
if (!event.data || typeof event.data !== 'object') return
if (event.data.type !== 'nie-sla:status') return
if (event.data.api_version !== 'v1') return
render(event.data.payload)
})Height Changes
parent.postMessage({
type: 'nie-sla:resize',
height: document.documentElement.scrollHeight
}, '*')Non-finite values fall back to the default; the host clamps the final height to 400-12000.
History Requests
{
type: 'nie-sla:request',
request_id: 'checks-vps-a-72h',
resource: 'checks',
query: { target_id: 'vps-a', hours: 72, limit: 864 }
}Field rules:
request_idis required, up to 80 characters; the caller avoids collisions.resourceonly allowsstatus,checks,metrics,pings,latency.queryreads at most the first 20 keys.- Keys start with a letter and contain letters, digits or underscores, up to 40 characters.
- Values accept only string, number and boolean; after conversion they are capped at 200 characters.
Success and Failure Responses
{
type: 'nie-sla:response',
api_version: 'v1',
request_id: 'checks-vps-a-72h',
ok: true,
payload: { /* corresponding v1 endpoint response */ }
}{
type: 'nie-sla:response',
api_version: 'v1',
request_id: 'checks-vps-a-72h',
ok: false,
error: 'HTTP 429'
}The theme correlates promises by request_id, sets a timeout, and cleans up pending requests when the iframe is destroyed. Error text is for display or log summaries only, never HTML.
The host drops invalid keys, complex query values and query items beyond the first 20; they are not forwarded to the API. Themes must not treat filtering as input validation; constrain parameters per the endpoint documentation before calling.
Why *
An iframe without allow-same-origin has an opaque Origin, so the host cannot specify a normal website Origin as targetOrigin. Senders use *; receivers verify event.source === parent and strictly constrain message types and capabilities.
Lifecycle
The host may send status once on iframe load and once when it receives nie-sla:ready; theme rendering must be idempotent. Switching or disabling a theme destroys the old iframe, and late responses from the old window must not update the new theme state. Keep a separate request table per mounted instance and clear timers on pagehide or unmount.