Most apps have a fixed core that the app’s team writes. Code from anyone else gets only the hooks the team chose to
expose, and two such add-ons rarely work with each other. A PLEX app is the plugins it loads. The navigation tree,
the settings page and the assistant are plugins too, so a plugin from outside the team uses the same API as a built-in
one.
A plugin says which object type it renders and where. The app asks for “the article for this object” and renders
whatever plugin answers, without importing it.
Role token for the article role. Subject defaults to any until narrowed
via
object
,
literal
, or
subject
. Extra passthrough
props are permitted.
Article,
classNote
Note),
8
component: React.ComponentType<{
role: string;
subject: Note & OfKind<EntityKind.Object>;
attendableId: string;
}>
Accepts any component type (not just a function) so a container re-exported through a
lazy() barrel as ComponentType<any> can be registered without a cast.
Maps the surface props onto the component's own props, so a plain container can be registered
directly instead of being wrapped in an adapter that unpacks data.
Prefer this over an inline component: ({ data }) => <Container … />: the mapper's input type
derives from the same filter that defines the surface's data shape, so the unpacking is
checked against the filter rather than restated by hand.
The resolved role NSID string (e.g. org.dxos.role.article). Present on
matched components only — multi-role containers can branch on this value
by comparing against a token's .role (e.g. role === AppSurface.Section.role).
Plugins extend each other through capabilities: typed slots that one module contributes to and another reads. A plugin
can render inside another plugin’s view by contributing a surface for a role, or add an action to another plugin’s
objects by adding nodes to App Graph. Neither plugin imports the other.
Surfaces and App Graph explain both.
An app with many plugins cannot load all of them at startup. Each module waits for an activation event, such as the
first time a view is needed. A surface module loads the first time one of its roles is requested, and an operation
handler loads the first time the operation runs. ActivationEvent lists the
events.
An operation is defined once, with a typed input and output. A button invokes it, the command palette lists it, and the
assistant calls it as a tool, reading the schema to fill in the input. None of the three needs code of its own.
Operations explains how.
A plugin’s data is ECHO objects in spaces. It syncs between a user’s devices and the people they share with, merges
concurrent edits and works offline, with no sync code in the plugin. Spaces explains the
model.
PLEX does not store or sync data; ECHO does. It is not a component library either: plugins build their views with
@dxos/react-ui, or with any React components.