Dollie Editor SDK guide
Persistence and Dynamic Data
Store page definitions in your application and safely resolve backend data into published pages
Dollie Editor separates editable Page content from host-owned application data.
The Page definition is portable JSON. Your application decides where it lives and which dynamic values it may reference.
Documents wrap Page definitions
A BuilderDocument can contain:
id;definition;revision;metadata;capabilities.
The editor changes definition. The surrounding document helps the host manage identity, concurrency, and permissions.
Transport connects the editor to the host
TransportClient describes the operations the editor may call:
- load;
- save;
- publish;
- validate;
- optional revision history;
- optional binding and AI-fill operations.
The transport does not prescribe HTTP, Laravel, or a database.
Revision is not wire version
These two values solve different problems:
PageConfig._versionidentifies the JSON wire-format version.BuilderDocument.revisionidentifies the current content revision and can prevent stale saves.
The wire version changes only for breaking format changes. The revision can change on every save.
Dynamic data uses bindings
Some values should come from the backend rather than be copied into the Page:
- the current course title;
- an instructor profile;
- a list of upcoming sessions;
- a tenant's subscription plans;
- recent activity.
A binding describes the allowed source and lookup. The host resolves it with tenant-aware context before rendering.
{
"$binding": {
"source": "course",
"kind": "item",
"field": "title"
},
"fallback": "Course title"
}
The fallback keeps the editor and published page understandable when data is unavailable.
Bindings are an allow-list
Do not expose a generic database query language.
The host registers binding providers that define:
- public fields;
- allowed collection projections;
- filters and sorts;
- maximum limits;
- tenant scope.
Resolution happens on the server with application context.
Live data inside a sentence
A binding replaces a whole value. When live data has to sit inside authored
copy — Welcome to {{academy.name}}, book now — the host owns the token format
and resolves it server-side before render, so the SDK never sees a token.
The editor helps the author write one. Pass a fieldTokens handle to
PageBuilderEditor and mount FieldTokenPicker; every text field then shows an
"Insert live data" button that places the chosen token at the caret:
const [tokenTarget, setTokenTarget] = useState<FieldTokenTarget | null>(null);
<PageBuilderEditor fieldTokens={{ ask: setTokenTarget }} … />
<FieldTokenPicker target={tokenTarget} groups={groups} onClose={() => setTokenTarget(null)} />
groups is the host's own list of { token, label, description, value, status }.
The SDK never invents a spelling, and the same list should feed every other
surface (a panel, an AI tool) so they cannot diverge. The handle is gated on the
bindings capability, like the binding picker.
Keep editable content and live data distinct
Use a normal Field when the Editor user owns the value.
Use a binding when the application owns the value and the Page only chooses where to display it.
This distinction prevents copied data from becoming stale and keeps permissions clear.