@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,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optimistic Update Service
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for optimistic UI updates with automatic rollback on failure.
|
|
5
|
+
* Implements a queue-based system for managing pending operations.
|
|
6
|
+
*/
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Operation Queue
|
|
9
|
+
// ============================================================================
|
|
10
|
+
const operationQueue = new Map();
|
|
11
|
+
const rollbackFunctions = new Map();
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Core Functions
|
|
14
|
+
// ============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Execute an optimistic update with automatic rollback on failure
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const result = await optimisticUpdate({
|
|
21
|
+
* type: 'file_save',
|
|
22
|
+
* payload: { path: '/src/main.ts', content: '...' },
|
|
23
|
+
* apply: () => {
|
|
24
|
+
* // Apply change locally immediately
|
|
25
|
+
* updateLocalFile(path, content);
|
|
26
|
+
* },
|
|
27
|
+
* rollback: () => {
|
|
28
|
+
* // Revert to previous state
|
|
29
|
+
* updateLocalFile(path, previousContent);
|
|
30
|
+
* },
|
|
31
|
+
* commit: async () => {
|
|
32
|
+
* // Persist to server
|
|
33
|
+
* return await vfsClient.writeFile(workspaceId, path, content);
|
|
34
|
+
* }
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export async function optimisticUpdate(options) {
|
|
39
|
+
const { type, payload, apply, rollback, commit, config = {} } = options;
|
|
40
|
+
const { maxRetries = 3, retryDelay = 1000, onCommit, onRollback, onRetry } = config;
|
|
41
|
+
const operation = {
|
|
42
|
+
id: crypto.randomUUID(),
|
|
43
|
+
type,
|
|
44
|
+
payload,
|
|
45
|
+
timestamp: Date.now(),
|
|
46
|
+
status: 'pending',
|
|
47
|
+
retryCount: 0,
|
|
48
|
+
maxRetries
|
|
49
|
+
};
|
|
50
|
+
// Store operation and rollback
|
|
51
|
+
operationQueue.set(operation.id, operation);
|
|
52
|
+
rollbackFunctions.set(operation.id, rollback);
|
|
53
|
+
// Apply optimistically
|
|
54
|
+
try {
|
|
55
|
+
apply();
|
|
56
|
+
}
|
|
57
|
+
catch (applyError) {
|
|
58
|
+
// If apply fails, don't even try to commit
|
|
59
|
+
operation.status = 'failed';
|
|
60
|
+
operationQueue.delete(operation.id);
|
|
61
|
+
rollbackFunctions.delete(operation.id);
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
error: applyError instanceof Error ? applyError : new Error(String(applyError)),
|
|
65
|
+
operation: operation
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// Try to commit with retries
|
|
69
|
+
let lastError;
|
|
70
|
+
while (operation.retryCount <= maxRetries) {
|
|
71
|
+
try {
|
|
72
|
+
const result = await commit();
|
|
73
|
+
operation.status = 'committed';
|
|
74
|
+
operationQueue.delete(operation.id);
|
|
75
|
+
rollbackFunctions.delete(operation.id);
|
|
76
|
+
onCommit?.(operation);
|
|
77
|
+
return {
|
|
78
|
+
success: true,
|
|
79
|
+
data: result,
|
|
80
|
+
operation: operation
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (commitError) {
|
|
84
|
+
lastError = commitError instanceof Error ? commitError : new Error(String(commitError));
|
|
85
|
+
operation.retryCount++;
|
|
86
|
+
if (operation.retryCount <= maxRetries) {
|
|
87
|
+
onRetry?.(operation, operation.retryCount);
|
|
88
|
+
await delay(retryDelay * operation.retryCount); // Exponential backoff
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// All retries failed - rollback
|
|
93
|
+
operation.status = 'failed';
|
|
94
|
+
try {
|
|
95
|
+
await rollback();
|
|
96
|
+
operation.status = 'rolledback';
|
|
97
|
+
onRollback?.(operation, lastError);
|
|
98
|
+
}
|
|
99
|
+
catch (rollbackError) {
|
|
100
|
+
console.error('Rollback failed:', rollbackError);
|
|
101
|
+
}
|
|
102
|
+
operationQueue.delete(operation.id);
|
|
103
|
+
rollbackFunctions.delete(operation.id);
|
|
104
|
+
return {
|
|
105
|
+
success: false,
|
|
106
|
+
error: lastError,
|
|
107
|
+
operation: operation
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Create an optimistic state manager for a specific resource
|
|
112
|
+
*/
|
|
113
|
+
export function createOptimisticState(initialValue) {
|
|
114
|
+
let currentValue = initialValue;
|
|
115
|
+
let pendingValue = null;
|
|
116
|
+
let isPending = false;
|
|
117
|
+
return {
|
|
118
|
+
get value() {
|
|
119
|
+
return pendingValue ?? currentValue;
|
|
120
|
+
},
|
|
121
|
+
get isPending() {
|
|
122
|
+
return isPending;
|
|
123
|
+
},
|
|
124
|
+
get confirmedValue() {
|
|
125
|
+
return currentValue;
|
|
126
|
+
},
|
|
127
|
+
/**
|
|
128
|
+
* Apply an optimistic update
|
|
129
|
+
*/
|
|
130
|
+
async update(newValue, commit, config) {
|
|
131
|
+
const previousValue = currentValue;
|
|
132
|
+
pendingValue = newValue;
|
|
133
|
+
isPending = true;
|
|
134
|
+
const result = await optimisticUpdate({
|
|
135
|
+
type: 'state_update',
|
|
136
|
+
payload: newValue,
|
|
137
|
+
apply: () => {
|
|
138
|
+
// Already set pendingValue above
|
|
139
|
+
},
|
|
140
|
+
rollback: () => {
|
|
141
|
+
pendingValue = null;
|
|
142
|
+
isPending = false;
|
|
143
|
+
},
|
|
144
|
+
commit: async () => {
|
|
145
|
+
const confirmed = await commit();
|
|
146
|
+
currentValue = confirmed;
|
|
147
|
+
pendingValue = null;
|
|
148
|
+
isPending = false;
|
|
149
|
+
return confirmed;
|
|
150
|
+
},
|
|
151
|
+
config
|
|
152
|
+
});
|
|
153
|
+
if (!result.success) {
|
|
154
|
+
pendingValue = null;
|
|
155
|
+
isPending = false;
|
|
156
|
+
currentValue = previousValue;
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
},
|
|
160
|
+
/**
|
|
161
|
+
* Confirm a pending value (e.g., from server response)
|
|
162
|
+
*/
|
|
163
|
+
confirm(value) {
|
|
164
|
+
currentValue = value;
|
|
165
|
+
pendingValue = null;
|
|
166
|
+
isPending = false;
|
|
167
|
+
},
|
|
168
|
+
/**
|
|
169
|
+
* Reset to initial value
|
|
170
|
+
*/
|
|
171
|
+
reset() {
|
|
172
|
+
currentValue = initialValue;
|
|
173
|
+
pendingValue = null;
|
|
174
|
+
isPending = false;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Batch multiple optimistic operations
|
|
180
|
+
*/
|
|
181
|
+
export async function batchOptimisticUpdates(operations, config) {
|
|
182
|
+
const results = [];
|
|
183
|
+
let failedCount = 0;
|
|
184
|
+
// Apply all optimistically first
|
|
185
|
+
const appliedOps = [];
|
|
186
|
+
for (const op of operations) {
|
|
187
|
+
try {
|
|
188
|
+
op.apply();
|
|
189
|
+
appliedOps.push({ op, rollback: op.rollback });
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// If any apply fails, rollback all previous
|
|
193
|
+
for (const applied of appliedOps.reverse()) {
|
|
194
|
+
try {
|
|
195
|
+
await applied.rollback();
|
|
196
|
+
}
|
|
197
|
+
catch (rollbackError) {
|
|
198
|
+
console.error('Batch rollback failed:', rollbackError);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
success: false,
|
|
203
|
+
results: [],
|
|
204
|
+
failedCount: operations.length
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Commit all
|
|
209
|
+
for (const { op, rollback } of appliedOps) {
|
|
210
|
+
const result = await optimisticUpdate({
|
|
211
|
+
...op,
|
|
212
|
+
apply: () => { }, // Already applied
|
|
213
|
+
rollback,
|
|
214
|
+
config
|
|
215
|
+
});
|
|
216
|
+
results.push(result);
|
|
217
|
+
if (!result.success)
|
|
218
|
+
failedCount++;
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
success: failedCount === 0,
|
|
222
|
+
results,
|
|
223
|
+
failedCount
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
// ============================================================================
|
|
227
|
+
// Queue Management
|
|
228
|
+
// ============================================================================
|
|
229
|
+
/**
|
|
230
|
+
* Get all pending operations
|
|
231
|
+
*/
|
|
232
|
+
export function getPendingOperations() {
|
|
233
|
+
return Array.from(operationQueue.values()).filter((op) => op.status === 'pending');
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Get operation by ID
|
|
237
|
+
*/
|
|
238
|
+
export function getOperation(id) {
|
|
239
|
+
return operationQueue.get(id);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Cancel a pending operation
|
|
243
|
+
*/
|
|
244
|
+
export async function cancelOperation(id) {
|
|
245
|
+
const operation = operationQueue.get(id);
|
|
246
|
+
if (!operation || operation.status !== 'pending') {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
const rollback = rollbackFunctions.get(id);
|
|
250
|
+
if (rollback) {
|
|
251
|
+
try {
|
|
252
|
+
await rollback();
|
|
253
|
+
operation.status = 'rolledback';
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
console.error('Cancel rollback failed:', error);
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
operationQueue.delete(id);
|
|
261
|
+
rollbackFunctions.delete(id);
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Cancel all pending operations
|
|
266
|
+
*/
|
|
267
|
+
export async function cancelAllOperations() {
|
|
268
|
+
const pending = getPendingOperations();
|
|
269
|
+
for (const op of pending) {
|
|
270
|
+
await cancelOperation(op.id);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Check if an error indicates a conflict
|
|
275
|
+
*/
|
|
276
|
+
export function isConflictError(error) {
|
|
277
|
+
const message = error.message.toLowerCase();
|
|
278
|
+
if (message.includes('version') || message.includes('conflict') || message.includes('stale')) {
|
|
279
|
+
return {
|
|
280
|
+
type: 'version',
|
|
281
|
+
timestamp: Date.now()
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
if (message.includes('lock') || message.includes('locked')) {
|
|
285
|
+
return {
|
|
286
|
+
type: 'lock',
|
|
287
|
+
timestamp: Date.now()
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
if (message.includes('concurrent') || message.includes('modified')) {
|
|
291
|
+
return {
|
|
292
|
+
type: 'concurrent',
|
|
293
|
+
timestamp: Date.now()
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Parse conflict details from error
|
|
300
|
+
*/
|
|
301
|
+
export function parseConflictDetails(error) {
|
|
302
|
+
// This would parse structured error responses from the server
|
|
303
|
+
// For now, return null as a placeholder
|
|
304
|
+
try {
|
|
305
|
+
const data = JSON.parse(error.message);
|
|
306
|
+
return {
|
|
307
|
+
localContent: data.localContent,
|
|
308
|
+
serverContent: data.serverContent,
|
|
309
|
+
baseContent: data.baseContent
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
// ============================================================================
|
|
317
|
+
// Utilities
|
|
318
|
+
// ============================================================================
|
|
319
|
+
function delay(ms) {
|
|
320
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Create a debounced optimistic updater
|
|
324
|
+
*/
|
|
325
|
+
export function createDebouncedOptimistic(commitFn, delayMs = 500) {
|
|
326
|
+
let timeoutId = null;
|
|
327
|
+
let pendingValue = null;
|
|
328
|
+
let pendingResolve = null;
|
|
329
|
+
return {
|
|
330
|
+
update(value, apply, rollback) {
|
|
331
|
+
// Apply immediately
|
|
332
|
+
apply();
|
|
333
|
+
pendingValue = value;
|
|
334
|
+
// Clear previous timeout
|
|
335
|
+
if (timeoutId) {
|
|
336
|
+
clearTimeout(timeoutId);
|
|
337
|
+
}
|
|
338
|
+
return new Promise((resolve) => {
|
|
339
|
+
pendingResolve = resolve;
|
|
340
|
+
timeoutId = setTimeout(async () => {
|
|
341
|
+
if (pendingValue === null)
|
|
342
|
+
return;
|
|
343
|
+
const result = await optimisticUpdate({
|
|
344
|
+
type: 'debounced_update',
|
|
345
|
+
payload: pendingValue,
|
|
346
|
+
apply: () => { }, // Already applied
|
|
347
|
+
rollback,
|
|
348
|
+
commit: () => commitFn(pendingValue)
|
|
349
|
+
});
|
|
350
|
+
pendingValue = null;
|
|
351
|
+
timeoutId = null;
|
|
352
|
+
pendingResolve?.(result);
|
|
353
|
+
pendingResolve = null;
|
|
354
|
+
}, delayMs);
|
|
355
|
+
});
|
|
356
|
+
},
|
|
357
|
+
flush() {
|
|
358
|
+
if (timeoutId) {
|
|
359
|
+
clearTimeout(timeoutId);
|
|
360
|
+
timeoutId = null;
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
get isPending() {
|
|
364
|
+
return pendingValue !== null;
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VFS Client Service
|
|
3
|
+
* Handles all HTTP interactions with a virtual filesystem (VFS) backend
|
|
4
|
+
*/
|
|
5
|
+
import { type VFSFile, type VFSFileInfo, type VFSDirectory, type VFSWorkspace, type VFSTransaction, type VFSTransactionResult, type VFSOperation, type VFSFileLock, type VFSLockAcquisitionOptions, type VFSClientConfig } from '../types';
|
|
6
|
+
export declare function configure(newConfig: Partial<VFSClientConfig>): void;
|
|
7
|
+
export declare function getConfig(): VFSClientConfig;
|
|
8
|
+
export declare function getWorkspace(workspaceId: string): Promise<VFSWorkspace>;
|
|
9
|
+
export declare function updateWorkspace(workspaceId: string, updates: Partial<VFSWorkspace>): Promise<VFSWorkspace>;
|
|
10
|
+
export declare function listWorkspaces(): Promise<VFSWorkspace[]>;
|
|
11
|
+
export declare function readFile(workspaceId: string, path: string): Promise<VFSFile>;
|
|
12
|
+
export declare function writeFile(workspaceId: string, path: string, content: string, version?: number): Promise<VFSFileInfo>;
|
|
13
|
+
export declare function deleteFile(workspaceId: string, path: string, version?: number): Promise<void>;
|
|
14
|
+
export declare function renameFile(workspaceId: string, oldPath: string, newPath: string, version?: number): Promise<VFSFileInfo>;
|
|
15
|
+
export declare function getFileInfo(workspaceId: string, path: string): Promise<VFSFileInfo>;
|
|
16
|
+
export declare function copyFile(workspaceId: string, sourcePath: string, destPath: string): Promise<VFSFileInfo>;
|
|
17
|
+
export declare function readDirectory(workspaceId: string, path: string): Promise<VFSDirectory>;
|
|
18
|
+
export declare function createDirectory(workspaceId: string, path: string): Promise<VFSFileInfo>;
|
|
19
|
+
export declare function deleteDirectory(workspaceId: string, path: string, recursive?: boolean): Promise<void>;
|
|
20
|
+
export declare function quickWriteFile(workspaceId: string, path: string, content: string): Promise<VFSFileInfo>;
|
|
21
|
+
export declare function quickDeleteFile(workspaceId: string, path: string): Promise<void>;
|
|
22
|
+
export declare function beginTransaction(workspaceId: string): Promise<string>;
|
|
23
|
+
export declare function commitTransaction(transactionId: string, operations: VFSOperation[]): Promise<VFSTransactionResult>;
|
|
24
|
+
export declare function rollbackTransaction(transactionId: string): Promise<void>;
|
|
25
|
+
export declare function getTransaction(transactionId: string): Promise<VFSTransaction>;
|
|
26
|
+
/**
|
|
27
|
+
* Execute multiple operations in a transaction
|
|
28
|
+
* Auto-commits on success, auto-rollbacks on failure
|
|
29
|
+
*/
|
|
30
|
+
export declare function executeTransaction(workspaceId: string, operations: VFSOperation[]): Promise<VFSTransactionResult>;
|
|
31
|
+
export declare function acquireLock(workspaceId: string, path: string, holder: string, options?: VFSLockAcquisitionOptions): Promise<VFSFileLock>;
|
|
32
|
+
export declare function releaseLock(workspaceId: string, path: string, holder: string): Promise<void>;
|
|
33
|
+
export declare function refreshLock(workspaceId: string, path: string, holder: string): Promise<VFSFileLock>;
|
|
34
|
+
export declare function getLockInfo(workspaceId: string, path: string): Promise<VFSFileLock | null>;
|
|
35
|
+
export declare function listLocks(workspaceId: string): Promise<VFSFileLock[]>;
|
|
36
|
+
export declare function forceReleaseLock(workspaceId: string, path: string, adminId: string): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Execute a function with a file lock
|
|
39
|
+
* Automatically acquires, executes, and releases
|
|
40
|
+
*/
|
|
41
|
+
export declare function withLock<T>(workspaceId: string, path: string, holder: string, fn: () => Promise<T>, options?: VFSLockAcquisitionOptions): Promise<T>;
|
|
42
|
+
/**
|
|
43
|
+
* Batch file operations with automatic locking and transaction
|
|
44
|
+
*/
|
|
45
|
+
export declare function batchUpdate(workspaceId: string, holder: string, updates: Array<{
|
|
46
|
+
path: string;
|
|
47
|
+
content: string;
|
|
48
|
+
version?: number;
|
|
49
|
+
}>): Promise<VFSTransactionResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Read file with automatic version tracking
|
|
52
|
+
*/
|
|
53
|
+
export declare function readFileWithVersion(workspaceId: string, path: string): Promise<{
|
|
54
|
+
content: string;
|
|
55
|
+
version: number;
|
|
56
|
+
}>;
|
|
57
|
+
/**
|
|
58
|
+
* Write file with version conflict detection
|
|
59
|
+
*/
|
|
60
|
+
export declare function safeWriteFile(workspaceId: string, path: string, content: string, expectedVersion: number): Promise<VFSFileInfo>;
|
|
61
|
+
export interface VFSSearchOptions {
|
|
62
|
+
pattern: string;
|
|
63
|
+
caseSensitive?: boolean;
|
|
64
|
+
regex?: boolean;
|
|
65
|
+
includeHidden?: boolean;
|
|
66
|
+
maxResults?: number;
|
|
67
|
+
filePatterns?: string[];
|
|
68
|
+
}
|
|
69
|
+
export interface VFSSearchResult {
|
|
70
|
+
path: string;
|
|
71
|
+
line: number;
|
|
72
|
+
column: number;
|
|
73
|
+
content: string;
|
|
74
|
+
matchStart: number;
|
|
75
|
+
matchEnd: number;
|
|
76
|
+
}
|
|
77
|
+
export declare function searchFiles(workspaceId: string, options: VFSSearchOptions): Promise<VFSSearchResult[]>;
|
|
78
|
+
export declare function healthCheck(): Promise<{
|
|
79
|
+
status: 'ok' | 'error';
|
|
80
|
+
latency: number;
|
|
81
|
+
}>;
|