Skip to main content
Server export turns documents into files in Node, with no browser and no React. You import @doconda/editor/server on your own server and call a function. It’s included in the editor licence. This is useful for:
  • Saving a co-editing room from your backend, instead of electing a browser to save for everyone.
  • Turning Markdown into a Word file without mounting a hidden editor.
It needs Node 22 or later, which has WebSocket built in.

Your documents stay on your server

Conversion and export run inside your process. Document content never goes through Doconda’s servers because of this function:
  • The only call to Doconda is the licence permit. It sends your API key and the mark of your copy, and nothing about the document: no bytes, no file name, no room contents.
  • Reading a room goes only through the transport you choose. With url or provider, Doconda isn’t involved. With token, changes pass through Doconda’s relay, which forwards them and stores nothing, like any co-editing session.

Convert a file

name is only used for its extension, which says what the bytes are. warnings lists what the engine had to report while opening or saving. PDF and PNG are refused with format_unsupported: PNG needs a canvas, and a PDF would be paginated without real font measurements. To get a PDF, use ref.save("pdf") in the browser.

Export a room

exportRoom joins the room, waits for what the others have, returns the file and leaves:
Behavior to be aware of:
  • Pass the file everyone opened. A room doesn’t hold the whole document: what nobody touched comes from file. A different file isn’t detected, and gives a wrong result.
  • It only reads. It writes nothing to the room, whichever file you pass, and doesn’t show up as a participant.
  • It reads only what’s in the room at that moment. Doconda’s relay stores nothing, so when the last person leaves, there’s nothing to read and you get collab_empty_room. To keep what was there, stay in the room. A relay of your own that keeps the state works too, if it answers the hello (message type 2) with that state.
  • An empty room is an error: you never get the old file or a blank document back.
  • A provider you pass stays open; closing it is up to you.

On Doconda’s server

Ask for a token with audience: "server", using your API key. A normal token is refused without a browser’s Origin.
In Python, doconda.editor.collab_token(room, audience="server"). Without the SDK, send POST /editor/collab/token with { "room": "…", "audience": "server" }. Keep this token on your server.

Stay in a room

joinRoom keeps a connection open and holds the document in memory, so it still has the state after everybody leaves:
It takes the same options as exportRoom, without to. Behavior to be aware of:
  • Nobody sees it. It sends no cursor or presence and isn’t counted in the others’ peers. It writes nothing to the room. It only sends the hello that asks the others for their state and, when it closes a connection it opened, the standard “this connection left” message for its own ID, which changes nothing for the others. On Doconda’s server it does take one of the 50 places in the room.
  • Join before people can leave. It only knows what it received while connected. Join when the room opens.
  • If the connection drops, it reconnects by itself and asks for the state again, so it recovers what was edited meanwhile if someone who has it is still connected. Pass token as a function: a fixed token is refused after 10 minutes.
  • If the room closes the connection for good (a code from 4000 to 4999), it keeps what it has. save() still works and adds a warning, because later edits may be missing.
  • save() with nothing received yet waits up to timeoutMs and then fails with collab_empty_room.
  • If joinRoom can’t connect within timeoutMs, or the room refuses it, it fails at once with collab_unreachable or collab_closed.
  • One session per file. Once you store a new version and people will open that one, close() and join again with it as file: a room’s changes only make sense on top of the file it opened.
  • The document lives in your process’s memory: if the process restarts, what wasn’t saved is gone.

Which one to use

exportRoom arriving after the last person left gets nothing, because the relay stores nothing. If you need what was there when everyone left, use joinRoom.

The licence on your server

  1. The function asks Doconda for a permit with your API key (POST /v1/editor/server/permit). There’s no domain check, because a server has no domain.
  2. Doconda checks the key and that your organization has an active licence, and returns a signed permit valid for 1 hour.
  3. The function checks the signature and keeps the permit in memory, renewing it when less than 15 minutes remain.
A server permit can’t open the editor in a browser and doesn’t let anyone into a room. There’s no development mode: on localhost you also need a key. If Doconda’s API is unreachable, a process that already holds a valid permit keeps working until the permit expires, so up to 1 hour. A process with no valid permit fails with editor_license_unreachable, and can try again later. If Doconda refuses the key (cancelled, rotated), the function stops at the next check. A session from joinRoom checks its permit at each save() and renews it there, so it can stay connected for longer than a permit lasts. An idle session makes no requests. If the licence is revoked mid-session, the connection and the document stay, and save() fails with editor_unlicensed from the next renewal, so within 1 hour; if the licence comes back, save() works again with nothing lost.

Errors

Every failure throws a DocondaServerError with a code:

Real-time co-editing

Rooms, tokens and running your own server.

Licence and domains

Your key, and what happens when the subscription ends.