Files
DocNest/frontend/src/lib/yjs.ts
2026-01-12 00:16:55 -08:00

94 lines
2.3 KiB
TypeScript

import { IndexeddbPersistence } from "y-indexeddb";
import { Awareness } from "y-protocols/awareness";
import { WebsocketProvider } from "y-websocket";
import * as Y from "yjs";
import { documentsApi } from "../api/document";
const WS_URL = import.meta.env.VITE_WS_URL;
export interface YjsProviders {
ydoc: Y.Doc;
websocketProvider: WebsocketProvider;
indexeddbProvider: IndexeddbPersistence;
awareness: Awareness;
}
export interface YjsUser {
id: string;
name: string;
avatar_url?: string;
}
export const createYjsDocument = async (
documentId: string,
_user: YjsUser,
token: string,
shareToken?: string
): Promise<YjsProviders> => {
// Create Yjs document
const ydoc = new Y.Doc();
// Load initial state from database BEFORE connecting providers
try {
const state = await documentsApi.getState(documentId);
if (state && state.length > 0) {
Y.applyUpdate(ydoc, state);
console.log('✓ Loaded document state from database');
}
} catch {
console.log('No existing state in database (new document)');
}
// IndexedDB persistence (offline support)
const indexeddbProvider = new IndexeddbPersistence(documentId, ydoc);
// WebSocket provider (real-time sync) with auth token
const wsParams: { [key: string]: string } = shareToken
? { share: shareToken }
: { token: token };
const websocketProvider = new WebsocketProvider(
WS_URL,
documentId,
ydoc,
{ params: wsParams }
);
// Awareness for cursors and presence
const awareness = websocketProvider.awareness;
return {
ydoc,
websocketProvider,
indexeddbProvider,
awareness,
};
};
export const destroyYjsDocument = (providers: YjsProviders) => {
providers.websocketProvider.destroy();
providers.indexeddbProvider.destroy();
providers.ydoc.destroy();
};
// Deterministic color generator based on user ID
export const getColorFromUserId = (userId: string | undefined): string => {
// Default color if no userId
if (!userId) {
return "#718096"; // Gray for anonymous/undefined users
}
// Hash user ID to consistent color index
const hash = userId.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
const colors = [
"#FF6B6B",
"#4ECDC4",
"#45B7D1",
"#FFA07A",
"#98D8C8",
"#F7DC6F",
"#BB8FCE",
"#85C1E2",
];
return colors[hash % colors.length];
};