mirror of
https://github.com/logseq/logseq.git
synced 2026-05-01 01:16:27 +00:00
5.0 KiB
5.0 KiB
DB-Sync Client-Server Protocol
Transport
- WebSocket
ws(s)to/sync/:graph-id. - Client builds URL from config and appends
?token=...when available. - Encoding: JSON objects;
txpayloads are Transit strings. - Note: keep this document in sync with the current implementation.
Client -> Server
{"type":"hello","client":"<repo-id>"}- Initial handshake from client.
{"type":"presence","editing-block-uuid":"<uuid|null>"}- Update current editing block for presence (omit or null to clear).
{"type":"pull","since":<t>}- Request txs after
since(defaults to 0).
- Request txs after
{"type":"tx/batch","t-before":<t>,"txs":["<tx-transit>", ...]}- Upload a batch of txs based on
t-before(required).
- Upload a batch of txs based on
{"type":"ping"}- Optional keepalive; server replies
pong.
- Optional keepalive; server replies
Server -> Client
{"type":"hello","t":<t>}- Server hello with current t.
{"type":"online-users","online-users":[{"user-id":"...","email":"...","username":"...","name":"..."}...]}- Presence update with currently online users (fields may be omitted).
- Optional
editing-block-uuidindicates the block the user is editing.
{"type":"pull/ok","t":<t>,"txs":[{"t":<t>,"tx":"<tx-transit>"}...]}- Pull response with txs.
{"type":"tx/batch/ok","t":<t>}- Batch accepted; server advanced to t.
{"type":"changed","t":<t>}- Broadcast that server state advanced; client should pull.
{"type":"tx/reject","reason":"stale","t":<t>}- Client tx is based on stale t.
{"type":"tx/reject","reason":"cycle","data":"<transit {:attr <kw> :server-values ...}>"}- Cycle detected with server values.
{"type":"tx/reject","reason":"empty tx data"|"invalid tx"|"invalid t-before"}- Invalid batch.
{"type":"pong"}- Keepalive response.
{"type":"error","message":"..."}- Invalid/unknown message. Current messages:
"unknown type","invalid request","server error","invalid since".
- Invalid/unknown message. Current messages:
HTTP API
- Auth: Bearer token via
Authorization: Bearer <token>or?token=.... - JSON body/response unless noted.
- Auth required for
/graphs,/sync/:graph-id/*, and/assets/*. Expect401(unauthorized) or403(forbidden) on access failure.
Worker Health
GET /health- Worker health check. Response:
{"ok":true}.
- Worker health check. Response:
Graphs (index DO)
GET /graphs- List graphs the user owns. Response:
{"graphs":[{graph-id, graph-name, schema-version?, created-at, updated-at}...]}.
- List graphs the user owns. Response:
POST /graphs- Create graph. Body:
{"graph-name":"...","schema-version":"<major>"}(schema-version optional). Response:{"graph-id":"..."}.
- Create graph. Body:
GET /graphs/:graph-id/access- Access check. Response:
{"ok":true},401(unauthorized),403(forbidden), or404(not found).
- Access check. Response:
GET /graphs/:graph-id/members- Graph members list. Response:
{"members":[{user-id, graph-id, role, invited-by, created-at, email?, username?}...]}.
- Graph members list. Response:
DELETE /graphs/:graph-id- Delete graph and reset data. Response:
{"graph-id":"...","deleted":true}or400(missing graph id).
- Delete graph and reset data. Response:
Sync (per-graph DO, via /sync/:graph-id/...)
GET /sync/:graph-id/health- Health check. Response:
{"ok":true}.
- Health check. Response:
GET /sync/:graph-id/pull?since=<t>- Same as WS pull. Response:
{"type":"pull/ok","t":<t>,"txs":[{"t":<t>,"tx":"<tx-transit>"}...]}. - Error response (400):
{"error":"invalid since"}.
- Same as WS pull. Response:
POST /sync/:graph-id/tx/batch- Same as WS tx/batch. Body:
{"t-before":<t>,"txs":["<tx-transit>", ...]}. - Response:
{"type":"tx/batch/ok","t":<t>}or{"type":"tx/reject","reason":...}. - Error response (400):
{"error":"missing body"|"invalid tx"}.
- Same as WS tx/batch. Body:
GET /sync/:graph-id/snapshot/download- Build a snapshot file in R2 and return a download URL.
- Response:
{"ok":true,"key":"<graph-id>/<uuid>.snapshot","url":"<origin>/assets/:graph-id/<uuid>.snapshot","content-encoding":"gzip"}. - The snapshot file is a framed Transit JSON stream of kvs rows, optionally gzip-compressed.
POST /sync/:graph-id/snapshot/upload?reset=true|false- Upload a snapshot stream (framed Transit JSON, optionally gzip-compressed). The server imports rows into kvs.
- Request body: binary stream; headers should include
content-type: application/transit+jsonandcontent-encoding: gzipwhen compressed. - Response:
{"ok":true,"count":<n>,"key":"<graph-id>/<uuid>.snapshot"}. - Error response (400):
{"error":"missing body"|"missing graph id"}.
DELETE /sync/:graph-id/admin/reset- Drop/recreate per-graph tables. Response:
{"ok":true}.
- Drop/recreate per-graph tables. Response:
Assets
GET /assets/:graph-id/:asset-uuid.:ext- Download asset (binary response,
content-typeset,x-asset-typeheader included).
- Download asset (binary response,
PUT /assets/:graph-id/:asset-uuid.:ext- Upload asset (binary body). Size limit ~100MB. Response:
{"ok":true}.
- Upload asset (binary body). Size limit ~100MB. Response:
DELETE /assets/:graph-id/:asset-uuid.:ext- Delete asset. Response:
{"ok":true}.
- Delete asset. Response:
- Asset error responses:
{"error":"invalid asset path"}(400),{"error":"not found"}(404),{"error":"asset too large"}(413),{"error":"method not allowed"}(405),{"error":"missing assets bucket"}(500).