@d34dman/flowdrop 0.0.61 → 0.0.63

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.
Files changed (204) hide show
  1. package/README.md +6 -0
  2. package/dist/adapters/WorkflowAdapter.d.ts +1 -1
  3. package/dist/adapters/agentspec/AgentSpecAdapter.js +3 -1
  4. package/dist/api/client.d.ts +4 -0
  5. package/dist/api/client.js +6 -1
  6. package/dist/api/enhanced-client.js +7 -6
  7. package/dist/components/App.svelte +143 -219
  8. package/dist/components/CanvasBanner.stories.svelte +25 -0
  9. package/dist/components/CanvasBanner.stories.svelte.d.ts +27 -0
  10. package/dist/components/CanvasBanner.svelte +2 -2
  11. package/dist/components/ConfigForm.svelte +37 -36
  12. package/dist/components/ConfigPanel.stories.svelte +38 -0
  13. package/dist/components/ConfigPanel.stories.svelte.d.ts +27 -0
  14. package/dist/components/ConfigPanel.svelte +2 -2
  15. package/dist/components/ConnectionLine.svelte +2 -2
  16. package/dist/components/FlowDropZone.svelte +18 -2
  17. package/dist/components/FlowDropZone.svelte.d.ts +2 -0
  18. package/dist/components/LoadingSpinner.stories.svelte +30 -0
  19. package/dist/components/LoadingSpinner.stories.svelte.d.ts +27 -0
  20. package/dist/components/Logo.stories.svelte +22 -0
  21. package/dist/components/Logo.stories.svelte.d.ts +27 -0
  22. package/dist/components/Logo.svelte +33 -13
  23. package/dist/components/Logo.svelte.d.ts +1 -1
  24. package/dist/components/MarkdownDisplay.stories.svelte +21 -0
  25. package/dist/components/MarkdownDisplay.stories.svelte.d.ts +27 -0
  26. package/dist/components/MarkdownDisplay.svelte +4 -3
  27. package/dist/components/Navbar.stories.svelte +41 -0
  28. package/dist/components/Navbar.stories.svelte.d.ts +27 -0
  29. package/dist/components/Navbar.svelte +4 -4
  30. package/dist/components/NodeSidebar.svelte +12 -12
  31. package/dist/components/NodeStatusOverlay.stories.svelte +74 -0
  32. package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +27 -0
  33. package/dist/components/PipelineStatus.svelte +11 -4
  34. package/dist/components/PortCoordinateTracker.svelte +1 -1
  35. package/dist/components/SchemaForm.stories.svelte +101 -0
  36. package/dist/components/SchemaForm.stories.svelte.d.ts +27 -0
  37. package/dist/components/SchemaForm.svelte +17 -12
  38. package/dist/components/SettingsModal.svelte +3 -3
  39. package/dist/components/SettingsPanel.svelte +23 -22
  40. package/dist/components/StatusIcon.stories.svelte +60 -0
  41. package/dist/components/StatusIcon.stories.svelte.d.ts +27 -0
  42. package/dist/components/StatusIcon.svelte +7 -0
  43. package/dist/components/StatusLabel.stories.svelte +17 -0
  44. package/dist/components/StatusLabel.stories.svelte.d.ts +27 -0
  45. package/dist/components/ThemeToggle.stories.svelte +25 -0
  46. package/dist/components/ThemeToggle.stories.svelte.d.ts +27 -0
  47. package/dist/components/ThemeToggle.svelte +8 -8
  48. package/dist/components/UniversalNode.svelte +1 -1
  49. package/dist/components/WorkflowEditor.svelte +298 -298
  50. package/dist/components/form/FormAutocomplete.svelte +20 -19
  51. package/dist/components/form/FormCheckboxGroup.stories.svelte +28 -0
  52. package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +27 -0
  53. package/dist/components/form/FormField.svelte +3 -3
  54. package/dist/components/form/FormFieldLight.svelte +2 -2
  55. package/dist/components/form/FormFieldWrapper.stories.svelte +31 -0
  56. package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +27 -0
  57. package/dist/components/form/FormFieldset.svelte +7 -7
  58. package/dist/components/form/FormNumberField.stories.svelte +33 -0
  59. package/dist/components/form/FormNumberField.stories.svelte.d.ts +27 -0
  60. package/dist/components/form/FormRangeField.stories.svelte +31 -0
  61. package/dist/components/form/FormRangeField.stories.svelte.d.ts +27 -0
  62. package/dist/components/form/FormSelect.stories.svelte +50 -0
  63. package/dist/components/form/FormSelect.stories.svelte.d.ts +27 -0
  64. package/dist/components/form/FormTemplateEditor.svelte +2 -1
  65. package/dist/components/form/FormTextField.stories.svelte +30 -0
  66. package/dist/components/form/FormTextField.stories.svelte.d.ts +27 -0
  67. package/dist/components/form/FormTextarea.stories.svelte +31 -0
  68. package/dist/components/form/FormTextarea.stories.svelte.d.ts +27 -0
  69. package/dist/components/form/FormToggle.stories.svelte +30 -0
  70. package/dist/components/form/FormToggle.stories.svelte.d.ts +27 -0
  71. package/dist/components/form/FormUISchemaRenderer.svelte +1 -1
  72. package/dist/components/form/types.d.ts +15 -47
  73. package/dist/components/interrupt/ChoicePrompt.stories.svelte +43 -0
  74. package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +27 -0
  75. package/dist/components/interrupt/ChoicePrompt.svelte +24 -24
  76. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +49 -0
  77. package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +27 -0
  78. package/dist/components/interrupt/ConfirmationPrompt.svelte +19 -19
  79. package/dist/components/interrupt/FormPrompt.svelte +15 -15
  80. package/dist/components/interrupt/InterruptBubble.svelte +202 -236
  81. package/dist/components/interrupt/InterruptBubble.svelte.d.ts +1 -1
  82. package/dist/components/interrupt/ReviewPrompt.stories.svelte +46 -0
  83. package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +27 -0
  84. package/dist/components/interrupt/ReviewPrompt.svelte +842 -0
  85. package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +23 -0
  86. package/dist/components/interrupt/TextInputPrompt.stories.svelte +34 -0
  87. package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +27 -0
  88. package/dist/components/interrupt/TextInputPrompt.svelte +21 -21
  89. package/dist/components/nodes/GatewayNode.stories.svelte +76 -0
  90. package/dist/components/nodes/GatewayNode.stories.svelte.d.ts +26 -0
  91. package/dist/components/nodes/GatewayNode.svelte +19 -17
  92. package/dist/components/nodes/IdeaNode.stories.svelte +48 -0
  93. package/dist/components/nodes/IdeaNode.stories.svelte.d.ts +26 -0
  94. package/dist/components/nodes/IdeaNode.svelte +10 -26
  95. package/dist/components/nodes/NotesNode.stories.svelte +69 -0
  96. package/dist/components/nodes/NotesNode.stories.svelte.d.ts +26 -0
  97. package/dist/components/nodes/NotesNode.svelte +8 -8
  98. package/dist/components/nodes/SimpleNode.stories.svelte +101 -0
  99. package/dist/components/nodes/SimpleNode.stories.svelte.d.ts +26 -0
  100. package/dist/components/nodes/SimpleNode.svelte +16 -24
  101. package/dist/components/nodes/SquareNode.stories.svelte +56 -0
  102. package/dist/components/nodes/SquareNode.stories.svelte.d.ts +26 -0
  103. package/dist/components/nodes/SquareNode.svelte +13 -21
  104. package/dist/components/nodes/TerminalNode.stories.svelte +25 -0
  105. package/dist/components/nodes/TerminalNode.stories.svelte.d.ts +26 -0
  106. package/dist/components/nodes/TerminalNode.svelte +7 -7
  107. package/dist/components/nodes/ToolNode.stories.svelte +71 -0
  108. package/dist/components/nodes/ToolNode.stories.svelte.d.ts +26 -0
  109. package/dist/components/nodes/ToolNode.svelte +7 -15
  110. package/dist/components/nodes/WorkflowNode.stories.svelte +50 -0
  111. package/dist/components/nodes/WorkflowNode.stories.svelte.d.ts +26 -0
  112. package/dist/components/nodes/WorkflowNode.svelte +13 -13
  113. package/dist/components/playground/ChatPanel.svelte +48 -48
  114. package/dist/components/playground/ExecutionLogs.svelte +23 -23
  115. package/dist/components/playground/InputCollector.svelte +24 -24
  116. package/dist/components/playground/MessageBubble.stories.svelte +49 -0
  117. package/dist/components/playground/MessageBubble.stories.svelte.d.ts +27 -0
  118. package/dist/components/playground/MessageBubble.svelte +49 -46
  119. package/dist/components/playground/Playground.svelte +194 -129
  120. package/dist/components/playground/PlaygroundModal.svelte +5 -5
  121. package/dist/components/playground/SessionManager.svelte +26 -26
  122. package/dist/config/constants.d.ts +22 -0
  123. package/dist/config/constants.js +22 -0
  124. package/dist/config/endpoints.d.ts +19 -0
  125. package/dist/config/runtimeConfig.js +2 -1
  126. package/dist/core/index.d.ts +5 -2
  127. package/dist/core/index.js +9 -1
  128. package/dist/editor/index.d.ts +13 -9
  129. package/dist/editor/index.js +15 -11
  130. package/dist/form/code.d.ts +2 -1
  131. package/dist/form/code.js +1 -3
  132. package/dist/form/markdown.d.ts +2 -1
  133. package/dist/form/markdown.js +1 -3
  134. package/dist/helpers/workflowEditorHelper.js +18 -33
  135. package/dist/mocks/app-forms.js +1 -0
  136. package/dist/mocks/app-navigation.js +3 -1
  137. package/dist/mocks/app-stores.d.ts +4 -4
  138. package/dist/playground/index.d.ts +4 -3
  139. package/dist/playground/index.js +12 -10
  140. package/dist/playground/mount.js +6 -13
  141. package/dist/services/agentSpecExecutionService.js +2 -1
  142. package/dist/services/api.js +10 -18
  143. package/dist/services/apiVariableService.js +2 -1
  144. package/dist/services/autoSaveService.d.ts +3 -3
  145. package/dist/services/autoSaveService.js +21 -17
  146. package/dist/services/categoriesApi.js +13 -5
  147. package/dist/services/draftStorage.js +5 -4
  148. package/dist/services/dynamicSchemaService.js +4 -4
  149. package/dist/services/globalSave.d.ts +60 -11
  150. package/dist/services/globalSave.js +160 -83
  151. package/dist/services/historyService.d.ts +2 -1
  152. package/dist/services/historyService.js +7 -3
  153. package/dist/services/interruptService.js +9 -8
  154. package/dist/services/nodeExecutionService.js +14 -6
  155. package/dist/services/playgroundService.js +2 -1
  156. package/dist/services/portConfigApi.js +11 -7
  157. package/dist/services/toastService.d.ts +1 -1
  158. package/dist/services/toastService.js +6 -5
  159. package/dist/services/variableService.js +3 -2
  160. package/dist/settings/index.d.ts +1 -1
  161. package/dist/settings/index.js +1 -1
  162. package/dist/stores/{categoriesStore.d.ts → categoriesStore.svelte.d.ts} +3 -3
  163. package/dist/stores/{categoriesStore.js → categoriesStore.svelte.js} +15 -18
  164. package/dist/stores/editorStateMachine.svelte.d.ts +42 -0
  165. package/dist/stores/editorStateMachine.svelte.js +132 -0
  166. package/dist/stores/{historyStore.d.ts → historyStore.svelte.d.ts} +18 -15
  167. package/dist/stores/{historyStore.js → historyStore.svelte.js} +40 -21
  168. package/dist/stores/{interruptStore.d.ts → interruptStore.svelte.d.ts} +16 -15
  169. package/dist/stores/{interruptStore.js → interruptStore.svelte.js} +85 -94
  170. package/dist/stores/{playgroundStore.d.ts → playgroundStore.svelte.d.ts} +41 -33
  171. package/dist/stores/{playgroundStore.js → playgroundStore.svelte.js} +164 -84
  172. package/dist/stores/{portCoordinateStore.d.ts → portCoordinateStore.svelte.d.ts} +10 -4
  173. package/dist/stores/{portCoordinateStore.js → portCoordinateStore.svelte.js} +38 -35
  174. package/dist/stores/{settingsStore.d.ts → settingsStore.svelte.d.ts} +45 -28
  175. package/dist/stores/{settingsStore.js → settingsStore.svelte.js} +169 -128
  176. package/dist/stores/{workflowStore.d.ts → workflowStore.svelte.d.ts} +101 -65
  177. package/dist/stores/{workflowStore.js → workflowStore.svelte.js} +285 -239
  178. package/dist/stories/CanvasDecorator.svelte +50 -0
  179. package/dist/stories/CanvasDecorator.svelte.d.ts +8 -0
  180. package/dist/stories/NodeDecorator.svelte +74 -0
  181. package/dist/stories/NodeDecorator.svelte.d.ts +8 -0
  182. package/dist/stories/utils.d.ts +93 -0
  183. package/dist/stories/utils.js +122 -0
  184. package/dist/styles/base.css +114 -61
  185. package/dist/styles/toast.css +2 -2
  186. package/dist/styles/tokens.css +250 -185
  187. package/dist/svelte-app.d.ts +0 -6
  188. package/dist/svelte-app.js +13 -31
  189. package/dist/types/index.d.ts +2 -0
  190. package/dist/types/interrupt.d.ts +89 -5
  191. package/dist/types/interrupt.js +13 -1
  192. package/dist/types/playground.d.ts +5 -0
  193. package/dist/types/settings.js +1 -1
  194. package/dist/utils/colors.js +4 -4
  195. package/dist/utils/connections.js +33 -8
  196. package/dist/utils/icons.js +1 -1
  197. package/dist/utils/logger.d.ts +47 -0
  198. package/dist/utils/logger.js +72 -0
  199. package/dist/utils/nodeWrapper.js +1 -1
  200. package/dist/utils/sanitize.d.ts +19 -0
  201. package/dist/utils/sanitize.js +31 -0
  202. package/dist/utils/validation.d.ts +29 -0
  203. package/dist/utils/validation.js +39 -0
  204. package/package.json +243 -232
