@flowdrop/flowdrop 1.15.0 → 2.0.0-beta.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.
Files changed (215) hide show
  1. package/CHANGELOG.md +475 -0
  2. package/MIGRATION-2.0.md +472 -0
  3. package/README.md +23 -23
  4. package/dist/adapters/WorkflowAdapter.d.ts +1 -1
  5. package/dist/adapters/WorkflowAdapter.js +14 -8
  6. package/dist/adapters/agentspec/AgentSpecAdapter.js +7 -7
  7. package/dist/chat/batchFeedback.d.ts +39 -0
  8. package/dist/chat/batchFeedback.js +51 -0
  9. package/dist/commands/executor.js +15 -1
  10. package/dist/commands/storeIntegration.svelte.d.ts +4 -1
  11. package/dist/commands/storeIntegration.svelte.js +26 -21
  12. package/dist/commands/types.d.ts +2 -0
  13. package/dist/components/App.svelte +162 -192
  14. package/dist/components/App.svelte.d.ts +47 -8
  15. package/dist/components/ConfigForm.svelte +71 -47
  16. package/dist/components/ConfigModal.svelte +7 -2
  17. package/dist/components/ConnectionLine.svelte +4 -2
  18. package/dist/components/Navbar.svelte +61 -1
  19. package/dist/components/NodeSidebar.svelte +27 -45
  20. package/dist/components/NodeStatusOverlay.svelte +94 -6
  21. package/dist/components/NodeSwapPicker.svelte +10 -8
  22. package/dist/components/PipelineStatus.svelte +16 -67
  23. package/dist/components/PortCoordinateTracker.svelte +5 -6
  24. package/dist/components/SchemaForm.stories.svelte +1 -3
  25. package/dist/components/SchemaForm.svelte +18 -25
  26. package/dist/components/SchemaForm.svelte.d.ts +0 -8
  27. package/dist/components/SettingsModal.svelte +8 -3
  28. package/dist/components/SettingsPanel.svelte +20 -4
  29. package/dist/components/SwapMappingEditor.svelte +67 -49
  30. package/dist/components/SwapMappingEditor.svelte.d.ts +0 -2
  31. package/dist/components/UniversalNode.svelte +9 -7
  32. package/dist/components/WorkflowEditor.svelte +118 -111
  33. package/dist/components/WorkflowEditor.svelte.d.ts +18 -10
  34. package/dist/components/chat/AIChatPanel.svelte +93 -89
  35. package/dist/components/chat/AIChatPanel.svelte.d.ts +0 -4
  36. package/dist/components/chat/CommandPreview.svelte +2 -1
  37. package/dist/components/console/CommandConsole.svelte +7 -5
  38. package/dist/components/console/ConsoleAutocomplete.svelte +10 -11
  39. package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +6 -0
  40. package/dist/components/console/ConsoleInput.svelte +15 -6
  41. package/dist/components/console/ConsoleOutput.svelte +2 -1
  42. package/dist/components/form/FormArray.svelte +5 -9
  43. package/dist/components/form/FormArray.svelte.d.ts +2 -1
  44. package/dist/components/form/FormAutocomplete.svelte +8 -6
  45. package/dist/components/form/FormField.svelte +4 -2
  46. package/dist/components/form/FormFieldLight.svelte +4 -2
  47. package/dist/components/form/FormMarkdownEditor.svelte +9 -4
  48. package/dist/components/form/FormRangeField.svelte +1 -0
  49. package/dist/components/form/FormTemplateEditor.svelte +11 -3
  50. package/dist/components/form/FormToggle.svelte +5 -12
  51. package/dist/components/form/FormToggle.svelte.d.ts +4 -2
  52. package/dist/components/form/templateAutocomplete.js +1 -5
  53. package/dist/components/form/types.d.ts +1 -14
  54. package/dist/components/interrupt/FormPrompt.svelte +3 -2
  55. package/dist/components/interrupt/InterruptBubble.svelte +16 -17
  56. package/dist/components/interrupt/ReviewPrompt.svelte +10 -3
  57. package/dist/components/interrupt/TextInputPrompt.svelte +2 -1
  58. package/dist/components/layouts/MainLayout.svelte +20 -13
  59. package/dist/components/layouts/MainLayout.svelte.d.ts +4 -0
  60. package/dist/components/nodes/AtomNode.svelte +17 -5
  61. package/dist/components/nodes/GatewayNode.svelte +19 -10
  62. package/dist/components/nodes/IdeaNode.svelte +7 -0
  63. package/dist/components/nodes/SimpleNode.svelte +11 -6
  64. package/dist/components/nodes/SquareNode.svelte +15 -8
  65. package/dist/components/nodes/TerminalNode.svelte +9 -4
  66. package/dist/components/nodes/ToolNode.svelte +7 -1
  67. package/dist/components/nodes/WorkflowNode.svelte +16 -7
  68. package/dist/components/playground/ChatInput.svelte +11 -14
  69. package/dist/components/playground/ChatPanel.svelte +6 -49
  70. package/dist/components/playground/ChatPanel.svelte.d.ts +0 -14
  71. package/dist/components/playground/ControlPanel.svelte +134 -123
  72. package/dist/components/playground/ControlPanel.svelte.d.ts +3 -0
  73. package/dist/components/playground/ExecutionLogs.svelte +11 -9
  74. package/dist/components/playground/InputCollector.svelte +11 -9
  75. package/dist/components/playground/MessageStream.svelte +17 -23
  76. package/dist/components/playground/PipelineKanbanView.svelte +65 -6
  77. package/dist/components/playground/PipelinePanel.svelte +11 -5
  78. package/dist/components/playground/PipelineTableView.svelte +186 -44
  79. package/dist/components/playground/Playground.svelte +90 -92
  80. package/dist/components/playground/Playground.svelte.d.ts +2 -0
  81. package/dist/components/playground/PlaygroundApp.svelte +6 -1
  82. package/dist/components/playground/PlaygroundApp.svelte.d.ts +3 -0
  83. package/dist/components/playground/PlaygroundModal.svelte +13 -3
  84. package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -0
  85. package/dist/components/playground/PlaygroundStudio.svelte +34 -32
  86. package/dist/components/playground/PlaygroundStudio.svelte.d.ts +3 -0
  87. package/dist/components/playground/SessionManager.svelte +9 -12
  88. package/dist/components/playground/pipelineViewUtils.svelte.d.ts +28 -0
  89. package/dist/components/playground/pipelineViewUtils.svelte.js +38 -1
  90. package/dist/config/endpoints.d.ts +0 -7
  91. package/dist/config/endpoints.js +2 -10
  92. package/dist/core/index.d.ts +4 -4
  93. package/dist/core/index.js +6 -6
  94. package/dist/display/index.d.ts +0 -2
  95. package/dist/display/index.js +0 -6
  96. package/dist/editor/index.d.ts +19 -20
  97. package/dist/editor/index.js +25 -35
  98. package/dist/form/code.d.ts +25 -15
  99. package/dist/form/code.js +44 -41
  100. package/dist/form/fieldRegistry.d.ts +17 -13
  101. package/dist/form/fieldRegistry.js +32 -12
  102. package/dist/form/full.d.ts +17 -13
  103. package/dist/form/full.js +22 -27
  104. package/dist/form/index.d.ts +3 -3
  105. package/dist/form/index.js +3 -3
  106. package/dist/form/markdown.d.ts +13 -8
  107. package/dist/form/markdown.js +22 -23
  108. package/dist/helpers/proximityConnect.d.ts +3 -2
  109. package/dist/helpers/proximityConnect.js +2 -5
  110. package/dist/helpers/workflowEditorHelper.d.ts +12 -5
  111. package/dist/helpers/workflowEditorHelper.js +27 -25
  112. package/dist/index.d.ts +28 -24
  113. package/dist/index.js +27 -50
  114. package/dist/messages/defaults.d.ts +2 -5
  115. package/dist/messages/defaults.js +3 -6
  116. package/dist/messages/index.d.ts +0 -1
  117. package/dist/messages/index.js +0 -1
  118. package/dist/mocks/app-forms.d.ts +6 -2
  119. package/dist/mocks/app-forms.js +11 -4
  120. package/dist/openapi/v1/openapi.yaml +3 -3
  121. package/dist/playground/index.d.ts +2 -3
  122. package/dist/playground/index.js +2 -30
  123. package/dist/playground/mount.d.ts +15 -0
  124. package/dist/playground/mount.js +46 -20
  125. package/dist/registry/{BaseRegistry.d.ts → BaseRegistry.svelte.d.ts} +22 -1
  126. package/dist/registry/{BaseRegistry.js → BaseRegistry.svelte.js} +37 -1
  127. package/dist/registry/builtinFormats.d.ts +9 -18
  128. package/dist/registry/builtinFormats.js +9 -39
  129. package/dist/registry/builtinNodes.d.ts +0 -25
  130. package/dist/registry/builtinNodes.js +1 -50
  131. package/dist/registry/index.d.ts +3 -4
  132. package/dist/registry/index.js +4 -6
  133. package/dist/registry/nodeComponentRegistry.d.ts +182 -15
  134. package/dist/registry/nodeComponentRegistry.js +235 -17
  135. package/dist/registry/workflowFormatRegistry.d.ts +14 -9
  136. package/dist/registry/workflowFormatRegistry.js +24 -8
  137. package/dist/{schema → schemas}/index.d.ts +2 -2
  138. package/dist/{schema → schemas}/index.js +2 -2
  139. package/dist/schemas/v1/workflow.schema.json +3 -3
  140. package/dist/services/agentSpecExecutionService.js +0 -1
  141. package/dist/services/apiVariableService.d.ts +2 -1
  142. package/dist/services/apiVariableService.js +5 -22
  143. package/dist/services/autoSaveService.d.ts +7 -0
  144. package/dist/services/autoSaveService.js +6 -4
  145. package/dist/services/chatService.d.ts +8 -4
  146. package/dist/services/chatService.js +15 -15
  147. package/dist/services/draftStorage.d.ts +129 -13
  148. package/dist/services/draftStorage.js +185 -37
  149. package/dist/services/dynamicSchemaService.d.ts +2 -1
  150. package/dist/services/dynamicSchemaService.js +5 -22
  151. package/dist/services/globalSave.d.ts +13 -12
  152. package/dist/services/globalSave.js +29 -51
  153. package/dist/services/historyService.d.ts +9 -3
  154. package/dist/services/historyService.js +9 -3
  155. package/dist/services/interruptService.d.ts +14 -9
  156. package/dist/services/interruptService.js +27 -27
  157. package/dist/services/nodeExecutionService.d.ts +18 -3
  158. package/dist/services/nodeExecutionService.js +71 -45
  159. package/dist/services/playgroundService.d.ts +14 -9
  160. package/dist/services/playgroundService.js +31 -30
  161. package/dist/services/variableService.d.ts +2 -1
  162. package/dist/services/variableService.js +2 -2
  163. package/dist/services/workflowStorage.js +6 -6
  164. package/dist/stores/apiContext.d.ts +45 -0
  165. package/dist/stores/apiContext.js +65 -0
  166. package/dist/stores/categoriesStore.svelte.d.ts +28 -23
  167. package/dist/stores/categoriesStore.svelte.js +70 -64
  168. package/dist/stores/getInstance.svelte.d.ts +39 -0
  169. package/dist/stores/getInstance.svelte.js +65 -0
  170. package/dist/stores/historyStore.svelte.d.ts +77 -93
  171. package/dist/stores/historyStore.svelte.js +134 -160
  172. package/dist/stores/instanceContainer.svelte.d.ts +111 -0
  173. package/dist/stores/instanceContainer.svelte.js +114 -0
  174. package/dist/stores/interruptStore.svelte.d.ts +112 -82
  175. package/dist/stores/interruptStore.svelte.js +253 -226
  176. package/dist/stores/pipelinePanelStore.svelte.d.ts +27 -3
  177. package/dist/stores/pipelinePanelStore.svelte.js +61 -14
  178. package/dist/stores/playgroundStore.svelte.d.ts +169 -222
  179. package/dist/stores/playgroundStore.svelte.js +515 -580
  180. package/dist/stores/portCoordinateStore.svelte.d.ts +57 -51
  181. package/dist/stores/portCoordinateStore.svelte.js +109 -98
  182. package/dist/stores/settingsStore.svelte.d.ts +4 -1
  183. package/dist/stores/settingsStore.svelte.js +47 -12
  184. package/dist/stores/workflowStore.svelte.d.ts +178 -213
  185. package/dist/stores/workflowStore.svelte.js +449 -501
  186. package/dist/stories/EdgeDecorator.svelte +5 -2
  187. package/dist/stories/NodeDecorator.svelte +5 -3
  188. package/dist/svelte-app.d.ts +60 -10
  189. package/dist/svelte-app.js +157 -53
  190. package/dist/types/events.d.ts +6 -3
  191. package/dist/types/index.d.ts +33 -3
  192. package/dist/types/navbar.d.ts +7 -0
  193. package/dist/types/playground.d.ts +18 -3
  194. package/dist/types/settings.d.ts +13 -0
  195. package/dist/types/settings.js +1 -0
  196. package/dist/utils/colors.d.ts +47 -21
  197. package/dist/utils/colors.js +69 -68
  198. package/dist/utils/connections.d.ts +9 -15
  199. package/dist/utils/connections.js +13 -32
  200. package/dist/utils/duration.d.ts +13 -0
  201. package/dist/utils/duration.js +45 -0
  202. package/dist/utils/icons.d.ts +5 -2
  203. package/dist/utils/icons.js +6 -5
  204. package/dist/utils/nodeSwap.d.ts +6 -2
  205. package/dist/utils/nodeSwap.js +62 -126
  206. package/dist/utils/nodeTypes.d.ts +17 -8
  207. package/dist/utils/nodeTypes.js +26 -19
  208. package/dist/utils/performanceUtils.js +7 -0
  209. package/package.json +6 -5
  210. package/dist/messages/deprecation.d.ts +0 -20
  211. package/dist/messages/deprecation.js +0 -33
  212. package/dist/registry/plugin.d.ts +0 -215
  213. package/dist/registry/plugin.js +0 -249
  214. package/dist/services/api.d.ts +0 -129
  215. package/dist/services/api.js +0 -217
