@nocturnium/svelte-ide 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +251 -0
- package/dist/components/agents/AgentActivityPanel.svelte +565 -0
- package/dist/components/agents/AgentActivityPanel.svelte.d.ts +24 -0
- package/dist/components/agents/AgentAvatar.svelte +417 -0
- package/dist/components/agents/AgentAvatar.svelte.d.ts +23 -0
- package/dist/components/agents/AgentCursor.svelte +224 -0
- package/dist/components/agents/AgentCursor.svelte.d.ts +35 -0
- package/dist/components/agents/AgentPresenceBar.svelte +261 -0
- package/dist/components/agents/AgentPresenceBar.svelte.d.ts +20 -0
- package/dist/components/agents/index.d.ts +4 -0
- package/dist/components/agents/index.js +5 -0
- package/dist/components/ai/AIConversationList.svelte +524 -0
- package/dist/components/ai/AIConversationList.svelte.d.ts +17 -0
- package/dist/components/ai/AIEditPreview.svelte +132 -0
- package/dist/components/ai/AIEditPreview.svelte.d.ts +8 -0
- package/dist/components/ai/AIInlineEdit.svelte +155 -0
- package/dist/components/ai/AIInlineEdit.svelte.d.ts +10 -0
- package/dist/components/ai/AIMessage.svelte +239 -0
- package/dist/components/ai/AIMessage.svelte.d.ts +13 -0
- package/dist/components/ai/AIMessageActions.svelte +176 -0
- package/dist/components/ai/AIMessageActions.svelte.d.ts +12 -0
- package/dist/components/ai/AIMessageContent.svelte +355 -0
- package/dist/components/ai/AIMessageContent.svelte.d.ts +7 -0
- package/dist/components/ai/AIPanel.svelte +561 -0
- package/dist/components/ai/AIPanel.svelte.d.ts +7 -0
- package/dist/components/ai/AISuggestionWidget.svelte +132 -0
- package/dist/components/ai/AISuggestionWidget.svelte.d.ts +10 -0
- package/dist/components/ai/AIToolCallDisplay.svelte +317 -0
- package/dist/components/ai/AIToolCallDisplay.svelte.d.ts +12 -0
- package/dist/components/ai/index.d.ts +9 -0
- package/dist/components/ai/index.js +10 -0
- package/dist/components/core/Avatar.svelte +110 -0
- package/dist/components/core/Avatar.svelte.d.ts +12 -0
- package/dist/components/core/Badge.svelte +98 -0
- package/dist/components/core/Badge.svelte.d.ts +11 -0
- package/dist/components/core/Button.svelte +175 -0
- package/dist/components/core/Button.svelte.d.ts +18 -0
- package/dist/components/core/ConnectionStatus.svelte +294 -0
- package/dist/components/core/ConnectionStatus.svelte.d.ts +20 -0
- package/dist/components/core/ContextMenu.svelte +176 -0
- package/dist/components/core/ContextMenu.svelte.d.ts +19 -0
- package/dist/components/core/ErrorBoundary.svelte +277 -0
- package/dist/components/core/ErrorBoundary.svelte.d.ts +23 -0
- package/dist/components/core/Icon.svelte +107 -0
- package/dist/components/core/Icon.svelte.d.ts +8 -0
- package/dist/components/core/Input.svelte +138 -0
- package/dist/components/core/Input.svelte.d.ts +20 -0
- package/dist/components/core/Kbd.svelte +34 -0
- package/dist/components/core/Kbd.svelte.d.ts +7 -0
- package/dist/components/core/ResizeHandle.svelte +200 -0
- package/dist/components/core/ResizeHandle.svelte.d.ts +23 -0
- package/dist/components/core/Spinner.svelte +35 -0
- package/dist/components/core/Spinner.svelte.d.ts +7 -0
- package/dist/components/core/Textarea.svelte +112 -0
- package/dist/components/core/Textarea.svelte.d.ts +18 -0
- package/dist/components/core/Tooltip.svelte +103 -0
- package/dist/components/core/Tooltip.svelte.d.ts +11 -0
- package/dist/components/core/index.d.ts +13 -0
- package/dist/components/core/index.js +14 -0
- package/dist/components/editor/AIFocusLayer.svelte +430 -0
- package/dist/components/editor/AIFocusLayer.svelte.d.ts +32 -0
- package/dist/components/editor/Breadcrumbs.svelte +435 -0
- package/dist/components/editor/Breadcrumbs.svelte.d.ts +33 -0
- package/dist/components/editor/BreakpointLayer.svelte +642 -0
- package/dist/components/editor/BreakpointLayer.svelte.d.ts +20 -0
- package/dist/components/editor/CognitiveLoadMeter.svelte +324 -0
- package/dist/components/editor/CognitiveLoadMeter.svelte.d.ts +18 -0
- package/dist/components/editor/CollaborativeEditor.svelte +218 -0
- package/dist/components/editor/CollaborativeEditor.svelte.d.ts +32 -0
- package/dist/components/editor/CommandPalette.svelte +434 -0
- package/dist/components/editor/CommandPalette.svelte.d.ts +11 -0
- package/dist/components/editor/ComplexityLayer.svelte +293 -0
- package/dist/components/editor/ComplexityLayer.svelte.d.ts +23 -0
- package/dist/components/editor/ConflictZoneLayer.svelte +441 -0
- package/dist/components/editor/ConflictZoneLayer.svelte.d.ts +25 -0
- package/dist/components/editor/ContextLens.svelte +262 -0
- package/dist/components/editor/ContextLens.svelte.d.ts +27 -0
- package/dist/components/editor/CustomEditor.svelte +1242 -0
- package/dist/components/editor/CustomEditor.svelte.d.ts +37 -0
- package/dist/components/editor/DebugConsole.svelte +646 -0
- package/dist/components/editor/DebugConsole.svelte.d.ts +41 -0
- package/dist/components/editor/EchoCursorLayer.svelte +363 -0
- package/dist/components/editor/EchoCursorLayer.svelte.d.ts +24 -0
- package/dist/components/editor/Editor.svelte +61 -0
- package/dist/components/editor/Editor.svelte.d.ts +22 -0
- package/dist/components/editor/EditorGutter.svelte +119 -0
- package/dist/components/editor/EditorGutter.svelte.d.ts +19 -0
- package/dist/components/editor/EditorLines.svelte +182 -0
- package/dist/components/editor/EditorLines.svelte.d.ts +43 -0
- package/dist/components/editor/EditorPane.svelte +134 -0
- package/dist/components/editor/EditorPane.svelte.d.ts +9 -0
- package/dist/components/editor/EditorSelections.svelte +186 -0
- package/dist/components/editor/EditorSelections.svelte.d.ts +25 -0
- package/dist/components/editor/EditorTabs.svelte +170 -0
- package/dist/components/editor/EditorTabs.svelte.d.ts +12 -0
- package/dist/components/editor/FileExplorer.svelte +811 -0
- package/dist/components/editor/FileExplorer.svelte.d.ts +67 -0
- package/dist/components/editor/FileIcon.svelte +110 -0
- package/dist/components/editor/FileIcon.svelte.d.ts +10 -0
- package/dist/components/editor/FindReplace.svelte +448 -0
- package/dist/components/editor/FindReplace.svelte.d.ts +40 -0
- package/dist/components/editor/GhostBracketLayer.svelte +391 -0
- package/dist/components/editor/GhostBracketLayer.svelte.d.ts +24 -0
- package/dist/components/editor/GitBlameLayer.svelte +436 -0
- package/dist/components/editor/GitBlameLayer.svelte.d.ts +18 -0
- package/dist/components/editor/InlineDiagnosticsLayer.svelte +540 -0
- package/dist/components/editor/InlineDiagnosticsLayer.svelte.d.ts +35 -0
- package/dist/components/editor/InlineDiffLayer.svelte +337 -0
- package/dist/components/editor/InlineDiffLayer.svelte.d.ts +31 -0
- package/dist/components/editor/MinimalEditor.svelte +75 -0
- package/dist/components/editor/MinimalEditor.svelte.d.ts +6 -0
- package/dist/components/editor/MinimalEditor2.svelte +84 -0
- package/dist/components/editor/MinimalEditor2.svelte.d.ts +6 -0
- package/dist/components/editor/Minimap.svelte +327 -0
- package/dist/components/editor/Minimap.svelte.d.ts +34 -0
- package/dist/components/editor/PluginPreviewSandbox.svelte +793 -0
- package/dist/components/editor/PluginPreviewSandbox.svelte.d.ts +49 -0
- package/dist/components/editor/ProblemsPanel.svelte +628 -0
- package/dist/components/editor/ProblemsPanel.svelte.d.ts +25 -0
- package/dist/components/editor/QuickActionsMenu.svelte +403 -0
- package/dist/components/editor/QuickActionsMenu.svelte.d.ts +18 -0
- package/dist/components/editor/SnippetPalette.svelte +530 -0
- package/dist/components/editor/SnippetPalette.svelte.d.ts +16 -0
- package/dist/components/editor/StructureMap.svelte +431 -0
- package/dist/components/editor/StructureMap.svelte.d.ts +37 -0
- package/dist/components/editor/SymbolOutline.svelte +722 -0
- package/dist/components/editor/SymbolOutline.svelte.d.ts +44 -0
- package/dist/components/editor/TimelineScrubber.svelte +470 -0
- package/dist/components/editor/TimelineScrubber.svelte.d.ts +40 -0
- package/dist/components/editor/TokenRenderer.svelte +69 -0
- package/dist/components/editor/TokenRenderer.svelte.d.ts +15 -0
- package/dist/components/editor/constants.d.ts +32 -0
- package/dist/components/editor/constants.js +36 -0
- package/dist/components/editor/core/ai-awareness.d.ts +176 -0
- package/dist/components/editor/core/ai-awareness.js +210 -0
- package/dist/components/editor/core/bracket-healer.d.ts +189 -0
- package/dist/components/editor/core/bracket-healer.js +406 -0
- package/dist/components/editor/core/breakpoints.d.ts +203 -0
- package/dist/components/editor/core/breakpoints.js +414 -0
- package/dist/components/editor/core/commands.d.ts +108 -0
- package/dist/components/editor/core/commands.js +246 -0
- package/dist/components/editor/core/complexity-analyzer.d.ts +123 -0
- package/dist/components/editor/core/complexity-analyzer.js +376 -0
- package/dist/components/editor/core/conflict-predictor.d.ts +135 -0
- package/dist/components/editor/core/conflict-predictor.js +316 -0
- package/dist/components/editor/core/crdt-binding.d.ts +118 -0
- package/dist/components/editor/core/crdt-binding.js +286 -0
- package/dist/components/editor/core/diagnostics.d.ts +210 -0
- package/dist/components/editor/core/diagnostics.js +335 -0
- package/dist/components/editor/core/echo-cursor.d.ts +201 -0
- package/dist/components/editor/core/echo-cursor.js +267 -0
- package/dist/components/editor/core/folding.d.ts +124 -0
- package/dist/components/editor/core/folding.js +672 -0
- package/dist/components/editor/core/ghost-pair.d.ts +122 -0
- package/dist/components/editor/core/ghost-pair.js +221 -0
- package/dist/components/editor/core/git-blame.d.ts +170 -0
- package/dist/components/editor/core/git-blame.js +324 -0
- package/dist/components/editor/core/index.d.ts +26 -0
- package/dist/components/editor/core/index.js +24 -0
- package/dist/components/editor/core/keybindings.d.ts +79 -0
- package/dist/components/editor/core/keybindings.js +357 -0
- package/dist/components/editor/core/multi-cursor.d.ts +196 -0
- package/dist/components/editor/core/multi-cursor.js +521 -0
- package/dist/components/editor/core/navigation.d.ts +107 -0
- package/dist/components/editor/core/navigation.js +408 -0
- package/dist/components/editor/core/quick-actions.d.ts +189 -0
- package/dist/components/editor/core/quick-actions.js +427 -0
- package/dist/components/editor/core/search.d.ts +88 -0
- package/dist/components/editor/core/search.js +192 -0
- package/dist/components/editor/core/semantic-analyzer.d.ts +77 -0
- package/dist/components/editor/core/semantic-analyzer.js +424 -0
- package/dist/components/editor/core/snippet-manager.d.ts +202 -0
- package/dist/components/editor/core/snippet-manager.js +565 -0
- package/dist/components/editor/core/state.d.ts +367 -0
- package/dist/components/editor/core/state.js +900 -0
- package/dist/components/editor/core/timeline.d.ts +204 -0
- package/dist/components/editor/core/timeline.js +349 -0
- package/dist/components/editor/editor-find.d.ts +56 -0
- package/dist/components/editor/editor-find.js +148 -0
- package/dist/components/editor/editor-input.d.ts +77 -0
- package/dist/components/editor/editor-input.js +445 -0
- package/dist/components/editor/editor-multicursor.d.ts +21 -0
- package/dist/components/editor/editor-multicursor.js +196 -0
- package/dist/components/editor/editor-scroll.d.ts +14 -0
- package/dist/components/editor/editor-scroll.js +34 -0
- package/dist/components/editor/index.d.ts +15 -0
- package/dist/components/editor/index.js +21 -0
- package/dist/components/editor/languages.d.ts +62 -0
- package/dist/components/editor/languages.js +285 -0
- package/dist/components/editor/theme.d.ts +88 -0
- package/dist/components/editor/theme.js +139 -0
- package/dist/components/editor/tokenizer/base.d.ts +40 -0
- package/dist/components/editor/tokenizer/base.js +203 -0
- package/dist/components/editor/tokenizer/index.d.ts +56 -0
- package/dist/components/editor/tokenizer/index.js +215 -0
- package/dist/components/editor/tokenizer/languages/css.d.ts +17 -0
- package/dist/components/editor/tokenizer/languages/css.js +194 -0
- package/dist/components/editor/tokenizer/languages/go.d.ts +17 -0
- package/dist/components/editor/tokenizer/languages/go.js +220 -0
- package/dist/components/editor/tokenizer/languages/html.d.ts +24 -0
- package/dist/components/editor/tokenizer/languages/html.js +145 -0
- package/dist/components/editor/tokenizer/languages/javascript.d.ts +56 -0
- package/dist/components/editor/tokenizer/languages/javascript.js +452 -0
- package/dist/components/editor/tokenizer/languages/json.d.ts +12 -0
- package/dist/components/editor/tokenizer/languages/json.js +91 -0
- package/dist/components/editor/tokenizer/languages/markdown.d.ts +16 -0
- package/dist/components/editor/tokenizer/languages/markdown.js +156 -0
- package/dist/components/editor/tokenizer/languages/python.d.ts +20 -0
- package/dist/components/editor/tokenizer/languages/python.js +227 -0
- package/dist/components/editor/tokenizer/languages/svelte.d.ts +40 -0
- package/dist/components/editor/tokenizer/languages/svelte.js +326 -0
- package/dist/components/editor/tokenizer/types.d.ts +86 -0
- package/dist/components/editor/tokenizer/types.js +4 -0
- package/dist/components/layout/IDELayout.svelte +274 -0
- package/dist/components/layout/IDELayout.svelte.d.ts +29 -0
- package/dist/components/layout/StatusBar.svelte +511 -0
- package/dist/components/layout/StatusBar.svelte.d.ts +47 -0
- package/dist/components/layout/index.d.ts +2 -0
- package/dist/components/layout/index.js +3 -0
- package/dist/components/lsp/AutocompleteWidget.svelte +364 -0
- package/dist/components/lsp/AutocompleteWidget.svelte.d.ts +33 -0
- package/dist/components/lsp/DiagnosticMarker.svelte +166 -0
- package/dist/components/lsp/DiagnosticMarker.svelte.d.ts +19 -0
- package/dist/components/lsp/DiagnosticsPanel.svelte +388 -0
- package/dist/components/lsp/DiagnosticsPanel.svelte.d.ts +21 -0
- package/dist/components/lsp/HoverTooltip.svelte +274 -0
- package/dist/components/lsp/HoverTooltip.svelte.d.ts +24 -0
- package/dist/components/lsp/LSPEditor.svelte +486 -0
- package/dist/components/lsp/LSPEditor.svelte.d.ts +39 -0
- package/dist/components/lsp/SignatureHelpWidget.svelte +216 -0
- package/dist/components/lsp/SignatureHelpWidget.svelte.d.ts +22 -0
- package/dist/components/lsp/index.d.ts +6 -0
- package/dist/components/lsp/index.js +7 -0
- package/dist/components/plugins/PluginCard.svelte +153 -0
- package/dist/components/plugins/PluginCard.svelte.d.ts +19 -0
- package/dist/components/plugins/PluginPanel.svelte +280 -0
- package/dist/components/plugins/PluginPanel.svelte.d.ts +8 -0
- package/dist/components/plugins/PluginProposalForm.svelte +250 -0
- package/dist/components/plugins/PluginProposalForm.svelte.d.ts +6 -0
- package/dist/components/plugins/PluginStatusBadge.svelte +14 -0
- package/dist/components/plugins/PluginStatusBadge.svelte.d.ts +8 -0
- package/dist/components/plugins/index.d.ts +4 -0
- package/dist/components/plugins/index.js +5 -0
- package/dist/components/vfs/LockConflictDialog.svelte +705 -0
- package/dist/components/vfs/LockConflictDialog.svelte.d.ts +21 -0
- package/dist/components/vfs/LockIndicator.svelte +194 -0
- package/dist/components/vfs/LockIndicator.svelte.d.ts +29 -0
- package/dist/components/vfs/LockOverlay.svelte +344 -0
- package/dist/components/vfs/LockOverlay.svelte.d.ts +17 -0
- package/dist/components/vfs/VersionConflictDialog.svelte +549 -0
- package/dist/components/vfs/VersionConflictDialog.svelte.d.ts +24 -0
- package/dist/components/vfs/index.d.ts +4 -0
- package/dist/components/vfs/index.js +5 -0
- package/dist/crdt/awareness.d.ts +42 -0
- package/dist/crdt/awareness.js +109 -0
- package/dist/crdt/document.d.ts +101 -0
- package/dist/crdt/document.js +187 -0
- package/dist/crdt/index.d.ts +9 -0
- package/dist/crdt/index.js +8 -0
- package/dist/crdt/provider.d.ts +85 -0
- package/dist/crdt/provider.js +150 -0
- package/dist/crdt/types.d.ts +61 -0
- package/dist/crdt/types.js +4 -0
- package/dist/crdt/undo.d.ts +34 -0
- package/dist/crdt/undo.js +70 -0
- package/dist/index.d.ts +277 -0
- package/dist/index.js +280 -0
- package/dist/plugins/index.d.ts +103 -0
- package/dist/plugins/index.js +153 -0
- package/dist/services/error-handling.d.ts +95 -0
- package/dist/services/error-handling.js +413 -0
- package/dist/services/ide-integration.d.ts +83 -0
- package/dist/services/ide-integration.js +367 -0
- package/dist/services/lsp-client.d.ts +69 -0
- package/dist/services/lsp-client.js +667 -0
- package/dist/services/mock-ai.d.ts +37 -0
- package/dist/services/mock-ai.js +318 -0
- package/dist/services/optimistic.d.ts +141 -0
- package/dist/services/optimistic.js +367 -0
- package/dist/services/vfs-client.d.ts +81 -0
- package/dist/services/vfs-client.js +348 -0
- package/dist/stores/agents.svelte.d.ts +85 -0
- package/dist/stores/agents.svelte.js +459 -0
- package/dist/stores/ai-persistence.svelte.d.ts +76 -0
- package/dist/stores/ai-persistence.svelte.js +334 -0
- package/dist/stores/ai.svelte.d.ts +140 -0
- package/dist/stores/ai.svelte.js +383 -0
- package/dist/stores/collaboration.svelte.d.ts +164 -0
- package/dist/stores/collaboration.svelte.js +334 -0
- package/dist/stores/editor.svelte.d.ts +131 -0
- package/dist/stores/editor.svelte.js +250 -0
- package/dist/stores/index.d.ts +10 -0
- package/dist/stores/index.js +29 -0
- package/dist/stores/layout.svelte.d.ts +171 -0
- package/dist/stores/layout.svelte.js +351 -0
- package/dist/stores/plugin.svelte.d.ts +121 -0
- package/dist/stores/plugin.svelte.js +410 -0
- package/dist/stores/vfs.svelte.d.ts +123 -0
- package/dist/stores/vfs.svelte.js +680 -0
- package/dist/styles/theme.css +623 -0
- package/dist/types/agents.d.ts +127 -0
- package/dist/types/agents.js +5 -0
- package/dist/types/ai.d.ts +137 -0
- package/dist/types/ai.js +4 -0
- package/dist/types/crdt.d.ts +222 -0
- package/dist/types/crdt.js +5 -0
- package/dist/types/editor.d.ts +52 -0
- package/dist/types/editor.js +18 -0
- package/dist/types/events.d.ts +133 -0
- package/dist/types/events.js +4 -0
- package/dist/types/filesystem.d.ts +77 -0
- package/dist/types/filesystem.js +4 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.js +12 -0
- package/dist/types/lsp.d.ts +691 -0
- package/dist/types/lsp.js +108 -0
- package/dist/types/plugin.d.ts +239 -0
- package/dist/types/plugin.js +5 -0
- package/dist/types/vfs.d.ts +191 -0
- package/dist/types/vfs.js +18 -0
- package/dist/utils/format.d.ts +55 -0
- package/dist/utils/format.js +152 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/keybindings.d.ts +33 -0
- package/dist/utils/keybindings.js +171 -0
- package/dist/utils/language.d.ts +27 -0
- package/dist/utils/language.js +222 -0
- package/package.json +178 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Awareness protocol for cursor and selection sync
|
|
3
|
+
*/
|
|
4
|
+
import { Awareness } from 'y-protocols/awareness';
|
|
5
|
+
/**
|
|
6
|
+
* Create an awareness protocol instance
|
|
7
|
+
*/
|
|
8
|
+
export function createAwarenessProtocol(doc) {
|
|
9
|
+
const awareness = new Awareness(doc);
|
|
10
|
+
const userChangeCallbacks = new Set();
|
|
11
|
+
// Track awareness changes
|
|
12
|
+
awareness.on('change', () => {
|
|
13
|
+
const users = getUsers();
|
|
14
|
+
userChangeCallbacks.forEach((cb) => cb(users));
|
|
15
|
+
});
|
|
16
|
+
function getLocalState() {
|
|
17
|
+
return awareness.getLocalState();
|
|
18
|
+
}
|
|
19
|
+
function setLocalState(updates) {
|
|
20
|
+
const current = getLocalState();
|
|
21
|
+
awareness.setLocalState({
|
|
22
|
+
...current,
|
|
23
|
+
...updates
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function getUsers() {
|
|
27
|
+
const states = awareness.getStates();
|
|
28
|
+
const users = [];
|
|
29
|
+
states.forEach((state) => {
|
|
30
|
+
if (state.user) {
|
|
31
|
+
users.push(state.user);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return users;
|
|
35
|
+
}
|
|
36
|
+
function getCursors() {
|
|
37
|
+
const states = awareness.getStates();
|
|
38
|
+
const cursors = new Map();
|
|
39
|
+
states.forEach((state, clientId) => {
|
|
40
|
+
if (state.user && state.cursor) {
|
|
41
|
+
cursors.set(clientId, {
|
|
42
|
+
user: state.user,
|
|
43
|
+
cursor: state.cursor
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
return cursors;
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
awareness,
|
|
51
|
+
setUser(user) {
|
|
52
|
+
setLocalState({ user, state: 'active' });
|
|
53
|
+
},
|
|
54
|
+
setCursor(anchor, head) {
|
|
55
|
+
setLocalState({ cursor: { anchor, head } });
|
|
56
|
+
},
|
|
57
|
+
setSelection(anchor, head) {
|
|
58
|
+
setLocalState({ selection: { anchor, head } });
|
|
59
|
+
},
|
|
60
|
+
setViewingFile(path) {
|
|
61
|
+
setLocalState({ viewingFile: path });
|
|
62
|
+
},
|
|
63
|
+
setEditingFile(path) {
|
|
64
|
+
setLocalState({ editingFile: path });
|
|
65
|
+
},
|
|
66
|
+
setState(state) {
|
|
67
|
+
setLocalState({ state });
|
|
68
|
+
},
|
|
69
|
+
getUsers,
|
|
70
|
+
getCursors,
|
|
71
|
+
onUsersChange(callback) {
|
|
72
|
+
userChangeCallbacks.add(callback);
|
|
73
|
+
// Immediately call with current users
|
|
74
|
+
callback(getUsers());
|
|
75
|
+
return () => userChangeCallbacks.delete(callback);
|
|
76
|
+
},
|
|
77
|
+
destroy() {
|
|
78
|
+
awareness.destroy();
|
|
79
|
+
userChangeCallbacks.clear();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Generate a random color for a user
|
|
85
|
+
*/
|
|
86
|
+
export function generateUserColor() {
|
|
87
|
+
const colors = [
|
|
88
|
+
'#60a5fa', // blue
|
|
89
|
+
'#a78bfa', // purple
|
|
90
|
+
'#4ade80', // green
|
|
91
|
+
'#f472b6', // pink
|
|
92
|
+
'#facc15', // yellow
|
|
93
|
+
'#fb923c', // orange
|
|
94
|
+
'#22d3ee', // cyan
|
|
95
|
+
'#e879f9' // fuchsia
|
|
96
|
+
];
|
|
97
|
+
return colors[Math.floor(Math.random() * colors.length)];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Generate initials from a name
|
|
101
|
+
*/
|
|
102
|
+
export function getInitials(name) {
|
|
103
|
+
return name
|
|
104
|
+
.split(' ')
|
|
105
|
+
.map((part) => part[0])
|
|
106
|
+
.join('')
|
|
107
|
+
.toUpperCase()
|
|
108
|
+
.slice(0, 2);
|
|
109
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collaborative Document using Yjs
|
|
3
|
+
* Provides a wrapper around Yjs Doc for IDE integration
|
|
4
|
+
*/
|
|
5
|
+
import * as Y from 'yjs';
|
|
6
|
+
import type { DocumentOptions } from './types';
|
|
7
|
+
export declare class CollaborativeDocument {
|
|
8
|
+
readonly doc: Y.Doc;
|
|
9
|
+
readonly id: string;
|
|
10
|
+
private texts;
|
|
11
|
+
private undoManager;
|
|
12
|
+
constructor(options: DocumentOptions);
|
|
13
|
+
/**
|
|
14
|
+
* Get or create a Y.Text for a given key
|
|
15
|
+
*/
|
|
16
|
+
getText(key?: string): Y.Text;
|
|
17
|
+
/**
|
|
18
|
+
* Get the content as a string
|
|
19
|
+
*/
|
|
20
|
+
getContent(key?: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Set the entire content (replaces existing)
|
|
23
|
+
*/
|
|
24
|
+
setContent(content: string, key?: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Insert text at position
|
|
27
|
+
*/
|
|
28
|
+
insert(index: number, content: string, key?: string): void;
|
|
29
|
+
/**
|
|
30
|
+
* Delete text at position
|
|
31
|
+
*/
|
|
32
|
+
delete(index: number, length: number, key?: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Apply a delta (for CodeMirror integration)
|
|
35
|
+
*/
|
|
36
|
+
applyDelta(changes: Array<{
|
|
37
|
+
from: number;
|
|
38
|
+
to: number;
|
|
39
|
+
insert: string;
|
|
40
|
+
}>, key?: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* Subscribe to text changes
|
|
43
|
+
*/
|
|
44
|
+
onTextChange(callback: (event: Y.YTextEvent, transaction: Y.Transaction) => void, key?: string): () => void;
|
|
45
|
+
/**
|
|
46
|
+
* Subscribe to any document updates
|
|
47
|
+
*/
|
|
48
|
+
onUpdate(callback: (update: Uint8Array, origin: unknown) => void): () => void;
|
|
49
|
+
/**
|
|
50
|
+
* Setup undo manager
|
|
51
|
+
*/
|
|
52
|
+
private setupUndoManager;
|
|
53
|
+
/**
|
|
54
|
+
* Track additional origins for undo
|
|
55
|
+
*/
|
|
56
|
+
trackOrigin(origin: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Undo last change
|
|
59
|
+
*/
|
|
60
|
+
undo(): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Redo last undone change
|
|
63
|
+
*/
|
|
64
|
+
redo(): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Check if can undo
|
|
67
|
+
*/
|
|
68
|
+
canUndo(): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Check if can redo
|
|
71
|
+
*/
|
|
72
|
+
canRedo(): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Clear undo/redo history
|
|
75
|
+
*/
|
|
76
|
+
clearHistory(): void;
|
|
77
|
+
/**
|
|
78
|
+
* Create a snapshot of the current state
|
|
79
|
+
*/
|
|
80
|
+
createSnapshot(): Uint8Array;
|
|
81
|
+
/**
|
|
82
|
+
* Apply a snapshot
|
|
83
|
+
*/
|
|
84
|
+
applySnapshot(snapshot: Uint8Array): void;
|
|
85
|
+
/**
|
|
86
|
+
* Get the state vector for sync
|
|
87
|
+
*/
|
|
88
|
+
getStateVector(): Uint8Array;
|
|
89
|
+
/**
|
|
90
|
+
* Get diff from a state vector
|
|
91
|
+
*/
|
|
92
|
+
getDiff(stateVector: Uint8Array): Uint8Array;
|
|
93
|
+
/**
|
|
94
|
+
* Merge updates from another document
|
|
95
|
+
*/
|
|
96
|
+
merge(update: Uint8Array): void;
|
|
97
|
+
/**
|
|
98
|
+
* Destroy the document
|
|
99
|
+
*/
|
|
100
|
+
destroy(): void;
|
|
101
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collaborative Document using Yjs
|
|
3
|
+
* Provides a wrapper around Yjs Doc for IDE integration
|
|
4
|
+
*/
|
|
5
|
+
import * as Y from 'yjs';
|
|
6
|
+
export class CollaborativeDocument {
|
|
7
|
+
doc;
|
|
8
|
+
id;
|
|
9
|
+
texts = new Map();
|
|
10
|
+
undoManager = null;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.id = options.documentId;
|
|
13
|
+
this.doc = new Y.Doc();
|
|
14
|
+
// Create initial text if provided
|
|
15
|
+
if (options.initialContent !== undefined) {
|
|
16
|
+
const text = this.getText('content');
|
|
17
|
+
text.insert(0, options.initialContent);
|
|
18
|
+
}
|
|
19
|
+
// Setup undo manager if enabled
|
|
20
|
+
if (options.enableUndo !== false) {
|
|
21
|
+
this.setupUndoManager(options.undoCaptureTimeout);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Get or create a Y.Text for a given key
|
|
26
|
+
*/
|
|
27
|
+
getText(key = 'content') {
|
|
28
|
+
let text = this.texts.get(key);
|
|
29
|
+
if (!text) {
|
|
30
|
+
text = this.doc.getText(key);
|
|
31
|
+
this.texts.set(key, text);
|
|
32
|
+
}
|
|
33
|
+
return text;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get the content as a string
|
|
37
|
+
*/
|
|
38
|
+
getContent(key = 'content') {
|
|
39
|
+
return this.getText(key).toString();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Set the entire content (replaces existing)
|
|
43
|
+
*/
|
|
44
|
+
setContent(content, key = 'content') {
|
|
45
|
+
const text = this.getText(key);
|
|
46
|
+
this.doc.transact(() => {
|
|
47
|
+
text.delete(0, text.length);
|
|
48
|
+
text.insert(0, content);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Insert text at position
|
|
53
|
+
*/
|
|
54
|
+
insert(index, content, key = 'content') {
|
|
55
|
+
this.getText(key).insert(index, content);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Delete text at position
|
|
59
|
+
*/
|
|
60
|
+
delete(index, length, key = 'content') {
|
|
61
|
+
this.getText(key).delete(index, length);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Apply a delta (for CodeMirror integration)
|
|
65
|
+
*/
|
|
66
|
+
applyDelta(changes, key = 'content') {
|
|
67
|
+
const text = this.getText(key);
|
|
68
|
+
this.doc.transact(() => {
|
|
69
|
+
// Apply changes in reverse order to maintain correct positions
|
|
70
|
+
const sortedChanges = [...changes].sort((a, b) => b.from - a.from);
|
|
71
|
+
for (const change of sortedChanges) {
|
|
72
|
+
const deleteLen = change.to - change.from;
|
|
73
|
+
if (deleteLen > 0) {
|
|
74
|
+
text.delete(change.from, deleteLen);
|
|
75
|
+
}
|
|
76
|
+
if (change.insert) {
|
|
77
|
+
text.insert(change.from, change.insert);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Subscribe to text changes
|
|
84
|
+
*/
|
|
85
|
+
onTextChange(callback, key = 'content') {
|
|
86
|
+
const text = this.getText(key);
|
|
87
|
+
text.observe(callback);
|
|
88
|
+
return () => text.unobserve(callback);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Subscribe to any document updates
|
|
92
|
+
*/
|
|
93
|
+
onUpdate(callback) {
|
|
94
|
+
this.doc.on('update', callback);
|
|
95
|
+
return () => this.doc.off('update', callback);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Setup undo manager
|
|
99
|
+
*/
|
|
100
|
+
setupUndoManager(captureTimeout = 500) {
|
|
101
|
+
const trackedOrigins = new Set([null, 'local']);
|
|
102
|
+
this.undoManager = new Y.UndoManager(this.getText(), {
|
|
103
|
+
trackedOrigins,
|
|
104
|
+
captureTimeout
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Track additional origins for undo
|
|
109
|
+
*/
|
|
110
|
+
trackOrigin(origin) {
|
|
111
|
+
if (this.undoManager) {
|
|
112
|
+
this.undoManager.trackedOrigins.add(origin);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Undo last change
|
|
117
|
+
*/
|
|
118
|
+
undo() {
|
|
119
|
+
if (!this.undoManager)
|
|
120
|
+
return false;
|
|
121
|
+
return this.undoManager.undo() !== null;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Redo last undone change
|
|
125
|
+
*/
|
|
126
|
+
redo() {
|
|
127
|
+
if (!this.undoManager)
|
|
128
|
+
return false;
|
|
129
|
+
return this.undoManager.redo() !== null;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Check if can undo
|
|
133
|
+
*/
|
|
134
|
+
canUndo() {
|
|
135
|
+
return this.undoManager?.canUndo() ?? false;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Check if can redo
|
|
139
|
+
*/
|
|
140
|
+
canRedo() {
|
|
141
|
+
return this.undoManager?.canRedo() ?? false;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Clear undo/redo history
|
|
145
|
+
*/
|
|
146
|
+
clearHistory() {
|
|
147
|
+
this.undoManager?.clear();
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Create a snapshot of the current state
|
|
151
|
+
*/
|
|
152
|
+
createSnapshot() {
|
|
153
|
+
return Y.encodeStateAsUpdate(this.doc);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Apply a snapshot
|
|
157
|
+
*/
|
|
158
|
+
applySnapshot(snapshot) {
|
|
159
|
+
Y.applyUpdate(this.doc, snapshot);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get the state vector for sync
|
|
163
|
+
*/
|
|
164
|
+
getStateVector() {
|
|
165
|
+
return Y.encodeStateVector(this.doc);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get diff from a state vector
|
|
169
|
+
*/
|
|
170
|
+
getDiff(stateVector) {
|
|
171
|
+
return Y.encodeStateAsUpdate(this.doc, stateVector);
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Merge updates from another document
|
|
175
|
+
*/
|
|
176
|
+
merge(update) {
|
|
177
|
+
Y.applyUpdate(this.doc, update);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Destroy the document
|
|
181
|
+
*/
|
|
182
|
+
destroy() {
|
|
183
|
+
this.undoManager?.destroy();
|
|
184
|
+
this.doc.destroy();
|
|
185
|
+
this.texts.clear();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRDT module for collaborative editing
|
|
3
|
+
* Uses Yjs for conflict-free replicated data types
|
|
4
|
+
*/
|
|
5
|
+
export { CollaborativeDocument } from './document';
|
|
6
|
+
export { CollaborativeProvider } from './provider';
|
|
7
|
+
export { createAwarenessProtocol } from './awareness';
|
|
8
|
+
export { createUndoManager } from './undo';
|
|
9
|
+
export type * from './types';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRDT module for collaborative editing
|
|
3
|
+
* Uses Yjs for conflict-free replicated data types
|
|
4
|
+
*/
|
|
5
|
+
export { CollaborativeDocument } from './document';
|
|
6
|
+
export { CollaborativeProvider } from './provider';
|
|
7
|
+
export { createAwarenessProtocol } from './awareness';
|
|
8
|
+
export { createUndoManager } from './undo';
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket provider for Yjs collaboration
|
|
3
|
+
* Handles connection, sync, and reconnection
|
|
4
|
+
*/
|
|
5
|
+
import { WebsocketProvider } from 'y-websocket';
|
|
6
|
+
import type { Doc as YDoc } from 'yjs';
|
|
7
|
+
import { Awareness } from 'y-protocols/awareness';
|
|
8
|
+
import type { ProviderOptions, ConnectionStatus, AwarenessState } from './types';
|
|
9
|
+
export declare class CollaborativeProvider {
|
|
10
|
+
readonly provider: WebsocketProvider;
|
|
11
|
+
readonly awareness: Awareness;
|
|
12
|
+
private statusListeners;
|
|
13
|
+
private syncListeners;
|
|
14
|
+
constructor(options: ProviderOptions);
|
|
15
|
+
private setupEventListeners;
|
|
16
|
+
/**
|
|
17
|
+
* Get current connection status
|
|
18
|
+
*/
|
|
19
|
+
get status(): ConnectionStatus;
|
|
20
|
+
/**
|
|
21
|
+
* Check if synced with server
|
|
22
|
+
*/
|
|
23
|
+
get synced(): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Connect to the server
|
|
26
|
+
*/
|
|
27
|
+
connect(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Disconnect from the server
|
|
30
|
+
*/
|
|
31
|
+
disconnect(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Set local awareness state
|
|
34
|
+
*/
|
|
35
|
+
setLocalState(state: Partial<AwarenessState>): void;
|
|
36
|
+
/**
|
|
37
|
+
* Get local awareness state
|
|
38
|
+
*/
|
|
39
|
+
getLocalState(): AwarenessState | null;
|
|
40
|
+
/**
|
|
41
|
+
* Get all awareness states
|
|
42
|
+
*/
|
|
43
|
+
getStates(): Map<number, AwarenessState>;
|
|
44
|
+
/**
|
|
45
|
+
* Get awareness state for a specific client
|
|
46
|
+
*/
|
|
47
|
+
getState(clientId: number): AwarenessState | undefined;
|
|
48
|
+
/**
|
|
49
|
+
* Subscribe to connection status changes
|
|
50
|
+
*/
|
|
51
|
+
onStatus(callback: (status: ConnectionStatus) => void): () => void;
|
|
52
|
+
/**
|
|
53
|
+
* Subscribe to sync state changes
|
|
54
|
+
*/
|
|
55
|
+
onSync(callback: (synced: boolean) => void): () => void;
|
|
56
|
+
/**
|
|
57
|
+
* Subscribe to awareness changes
|
|
58
|
+
*/
|
|
59
|
+
onAwarenessChange(callback: (changes: {
|
|
60
|
+
added: number[];
|
|
61
|
+
updated: number[];
|
|
62
|
+
removed: number[];
|
|
63
|
+
}, origin: string) => void): () => void;
|
|
64
|
+
/**
|
|
65
|
+
* Get all connected client IDs
|
|
66
|
+
*/
|
|
67
|
+
getClientIds(): number[];
|
|
68
|
+
/**
|
|
69
|
+
* Get the local client ID
|
|
70
|
+
*/
|
|
71
|
+
get clientId(): number;
|
|
72
|
+
/**
|
|
73
|
+
* Destroy the provider
|
|
74
|
+
*/
|
|
75
|
+
destroy(): void;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Create a provider with sensible defaults for IDE usage
|
|
79
|
+
*/
|
|
80
|
+
export declare function createProvider(doc: YDoc, serverUrl: string, roomId: string, user: {
|
|
81
|
+
id: string;
|
|
82
|
+
name: string;
|
|
83
|
+
color: string;
|
|
84
|
+
isAI?: boolean;
|
|
85
|
+
}): CollaborativeProvider;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket provider for Yjs collaboration
|
|
3
|
+
* Handles connection, sync, and reconnection
|
|
4
|
+
*/
|
|
5
|
+
import { WebsocketProvider } from 'y-websocket';
|
|
6
|
+
import { Awareness } from 'y-protocols/awareness';
|
|
7
|
+
export class CollaborativeProvider {
|
|
8
|
+
provider;
|
|
9
|
+
awareness;
|
|
10
|
+
statusListeners = new Set();
|
|
11
|
+
syncListeners = new Set();
|
|
12
|
+
constructor(options) {
|
|
13
|
+
// Create awareness if not provided
|
|
14
|
+
this.awareness = options.awareness ?? new Awareness(options.doc);
|
|
15
|
+
// Create WebSocket provider
|
|
16
|
+
this.provider = new WebsocketProvider(options.serverUrl, options.roomId, options.doc, {
|
|
17
|
+
awareness: this.awareness,
|
|
18
|
+
params: options.params,
|
|
19
|
+
connect: options.connect ?? true,
|
|
20
|
+
resyncInterval: options.resyncInterval ?? 30000,
|
|
21
|
+
maxBackoffTime: options.maxBackoffTime ?? 10000
|
|
22
|
+
});
|
|
23
|
+
// Setup event forwarding
|
|
24
|
+
this.setupEventListeners();
|
|
25
|
+
}
|
|
26
|
+
setupEventListeners() {
|
|
27
|
+
this.provider.on('status', ({ status }) => {
|
|
28
|
+
const mappedStatus = status;
|
|
29
|
+
this.statusListeners.forEach((listener) => listener(mappedStatus));
|
|
30
|
+
});
|
|
31
|
+
this.provider.on('sync', (synced) => {
|
|
32
|
+
this.syncListeners.forEach((listener) => listener(synced));
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get current connection status
|
|
37
|
+
*/
|
|
38
|
+
get status() {
|
|
39
|
+
if (this.provider.wsconnected)
|
|
40
|
+
return 'connected';
|
|
41
|
+
if (this.provider.wsconnecting)
|
|
42
|
+
return 'connecting';
|
|
43
|
+
return 'disconnected';
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if synced with server
|
|
47
|
+
*/
|
|
48
|
+
get synced() {
|
|
49
|
+
return this.provider.synced;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Connect to the server
|
|
53
|
+
*/
|
|
54
|
+
connect() {
|
|
55
|
+
this.provider.connect();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Disconnect from the server
|
|
59
|
+
*/
|
|
60
|
+
disconnect() {
|
|
61
|
+
this.provider.disconnect();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Set local awareness state
|
|
65
|
+
*/
|
|
66
|
+
setLocalState(state) {
|
|
67
|
+
const currentState = this.awareness.getLocalState();
|
|
68
|
+
this.awareness.setLocalState({
|
|
69
|
+
...currentState,
|
|
70
|
+
...state
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Get local awareness state
|
|
75
|
+
*/
|
|
76
|
+
getLocalState() {
|
|
77
|
+
return this.awareness.getLocalState();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get all awareness states
|
|
81
|
+
*/
|
|
82
|
+
getStates() {
|
|
83
|
+
return this.awareness.getStates();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get awareness state for a specific client
|
|
87
|
+
*/
|
|
88
|
+
getState(clientId) {
|
|
89
|
+
return this.getStates().get(clientId);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Subscribe to connection status changes
|
|
93
|
+
*/
|
|
94
|
+
onStatus(callback) {
|
|
95
|
+
this.statusListeners.add(callback);
|
|
96
|
+
return () => this.statusListeners.delete(callback);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Subscribe to sync state changes
|
|
100
|
+
*/
|
|
101
|
+
onSync(callback) {
|
|
102
|
+
this.syncListeners.add(callback);
|
|
103
|
+
return () => this.syncListeners.delete(callback);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Subscribe to awareness changes
|
|
107
|
+
*/
|
|
108
|
+
onAwarenessChange(callback) {
|
|
109
|
+
this.awareness.on('change', callback);
|
|
110
|
+
return () => this.awareness.off('change', callback);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get all connected client IDs
|
|
114
|
+
*/
|
|
115
|
+
getClientIds() {
|
|
116
|
+
return Array.from(this.getStates().keys());
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get the local client ID
|
|
120
|
+
*/
|
|
121
|
+
get clientId() {
|
|
122
|
+
return this.awareness.clientID;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Destroy the provider
|
|
126
|
+
*/
|
|
127
|
+
destroy() {
|
|
128
|
+
this.provider.destroy();
|
|
129
|
+
this.awareness.destroy();
|
|
130
|
+
this.statusListeners.clear();
|
|
131
|
+
this.syncListeners.clear();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Create a provider with sensible defaults for IDE usage
|
|
136
|
+
*/
|
|
137
|
+
export function createProvider(doc, serverUrl, roomId, user) {
|
|
138
|
+
const provider = new CollaborativeProvider({
|
|
139
|
+
serverUrl,
|
|
140
|
+
roomId,
|
|
141
|
+
doc,
|
|
142
|
+
connect: true
|
|
143
|
+
});
|
|
144
|
+
// Set initial awareness state
|
|
145
|
+
provider.setLocalState({
|
|
146
|
+
user,
|
|
147
|
+
state: 'active'
|
|
148
|
+
});
|
|
149
|
+
return provider;
|
|
150
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRDT-specific types for the collaboration module
|
|
3
|
+
*/
|
|
4
|
+
import type { Doc as YDoc } from 'yjs';
|
|
5
|
+
import type { Awareness } from 'y-protocols/awareness';
|
|
6
|
+
export interface DocumentOptions {
|
|
7
|
+
documentId: string;
|
|
8
|
+
initialContent?: string;
|
|
9
|
+
enableUndo?: boolean;
|
|
10
|
+
undoCaptureTimeout?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface ProviderOptions {
|
|
13
|
+
serverUrl: string;
|
|
14
|
+
roomId: string;
|
|
15
|
+
doc: YDoc;
|
|
16
|
+
awareness?: Awareness;
|
|
17
|
+
params?: Record<string, string>;
|
|
18
|
+
connect?: boolean;
|
|
19
|
+
resyncInterval?: number;
|
|
20
|
+
maxBackoffTime?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface AwarenessState {
|
|
23
|
+
user: {
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
color: string;
|
|
27
|
+
isAI?: boolean;
|
|
28
|
+
};
|
|
29
|
+
cursor?: {
|
|
30
|
+
anchor: number;
|
|
31
|
+
head: number;
|
|
32
|
+
};
|
|
33
|
+
selection?: {
|
|
34
|
+
anchor: number;
|
|
35
|
+
head: number;
|
|
36
|
+
};
|
|
37
|
+
viewingFile?: string;
|
|
38
|
+
editingFile?: string;
|
|
39
|
+
state: 'active' | 'idle' | 'away';
|
|
40
|
+
}
|
|
41
|
+
export interface CRDTChange {
|
|
42
|
+
origin: string | null;
|
|
43
|
+
local: boolean;
|
|
44
|
+
added: Set<number>;
|
|
45
|
+
updated: Set<number>;
|
|
46
|
+
removed: Set<number>;
|
|
47
|
+
}
|
|
48
|
+
export interface SyncState {
|
|
49
|
+
synced: boolean;
|
|
50
|
+
pending: number;
|
|
51
|
+
}
|
|
52
|
+
export type ConnectionStatus = 'connecting' | 'connected' | 'disconnected';
|
|
53
|
+
export interface CRDTEventMap {
|
|
54
|
+
sync: (synced: boolean) => void;
|
|
55
|
+
update: (update: Uint8Array, origin: string | null) => void;
|
|
56
|
+
'awareness-change': (changes: CRDTChange) => void;
|
|
57
|
+
status: (status: {
|
|
58
|
+
status: ConnectionStatus;
|
|
59
|
+
}) => void;
|
|
60
|
+
error: (error: Error) => void;
|
|
61
|
+
}
|