DocumentationDocumentation
API reference/Python API

Actions and call context

Find action registration, arguments, context, resource attachments, and result contracts.

action: register an operation callable from the page

After binding successfully, use plugin.bridge() to obtain the bridge and register the action once. Only trusted local pages can call it; development-server and remote pages do not receive the bridge. See Call Python from the interface.

WebBridge
Public definitions
class WebBridge (Protocol):
  action(self, name: 'str', handler: 'WebBridgeActionHandler | None' = None, *, invalidates: 'tuple[str, ...]' = (), permissions: 'tuple[str, ...]' = ('nexus_web.action.plugin.call',), state_guard_keys: 'tuple[str, ...]' = ()) -> 'WebBridgeActionHandler | Callable[[WebBridgeActionHandler], WebBridgeActionHandler]'
  dispose(self) -> 'None'
  @property event(self) -> 'WebBridgeEvent'
  remove_action(self, name: 'str') -> 'None'
  @property resource(self) -> 'WebBridgeResource'
  @property state(self) -> 'WebBridgeState'
Parameter Meaning and default behavior
name Required. Use a plugin.* name such as plugin.my_addon.inspect, identical on both sides. Do not impersonate built-in blender.* operations.
handler Handler function. Passing it registers and returns that function; omitting it returns a decorator. Registration does not return an action execution result.
invalidates An empty tuple by default. After a successful protocol call, invalidates these plugin.* states in this client so subscription snapshots can be regenerated.
permissions Includes nexus_web.action.plugin.call by default. To consume uploaded resources, also declare nexus_web.resource.write. This list replaces the defaults; permissions are not appended automatically.
state_guard_keys An empty tuple by default. A nonempty value requires valid subscription snapshots for the specified plugin.* states. See state guards below.

Registering the same action name twice fails. Do not register on every click or window opening. Remove the original registration before replacing its handler.

Handlers: input, return values, and execution context

WebBridgeActionHandler
Public definitions
WebBridgeActionHandler = collections.abc.Callable[[str | int | float | bool | None | list['WebJSONValue'] | dict[str, 'WebJSONValue'], nexus_web.public.WebBridgeContext], str | int | float | bool | None | list['WebJSONValue'] | dict[str, 'WebJSONValue']]

The function receives two positional arguments: (payload, context). The payload is JSON data from the page and is not necessarily a dictionary. Validate structure, types, and business limits before accessing data. context is not bpy.context. Callbacks run synchronously on Blender's main thread; do not return a coroutine or perform long blocking work.

WebJSONValue
Public definitions
WebJSONValue = str | int | float | bool | None | list['WebJSONValue'] | dict[str, 'WebJSONValue']
View JSON scalar types
WebJSONScalar
Public definitions
WebJSONScalar = str | int | float | bool | None

Results may contain only strings, finite numbers, booleans, None, lists, and dictionaries with string keys. Do not return Blender objects, vectors, Path, bytes, sets, or coroutines. Pass binary content through Resource references. JSON null corresponds to Python None.

Call once after binding; echoes text without changing the scene
python
from .nexus_web import WebBridgeContext, WebJSONValue, WebPlugin

def echo_text(payload: WebJSONValue, context: WebBridgeContext) -> WebJSONValue:
    if not isinstance(payload, dict):
        return {"ok": False, "message": "请输入文本参数。"}
    text = payload.get("text")
    if not isinstance(text, str) or len(text) > 200:
        return {"ok": False, "message": "文本须为 200 字以内的字符串。"}
    return {"ok": True, "text": text}

def setup_actions(plugin: WebPlugin) -> None:
    plugin.bridge().action("plugin.my_addon.echo", echo_text)

Replace my_addon with your add-on's name and update the page call to match. The decorator form is also available: @bridge.action("plugin.my_addon.echo"). Choose one registration form; do not register the same action with both.

WebBridgeContext: where this call originated