@@ -3,30 +3,35 @@
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
+ *
7
+ * The reactive state lives in the {@link CategoriesStore} class — one per
8
+ * FlowDrop instance, resolved in components via `getInstance().categories`.
9
+ *
10
+ * @module stores/categoriesStore
6
11
  */
7
12
  import type { CategoryDefinition, NodeCategory } from '../types/index.js';
8
13
  /**
9
- * Get all category definitions, sorted by weight.
10
- */
11
- export declare function getCategories(): CategoryDefinition[];
12
- /**
13
- * Initialize categories with API data, merging with defaults.
14
- * API categories override defaults by name; custom categories are appended.
15
- */
16
- export declare function initializeCategories(apiCategories: CategoryDefinition[]): void;
17
- /**
18
- * Get the display label for a category.
19
- */
20
- export declare function getCategoryLabel(category: NodeCategory): string;
21
- /**
22
- * Get the icon for a category.
23
- */
24
- export declare function getCategoryIcon(category: NodeCategory): string;
25
- /**
26
- * Get the color token for a category.
27
- */
28
- export declare function getCategoryColor(category: NodeCategory): string;
29
- /**
30
- * Get the full category definition, or undefined if not found.
14
+ * Per-instance category definitions with a derived name→definition lookup.
15
+ *
16
+ * Reads go through getters backed by `$state`/`$derived`, so they track
17
+ * reactively in templates and `$derived`, exactly like the legacy
18
+ * module-level functions did.
31
19
  */
