#Collaborative Document Editing
Real-time collaborative editing with cursor positions and document changes.
#Backend Configuration
// collab.config.ts
import { createDialogue, defineEvent } from "./dialogue";
import { z } from "zod";
export const DocumentChange = defineEvent("doc:change", {
schema: z.object({
userId: z.string(),
operations: z.array(
z.object({
type: z.enum(["insert", "delete", "retain"]),
position: z.number(),
text: z.string().optional(),
length: z.number().optional(),
})
),
version: z.number(),
}),
});
export const CursorUpdate = defineEvent("cursor:update", {
schema: z.object({
userId: z.string(),
username: z.string(),
position: z.number(),
selection: z
.object({
start: z.number(),
end: z.number(),
})
.optional(),
color: z.string(),
}),
});
export const UserPresence = defineEvent("user:presence", {
schema: z.object({
userId: z.string(),
username: z.string(),
color: z.string(),
status: z.enum(["active", "idle", "away"]),
}),
});
export const dialogue = createDialogue({
port: 3000,
rooms: {},
hooks: {
clients: {
onConnected: (client) => {
// Rooms are created per document
// Join handled by explicit API call
},
},
},
});
// Create room for a document
export function createDocumentRoom(documentId: string): void {
// In a real app, you'd dynamically register rooms
// or use a pattern-based room system
}
// Broadcast document change
export function broadcastChange(
documentId: string,
change: z.infer<typeof DocumentChange.schema>
): void {
dialogue.trigger(`doc:${documentId}`, DocumentChange, change, change.userId);
}This documentation reflects the current implementation and is subject to evolution. Contributions and feedback are welcome.