Files
FrenoCorp/src/lib/collaboration/yjs-document.ts
Michael Freno 7c684a42cc FRE-600: Fix code review blockers
- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-25 00:08:01 -04:00

95 lines
2.3 KiB
TypeScript

/**
* Yjs document structure for screenplay collaboration
* Defines the shared types used in the CRDT document
*/
import { Doc, Text, Map as YMap, Array as YArray } from 'yjs';
/**
* Screenplay metadata stored in Yjs Map
*/
export interface ScreenplayMetadata {
title: string;
author: string;
projectId: string;
createdAt: string;
updatedAt: string;
version: number;
}
/**
* Character reference for the screenplay
*/
export interface CharacterRef {
id: string;
name: string;
shortName: string;
description?: string;
}
/**
* Scene metadata
*/
export interface SceneMeta {
id: string;
slugline: string;
startTime: number; // Position in document
duration: number;
}
/**
* Create a new Yjs document with the screenplay structure
*/
export function createScreenplayDoc(
projectId: string,
metadata: Partial<ScreenplayMetadata>
): Doc {
const doc = new Doc();
// Apply updates from remote clients
doc.on('update', (update: Uint8Array, origin: unknown) => {
// Origin can be 'local', 'remote', or a WebSocket provider
const isLocal = origin === 'local';
if (!isLocal) {
console.log(`Received update from ${origin}`);
}
});
// Initialize shared types
const text = doc.getText('main');
const meta = doc.getMap<ScreenplayMetadata>('metadata');
const characters = doc.getMap<CharacterRef>('characters');
const scenes = doc.getMap<SceneMeta>('scenes');
// Set default metadata
const defaultMeta: ScreenplayMetadata = {
title: metadata.title || 'Untitled Screenplay',
author: metadata.author || '',
projectId,
createdAt: metadata.createdAt || new Date().toISOString(),
updatedAt: metadata.updatedAt || new Date().toISOString(),
version: metadata.version || 1,
};
// Initialize metadata if empty
if (!meta.get('projectId')) {
Object.entries(defaultMeta).forEach(([key, value]) => {
meta.set(key as keyof ScreenplayMetadata, value);
});
}
return doc;
}
/**
* Get or create a shared type from the document
*/
export function getOrCreateSharedTypes(doc: Doc) {
return {
text: doc.getText('main'),
metadata: doc.getMap<ScreenplayMetadata>('metadata'),
characters: doc.getMap<CharacterRef>('characters'),
scenes: doc.getMap<SceneMeta>('scenes'),
};
}