Skip to main content

Events, Types, and Error Codes

Events

WidgetEventName has 8 event names in total, all subscribable via api.on(name, listener) (which returns an unsubscribe function). Some capabilities additionally have dedicated subscription entry points (storage.onChanged, todos.onChanged, channel.subscribe, onWidgetThemeChanged):

Event namePayload typeShape
channelMessageWidgetChannelMessageEvent{ message: WidgetJsonValue }, a structured-clone copy
localeChangedWidgetLocaleChangedEvent{ locale: 'zh-CN' | 'en-US' }
sizeChangedWidgetSizeChangedEvent{ previousSize: WidgetTileSize; size: WidgetTileSize }
storageChangedWidgetStorageChangedEvent{ key: string; operation: 'set' | 'remove' }, deliberately without the value
themeChangedWidgetThemeChangedEvent{ theme: 'light' | 'dark'; reducedMotion: boolean; tokens?: WidgetThemeTokens }
todoChangedWidgetTodoChangedEvent{ change: 'created' | 'updated' | 'deleted'; id: string }
variantChangedWidgetVariantChangedEvent{ previousVariantId?: string; variantId?: string }
visibilityChangedWidgetVisibilityChangedEvent{ visible: boolean }; hiding does not destroy instance storage or the session

Event DTOs carry protocol/apiVersion/sessionId, and the SDK validates them before delivering to listeners; mismatched port messages are silently ignored.

WidgetContext

interface WidgetContext {
componentId: string
instanceId: string
componentVersion: string
apiVersion: 1
surface: string
size: WidgetTileSize // {w:1,h:1} | {w:2,h:2} | {w:3,h:2} | {w:4,h:2}
variantId?: string
locale: 'zh-CN' | 'en-US'
theme: 'light' | 'dark'
reducedMotion: boolean
visible: boolean
permissions: WidgetPermissionSnapshot
}

interface WidgetPermissionSnapshot {
granted: readonly WidgetPermission[]
networkOrigins: readonly `https://${string}`[]
}

Obtained via api.context.get(); each call returns a copy, and event payloads are the current snapshot after the change.

WidgetJsonValue

The only payload shape allowed by storage and channel — plain JSON that can be transferred across a MessagePort:

type WidgetJsonValue =
| null
| boolean
| number
| string
| readonly WidgetJsonValue[]
| { readonly [key: string]: WidgetJsonValue }

WidgetThemeTokens

A versioned theme-token snapshot that the themeChanged event may carry:

interface WidgetThemeTokens {
version: 1
values: Readonly<Record<WidgetThemeTokenName, string>>
}

WidgetThemeTokenName is a union type of the 20 --pt-* token names; see theme.css and Theme Tokens for the full list.

Permission Types

const WIDGET_TODO_PERMISSIONS = ['todos.read', 'todos.create', 'todos.update', 'todos.delete'] as const
const WIDGET_PERMISSIONS = WIDGET_TODO_PERMISSIONS // v1 全部可声明权限

type WidgetPermission = (typeof WIDGET_PERMISSIONS)[number]
type WidgetPermissionSet = readonly WidgetPermission[]

interface WidgetPermissionDeclarations {
required?: readonly WidgetPermission[]
optional?: readonly WidgetPermission[]
}

function validateWidgetPermissionDeclarations(
declarations: WidgetPermissionDeclarations | undefined,
): WidgetContractValidationResult

The validator rejects: unknown permissions, duplicate declarations within the same list, and the same permission appearing in both required and optional. Failure results carry an INVALID_ARGUMENT error with a field path (e.g. permissions.required[0]).

Error Codes

When a host API fails, it returns a stable error code via WidgetApiError (WidgetErrorCode, 19 in total):

Error codeTrigger scenario
API_INCOMPATIBLEThe Manifest's apiVersion does not match the host's API major version
CONCURRENCY_LIMITConcurrent request limit exceeded (16 total / 4 network)
INSTANCE_DISABLEDThe instance was automatically disabled due to consecutive failures
INTEGRITY_FAILEDIntegrity manifest verification failed
INVALID_ARGUMENTAn argument failed contract validation
INVALID_PACKAGEThe widget package is invalid
INVALID_REQUESTThe RPC message shape/protocol/session is invalid
MANIFEST_INVALIDThe Manifest failed Schema validation
ORIGIN_NOT_ALLOWEDThe network origin is not declared/authorized, or the URL is invalid
PERMISSION_DENIEDA permission has not been granted or has been revoked
QUOTA_EXCEEDEDInstance storage exceeded the 1 MiB quota
RATE_LIMITEDRequest rate limit exceeded (100 requests per 10 seconds)
RESPONSE_TOO_LARGEThe network response body exceeded 2 MiB
SAFE_MODE_ACTIVEThe host is in safe mode; third-party widgets are paused
SIGNATURE_INVALIDSignature verification failed
SURFACE_LIMIT_REACHEDThe instance already has an overlay open; a duplicate open was requested
SURFACE_NOT_DECLAREDThe requested surface is not declared in the Manifest
TIMEOUTHost-side processing timed out
UNKNOWN_METHODUnknown RPC method name

Error messages are user-facing and contain no host-internal details; the path field only points to the offending field of a public DTO. All error codes can also be read from the WIDGET_ERROR_CODES constant array.

Validation Result Types

The SDK's pure validation functions uniformly return:

type WidgetContractValidationResult =
| { valid: true }
| { valid: false; error: WidgetApiError }

function createWidgetContractValidationSuccess(): WidgetContractValidationSuccess
function createWidgetContractValidationFailure(
code: WidgetErrorCode, message: string, path: string,
): WidgetContractValidationFailure