@@ -5,6 +5,7 @@
5
5
  *
6
6
  * @module services/variableService
7
7
  */
8
+ import { logger } from '../utils/logger.js';
8
9
  /**
9
10
  * Converts a JSON Schema property type to a TemplateVariableType.
10
11
  *
@@ -430,13 +431,13 @@ export async function getVariableSchema(node, nodes, edges, config, workflowId,
430
431
  }
431
432
  else if (!config.api.fallbackOnError) {
432
433
  // API failed and fallback is disabled - return empty schema
433
- console.error('Failed to fetch variables from API:', apiResult.error);
434
+ logger.error('Failed to fetch variables from API:', apiResult.error);
434
435
  return { variables: {} };
435
436
  }
436
437
  // If fallback is enabled (default), continue to schema-based mode below
437
438
  }
438
439
  catch (error) {
439
- console.error('Error fetching variables from API:', error);
440
+ logger.error('Error fetching variables from API:', error);
440
441
  // If fallback is disabled, return empty schema
441
442
  if (config.api.fallbackOnError === false) {
442
443
  return { variables: {} };
@@ -21,5 +21,5 @@ export { default as SettingsPanel } from '../components/SettingsPanel.svelte';
21
21
  export { default as SettingsModal } from '../components/SettingsModal.svelte';
22
22
  export type { ThemeSettings, EditorSettings, UISettings, BehaviorSettings, ApiSettings, FlowDropSettings, SettingsCategory, PartialSettings, DeepPartial, SettingsChangeEvent, SettingsChangeCallback, SyncStatus, SettingsStoreState } from '../types/settings.js';
23
23
  export { SETTINGS_CATEGORIES, SETTINGS_CATEGORY_LABELS, SETTINGS_CATEGORY_ICONS, DEFAULT_THEME_SETTINGS, DEFAULT_EDITOR_SETTINGS, DEFAULT_UI_SETTINGS, DEFAULT_BEHAVIOR_SETTINGS, DEFAULT_API_SETTINGS, DEFAULT_SETTINGS, SETTINGS_STORAGE_KEY } from '../types/settings.js';
24
- export { settingsStore, themeSettings, editorSettings, uiSettings, behaviorSettings, apiSettings, syncStatusStore, updateSettings, resetSettings, getSettings, initializeSettings, setSettingsService, syncSettingsToApi, loadSettingsFromApi, onSettingsChange } from '../stores/settingsStore.js';
24
+ export { getSettings as settingsStore, getThemeSettings as themeSettings, getEditorSettings as editorSettings, getUiSettings as uiSettings, getBehaviorSettings as behaviorSettings, getApiSettings as apiSettings, getSyncStatus as syncStatusStore, updateSettings, resetSettings, getSettings, initializeSettings, setSettingsService, syncSettingsToApi, loadSettingsFromApi, onSettingsChange } from '../stores/settingsStore.svelte.js';
25
25
  export { settingsApi, SettingsService, createSettingsService, setSettingsEndpointConfig, getSettingsEndpointConfig } from '../services/settingsService.js';
@@ -26,7 +26,7 @@ export { SETTINGS_CATEGORIES, SETTINGS_CATEGORY_LABELS, SETTINGS_CATEGORY_ICONS,
26
26
  // ============================================================================
27
27
  // Settings Stores
28
28
  // ============================================================================
29
- export { settingsStore, themeSettings, editorSettings, uiSettings, behaviorSettings, apiSettings, syncStatusStore, updateSettings, resetSettings, getSettings, initializeSettings, setSettingsService, syncSettingsToApi, loadSettingsFromApi, onSettingsChange } from '../stores/settingsStore.js';
29
+ export { getSettings as settingsStore, getThemeSettings as themeSettings, getEditorSettings as editorSettings, getUiSettings as uiSettings, getBehaviorSettings as behaviorSettings, getApiSettings as apiSettings, getSyncStatus as syncStatusStore, updateSettings, resetSettings, getSettings, initializeSettings, setSettingsService, syncSettingsToApi, loadSettingsFromApi, onSettingsChange } from '../stores/settingsStore.svelte.js';
30
30
  // ============================================================================
31
31
  // Settings Service
32
32
  // ============================================================================
@@ -1,14 +1,14 @@
1
1
  /**
2
- * Categories Store for FlowDrop
2
+ * Categories Store for FlowDrop (Svelte 5 Runes)
3
3
  *
4
4
  * Manages category definitions with merged defaults and API-provided overrides.
5
5
  * Exposes lookup helpers for icon, color, and label resolution.
6
6
  */
