Roles and permissions
What a participant is allowed to do, enforced everywhere.
These docs are for version 2.3.x. See the latest version.
A mode is something the user switches between: editing or suggesting. A role limits what the user can do. It cannot be changed from inside the editor.
<ReviseEditor
role="suggester"
initialDocuments={[
{ id: "contract-1", source: file },
{ id: "exhibit-a", source: exhibit, role: "viewer" }, // per document
]}
/>| Role | Edits | Direct edits | Accept / reject | Comments |
|---|---|---|---|---|
editor (default) | Yes | Yes | Yes | Yes |
suggester | As tracked suggestions only | No | No | Yes |
viewer | No | No | No | No |
Why a suggester cannot accept#
Accepting a tracked change is an edit. If a suggester could accept their own suggestions, every change could skip review by someone else.
A suggester can still navigate review, preview accept and reject without changing the document, and comment.
Enforcement#
The role applies to every surface:
- Typing and the toolbar. The document stays in a mode the role permits.
setDocumentMode()clamps the requested mode: asking for"editing"as a suggester sets"suggesting". TheonDocumentModeChangecallback reports the resulting mode. - The built-in chrome. The mode toggle is hidden when the role has one mode. The ribbon shows review navigation without accept and reject. The inline accept and reject tooltip on each suggestion is hidden.
- The handle.
review.acceptCurrent(),acceptAll(),acceptSuggestions(), and the reject counterparts returnfalseor a decision with every IDunresolved. Comment mutations do nothing for a viewer. - Agent tools.
tools.execute()returns{ ok: false, error: { code: "role_not_permitted" } }for a mutation a viewer cannot make, and for anydirectModecall from a suggester. A delegatedagent.run()is checked before it starts and throwsReviseRoleErrorinstead.
import { ReviseRoleError } from "@reviseio/editor";
const result = await editor.tools.execute("replace", input, { directMode: true });
if (!result.ok && result.error.code === "role_not_permitted") {
// A suggester can't apply changes directly; without directMode, the same
// call adds the edit as a suggestion.
}
try {
await editor.agent.run(task, { directMode: true });
} catch (error) {
if (error instanceof ReviseRoleError) {
// error.role === "suggester", error.action === "apply changes directly"
}
}directMode applies a change without a tracked change, so a suggester cannot
use it. Without directMode, the same tool call adds the edit as a
suggestion.
Read the role#
editor.getRole(); // active document
editor.getRole("exhibit-a"); // a specific oneA role is a UI and API boundary, not a security control. It limits what this browser can do through the SDK. It does not authenticate anyone. In a shared room, each participant sets their own role. To make a role authoritative, your server must assign it and your transport must reject writes that violate it. Revise does not run a server here.