Skip to main content

SDK Architecture

This document is the canonical architecture reference for @anikitenko/fdo-sdk.

Runtime Model

The SDK spans two runtimes:
  • Backend/plugin runtime:
    • plugin class lifecycle (init, handlers, stores, logging)
    • communicator and host IPC handling
    • persistence and diagnostics
  • Iframe UI runtime (FDO host managed):
    • plugin UI code produced by render()
    • host-injected browser/UI helpers
    • React-hosted iframe render pipeline
For detailed render semantics, see RENDER_RUNTIME_CONTRACT.md.

Lifecycle Model

Primary plugin lifecycle:
  • init():
    • setup and registrations
    • may fail; communicator returns stable failure payload
  • render():
    • returns UI source string
    • serialized for host transport via explicit SDK methods
  • renderOnLoad():
    • optional payload for UI on-load behavior
    • supported authoring forms: source string, function, or defineRenderOnLoad(...) module
Transport helpers:
  • serializeRender()
  • serializeRenderOnLoad()
These methods are transport boundaries, not authoring lifecycle overrides.

Message Flow

Inbound host messages are validated in runtime contract validators:
  • envelope validation (MESSAGE_TYPE, payload shape)
  • UI message payload validation (handler, content)
Core message paths:
  • PLUGIN_READY
  • PLUGIN_INIT
  • PLUGIN_RENDER
  • UI_MESSAGE
PLUGIN_INIT may include an optional content.apiVersion from the host. The SDK validates the value and enforces major-version compatibility against FDO_SDK.API_VERSION. PLUGIN_INIT may also include content.capabilities to opt in privileged features for that plugin instance. Failure behavior:
  • PLUGIN_INIT failure: empty capabilities + error
  • PLUGIN_RENDER failure: fallback error UI + error
  • UI_MESSAGE failure: { error: string }

Storage Model

Storage is plugin-scoped through PluginRegistry.useStore(...).
  • default store:
    • in-memory
    • scoped by plugin identity
  • json store:
    • persistent
    • requires explicit storage root (configureStorage or FDO_SDK_STORAGE_ROOT)
    • path is namespaced by plugin scope
Store lifecycle hooks are supported:
  • init(context)
  • flush()
  • dispose()
  • optional capability metadata and migration/version hooks
Runtime permission model:
  • privileged SDK features are capability-gated (storage, storage.<backend> such as storage.json, system.network, system.network.<transport> such as system.network.https, sudo.prompt, system.hosts.write, system.fs.scope.<scope-id>, system.process.exec, system.process.scope.<scope-id>)
  • host grants are configured via PluginRegistry.configureCapabilities(...) (usually through validated PLUGIN_INIT payload)
  • diagnostics include granted capabilities and usage/denial counters for auditing
  • diagnostics also include SDK handshake metadata (sdkVersion, apiVersion, capability schema version, feature flags) for host compatibility gating
  • hosts should evaluate this handshake contract with evaluateSdkHandshakeCompatibility(...) instead of ad hoc version checks
Host-mediated privileged actions:
  • SDK defines a strict contract validator for host privileged requests (validateHostPrivilegedActionRequest)
  • current action contracts are intentionally scoped (system.hosts.write, system.fs.mutate, system.process.exec)
  • host must enforce confirmation, path/command boundaries, and auditing; plugins should not receive generic arbitrary-write permissions
Operator-style plugins should be built on top of these scoped host contracts rather than direct shell/process assumptions. This includes Docker Desktop-like plugins, Kubernetes dashboards, Helm managers, Terraform consoles, and similar operational tooling.

Validation Boundaries

Runtime validation currently covers:
  • plugin metadata (including BlueprintJS v6 icon name)
  • serialized render payload shape
  • host message envelope shape
  • UI message payload shape
Validation should happen at boundaries, not in arbitrary inner layers.

Extension Points

Stable extension points for plugin authors:
  • FDO_SDK lifecycle methods
  • PluginRegistry.registerHandler(...)
  • PluginRegistry.useStore(...)
  • mixins (QuickActionMixin, SidePanelMixin)
  • DOM helper modules for UI-source generation

Internal Boundaries

Internal modules that should not be treated as public plugin API contracts:
  • communicator implementation details
  • private registry internals
  • store internals prefixed with _ fields
  • decorator internals outside documented behavior

Design Constraints

  • prioritize predictable host/plugin boundaries over convenience
  • avoid runtime assumptions leaking between backend and iframe contexts
  • keep metadata, transport, and store contracts explicit and machine-readable
  • preserve deterministic behavior in failure paths