32
- export declare function getCategoryDefinition(category: NodeCategory): CategoryDefinition | undefined;
20
+ export declare class CategoriesStore {
21
+ #private;
22
+ /** All category definitions, sorted by weight (reactive). */
23
+ get categories(): CategoryDefinition[];
24
+ /**
25
+ * Initialize categories with API data, merging with defaults.
26
+ * API categories override defaults by name; custom categories are appended.
27
+ */
28
+ initialize(apiCategories: CategoryDefinition[]): void;
29
+ /** Get the display label for a category. */
30
+ getLabel(category: NodeCategory): string;
31
+ /** Get the icon for a category. */
32
+ getIcon(category: NodeCategory): string;
33
+ /** Get the color token for a category. */
34
+ getColor(category: NodeCategory): string;
35
+ /** Get the full category definition, or undefined if not found. */
36
+ getDefinition(category: NodeCategory): CategoryDefinition | undefined;
37
+ }
@@ -3,75 +3,81 @@
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
+ *
7
+ * The reactive state lives in the {@link CategoriesStore} class — one per
8
+ * FlowDrop instance, resolved in components via `getInstance().categories`.
9
+ *
10
+ * @module stores/categoriesStore
6
11
  */
7
12
  import { DEFAULT_CATEGORIES } from '../config/defaultCategories.js';
