Skip to content
SumOfficeSumOfficeSumOffice

SumSheet as a server-side processor

The proposed server scheme, what already exists, and what isn't a ready-made product yet.

There are two different server scenarios, and it’s important not to mix them up.

Scenario Where the core computes What the server does
The browser computes On the user’s device, as a WebAssembly build. Serves the app and the file, stores versions, accepts the result.
The server computes As a separate process alongside your server. Starts the job and the session, passes the document, limits resources, accepts the finished file.
  • Entry point — user sign-in, keeping clients separate from each other, consumption limits.
  • Session management — jobs, time limits, cancellation.
  • Core worker process — the same operations contract and workbook session as on a workstation.
  • File storage — source workbooks and results.

What exists, and what isn’t a ready-made product yet

Section titled “What exists, and what isn’t a ready-made product yet”
Status Item What it means
Exists A long-lived core session A separate process and the same operations contract as everywhere else.
Exists Handling the workbook as bytes You can pass the document by content, not only by a path to a file on disk.
Available, as a ready-made image SumSheet web host A multi-user service: every user gets an isolated process with its own copy of the workbook, sign-in is checked by calling your system, and pages and traffic go through the manager. Several people can edit one workbook at once: other people’s input shows up as they type, and whoever opened the workbook first writes the file to the host. It ships as a ready-made Docker image — an archive in the webhost/ folder of the release catalog and an image on Docker Hub; it isn’t part of the engine packages. How to start it — below.
Available, installed separately Workbook check service A small service next to the web host: it accepts a workbook up to 50 MB (.xlsx, .xlsm, .xlsb, .xls, .xltm, .xltx, .xlam) without an account, executes nothing from it, and deletes it after 24 hours; the report covers functions, pivot tables, Power Query, external links, and the route of every macro. The bot for Slack and Telegram works through it too. It isn’t part of the web host image; on your own server it’s installed by a separate request — how to check workbooks before the pilot.
You’ll need to build it yourself Load wrapper A job queue, per-tenant quotas, load monitoring, and scaling under it. The web host is designed for people at the editor, not for batch processing.
Needs to be agreed in the contract Commitments and deployment Redundancy, updates, key storage, and who’s responsible for the service’s operation.

The web host ships as a ready-made Docker image for Linux x86-64: the sandbox manager, the built page, and the core of the same release inside — there’s nothing for them to drift apart on. The image archive is in the webhost/ folder of the release catalog together with INSTALL.md and SHA256SUMS; the same image is published on Docker Hub: docker pull hissih/sumsheet-webhost:latest. The machine needs 2 GB of memory plus about 250 MB per open workbook.

Terminal window
docker load -i SumSheet-<version>-webhost-docker.tar.gz # from the archive, no internet needed
docker run -d --name f1-webhost --restart unless-stopped \
-p 127.0.0.1:8092:8092 \
-v /srv/f1-cabins:/data/cabins \
hissih/sumsheet-webhost:latest \
--base-path /f1 --max-cabins 12 --idle-min 20 \
--auth-url 'https://your-host/api/me' \
--attach-url 'https://your-host/api/files/{id}/content'

Check: curl http://127.0.0.1:8092/f1/health — the response contains "status": "ok" and "skewMin": 0; the second means the page and the core are from the same release. Sandboxes live in the /data/cabins volume and survive an image update: docker load the new archive, remove the old container, and run the same start command with the new image. The path to the core, the folder with the WebSocket library, and the listen address are already set in the image.

The sandbox manager starts with a single command on bare Node ≥ 22; it takes the core from the installed delivery, and the path to it is passed as an environment variable.

Terminal window
FASTSHEET_NATIVE_COMPUTE_HOST_BIN="$CLI" \
WEBHOST_WS_DIR=/opt/fastsheet/webhost \
node webhost/cabin-manager.mjs \
--template /opt/fastsheet/blank.xlsx \
--docs-dir /opt/fastsheet/cabins \
--port 8090 \
--auth-url 'https://your-host/api/me' \
--attach-url 'https://your-host/api/files/{id}/content'

Both variables in the first lines are required for a manual start, and they behave differently. FASTSHEET_NATIVE_COMPUTE_HOST_BIN is the path to the processor, the same $CLI as during installation: without it, the manager starts, but no sandbox opens — there’s nothing to start the core with. WEBHOST_WS_DIR is the folder that holds node_modules/ws: the WebSocket library is taken from there. Without it, the manager doesn’t start at all — it prints “WEBHOST_WS_DIR is not set” and exits immediately.

