Server
Server-side implementation of DocSync
DocSyncServer
Creates a DocSync server that handles WebSocket connections, authentication, authorization, and document synchronization.
import {
DocSyncServer,
inMemoryServerProvider, // don't use in production
} from "@docukit/docsync/server";
const server = new DocSyncServer({
port: 8080,
docBinding,
provider: inMemoryServerProvider(),
async authenticate({ request, token }) {
// Authenticate via request, commonly with cookies.
const session = await getSessionFromCookie(request.headers);
if (session) {
return { userId: session.user.id, context: { role: session.user.role } };
}
// Or authenticate via token.
if (!token) return undefined;
const tokenUser = await verifyToken(token);
if (!tokenUser) return undefined;
return { userId: tokenUser.id, context: { role: tokenUser.role } };
},
async authorize({ type, req, userId, context }) {
return true;
},
});See Providers to bring your own storage backend (Postgres, MySQL, etc.).
Props
Prop
Type
authenticate
Called once per WebSocket connection attempt. Must validate the handshake request, optional token, or both, and resolve the canonical userId.
For browser apps with HttpOnly session cookies, prefer reading the cookie from
request.headers first. Keep the token branch for non-browser clients and
short-lived scoped grants.
async authenticate({ request, token }) {
// Authenticate via request, commonly with cookies.
const session = await getSessionFromCookie(request.headers);
if (session) return { userId: session.user.id };
// Or authenticate via token.
if (!token) return undefined;
const tokenUser = await verifyToken(token);
if (!tokenUser) return undefined;
return {
userId: tokenUser.id,
context: { role: tokenUser.role, orgId: tokenUser.orgId },
};
}Props
Prop
Type
Returns
Prop
Type
Return undefined to reject the connection.
authorize
Called for each operation after authentication. Use this to implement fine-grained access control.
async authorize({ type, req, userId, context }) {
if (type === "sync") {
const { docId } = req;
return await canUserAccessDoc(userId, docId, context.orgId);
}
return true;
}Props
Prop
Type
Returns
Return true to allow the operation, false to deny.
Events
onClientConnect
Called when a client successfully connects after authentication.
server.onClientConnect((event) => {
console.log(`User ${event.userId} connected from device ${event.deviceId}`);
});Prop
Type
onClientDisconnect
Called when a client disconnects.
server.onClientDisconnect((event) => {
console.log(`User ${event.userId} disconnected: ${event.reason}`);
});Prop
Type
onDocSubscribe
Called when a connected client starts syncing a document.
server.onDocSubscribe((event) => {
console.log(`Client ${event.clientId} opened doc ${event.docId}`);
});Prop
Type
onDocUnsubscribe
Called when a connected client stops syncing a document, either by unsubscribing or disconnecting.
server.onDocUnsubscribe((event) => {
console.log(
`Client ${event.clientId} closed doc ${event.docId}: ${event.reason}`,
);
});Prop
Type
onSyncRequest
Called after each sync request completes. Follows "wide events" philosophy: one event per operation with all context.
server.onSyncRequest((event) => {
console.log(
`Sync ${event.status} for doc ${event.req.docId} in ${event.durationMs}ms`,
);
});Prop
Type
close
Closes the server and all connections.
await server.close();