7
7
  import type { CategoryDefinition, NodeCategory } from '../types/index.js';
8
8
  /**
9
- * Readable store of all category definitions, sorted by weight.
9
+ * Get all category definitions, sorted by weight.
10
10
  */
11
- export declare const categories: import("svelte/store").Readable<CategoryDefinition[]>;
11
+ export declare function getCategories(): CategoryDefinition[];
12
12
  /**
13
13
  * Initialize categories with API data, merging with defaults.
14
14
  * API categories override defaults by name; custom categories are appended.
@@ -1,30 +1,31 @@
1
1
  /**
2
- * Categories Store for FlowDrop
2
+ * Categories Store for FlowDrop (Svelte 5 Runes)
3
3
  *
4
4
  * Manages category definitions with merged defaults and API-provided overrides.
5
5
  * Exposes lookup helpers for icon, color, and label resolution.
6
6
  */
7
- import { writable, derived, get } from 'svelte/store';
8
7
  import { DEFAULT_CATEGORIES } from '../config/defaultCategories.js';
9
8
  /**
10
- * Internal writable store holding the category definitions.
9
+ * Internal reactive state holding the category definitions.
11
10
  * Initialized with defaults, updated when API data is fetched.
12
11
  */
13
- const categoriesInternal = writable(DEFAULT_CATEGORIES);
12
+ let categoriesState = $state([...DEFAULT_CATEGORIES]);
14
13
  /**
15
14
  * Derived lookup map: category name → CategoryDefinition
16
15
  */