13
+ // =========================================================================
14
+ // CategoriesStore (per-instance reactive state)
15
+ // =========================================================================
8
16
  /**
9
- * Internal reactive state holding the category definitions.
10
- * Initialized with defaults, updated when API data is fetched.
11
- */
12
- let categoriesState = $state([...DEFAULT_CATEGORIES]);
13
- /**
14
- * Derived lookup map: category name → CategoryDefinition
17
+ * Per-instance category definitions with a derived name→definition lookup.
18
+ *
19
+ * Reads go through getters backed by `$state`/`$derived`, so they track
20
+ * reactively in templates and `$derived`, exactly like the legacy
21
+ * module-level functions did.
15
22
  */
16
- let categoryMap = $derived((() => {
17
- const map = new Map();
18
- for (const cat of categoriesState) {
19
- map.set(cat.name, cat);
23
+ export class CategoriesStore {
24
+ /**
25
+ * Reactive state holding the category definitions.
26
+ * Initialized with defaults, updated when API data is fetched.
27
+ */
28
+ #categories = $state([...DEFAULT_CATEGORIES]);
29
+ /** Derived lookup map: category name → CategoryDefinition. */
30
+ #categoryMap = $derived((() => {
31
+ // eslint-disable-next-line svelte/prefer-svelte-reactivity -- rebuilt whole inside $derived, never mutated afterwards
32
+ const map = new Map();
33
+ for (const cat of this.#categories) {
34
+ map.set(cat.name, cat);
35
+ }
36
+ return map;
37
+ })());
38
+ /** All category definitions, sorted by weight (reactive). */
39
+ get categories() {
40
+ return [...this.#categories].sort((a, b) => (a.weight ?? 999) - (b.weight ?? 999));
20
41
  }
21
- return map;
22
- })());
23
- /**
24
- * Get all category definitions, sorted by weight.
25
- */
26
- export function getCategories() {
27
- return [...categoriesState].sort((a, b) => (a.weight ?? 999) - (b.weight ?? 999));
28
- }
29
- /**
30
- * Initialize categories with API data, merging with defaults.
31
- * API categories override defaults by name; custom categories are appended.
32
- */
33
- export function initializeCategories(apiCategories) {
34
- const defaultMap = new Map();
35
- for (const cat of DEFAULT_CATEGORIES) {
36
- defaultMap.set(cat.name, cat);
42
+ /**
43
+ * Initialize categories with API data, merging with defaults.
44
+ * API categories override defaults by name; custom categories are appended.
45
+ */
46
+ initialize(apiCategories) {
47
+ const defaultMap = new Map();
48
+ for (const cat of DEFAULT_CATEGORIES) {
49
+ defaultMap.set(cat.name, cat);
50
+ }
51
+ // API categories override defaults by name
52
+ for (const cat of apiCategories) {
53
+ defaultMap.set(cat.name, {
54
+ ...defaultMap.get(cat.name),
55
+ ...cat
56
+ });
57
+ }
58
+ this.#categories = Array.from(defaultMap.values());
37
59
  }
38
- // API categories override defaults by name
39
- for (const cat of apiCategories) {
40
- defaultMap.set(cat.name, {
41
- ...defaultMap.get(cat.name),
42
- ...cat
43
- });
60
+ /** Get the display label for a category. */
61
+ getLabel(category) {
62
+ const def = this.#categoryMap.get(category);
63
+ if (def?.label)
64
+ return def.label;
65
+ // Auto-generate: capitalize each word
66
+ return category
67
+ .split(/[\s_-]+/)
68
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
69
+ .join(' ');
70
+ }
71
+ /** Get the icon for a category. */
72
+ getIcon(category) {
73
+ return this.#categoryMap.get(category)?.icon ?? 'mdi:folder';
74
+ }
75
+ /** Get the color token for a category. */
76
+ getColor(category) {
77
+ return this.#categoryMap.get(category)?.color ?? 'var(--fd-node-slate)';
78
+ }
79
+ /** Get the full category definition, or undefined if not found. */
80
+ getDefinition(category) {
81
+ return this.#categoryMap.get(category);
44
82
  }
45
- categoriesState = Array.from(defaultMap.values());
46
- }
47
- /**
48
- * Get the display label for a category.
49
- */
50
- export function getCategoryLabel(category) {
51
- const def = categoryMap.get(category);
52
- if (def?.label)
53
- return def.label;
54
- // Auto-generate: capitalize each word
55
- return category
56
- .split(/[\s_-]+/)
57
- .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
58
- .join(' ');
59
- }
60
- /**
61
- * Get the icon for a category.
62
- */
63
- export function getCategoryIcon(category) {
64
- return categoryMap.get(category)?.icon ?? 'mdi:folder';
65
- }
66
- /**
67
- * Get the color token for a category.
68
- */
69
- export function getCategoryColor(category) {
70
- return categoryMap.get(category)?.color ?? 'var(--fd-node-slate)';
71
- }
72
- /**
73
- * Get the full category definition, or undefined if not found.
74
- */
75
- export function getCategoryDefinition(category) {
76
- return categoryMap.get(category);
77
83
  }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Per-component access to the FlowDrop instance container.
3
+ *
4
+ * Components call `getInstance()` during init to resolve the instance
5
+ * provided by the nearest `<App>` / `<WorkflowEditor>` via Svelte context.
6
+ * When no provider exists (legacy single-instance usage), it falls back to
7
+ * the browser-only default instance.
8
+ *
9
+ * @module stores/getInstance
10
+ */
11
+ import { type FlowDropInstance } from './instanceContainer.svelte.js';
12
+ /**
13
+ * Context key under which the FlowDrop instance is provided.
14
+ * A Symbol (matching `messages/context.ts`) so consumer context can't collide.
15
+ */
16
+ export declare const FLOWDROP_INSTANCE_KEY: unique symbol;
17
+ /**
18
+ * Resolve the FlowDrop instance for the current component tree.
19
+ *
20
+ * Must be called during component initialisation (it reads Svelte context).
21
+ *
22
+ * Unlike the messages-context fallback (immutable defaults, silent), this
23
+ * fallback hands out *mutable shared state*, so it warns once in dev and
24
+ * throws during SSR rather than leaking state across server requests.
25
+ */
26
+ export declare function getInstance(): FlowDropInstance;
27
+ /**
28
+ * Resolve and provide the FlowDrop instance for a provider component
29
+ * (`<App>`, `<WorkflowEditor>`, `<Playground>`, `<PlaygroundStudio>`).
30
+ *
31
+ * Must be called during component initialisation. Resolution order:
32
+ * 1. An explicitly passed instance (from a mount function or consumer)
33
+ * 2. An instance already in context (provider nested inside another provider)
34
+ * 3. Browser: the page-default instance (legacy single-instance behavior)
35
+ * Server: a fresh per-render instance (no cross-request leakage)
36
+ *
37
+ * The resolved instance is (re-)provided via context for all children.
38
+ */
39
+ export declare function provideInstance(explicit?: FlowDropInstance): FlowDropInstance;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Per-component access to the FlowDrop instance container.
3
+ *
4
+ * Components call `getInstance()` during init to resolve the instance
5
+ * provided by the nearest `<App>` / `<WorkflowEditor>` via Svelte context.
6
+ * When no provider exists (legacy single-instance usage), it falls back to
7
+ * the browser-only default instance.
8
+ *
9
+ * @module stores/getInstance
10
+ */
11
+ import { DEV } from 'esm-env';
12
+ import { getContext, setContext } from 'svelte';
13
+ import { createFlowDropInstance, getDefaultInstance } from './instanceContainer.svelte.js';
14
+ /**
15
+ * Context key under which the FlowDrop instance is provided.
16
+ * A Symbol (matching `messages/context.ts`) so consumer context can't collide.
17
+ */
18
+ export const FLOWDROP_INSTANCE_KEY = Symbol('flowdrop.instance');
19
+ let warnedAboutFallback = false;
20
+ /**
21
+ * Resolve the FlowDrop instance for the current component tree.
22
+ *
23
+ * Must be called during component initialisation (it reads Svelte context).
24
+ *
25
+ * Unlike the messages-context fallback (immutable defaults, silent), this
26
+ * fallback hands out *mutable shared state*, so it warns once in dev and
27
+ * throws during SSR rather than leaking state across server requests.
28
+ */
29
+ export function getInstance() {
30
+ const instance = getContext(FLOWDROP_INSTANCE_KEY);
31
+ if (instance) {
32
+ return instance;
33
+ }
34
+ if (typeof window === 'undefined') {
35
+ throw new Error('[flowdrop] No FlowDrop instance in context during SSR. Render inside ' +
36
+ '<App> or <WorkflowEditor> (which set context), or provide one with ' +
37
+ 'setContext(FLOWDROP_INSTANCE_KEY, createFlowDropInstance()).');
38
+ }
39
+ if (DEV && !warnedAboutFallback) {
40
+ warnedAboutFallback = true;
41
+ // eslint-disable-next-line no-console -- intentional one-time dev diagnostic for silent shared-state fallback
42
+ console.warn('[flowdrop] getInstance() fell back to the page-default instance — ' +
43
+ 'fine for a single editor, but two editors mounted this way will share state.');
44
+ }
45
+ return getDefaultInstance();
46
+ }
47
+ /**
48
+ * Resolve and provide the FlowDrop instance for a provider component
49
+ * (`<App>`, `<WorkflowEditor>`, `<Playground>`, `<PlaygroundStudio>`).
50
+ *
51
+ * Must be called during component initialisation. Resolution order:
52
+ * 1. An explicitly passed instance (from a mount function or consumer)
53
+ * 2. An instance already in context (provider nested inside another provider)
54
+ * 3. Browser: the page-default instance (legacy single-instance behavior)
55
+ * Server: a fresh per-render instance (no cross-request leakage)
56
+ *
57
+ * The resolved instance is (re-)provided via context for all children.
58
+ */
59
+ export function provideInstance(explicit) {
60
+ const instance = explicit ??
61
+ getContext(FLOWDROP_INSTANCE_KEY) ??
62
+ (typeof window === 'undefined' ? createFlowDropInstance() : getDefaultInstance());
63
+ setContext(FLOWDROP_INSTANCE_KEY, instance);
64
+ return instance;
65
+ }
@@ -1,136 +1,120 @@
1
1
  /**
2
2
  * History Store for FlowDrop (Svelte 5 Runes)
3
3
  *
4
- * Provides reactive Svelte 5 rune-based bindings for the history service.
4
+ * Provides reactive Svelte 5 rune-based bindings for a history service.
5
5
  * Exposes undo/redo state and actions for the workflow editor.
6
6
  *
7
+ * The reactive state lives in the {@link HistoryStore} class — one per
8
+ * FlowDrop instance, created by `createFlowDropInstance()` and resolved in
9
+ * components via `getInstance().historyBindings`.
10
+ *
7
11
  * @module stores/historyStore
8
12
  */
9
- import { type HistoryState, type PushOptions } from '../services/historyService.js';
13
+ import { HistoryService, type HistoryState, type PushOptions } from '../services/historyService.js';
10
14
  import type { Workflow } from '../types/index.js';
11
15
  /**
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.
15
- */
16
- export declare function cleanupHistorySubscription(): void;
17
- /**
18
- * Get the current history state snapshot.
19
- *
20
- * Use this for binding to UI elements like undo/redo buttons.
16
+ * Undo/redo actions for a {@link HistoryStore}.
21
17
  *
22
- * @example
23
- * ```svelte
24
- * <script>
25
- * import { getHistoryState } from "./historyStore.svelte.js";
26
- *
27
- * const state = $derived(getHistoryState());
28
- * </script>
29
- *
30
- * <button disabled={!state.canUndo} onclick={historyActions.undo}>
31
- * Undo
32
- * </button>
33
- * ```
18
+ * Bound facade — safe to detach (`onclick={fd.historyBindings.actions.undo}`)
19
+ * because every entry is bound to its store in the constructor.
34
20
  */
35
- export declare function getHistoryState(): HistoryState;
36
- /**
37
- * Convenience getter for canUndo state.
38
- *
39
- * @returns Whether undo is currently available
40
- */
41
- export declare function getCanUndo(): boolean;
42
- /**
43
- * Convenience getter for canRedo state.
44
- *
45
- * @returns Whether redo is currently available
46
- */
47
- export declare function getCanRedo(): boolean;
48
- /**
49
- * Set the callback for restoring workflow state
50
- *
51
- * This callback is invoked when undo/redo operations return a workflow.
52
- * Use this to update the workflow store or other state management.
53
- *
54
- * @param callback - Function to call with restored workflow
55
- */
56
- export declare function setOnRestoreCallback(callback: ((workflow: Workflow) => void) | null): void;
21
+ export interface HistoryStoreActions {
22
+ initialize: (workflow: Workflow) => void;
23
+ pushState: (workflow: Workflow, options?: PushOptions) => void;
24
+ undo: () => boolean;
25
+ redo: () => boolean;
26
+ startTransaction: (workflow: Workflow, description?: string) => void;
27
+ commitTransaction: () => void;
28
+ cancelTransaction: () => void;
29
+ clear: (currentWorkflow?: Workflow) => void;
30
+ canUndo: () => boolean;
31
+ canRedo: () => boolean;
32
+ getState: () => HistoryState;
33
+ }
57
34
  /**
58
- * History actions for undo/redo operations
35
+ * Reactive rune bindings around a {@link HistoryService}.
59
36
  *
60
- * Use these functions to interact with the history service.
61
- * They handle the coordination between history and workflow state.
37
+ * Subscribes to the service on construction; call {@link cleanup} when the
38
+ * owning instance is destroyed to release the subscription.
62
39
  */
63
- export declare const historyActions: {
40
+ export declare class HistoryStore {
41
+ #private;
42
+ /** Bound action facade — see {@link HistoryStoreActions}. */
43
+ readonly actions: HistoryStoreActions;
44
+ constructor(service: HistoryService);
64
45
  /**
65
- * Initialize history with the current workflow
46
+ * The current history state snapshot.
47
+ *
48
+ * Use this for binding to UI elements like undo/redo buttons.
66
49
  *
67
- * Call this when loading a new workflow to reset history.
50
+ * @example
51
+ * ```svelte
52
+ * <script>
53
+ * const fd = getInstance();
54
+ * const state = $derived(fd.historyBindings.state);
55
+ * </script>
68
56
  *
69
- * @param workflow - The initial workflow state
57
+ * <button disabled={!state.canUndo} onclick={fd.historyBindings.actions.undo}>
58
+ * Undo
59
+ * </button>
60
+ * ```
70
61
  */
71
- initialize: (workflow: Workflow) => void;
62
+ get state(): HistoryState;
63
+ /** Whether undo is currently available (reactive). */
64
+ get canUndo(): boolean;
65
+ /** Whether redo is currently available (reactive). */
66
+ get canRedo(): boolean;
72
67
  /**
73
- * Push the current state to history before making changes
68
+ * Set the callback for restoring workflow state.
74
69
  *
75
- * Call this BEFORE modifying the workflow to capture the "before" state.
70
+ * This callback is invoked when undo/redo operations return a workflow.
71
+ * Use this to update the workflow store or other state management.
72
+ */
73
+ setOnRestoreCallback(callback: ((workflow: Workflow) => void) | null): void;
74
+ /**
75
+ * Release the history service subscription.
76
+ * Called by the owning instance's destroy(); safe to call repeatedly.
77
+ */
78
+ cleanup(): void;
79
+ /** Initialize history with the current workflow (resets history). */
80
+ initialize(workflow: Workflow): void;
81
+ /**
82
+ * Push the current state to history before making changes.
76
83
  *
77
- * @param workflow - The current workflow state (before changes)
78
- * @param options - Options for this history entry
84
+ * Call this BEFORE modifying the workflow to capture the "before" state.
79
85
  */
80
- pushState: (workflow: Workflow, options?: PushOptions) => void;
86
+ pushState(workflow: Workflow, options?: PushOptions): void;
81
87
  /**
82
- * Undo the last change
88
+ * Undo the last change.
83
89
  *
84
90
  * Restores the previous workflow state and invokes the restore callback.
85
91
  *
86
92
  * @returns true if undo was successful, false if at beginning of history
87
93
  */
88
- undo: () => boolean;
94
+ undo(): boolean;
89
95
  /**
90
- * Redo the last undone change
96
+ * Redo the last undone change.
91
97
  *
92
98
  * Restores the next workflow state and invokes the restore callback.
93
99
  *
94
100
  * @returns true if redo was successful, false if at end of history
95
101
  */
96
- redo: () => boolean;
102
+ redo(): boolean;
97
103
  /**
98
- * Start a transaction for grouping multiple changes
104
+ * Start a transaction for grouping multiple changes.
99
105
  *
100
106
  * All changes during a transaction are combined into a single undo entry.
101
- *
102
- * @param workflow - The current workflow state (before changes)
103
- * @param description - Description for the combined change
104
- */
105
- startTransaction: (workflow: Workflow, description?: string) => void;
106
- /**
107
- * Commit the current transaction
108
- */
109
- commitTransaction: () => void;
110
- /**
111
- * Cancel the current transaction without committing
112
107
  */
113
- cancelTransaction: () => void;
108
+ startTransaction(workflow: Workflow, description?: string): void;
109
+ /** Commit the current transaction. */
110
+ commitTransaction(): void;
111
+ /** Cancel the current transaction without committing. */
112
+ cancelTransaction(): void;
114
113
  /**
115
- * Clear all history
114
+ * Clear all history.
116
115
  *
117
116
  * @param currentWorkflow - If provided, keeps this as the initial state
118
117
  */
119
- clear: (currentWorkflow?: Workflow) => void;
120
- /**
121
- * Check if undo is available
122
- */
123
- canUndo: () => boolean;
124
- /**
125
- * Check if redo is available
126
- */
127
- canRedo: () => boolean;
128
- /**
129
- * Get the current history state synchronously
130
- *
131
- * @returns The current history state
132
- */
133
- getState: () => HistoryState;
134
- };
118
+ clear(currentWorkflow?: Workflow): void;
119
+ }
135
120
  export type { HistoryEntry, HistoryState, PushOptions } from '../services/historyService.js';
136
- export { HistoryService, historyService } from '../services/historyService.js';