By default, the manager listens only on the local address — you can’t connect to it from outside, even from your own network. This isn’t a limitation but a safeguard: your server exposes the service by proxying it and adding its own sign-in (the proxy must pass WebSocket and the cookie through). In the container, the image sets the address (WEBHOST_BIND=0.0.0.0), and the boundary is kept by publishing the port on 127.0.0.1. --base-path is handled the same way if the service doesn’t live at the domain’s root.

Flag Default What it does
--port 8090 (8092 in the image) The manager’s port.
--bind 127.0.0.1 or WEBHOST_BIND The listen address; in the image — all addresses of the container.
--template The empty workbook that sandboxes start from.
--docs-dir next to the template The folder for working copies of workbooks, per sandbox.
--auth-url none Your “who am I” address: as long as it’s set, sign-in only goes through your permission check.
--attach-url none Your “file by ID” address; the sandbox downloads the workbook using the request’s own credentials.
--create-url none Your “create file” endpoint — needed for a new workbook and for a copy of a busy workbook.
--base-path none A subpath, if the service doesn’t live at the domain’s root.
--ui-locale none The language of the manager’s service pages: ru, en, or auto — by the browser language. Without the flag — English.
--warm 0 How many sandboxes to keep warmed up. For spreadsheets, warm-up is off by default.
--idle-min 30 How many minutes of idling before a sandbox shuts down, taking anything unsaved with it.
--max-cabins 0 — computed from the machine The limit on simultaneous sandboxes: at zero, the manager picks it itself, based on memory and core count.
--chrome none The window’s top bar: full, slim, or none.
--entry none A fallback pass around your “who am I”.

The web host stores neither users nor files: it goes to two endpoints for them, and a third one is needed if you allow creating workbooks. The browser’s cookie and Authorization header are passed to them as is, so there’s no separate sign-in to the editor.

Endpoint Why What it must respond
--auth-url find out who signed in 2xx and JSON with an email or id field; otherwise 401 or 403
--attach-url, GET …/{id}/content return the workbook by ID the .xlsx file itself — only to someone who has the right; a 302 to a signed link is acceptable
the same endpoint with /replace instead of /content accept an edit POST multipart/form-data, part file; parse the part, not the raw body
--create-url, {userId} is substituted create a workbook POST multipart/form-data, part file, the workbook name in the x-f1-name header (percent-encoded); the response is JSON with the id of the new file

The workbook link for the user: https://your-domain/f1/?doc=<id>.

Everyone can type. Edits travel between sandboxes through the manager: it keeps the canonical state per cell — the last edit confirmed by the core wins — and broadcasts it to everyone, so everyone ends up with the same workbook. Inserting and deleting rows and columns go through a separate shift log, and the manager fixes up lagging edits itself. One person writes the file to the host — whoever opened the workbook first; everyone else’s edits leave together with that save.

The workbook shows “in the workbook: N” with names, and another person’s cursor as a colored frame with a name on a visible cell, or a label at the edge if the cell is off screen. Presence is ephemeral: a lost frame is fixed by the next move, and a sandbox’s death removes its cursor for everyone right away. Every 15 seconds, the manager compares each sandbox against the canonical state and patches up what has drifted. Undo removes only your own edits: your neighbors’ edits don’t enter your undo stack.

For systems that speak WOPI (Nextcloud, ownCloud, SharePoint), the web host opens a second entrance — the wopi-facade.mjs facade from the same delivery, placed in front of the manager. To the outside it’s a WOPI client: discovery, a proof signature on every request, CheckFileInfo, GetFile, PutFile, Lock/Unlock/RefreshLock, PutRelativeFile, RenameFile, and the host page’s postMessage API. To the inside — exactly the host contract from the table above; the manager doesn’t change by a single line.

8110/v1/me
node webhost/wopi-facade.mjs \
--port 8110 --manager http://127.0.0.1:8090 \
--public-url https://your-domain/f1 --wopi-allow storage1,storage2
# --attach-url 'http://127.0.0.1:8110/v1/attachments/{id}/content'

--wopi-allow is a comma-separated allowlist of storages; there’s one lock per file, it lives as long as at least one writing session of the workbook is alive, and it’s renewed every 25 minutes. The manager checks the UserCanWrite right from CheckFileInfo on every edit: without it, the workbook opens read-only. The entrance has been verified against our own test WOPI host; it isn’t certified against Nextcloud, SharePoint, or ownCloud.

Documentation assistant

Answers are assembled from the documentation and may be inaccurate — check the sources.