WebBridgeContext
Public definitions
class WebBridgeContext (dataclass frozen slots):
  __init__(origin: 'str', user_initiated: 'bool' = True, window_key: 'str | None' = None, resource: 'WebBridgeActionResource' = <factory>) -> None
  origin: str
  user_initiated: bool = True
  window_key: str | None = None
  resource: WebBridgeActionResource = <factory: _unavailable_action_resource>  # repr=False compare=False
  • origin: the page's source identifier for this call. Context information, not a user identity.
  • user_initiated: a public context flag, True by default. It is not independent proof of application authorization or a physical mouse click.
  • window_key: an optional real window key. Use it to identify the current instance in multi-window workflows instead of guessing from selection.
  • resource: receives uploaded resources for this action. Ordinary application code does not construct it manually.

The default resource factory in the type definition cannot receive real resources. Use the context supplied by the framework, and do not retain it for another operation.

Distinguish application results from call failures

The page uses await webui.action.call(name, payload) to obtain the Python return value. A normal return of {"ok": False} is still a successful protocol call. Check the application result fields; configured invalidations may still run. Exceptions, missing registrations, insufficient permissions, or invalid connections are call failures.

Call from an existing button handler; output is the page's message element
javascript
async function echoFromClick(output) {
  try {
    const webui = window.acquireNexusWebUI();
    const result = await webui.action.call("plugin.my_addon.echo", { text: "你好" });
    output.textContent = result.ok ? result.text : result.message;
  } catch (error) {
    output.textContent = `调用失败:${error.message || String(error)}`;
  }
}

Actions do not guarantee Blender undo and do not automatically roll back changes made before a handler fails. Use your add-on's undo and error-handling design. For transform interactions, see Value dragging and undo.

State guards: avoid writing to the wrong object from a stale list

With state_guard_keys, page payloads must include stateKey, canonicalKey, subscriptionId, and snapshotRevision from the matching live subscription. Do not invent revision numbers or use a one-time query's stateRef as a custom subscription guard.

With resource-write permission, also include targetId, targetIds, or targetRef.id(s). Targets must belong to the guarded snapshot. If the snapshot is stale or targets do not match, the handler does not run. Refresh state and ask the user to confirm targets instead of removing guard fields to force a retry.

The add-on must still verify that write targets exist and meet type and application requirements. Guards do not replace business validation. For page-side fields, see Persistent snapshots and release.

Receive a one-time uploaded resource

WebBridgeActionResource
Public definitions
class WebBridgeActionResource (Protocol):
  take(self, resource_id: 'str') -> 'WebTakenResource'
WebTakenResource
Public definitions
class WebTakenResource (dataclass frozen slots):
  __init__(resource_id: 'str', path: 'Path', mime: 'str', byte_length: 'int') -> None
  resource_id: str
  path: Path
  mime: str
  byte_length: int

After callWithResource uploads a resource, payload.resourceId is its receipt key. Call context.resource.take(resourceId) in the handler. Only actions with resource-write permission may consume uploads, and the resource must belong to the current action source. Arbitrary disk paths are not accepted.

A successful result contains resource_id, temporary path, mime, and byte_length. Each resource can be taken successfully once. The framework cleans up the temporary file after the handler ends. Read its content or write it to the application target inside the callback; do not pass its temporary path to a later task. Validate format, size, and targets. See Resources and file configuration.

Remove registrations and clean up

bridge.remove_action(name) Removes the specified action for this client and returns None. It does not undo completed application changes. bridge.dispose() Clears this bridge's registrations. When disabling the whole add-on, use Client release flow rather than clearing the bridge and leaving windows behind.

Preserve actual Python registration errors and show understandable page-side call errors. Do not infer built-in versus custom action error categories by matching Chinese messages.

Definitions come from the public API baseline; behavior is checked against registration, dispatch, resource permissions, and communication contracts.

Back to API reference · All topics