17
- const categoryMap = derived(categoriesInternal, ($categories) => {
16
+ let categoryMap = $derived((() => {
18
17
  const map = new Map();
19
- for (const cat of $categories) {
18
+ for (const cat of categoriesState) {
20
19
  map.set(cat.name, cat);
21
20
  }
22
21
  return map;
23
- });
22
+ })());
24
23
  /**
25
- * Readable store of all category definitions, sorted by weight.
24
+ * Get all category definitions, sorted by weight.
26
25
  */
27
- export const categories = derived(categoriesInternal, ($categories) => [...$categories].sort((a, b) => (a.weight ?? 999) - (b.weight ?? 999)));
26
+ export function getCategories() {
27
+ return [...categoriesState].sort((a, b) => (a.weight ?? 999) - (b.weight ?? 999));
28
+ }
28
29
  /**
29
30
  * Initialize categories with API data, merging with defaults.
30
31
  * API categories override defaults by name; custom categories are appended.
@@ -41,14 +42,13 @@ export function initializeCategories(apiCategories) {
41
42
  ...cat
42
43
  });
43
44
  }
44
- categoriesInternal.set(Array.from(defaultMap.values()));
45
+ categoriesState = Array.from(defaultMap.values());
45
46
  }
46
47
  /**
47
48
  * Get the display label for a category.
48
49
  */
49
50
  export function getCategoryLabel(category) {
50
- const map = get(categoryMap);
51
- const def = map.get(category);
51
+ const def = categoryMap.get(category);
52
52
  if (def?.label)
53
53
  return def.label;
54
54
  // Auto-generate: capitalize each word
@@ -61,20 +61,17 @@ export function getCategoryLabel(category) {
61
61
  * Get the icon for a category.
62
62
  */
63
63
  export function getCategoryIcon(category) {
64
- const map = get(categoryMap);
65
- return map.get(category)?.icon ?? 'mdi:folder';
64
+ return categoryMap.get(category)?.icon ?? 'mdi:folder';
66
65
  }
67
66
  /**
68
67
  * Get the color token for a category.
69
68
  */
70
69
  export function getCategoryColor(category) {
71
- const map = get(categoryMap);
72
- return map.get(category)?.color ?? 'var(--fd-node-slate)';
70
+ return categoryMap.get(category)?.color ?? 'var(--fd-node-slate)';
73
71
  }
74
72
  /**
75
73
  * Get the full category definition, or undefined if not found.
76
74
  */
77
75
  export function getCategoryDefinition(category) {
78
- const map = get(categoryMap);
79
- return map.get(category);
76
+ return categoryMap.get(category);
80
77
  }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Editor State Machine for WorkflowEditor (Svelte 5 Runes)
3
+ *
4
+ * Centralizes all reactive guard logic into explicit states and transitions.
5
+ * Replaces scattered boolean flags (isDraggingNode, isRestoringFromHistory,
6
+ * lastEditorStoreValue identity checks) with a single source of truth.
7
+ *
8
+ * @module stores/editorStateMachine
9
+ */
10
+ export type EditorState = 'uninitialized' | 'loading' | 'idle' | 'dragging' | 'connecting' | 'dropping' | 'restoring' | 'deleting' | 'updating_node';
11
+ export type EditorEvent = 'WORKFLOW_LOADED' | 'LOAD_COMPLETE' | 'START_DRAG' | 'STOP_DRAG' | 'START_CONNECT' | 'CONNECTION_MADE' | 'CONNECTION_CANCELLED' | 'START_DROP' | 'DROP_COMPLETE' | 'DROP_CANCELLED' | 'START_RESTORE' | 'RESTORE_COMPLETE' | 'EXTERNAL_STORE_CHANGE' | 'SYNC_COMPLETE' | 'START_DELETE' | 'DELETE_COMPLETE' | 'START_NODE_UPDATE' | 'UPDATE_COMPLETE' | 'WORKFLOW_SWITCHED' | 'WORKFLOW_CLEARED' | 'RESET';
12
+ /** What operations are permitted in the current state */
13
+ export interface StatePermissions {
14
+ /** Whether the editor can write to the global workflow store */
15
+ canWriteToStore: boolean;
16
+ /** Whether the editor can push to undo/redo history */
17
+ canPushHistory: boolean;
18
+ /** Suppress the store → flowNodes/flowEdges sync effect */
19
+ suppressEffect: boolean;
20
+ }
21
+ export interface EditorStateMachine {
22
+ /** Current state (reactive via $state) */
23
+ readonly current: EditorState;
24
+ /** Current permissions (reactive, derived from current state) */
25
+ readonly permissions: StatePermissions;
26
+ /** Attempt a transition. Returns true if the transition was valid. */
27
+ send(event: EditorEvent): boolean;
28
+ /** Check if an event is valid from the current state */
29
+ canSend(event: EditorEvent): boolean;
30
+ /** Subscribe to state changes (for debugging/logging). Returns unsubscribe function. */
31
+ onTransition(callback: (from: EditorState, event: EditorEvent, to: EditorState) => void): () => void;
32
+ }
33
+ /**
34
+ * Create an editor state machine instance.
35
+ *
36
+ * Uses Svelte 5 `$state` rune for reactivity so that components can
37
+ * read `machine.current` and `machine.permissions` inside `$derived`
38
+ * or `$effect` blocks and react to state changes.
39
+ *
40
+ * Each WorkflowEditor component instance should create its own machine.
41
+ */
42
+ export declare function createEditorStateMachine(initialState?: EditorState): EditorStateMachine;
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Editor State Machine for WorkflowEditor (Svelte 5 Runes)
3
+ *
4
+ * Centralizes all reactive guard logic into explicit states and transitions.
5
+ * Replaces scattered boolean flags (isDraggingNode, isRestoringFromHistory,
6
+ * lastEditorStoreValue identity checks) with a single source of truth.
7
+ *
8
+ * @module stores/editorStateMachine
9
+ */
10
+ import { logger } from '../utils/logger.js';
11
+ const transitions = {
12
+ uninitialized: {
13
+ WORKFLOW_LOADED: 'loading'
14
+ },
15
+ loading: {
16
+ LOAD_COMPLETE: 'idle'
17
+ },
18
+ idle: {
19
+ START_DRAG: 'dragging',
20
+ START_CONNECT: 'connecting',
21
+ START_DROP: 'dropping',
22
+ START_RESTORE: 'restoring',
23
+ EXTERNAL_STORE_CHANGE: 'loading',
24
+ START_DELETE: 'deleting',
25
+ START_NODE_UPDATE: 'updating_node',
26
+ WORKFLOW_SWITCHED: 'loading',
27
+ WORKFLOW_CLEARED: 'uninitialized'
28
+ },
29
+ dragging: {
30
+ STOP_DRAG: 'idle'
31
+ },
32
+ connecting: {
33
+ CONNECTION_MADE: 'idle',
34
+ CONNECTION_CANCELLED: 'idle'
35
+ },
36
+ dropping: {
37
+ DROP_COMPLETE: 'idle',
38
+ DROP_CANCELLED: 'idle'
39
+ },
40
+ restoring: {
41
+ RESTORE_COMPLETE: 'idle'
42
+ },
43
+ deleting: {
44
+ DELETE_COMPLETE: 'idle'
45
+ },
46
+ updating_node: {
47
+ UPDATE_COMPLETE: 'idle'
48
+ }
49
+ };
50
+ /** Global transitions valid from any state */
51
+ const globalTransitions = {
52
+ RESET: 'uninitialized',
53
+ WORKFLOW_CLEARED: 'uninitialized'
54
+ };
55
+ // ---------------------------------------------------------------------------
56
+ // Permissions table
57
+ // ---------------------------------------------------------------------------
58
+ const permissions = {
59
+ uninitialized: { canWriteToStore: false, canPushHistory: false, suppressEffect: false },
60
+ loading: { canWriteToStore: false, canPushHistory: false, suppressEffect: false },
61
+ idle: { canWriteToStore: true, canPushHistory: true, suppressEffect: false },
62
+ dragging: { canWriteToStore: true, canPushHistory: false, suppressEffect: true },
63
+ connecting: { canWriteToStore: true, canPushHistory: false, suppressEffect: true },
64
+ dropping: { canWriteToStore: true, canPushHistory: false, suppressEffect: true },
65
+ restoring: { canWriteToStore: true, canPushHistory: false, suppressEffect: true },
66
+ deleting: { canWriteToStore: true, canPushHistory: false, suppressEffect: true },
67
+ updating_node: { canWriteToStore: true, canPushHistory: false, suppressEffect: true }
68
+ };
69
+ // ---------------------------------------------------------------------------
70
+ // Factory
71
+ // ---------------------------------------------------------------------------
72
+ /**
73
+ * Create an editor state machine instance.
74
+ *
75
+ * Uses Svelte 5 `$state` rune for reactivity so that components can
76
+ * read `machine.current` and `machine.permissions` inside `$derived`
77
+ * or `$effect` blocks and react to state changes.
78
+ *
79
+ * Each WorkflowEditor component instance should create its own machine.
80
+ */
81
+ export function createEditorStateMachine(initialState = 'uninitialized') {
82
+ let _current = $state(initialState);
83
+ let _permissions = $state(permissions[initialState]);
84
+ const _listeners = new Set();
85
+ function send(event) {
86
+ // Check global transitions first (valid from any state)
87
+ const globalTarget = globalTransitions[event];
88
+ if (globalTarget !== undefined) {
89
+ const from = _current;
90
+ _current = globalTarget;
91
+ _permissions = permissions[globalTarget];
92
+ for (const cb of _listeners)
93
+ cb(from, event, globalTarget);
94
+ return true;
95
+ }
96
+ // Check state-specific transitions
97
+ const stateTransitions = transitions[_current];
98
+ const target = stateTransitions?.[event];
99
+ if (target === undefined) {
100
+ logger.warn(`[EditorFSM] Invalid transition: ${_current} + ${event}`);
101
+ return false;
102
+ }
103
+ const from = _current;
104
+ _current = target;
105
+ _permissions = permissions[target];
106
+ for (const cb of _listeners)
107
+ cb(from, event, target);
108
+ return true;
109
+ }
110
+ function canSend(event) {
111
+ if (globalTransitions[event] !== undefined)
112
+ return true;
113
+ return transitions[_current]?.[event] !== undefined;
114
+ }
115
+ function onTransition(callback) {
116
+ _listeners.add(callback);
117
+ return () => {
118
+ _listeners.delete(callback);
119
+ };
120
+ }
121
+ return {
122
+ get current() {
123
+ return _current;
124
+ },
125
+ get permissions() {
126
+ return _permissions;
127
+ },
128
+ send,
129
+ canSend,
130
+ onTransition
131
+ };
132
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
- * History Store for FlowDrop
2
+ * History Store for FlowDrop (Svelte 5 Runes)
3
3
  *
4
- * Provides reactive Svelte store bindings for the history service.
4
+ * Provides reactive Svelte 5 rune-based bindings for the history service.
5
5
  * Exposes undo/redo state and actions for the workflow editor.
6
6
  *
7
7
  * @module stores/historyStore
@@ -9,39 +9,42 @@
9
9
  import { type HistoryState, type PushOptions } from '../services/historyService.js';
10
10
  import type { Workflow } from '../types/index.js';
11
11
  /**
12
- * Internal writable store for history state
12
+ * Clean up the historyService subscription created at module initialisation.
13
+ * Call this when tearing down the history store (e.g., in tests or on app
14
+ * unmount) to prevent memory leaks.
13
15
  */
14
- declare const historyStateStore: import("svelte/store").Writable<HistoryState>;
16
+ export declare function cleanupHistorySubscription(): void;
15
17
  /**
16
- * Reactive history state store
18
+ * Get the current history state snapshot.
17
19
  *
18
20
  * Use this for binding to UI elements like undo/redo buttons.
19
- * Subscribe using Svelte's $ prefix or the subscribe method.
20
21
  *
21
22
  * @example
22
23
  * ```svelte
23
24
  * <script>
24
- * import { historyStateStore } from "./historyStore.js";
25
+ * import { getHistoryState } from "./historyStore.svelte.js";
26
+ *
27
+ * const state = $derived(getHistoryState());
25
28
  * </script>
26
29
  *
27
- * <button disabled={!$historyStateStore.canUndo} onclick={historyActions.undo}>
30
+ * <button disabled={!state.canUndo} onclick={historyActions.undo}>
28
31
  * Undo
29
32
  * </button>
30
33
  * ```
31
34
  */
32
- export { historyStateStore };
35
+ export declare function getHistoryState(): HistoryState;
33
36
  /**
34
- * Derived store for canUndo state
37
+ * Convenience getter for canUndo state.
35
38
  *
36
- * Convenience store that directly exposes the canUndo boolean.
39
+ * @returns Whether undo is currently available
37
40
  */
38
- export declare const canUndo: import("svelte/store").Readable<boolean>;
41
+ export declare function getCanUndo(): boolean;
39
42
  /**
40
- * Derived store for canRedo state
43
+ * Convenience getter for canRedo state.
41
44
  *
42
- * Convenience store that directly exposes the canRedo boolean.
45
+ * @returns Whether redo is currently available
43
46
  */
44
- export declare const canRedo: import("svelte/store").Readable<boolean>;
47
+ export declare function getCanRedo(): boolean;
45
48
  /**
46
49
  * Set the callback for restoring workflow state
47
50
  *
@@ -1,60 +1,79 @@
1
1
  /**
2
- * History Store for FlowDrop
2
+ * History Store for FlowDrop (Svelte 5 Runes)
3
3
  *
4
- * Provides reactive Svelte store bindings for the history service.
4
+ * Provides reactive Svelte 5 rune-based bindings for the history service.
5
5
  * Exposes undo/redo state and actions for the workflow editor.
6
6
  *
7
7
  * @module stores/historyStore
8
8
  */
9
- import { writable, derived, get } from 'svelte/store';
10
9
  import { historyService } from '../services/historyService.js';
11
10
  // =========================================================================
12
- // Reactive State Store
11
+ // Reactive State (Runes)
13
12
  // =========================================================================
14
13
  /**
15
- * Internal writable store for history state
14
+ * Internal reactive state for history, powered by $state.
16
15
  */
17
- const historyStateStore = writable({
16
+ let historyState = $state({
18
17
  canUndo: false,
19
18
  canRedo: false,
20
19
  currentIndex: 0,
21
20
  historyLength: 0,
22
21
  isInTransaction: false
23
22
  });
24
- // Subscribe to history service changes and update the store
25
- historyService.subscribe((state) => {
26
- historyStateStore.set(state);
23
+ // Subscribe to history service changes and update the rune state.
24
+ // The unsubscribe function is stored so it can be called via
25
+ // cleanupHistorySubscription() when the store is torn down.
26
+ const _unsubscribeHistoryService = historyService.subscribe((state) => {
27
+ historyState = state;
27
28
  });
28
29
  /**
29
- * Reactive history state store
30
+ * Clean up the historyService subscription created at module initialisation.
31
+ * Call this when tearing down the history store (e.g., in tests or on app
32
+ * unmount) to prevent memory leaks.
33
+ */
34
+ export function cleanupHistorySubscription() {
35
+ _unsubscribeHistoryService();
36
+ }
37
+ // =========================================================================
38
+ // Reactive Getters
39
+ // =========================================================================
40
+ /**
41
+ * Get the current history state snapshot.
30
42
  *
31
43
  * Use this for binding to UI elements like undo/redo buttons.
32
- * Subscribe using Svelte's $ prefix or the subscribe method.
33
44
  *
34
45
  * @example
35
46
  * ```svelte
36
47
  * <script>
37
- * import { historyStateStore } from "./historyStore.js";
48
+ * import { getHistoryState } from "./historyStore.svelte.js";
49
+ *
50
+ * const state = $derived(getHistoryState());
38
51
  * </script>
39
52
  *
40
- * <button disabled={!$historyStateStore.canUndo} onclick={historyActions.undo}>
53
+ * <button disabled={!state.canUndo} onclick={historyActions.undo}>
41
54
  * Undo
42
55
  * </button>
43
56
  * ```
44
57
  */
45
- export { historyStateStore };
58
+ export function getHistoryState() {
59
+ return historyState;
60
+ }
46
61
  /**
47
- * Derived store for canUndo state
62
+ * Convenience getter for canUndo state.
48
63
  *
49
- * Convenience store that directly exposes the canUndo boolean.
64
+ * @returns Whether undo is currently available
50
65
  */
51
- export const canUndo = derived(historyStateStore, ($state) => $state.canUndo);
66
+ export function getCanUndo() {
67
+ return historyState.canUndo;
68
+ }
52
69
  /**
53
- * Derived store for canRedo state
70
+ * Convenience getter for canRedo state.
54
71
  *
55
- * Convenience store that directly exposes the canRedo boolean.
72
+ * @returns Whether redo is currently available
56
73
  */
57
- export const canRedo = derived(historyStateStore, ($state) => $state.canRedo);
74
+ export function getCanRedo() {
75
+ return historyState.canRedo;
76
+ }
58
77
  // =========================================================================
59
78
  // History Actions
60
79
  // =========================================================================
@@ -182,7 +201,7 @@ export const historyActions = {
182
201
  * @returns The current history state
183
202
  */
184
203
  getState: () => {
185
- return get(historyStateStore);
204
+ return historyState;
186
205
  }
187
206
  };
188
207
  export { HistoryService, historyService } from '../services/historyService.js';
@@ -1,11 +1,12 @@
1
1
  /**
2
- * Interrupt Store
2
+ * Interrupt Store (Svelte 5 Runes)
3
3
  *
4
- * Svelte stores for managing interrupt state using a lightweight state machine.
4
+ * Rune-based reactive state for managing interrupt state using a lightweight state machine.
5
5
  * Ensures valid state transitions and prevents deadlocks.
6
6
  *
7
7
  * @module stores/interruptStore
8
8
  */
9
+ import { SvelteMap } from 'svelte/reactivity';
9
10
  import type { Interrupt } from '../types/interrupt.js';
10
11
  import { type InterruptState, type TransitionResult } from '../types/interruptState.js';
11
12
  /**
@@ -16,30 +17,30 @@ export interface InterruptWithState extends Interrupt {
16
17
  machineState: InterruptState;
17
18
  }
18
19
  /**
19
- * Map of all interrupts by ID
20
- * Key: interrupt ID, Value: Interrupt object with state
20
+ * Get the reactive interrupts map.
21
+ * Use this in components within $derived() for reactivity.
21
22
  */
22
- export declare const interrupts: import("svelte/store").Writable<Map<string, InterruptWithState>>;
23
+ export declare function getInterruptsMap(): SvelteMap<string, InterruptWithState>;
23
24
  /**
24
- * Derived store for pending interrupt IDs
25
+ * Get pending interrupt IDs (interrupts not in a terminal state)
25
26
  */
26
- export declare const pendingInterruptIds: import("svelte/store").Readable<string[]>;
27
+ export declare function getPendingInterruptIds(): string[];
27
28
  /**
28
- * Derived store for pending interrupts array
29
+ * Get pending interrupts array (interrupts not in a terminal state)
29
30
  */
30
- export declare const pendingInterrupts: import("svelte/store").Readable<InterruptWithState[]>;
31
+ export declare function getPendingInterrupts(): InterruptWithState[];
31
32
  /**
32
- * Derived store for count of pending interrupts
33
+ * Get count of pending interrupts
33
34
  */
34
- export declare const pendingInterruptCount: import("svelte/store").Readable<number>;
35
+ export declare function getPendingInterruptCount(): number;
35
36
  /**
36
- * Derived store for resolved interrupts
37
+ * Get resolved interrupts array
37
38
  */
38
- export declare const resolvedInterrupts: import("svelte/store").Readable<InterruptWithState[]>;
39
+ export declare function getResolvedInterrupts(): InterruptWithState[];
39
40
  /**
40
- * Derived store to check if any interrupt is currently submitting
41
+ * Check if any interrupt is currently submitting
41
42
  */
42
- export declare const isAnySubmitting: import("svelte/store").Readable<boolean>;
43
+ export declare function getIsAnySubmitting(): boolean;
43
44
  /**
44
45
  * Interrupt store actions for modifying state
45
46
  */