@flowdrop/flowdrop 1.14.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 (218) 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 +110 -66
  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 +45 -40
  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 +29 -13
  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 +292 -0
  61. package/dist/components/nodes/AtomNode.svelte.d.ts +26 -0
  62. package/dist/components/nodes/GatewayNode.svelte +19 -10
  63. package/dist/components/nodes/IdeaNode.svelte +7 -0
  64. package/dist/components/nodes/SimpleNode.svelte +11 -6
  65. package/dist/components/nodes/SquareNode.svelte +15 -8
  66. package/dist/components/nodes/TerminalNode.svelte +9 -4
  67. package/dist/components/nodes/ToolNode.svelte +7 -1
  68. package/dist/components/nodes/WorkflowNode.svelte +16 -7
  69. package/dist/components/playground/ChatInput.svelte +11 -14
  70. package/dist/components/playground/ChatPanel.svelte +6 -49
  71. package/dist/components/playground/ChatPanel.svelte.d.ts +0 -14
  72. package/dist/components/playground/ControlPanel.svelte +134 -123
  73. package/dist/components/playground/ControlPanel.svelte.d.ts +3 -0
  74. package/dist/components/playground/ExecutionLogs.svelte +11 -9
  75. package/dist/components/playground/InputCollector.svelte +11 -9
  76. package/dist/components/playground/MessageStream.svelte +17 -23
  77. package/dist/components/playground/PipelineKanbanView.svelte +65 -6
  78. package/dist/components/playground/PipelinePanel.svelte +11 -5
  79. package/dist/components/playground/PipelineTableView.svelte +186 -44
  80. package/dist/components/playground/Playground.svelte +95 -92
  81. package/dist/components/playground/Playground.svelte.d.ts +2 -0
  82. package/dist/components/playground/PlaygroundApp.svelte +6 -1
  83. package/dist/components/playground/PlaygroundApp.svelte.d.ts +3 -0
  84. package/dist/components/playground/PlaygroundModal.svelte +13 -3
  85. package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -0
  86. package/dist/components/playground/PlaygroundStudio.svelte +34 -32
  87. package/dist/components/playground/PlaygroundStudio.svelte.d.ts +3 -0
  88. package/dist/components/playground/SessionManager.svelte +9 -12
  89. package/dist/components/playground/pipelineViewUtils.svelte.d.ts +28 -0
  90. package/dist/components/playground/pipelineViewUtils.svelte.js +38 -1
  91. package/dist/config/endpoints.d.ts +0 -7
  92. package/dist/config/endpoints.js +2 -10
  93. package/dist/core/index.d.ts +4 -4
  94. package/dist/core/index.js +6 -6
  95. package/dist/display/index.d.ts +0 -2
  96. package/dist/display/index.js +0 -6
  97. package/dist/editor/index.d.ts +19 -20
  98. package/dist/editor/index.js +25 -35
  99. package/dist/form/code.d.ts +25 -15
  100. package/dist/form/code.js +44 -41
  101. package/dist/form/fieldRegistry.d.ts +17 -13
  102. package/dist/form/fieldRegistry.js +32 -12
  103. package/dist/form/full.d.ts +17 -13
  104. package/dist/form/full.js +22 -27
  105. package/dist/form/index.d.ts +3 -3
  106. package/dist/form/index.js +3 -3
  107. package/dist/form/markdown.d.ts +13 -8
  108. package/dist/form/markdown.js +22 -23
  109. package/dist/helpers/proximityConnect.d.ts +7 -3
  110. package/dist/helpers/proximityConnect.js +19 -6
  111. package/dist/helpers/workflowEditorHelper.d.ts +12 -5
  112. package/dist/helpers/workflowEditorHelper.js +27 -25
  113. package/dist/index.d.ts +28 -24
  114. package/dist/index.js +27 -50
  115. package/dist/messages/defaults.d.ts +2 -5
  116. package/dist/messages/defaults.js +3 -6
  117. package/dist/messages/index.d.ts +0 -1
  118. package/dist/messages/index.js +0 -1
  119. package/dist/mocks/app-forms.d.ts +6 -2
  120. package/dist/mocks/app-forms.js +11 -4
  121. package/dist/openapi/v1/openapi.yaml +227 -164
  122. package/dist/playground/index.d.ts +2 -3
  123. package/dist/playground/index.js +2 -30
  124. package/dist/playground/mount.d.ts +15 -0
  125. package/dist/playground/mount.js +46 -20
  126. package/dist/registry/{BaseRegistry.d.ts → BaseRegistry.svelte.d.ts} +22 -1
  127. package/dist/registry/{BaseRegistry.js → BaseRegistry.svelte.js} +37 -1
  128. package/dist/registry/builtinFormats.d.ts +9 -18
  129. package/dist/registry/builtinFormats.js +9 -39
  130. package/dist/registry/builtinNodes.d.ts +1 -26
  131. package/dist/registry/builtinNodes.js +14 -50
  132. package/dist/registry/index.d.ts +3 -4
  133. package/dist/registry/index.js +4 -6
  134. package/dist/registry/nodeComponentRegistry.d.ts +182 -15
  135. package/dist/registry/nodeComponentRegistry.js +235 -17
  136. package/dist/registry/workflowFormatRegistry.d.ts +14 -9
  137. package/dist/registry/workflowFormatRegistry.js +24 -8
  138. package/dist/{schema → schemas}/index.d.ts +2 -2
  139. package/dist/{schema → schemas}/index.js +2 -2
  140. package/dist/schemas/v1/workflow.schema.json +53 -6
  141. package/dist/services/agentSpecExecutionService.js +0 -1
  142. package/dist/services/apiVariableService.d.ts +2 -1
  143. package/dist/services/apiVariableService.js +5 -22
  144. package/dist/services/autoSaveService.d.ts +7 -0
  145. package/dist/services/autoSaveService.js +6 -4
  146. package/dist/services/chatService.d.ts +8 -4
  147. package/dist/services/chatService.js +15 -15
  148. package/dist/services/draftStorage.d.ts +129 -13
  149. package/dist/services/draftStorage.js +185 -37
  150. package/dist/services/dynamicSchemaService.d.ts +2 -1
  151. package/dist/services/dynamicSchemaService.js +5 -22
  152. package/dist/services/globalSave.d.ts +13 -12
  153. package/dist/services/globalSave.js +29 -51
  154. package/dist/services/historyService.d.ts +9 -3
  155. package/dist/services/historyService.js +9 -3
  156. package/dist/services/interruptService.d.ts +14 -9
  157. package/dist/services/interruptService.js +27 -27
  158. package/dist/services/nodeExecutionService.d.ts +18 -3
  159. package/dist/services/nodeExecutionService.js +71 -45
  160. package/dist/services/playgroundService.d.ts +14 -9
  161. package/dist/services/playgroundService.js +31 -30
  162. package/dist/services/variableService.d.ts +2 -1
  163. package/dist/services/variableService.js +2 -2
  164. package/dist/services/workflowStorage.js +6 -6
  165. package/dist/stores/apiContext.d.ts +45 -0
  166. package/dist/stores/apiContext.js +65 -0
  167. package/dist/stores/categoriesStore.svelte.d.ts +28 -23
  168. package/dist/stores/categoriesStore.svelte.js +70 -64
  169. package/dist/stores/getInstance.svelte.d.ts +39 -0
  170. package/dist/stores/getInstance.svelte.js +65 -0
  171. package/dist/stores/historyStore.svelte.d.ts +77 -93
  172. package/dist/stores/historyStore.svelte.js +134 -160
  173. package/dist/stores/instanceContainer.svelte.d.ts +111 -0
  174. package/dist/stores/instanceContainer.svelte.js +114 -0
  175. package/dist/stores/interruptStore.svelte.d.ts +112 -82
  176. package/dist/stores/interruptStore.svelte.js +253 -226
  177. package/dist/stores/pipelinePanelStore.svelte.d.ts +27 -3
  178. package/dist/stores/pipelinePanelStore.svelte.js +61 -14
  179. package/dist/stores/playgroundStore.svelte.d.ts +169 -216
  180. package/dist/stores/playgroundStore.svelte.js +515 -572
  181. package/dist/stores/portCoordinateStore.svelte.d.ts +57 -51
  182. package/dist/stores/portCoordinateStore.svelte.js +109 -98
  183. package/dist/stores/settingsStore.svelte.d.ts +4 -1
  184. package/dist/stores/settingsStore.svelte.js +47 -12
  185. package/dist/stores/workflowStore.svelte.d.ts +178 -213
  186. package/dist/stores/workflowStore.svelte.js +449 -501
  187. package/dist/stories/EdgeDecorator.svelte +5 -2
  188. package/dist/stories/NodeDecorator.svelte +5 -3
  189. package/dist/svelte-app.d.ts +60 -10
  190. package/dist/svelte-app.js +157 -53
  191. package/dist/types/events.d.ts +6 -3
  192. package/dist/types/index.d.ts +71 -6
  193. package/dist/types/navbar.d.ts +7 -0
  194. package/dist/types/playground.d.ts +18 -3
  195. package/dist/types/settings.d.ts +13 -0
  196. package/dist/types/settings.js +1 -0
  197. package/dist/utils/colors.d.ts +47 -21
  198. package/dist/utils/colors.js +69 -68
  199. package/dist/utils/connections.d.ts +9 -15
  200. package/dist/utils/connections.js +13 -32
  201. package/dist/utils/duration.d.ts +13 -0
  202. package/dist/utils/duration.js +45 -0
  203. package/dist/utils/formMerge.d.ts +36 -0
  204. package/dist/utils/formMerge.js +70 -0
  205. package/dist/utils/icons.d.ts +5 -2
  206. package/dist/utils/icons.js +6 -5
  207. package/dist/utils/nodeSwap.d.ts +6 -2
  208. package/dist/utils/nodeSwap.js +62 -126
  209. package/dist/utils/nodeTypes.d.ts +17 -8
  210. package/dist/utils/nodeTypes.js +27 -19
  211. package/dist/utils/performanceUtils.js +7 -0
  212. package/package.json +6 -5
  213. package/dist/messages/deprecation.d.ts +0 -20
  214. package/dist/messages/deprecation.js +0 -33
  215. package/dist/registry/plugin.d.ts +0 -215
  216. package/dist/registry/plugin.js +0 -249
  217. package/dist/services/api.d.ts +0 -129
  218. package/dist/services/api.js +0 -217
@@ -5,9 +5,14 @@
5
5
  * building visual workflow editors. This module includes @xyflow/svelte
6
6
  * and all node components.
7
7
  *
8
- * **Important: Single-instance only.** FlowDrop uses module-level singleton
9
- * stores for state management. Only one FlowDrop editor instance per page
10
- * is supported. This is a known architectural limitation.
8
+ * **Multi-instance support.** Each mount gets its own `FlowDropInstance`
9
+ * state container (workflow, undo/redo, playground, …), so multiple editors
10
+ * can coexist on one page. Pass `instanceId` to the mount options to scope
11
+ * draft/panel storage keys per editor; in Svelte, pass `instance` to <App>
12
+ * or resolve it in components via `getInstance()`. State is addressed through
13
+ * the instance — there is no page-default module-level store API.
14
+ * Page-global by design: theme/settings, port-compatibility config, and API
15
+ * endpoint config.
11
16
  *
12
17
  * @module editor
13
18
  *
@@ -32,12 +37,6 @@
32
37
  * ```
33
38
  */
34
39
  // ============================================================================
35
- // Initialize Built-in Nodes
36
- // This side effect is intentional for the editor module - users importing
37
- // the editor expect all node types to be available.
38
- // ============================================================================
39
- import '../registry/builtinNodes.js';
40
- // ============================================================================
41
40
  // Main Editor Components
42
41
  // ============================================================================
43
42
  export { default as WorkflowEditor } from '../components/WorkflowEditor.svelte';
@@ -73,14 +72,6 @@ export { default as Navbar } from '../components/Navbar.svelte';
73
72
  export { default as Logo } from '../components/Logo.svelte';
74
73
  // Console Components
75
74
  export { default as CommandConsole } from '../components/console/CommandConsole.svelte';
76
- // Playground Components
77
- export { default as Playground } from '../components/playground/Playground.svelte';
78
- export { default as PlaygroundModal } from '../components/playground/PlaygroundModal.svelte';
79
- export { default as ChatPanel } from '../components/playground/ChatPanel.svelte';
80
- export { default as SessionManager } from '../components/playground/SessionManager.svelte';
81
- export { default as InputCollector } from '../components/playground/InputCollector.svelte';
82
- export { default as ExecutionLogs } from '../components/playground/ExecutionLogs.svelte';
83
- export { default as MessageBubble } from '../components/playground/MessageBubble.svelte';
84
75
  // ============================================================================
85
76
  // Mount Functions
86
77
  // ============================================================================
@@ -89,12 +80,12 @@ export { mountWorkflowEditor, mountFlowDropApp, unmountFlowDropApp } from '../sv
89
80
  // Node Component Registry
90
81
  // ============================================================================
91
82
  export {
92
- // Core registry
93
- nodeComponentRegistry, createNamespacedType, parseNamespacedType,
83
+ // Core registry (the class — instances live on `fd.nodes`)
84
+ NodeComponentRegistry, createNamespacedType, parseNamespacedType,
94
85
  // Built-in nodes
95
- BUILTIN_NODE_COMPONENTS, BUILTIN_NODE_TYPES, FLOWDROP_SOURCE, registerBuiltinNodes, areBuiltinsRegistered, isBuiltinType, getBuiltinTypes, resolveBuiltinAlias,
86
+ BUILTIN_NODE_COMPONENTS, BUILTIN_NODE_TYPES, FLOWDROP_SOURCE, isBuiltinType, getBuiltinTypes, resolveBuiltinAlias,
96
87
  // Plugin system
97
- registerFlowDropPlugin, unregisterFlowDropPlugin, registerCustomNode, createPlugin, isValidNamespace, getRegisteredPlugins, getPluginNodeCount } from '../registry/index.js';
88
+ createPlugin, isValidNamespace } from '../registry/index.js';
98
89
  // ============================================================================
99
90
  // Editor Helpers
100
91
  // ============================================================================
@@ -102,30 +93,29 @@ export { EdgeStylingHelper, NodeOperationsHelper, WorkflowOperationsHelper, Conf
102
93
  // ============================================================================
103
94
  // Stores
104
95
  // ============================================================================
105
- export { getWorkflowStore, workflowActions, getWorkflowId, getWorkflowName, getWorkflowNodes, getWorkflowEdges, getWorkflowMetadata, getWorkflowFormat, getWorkflowChanged, getWorkflowValidation, getWorkflowMetadataChanged, getConnectedHandles,
106
- // Dirty state tracking & version counter
107
- getIsDirty, isDirty, markAsSaved, getEditVersion, getWorkflow as getWorkflowFromStore, setOnDirtyStateChange, setOnWorkflowChange,
108
- // History control
109
- setHistoryEnabled, isHistoryEnabled, setRestoringFromHistory } from '../stores/workflowStore.svelte.js';
96
+ // Multi-instance support: per-instance state containers + context helpers.
97
+ // All workflow/history/playground state is addressed through an instance.
98
+ export { createFlowDropInstance, getDefaultInstance } from '../stores/instanceContainer.svelte.js';
99
+ export { getInstance, provideInstance, FLOWDROP_INSTANCE_KEY } from '../stores/getInstance.svelte.js';
100
+ export { WorkflowStore } from '../stores/workflowStore.svelte.js';
101
+ export { HistoryStore } from '../stores/historyStore.svelte.js';
102
+ // Per-instance API context (endpoints + auth provider + lazily-built client).
103
+ export { ApiContext } from '../stores/apiContext.js';
110
104
  // Port Coordinate Store (Svelte 5 runes-based)
111
- export { rebuildAllPortCoordinates, updateNodePortCoordinates, removeNodePortCoordinates, getPortCoordinate, getNodePortCoordinates, getPortCoordinateSnapshot, getPortCoordinates } from '../stores/portCoordinateStore.svelte.js';
112
- // History Store and Service
113
- export { getHistoryState, getCanUndo, getCanRedo, historyActions, setOnRestoreCallback, cleanupHistorySubscription, historyService, HistoryService } from '../stores/historyStore.svelte.js';
105
+ export { PortCoordinateStore } from '../stores/portCoordinateStore.svelte.js';
106
+ // History Service (the undo/redo engine class)
107
+ export { HistoryService } from '../services/historyService.js';
114
108
  // ============================================================================
115
109
  // Services
116
110
  // ============================================================================
117
- export { setEndpointConfig, getEndpointConfig, nodeApi, workflowApi, api } from '../services/api.js';
118
111
  export { showSuccess, showError, showWarning, showInfo, showLoading, dismissToast, dismissAllToasts, showPromise, showConfirmation, apiToasts, workflowToasts, pipelineToasts } from '../services/toastService.js';
119
112
  export { NodeExecutionService, nodeExecutionService } from '../services/nodeExecutionService.js';
120
- // Playground Service and Store
121
- export { PlaygroundService, playgroundService } from '../services/playgroundService.js';
122
- export { getCurrentSession, getSessions, getMessages, getIsExecuting, getCanSendMessage, getIsLoading, getError as getPlaygroundError, getCurrentWorkflow, getLastPollSequenceNumber, getSessionStatus, getMessageCount, getChatMessages, getLogMessages, getLatestMessage, getInputFields, getHasChatInput, getSessionCount, playgroundActions, applyServerResponse, subscribeToSessionStatus, getCurrentSessionId, isSessionSelected, getMessagesSnapshot, getLatestSequenceNumber } from '../stores/playgroundStore.svelte.js';
123
113
  export { saveWorkflow, updateWorkflow, getWorkflow, getWorkflows, deleteWorkflow, getWorkflowCount, initializeSampleWorkflows } from '../services/workflowStorage.js';
124
114
  export { globalSaveWorkflow, globalExportWorkflow } from '../services/globalSave.js';
125
115
  export { fetchPortConfig, validatePortConfig } from '../services/portConfigApi.js';
126
116
  export { fetchCategories, validateCategories } from '../services/categoriesApi.js';
127
117
  export { fetchDynamicSchema, resolveExternalEditUrl, getEffectiveConfigEditOptions, clearSchemaCache, invalidateSchemaCache, hasConfigEditOptions, shouldShowExternalEdit, shouldUseDynamicSchema } from '../services/dynamicSchemaService.js';
128
- export { getDraftStorageKey, saveDraft, loadDraft, deleteDraft, hasDraft, getDraftMetadata, clearAllDrafts, DraftAutoSaveManager } from '../services/draftStorage.js';
118
+ export { getDraftStorageKey, saveDraft, loadDraft, deleteDraft, hasDraft, getDraftMetadata, clearAllDrafts, setDraftStorage, getDraftStorage, resolveDraftStorage, DraftAutoSaveManager } from '../services/draftStorage.js';
129
119
  // ============================================================================
130
120
  // API Clients
131
121
  // ============================================================================
@@ -133,7 +123,7 @@ export { EnhancedFlowDropApiClient, ApiError } from '../api/enhanced-client.js';
133
123
  // ============================================================================
134
124
  // Connection Utilities
135
125
  // ============================================================================
136
- export { isLoopbackEdge, isValidLoopbackCycle, PortCompatibilityChecker, initializePortCompatibility, getPortCompatibilityChecker, getPossibleConnections, validateConnection, getConnectionSuggestions, hasCycles, hasInvalidCycles, getExecutionOrder } from '../utils/connections.js';
126
+ export { isLoopbackEdge, isValidLoopbackCycle, PortCompatibilityChecker, getPossibleConnections, validateConnection, getConnectionSuggestions, hasCycles, hasInvalidCycles, getExecutionOrder } from '../utils/connections.js';
137
127
  // ============================================================================
138
128
  // Runtime Configuration
139
129
  // ============================================================================
@@ -11,16 +11,17 @@
11
11
  * import { SchemaForm } from "@flowdrop/flowdrop/form";
12
12
  * import { registerCodeEditorField, registerTemplateEditorField } from "@flowdrop/flowdrop/form/code";
13
13
  *
14
- * // Register code editor support (call once at app startup)
15
- * registerCodeEditorField();
14
+ * // Register code editor support into an instance's field registry
15
+ * // (call once at app startup)
16
+ * registerCodeEditorField(fd.fields);
16
17
  *
17
18
  * // Optionally also register template editor
18
- * registerTemplateEditorField();
19
+ * registerTemplateEditorField(fd.fields);
19
20
  *
20
21
  * // Now SchemaForm will render code editors for format: "json", "code", or "template"
21
22
  * ```
22
23
  */
23
- import type { FieldComponent } from './fieldRegistry.js';
24
+ import type { FieldComponent, FieldComponentRegistry } from './fieldRegistry.js';
24
25
  import type { FieldSchema } from '../components/form/types.js';
25
26
  export { default as FormCodeEditor } from '../components/form/FormCodeEditor.svelte';
26
27
  export { default as FormTemplateEditor } from '../components/form/FormTemplateEditor.svelte';
@@ -41,6 +42,7 @@ export declare function templateEditorFieldMatcher(schema: FieldSchema): boolean
41
42
  * Call this function once at application startup to enable
42
43
  * code editor fields in SchemaForm. This loads CodeMirror dependencies.
43
44
  *
45
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
44
46
  * @param priority - Priority for field matching (default: 100)
45
47
  *
46
48
  * @example
@@ -48,16 +50,17 @@ export declare function templateEditorFieldMatcher(schema: FieldSchema): boolean
48
50
  * // In your app's entry point:
49
51
  * import { registerCodeEditorField } from "@flowdrop/flowdrop/form/code";
50
52
  *
51
- * registerCodeEditorField();
53
+ * registerCodeEditorField(fd.fields);
52
54
  * ```
53
55
  */
54
- export declare function registerCodeEditorField(priority?: number): void;
56
+ export declare function registerCodeEditorField(registry: FieldComponentRegistry, priority?: number): void;
55
57
  /**
56
58
  * Register the template editor field component
57
59
  *
58
60
  * Call this function once at application startup to enable
59
61
  * template editor fields (Twig/Liquid syntax) in SchemaForm.
60
62
  *
63
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
61
64
  * @param priority - Priority for field matching (default: 100)
62
65
  *
63
66
  * @example
@@ -65,37 +68,44 @@ export declare function registerCodeEditorField(priority?: number): void;
65
68
  * // In your app's entry point:
66
69
  * import { registerTemplateEditorField } from "@flowdrop/flowdrop/form/code";
67
70
  *
68
- * registerTemplateEditorField();
71
+ * registerTemplateEditorField(fd.fields);
69
72
  * ```
70
73
  */
71
- export declare function registerTemplateEditorField(priority?: number): void;
74
+ export declare function registerTemplateEditorField(registry: FieldComponentRegistry, priority?: number): void;
72
75
  /**
73
76
  * Register all code-related editor fields (code + template)
74
77
  *
75
78
  * Convenience function to register both code editor types at once.
76
79
  *
80
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
77
81
  * @param priority - Priority for field matching (default: 100)
78
82
  */
79
- export declare function registerAllCodeEditors(priority?: number): void;
83
+ export declare function registerAllCodeEditors(registry: FieldComponentRegistry, priority?: number): void;
80
84
  /**
81
85
  * Synchronously register code editor field using the imported component
82
86
  *
83
87
  * Use this when you've already imported the component and want immediate registration.
84
88
  *
89
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
90
+ * @param component - The pre-imported code editor component
85
91
  * @param priority - Priority for field matching (default: 100)
86
92
  *
87
93
  * @example
88
94
  * ```typescript
89
95
  * import { registerCodeEditorFieldWithComponent, FormCodeEditor } from "@flowdrop/flowdrop/form/code";
90
- * registerCodeEditorFieldWithComponent(FormCodeEditor);
96
+ * registerCodeEditorFieldWithComponent(fd.fields, FormCodeEditor);
91
97
  * ```
92
98
  */
93
- export declare function registerCodeEditorFieldWithComponent(component: FieldComponent, priority?: number): void;
99
+ export declare function registerCodeEditorFieldWithComponent(registry: FieldComponentRegistry, component: FieldComponent, priority?: number): void;
94
100
  /**
95
- * Check if code editor field is registered
101
+ * Check if code editor field is registered in the given registry.
102
+ *
103
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
96
104
  */
97
- export declare function isCodeEditorRegistered(): boolean;
105
+ export declare function isCodeEditorRegistered(registry: FieldComponentRegistry): boolean;
98
106
  /**
99
- * Check if template editor field is registered
107
+ * Check if template editor field is registered in the given registry.
108
+ *
109
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
100
110
  */
101
- export declare function isTemplateEditorRegistered(): boolean;
111
+ export declare function isTemplateEditorRegistered(registry: FieldComponentRegistry): boolean;
package/dist/form/code.js CHANGED
@@ -11,16 +11,16 @@
11
11
  * import { SchemaForm } from "@flowdrop/flowdrop/form";
12
12
  * import { registerCodeEditorField, registerTemplateEditorField } from "@flowdrop/flowdrop/form/code";
13
13
  *
14
- * // Register code editor support (call once at app startup)
15
- * registerCodeEditorField();
14
+ * // Register code editor support into an instance's field registry
15
+ * // (call once at app startup)
16
+ * registerCodeEditorField(fd.fields);
16
17
  *
17
18
  * // Optionally also register template editor
18
- * registerTemplateEditorField();
19
+ * registerTemplateEditorField(fd.fields);
19
20
  *
20
21
  * // Now SchemaForm will render code editors for format: "json", "code", or "template"
21
22
  * ```
22
23
  */
23
- import { fieldComponentRegistry } from './fieldRegistry.js';
24
24
  // Re-export the components for direct usage if needed
25
25
  export { default as FormCodeEditor } from '../components/form/FormCodeEditor.svelte';
26
26
  export { default as FormTemplateEditor } from '../components/form/FormTemplateEditor.svelte';
@@ -46,25 +46,13 @@ export function codeEditorFieldMatcher(schema) {
46
46
  export function templateEditorFieldMatcher(schema) {
47
47
  return schema.format === 'template';
48
48
  }
49
- /**
50
- * Track if code editor is registered
51
- */
52
- let codeEditorRegistered = false;
53
- /**
54
- * Track if template editor is registered
55
- */
56
- let templateEditorRegistered = false;
57
- // Sync registration flags with registry.clear() for test isolation
58
- fieldComponentRegistry.onClear(() => {
59
- codeEditorRegistered = false;
60
- templateEditorRegistered = false;
61
- });
62
49
  /**
63
50
  * Register the code/JSON editor field component
64
51
  *
65
52
  * Call this function once at application startup to enable
66
53
  * code editor fields in SchemaForm. This loads CodeMirror dependencies.
67
54
  *
55
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
68
56
  * @param priority - Priority for field matching (default: 100)
69
57
  *
70
58
  * @example
@@ -72,21 +60,25 @@ fieldComponentRegistry.onClear(() => {
72
60
  * // In your app's entry point:
73
61
  * import { registerCodeEditorField } from "@flowdrop/flowdrop/form/code";
74
62
  *
75
- * registerCodeEditorField();
63
+ * registerCodeEditorField(fd.fields);
76
64
  * ```
77
65
  */
78
- export function registerCodeEditorField(priority = 100) {
79
- if (codeEditorRegistered) {
66
+ export function registerCodeEditorField(registry, priority = 100) {
67
+ if (registry.has('code-editor')) {
80
68
  return;
81
69
  }
82
70
  // Dynamic import to ensure proper code splitting
83
71
  import('../components/form/FormCodeEditor.svelte').then((module) => {
84
- fieldComponentRegistry.register('code-editor', {
72
+ // Re-check inside the async callback: two rapid synchronous calls both pass
73
+ // the guard above before either import resolves, so guard again here.
74
+ if (registry.has('code-editor')) {
75
+ return;
76
+ }
77
+ registry.register('code-editor', {
85
78
  component: module.default,
86
79
  matcher: codeEditorFieldMatcher,
87
80
  priority
88
81
  });
89
- codeEditorRegistered = true;
90
82
  });
91
83
  }
92
84
  /**
@@ -95,6 +87,7 @@ export function registerCodeEditorField(priority = 100) {
95
87
  * Call this function once at application startup to enable
96
88
  * template editor fields (Twig/Liquid syntax) in SchemaForm.
97
89
  *
90
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
98
91
  * @param priority - Priority for field matching (default: 100)
99
92
  *
100
93
  * @example
@@ -102,21 +95,25 @@ export function registerCodeEditorField(priority = 100) {
102
95
  * // In your app's entry point:
103
96
  * import { registerTemplateEditorField } from "@flowdrop/flowdrop/form/code";
104
97
  *
105
- * registerTemplateEditorField();
98
+ * registerTemplateEditorField(fd.fields);
106
99
  * ```
107
100
  */
108
- export function registerTemplateEditorField(priority = 100) {
109
- if (templateEditorRegistered) {
101
+ export function registerTemplateEditorField(registry, priority = 100) {
102
+ if (registry.has('template-editor')) {
110
103
  return;
111
104
  }
112
105
  // Dynamic import to ensure proper code splitting
113
106
  import('../components/form/FormTemplateEditor.svelte').then((module) => {
114
- fieldComponentRegistry.register('template-editor', {
107
+ // Re-check inside the async callback: two rapid synchronous calls both pass
108
+ // the guard above before either import resolves, so guard again here.
109
+ if (registry.has('template-editor')) {
110
+ return;
111
+ }
112
+ registry.register('template-editor', {
115
113
  component: module.default,
116
114
  matcher: templateEditorFieldMatcher,
117
115
  priority
118
116
  });
119
- templateEditorRegistered = true;
120
117
  });
121
118
  }
122
119
  /**
@@ -124,45 +121,51 @@ export function registerTemplateEditorField(priority = 100) {
124
121
  *
125
122
  * Convenience function to register both code editor types at once.
126
123
  *
124
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
127
125
  * @param priority - Priority for field matching (default: 100)
128
126
  */
129
- export function registerAllCodeEditors(priority = 100) {
130
- registerCodeEditorField(priority);
131
- registerTemplateEditorField(priority);
127
+ export function registerAllCodeEditors(registry, priority = 100) {
128
+ registerCodeEditorField(registry, priority);
129
+ registerTemplateEditorField(registry, priority);
132
130
  }
133
131
  /**
134
132
  * Synchronously register code editor field using the imported component
135
133
  *
136
134
  * Use this when you've already imported the component and want immediate registration.
137
135
  *
136
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
137
+ * @param component - The pre-imported code editor component
138
138
  * @param priority - Priority for field matching (default: 100)
139
139
  *
140
140
  * @example
141
141
  * ```typescript
142
142
  * import { registerCodeEditorFieldWithComponent, FormCodeEditor } from "@flowdrop/flowdrop/form/code";
143
- * registerCodeEditorFieldWithComponent(FormCodeEditor);
143
+ * registerCodeEditorFieldWithComponent(fd.fields, FormCodeEditor);
144
144
  * ```
145
145
  */
146
- export function registerCodeEditorFieldWithComponent(component, priority = 100) {
147
- if (codeEditorRegistered) {
146
+ export function registerCodeEditorFieldWithComponent(registry, component, priority = 100) {
147
+ if (registry.has('code-editor')) {
148
148
  return;
149
149
  }
150
- fieldComponentRegistry.register('code-editor', {
150
+ registry.register('code-editor', {
151
151
  component,
152
152
  matcher: codeEditorFieldMatcher,
153
153
  priority
154
154
  });
155
- codeEditorRegistered = true;
156
155
  }
157
156
  /**
158
- * Check if code editor field is registered
157
+ * Check if code editor field is registered in the given registry.
158
+ *
159
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
159
160
  */
160
- export function isCodeEditorRegistered() {
161
- return codeEditorRegistered;
161
+ export function isCodeEditorRegistered(registry) {
162
+ return registry.has('code-editor');
162
163
  }
163
164
  /**
164
- * Check if template editor field is registered
165
+ * Check if template editor field is registered in the given registry.
166
+ *
167
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
165
168
  */
166
- export function isTemplateEditorRegistered() {
167
- return templateEditorRegistered;
169
+ export function isTemplateEditorRegistered(registry) {
170
+ return registry.has('template-editor');
168
171
  }
@@ -18,19 +18,15 @@
18
18
  *
19
19
  * @example Adding code editor support:
20
20
  * ```typescript
21
- * import { fieldComponentRegistry } from "@flowdrop/flowdrop/form";
22
- * import { FormCodeEditor, codeEditorFieldMatcher } from "@flowdrop/flowdrop/form/code";
21
+ * import { registerCodeEditorField } from "@flowdrop/flowdrop/form/code";
23
22
  *
24
- * fieldComponentRegistry.register("code-editor", {
25
- * component: FormCodeEditor,
26
- * matcher: codeEditorFieldMatcher,
27
- * priority: 100
28
- * });
23
+ * // Registers the code editor into this instance's field registry.
24
+ * registerCodeEditorField(fd.fields);
29
25
  * ```
30
26
  */
31
27
  import type { Component } from 'svelte';
32
28
  import type { FieldSchema } from '../components/form/types.js';
33
- import { BaseRegistry } from '../registry/BaseRegistry.js';
29
+ import { BaseRegistry } from '../registry/BaseRegistry.svelte.js';
34
30
  /**
35
31
  * Base field component props that all registered field components should accept.
36
32
  * Components may have additional specific props.
@@ -82,12 +78,23 @@ export interface FieldComponentRegistration extends FieldMatcherRegistration {
82
78
  * Class-based field component registry.
83
79
  * Extends BaseRegistry with priority-based field resolution.
84
80
  */
85
- declare class FieldComponentRegistry extends BaseRegistry<string, FieldComponentRegistration> {
81
+ export declare class FieldComponentRegistry extends BaseRegistry<string, FieldComponentRegistration> {
86
82
  /** Cached ordered keys by priority (highest first), invalidated on mutation */
87
83
  private orderedKeys;
84
+ /**
85
+ * @param seed - Optional initial field registrations keyed by type. The
86
+ * registry starts empty by default — the built-in light fields are
87
+ * resolved inline by FormField/FormFieldLight, and heavy editors are
88
+ * registered on demand via `form/code`, `form/markdown`, etc.
89
+ */
90
+ constructor(seed?: Record<string, FieldComponentRegistration>);
88
91
  /**
89
92
  * Register a field component.
90
- * Silently overwrites existing registrations (preserves legacy behavior).
93
+ *
94
+ * Re-registering an existing type overwrites it — useful for hosts
95
+ * replacing a built-in field — but warns in dev, since an *accidental*
96
+ * duplicate registration silently swallowing a field implementation is a
97
+ * miserable bug to track down.
91
98
  *
92
99
  * @param type - Unique identifier for this field type
93
100
  * @param registration - The field component registration
@@ -114,8 +121,6 @@ declare class FieldComponentRegistry extends BaseRegistry<string, FieldComponent
114
121
  */
115
122
  private getOrderedKeys;
116
123
  }
117
- /** Singleton instance of the field component registry */
118
- export declare const fieldComponentRegistry: FieldComponentRegistry;
119
124
  /**
120
125
  * Matcher for hidden fields (should not render)
121
126
  */
@@ -166,4 +171,3 @@ export declare const arrayMatcher: FieldMatcher;
166
171
  * Matches when format is "autocomplete" and autocomplete config with URL is provided
167
172
  */
168
173
  export declare const autocompleteMatcher: FieldMatcher;
169
- export {};
@@ -18,34 +18,55 @@
18
18
  *
19
19
  * @example Adding code editor support:
20
20
  * ```typescript
21
- * import { fieldComponentRegistry } from "@flowdrop/flowdrop/form";
22
- * import { FormCodeEditor, codeEditorFieldMatcher } from "@flowdrop/flowdrop/form/code";
21
+ * import { registerCodeEditorField } from "@flowdrop/flowdrop/form/code";
23
22
  *
24
- * fieldComponentRegistry.register("code-editor", {
25
- * component: FormCodeEditor,
26
- * matcher: codeEditorFieldMatcher,
27
- * priority: 100
28
- * });
23
+ * // Registers the code editor into this instance's field registry.
24
+ * registerCodeEditorField(fd.fields);
29
25
  * ```
30
26
  */
31
- import { BaseRegistry } from '../registry/BaseRegistry.js';
27
+ import { DEV } from 'esm-env';
28
+ import { BaseRegistry } from '../registry/BaseRegistry.svelte.js';
32
29
  /**
33
30
  * Class-based field component registry.
34
31
  * Extends BaseRegistry with priority-based field resolution.
35
32
  */
36
- class FieldComponentRegistry extends BaseRegistry {
33
+ export class FieldComponentRegistry extends BaseRegistry {
37
34
  /** Cached ordered keys by priority (highest first), invalidated on mutation */
38
35
  orderedKeys = null;
36
+ /**
37
+ * @param seed - Optional initial field registrations keyed by type. The
38
+ * registry starts empty by default — the built-in light fields are
39
+ * resolved inline by FormField/FormFieldLight, and heavy editors are
40
+ * registered on demand via `form/code`, `form/markdown`, etc.
41
+ */
42
+ constructor(seed) {
43
+ super();
44
+ if (seed) {
45
+ for (const [type, registration] of Object.entries(seed)) {
46
+ this.register(type, registration);
47
+ }
48
+ }
49
+ }
39
50
  /**
40
51
  * Register a field component.
41
- * Silently overwrites existing registrations (preserves legacy behavior).
52
+ *
53
+ * Re-registering an existing type overwrites it — useful for hosts
54
+ * replacing a built-in field — but warns in dev, since an *accidental*
55
+ * duplicate registration silently swallowing a field implementation is a
56
+ * miserable bug to track down.
42
57
  *
43
58
  * @param type - Unique identifier for this field type
44
59
  * @param registration - The field component registration
45
60
  */
46
61
  register(type, registration) {
62
+ if (DEV && this.items.has(type)) {
63
+ // eslint-disable-next-line no-console -- intentional dev diagnostic for accidental duplicate registrations
64
+ console.warn(`[flowdrop] Field type "${type}" is already registered — overwriting. ` +
65
+ 'If this is intentional (replacing a built-in field), ignore this warning.');
66
+ }
47
67
  this.items.set(type, registration);
48
68
  this.orderedKeys = null;
69
+ this.touch();
49
70
  this.notifyListeners();
50
71
  }
51
72
  /**
@@ -73,6 +94,7 @@ class FieldComponentRegistry extends BaseRegistry {
73
94
  * @returns The matching registration or null if no match
74
95
  */
75
96
  resolveFieldComponent(schema) {
97
+ this.trackVersion(); // reactive dependency — cached orderedKeys path still tracks mutations
76
98
  const keys = this.getOrderedKeys();
77
99
  for (const key of keys) {
78
100
  const registration = this.items.get(key);
@@ -94,8 +116,6 @@ class FieldComponentRegistry extends BaseRegistry {
94
116
  return this.orderedKeys;
95
117
  }
96
118
  }
97
- /** Singleton instance of the field component registry */
98
- export const fieldComponentRegistry = new FieldComponentRegistry();
99
119
  // ============================================================================
100
120
  // Built-in Field Matchers (for light fields)
101
121
  // These are always available and used by the base FormField component
@@ -14,8 +14,8 @@
14
14
  * // Single import that sets up everything
15
15
  * import { SchemaForm, initializeAllFieldTypes } from "@flowdrop/flowdrop/form/full";
16
16
  *
17
- * // Call once at app startup
18
- * initializeAllFieldTypes();
17
+ * // Call once at app startup, against an instance's field registry
18
+ * initializeAllFieldTypes(fd.fields);
19
19
  *
20
20
  * // Now all field types are available
21
21
  * ```
@@ -23,7 +23,8 @@
23
23
  export { SchemaForm, FormField, FormFieldFull, FormFieldWrapper, FormTextField, FormTextarea, FormNumberField, FormRangeField, FormToggle, FormSelect, FormCheckboxGroup, FormArray, FormFieldset, FormUISchemaRenderer } from './index.js';
24
24
  export type { FieldSchema, FieldType, FieldFormat, FieldOption, OneOfItem, SchemaFormProps, BaseFieldProps, TextFieldProps, TextareaFieldProps, NumberFieldProps, ToggleFieldProps, RangeFieldProps, SelectFieldProps, CheckboxGroupFieldProps, ArrayFieldProps, FormFieldFactoryProps, FormFieldWrapperProps, FieldComponentProps, FieldMatcher, FieldMatcherRegistration, FieldComponent, FieldComponentRegistration } from './index.js';
25
25
  export { isFieldOptionArray, isOneOfArray, normalizeOptions, oneOfToOptions, getSchemaOptions } from './index.js';
26
- export { fieldComponentRegistry, hiddenFieldMatcher, checkboxGroupMatcher, enumSelectMatcher, textareaMatcher, rangeMatcher, textFieldMatcher, numberFieldMatcher, toggleMatcher, selectOptionsMatcher, arrayMatcher } from './index.js';
26
+ export { FieldComponentRegistry, hiddenFieldMatcher, checkboxGroupMatcher, enumSelectMatcher, textareaMatcher, rangeMatcher, textFieldMatcher, numberFieldMatcher, toggleMatcher, selectOptionsMatcher, arrayMatcher } from './index.js';
27
+ import type { FieldComponentRegistry } from './fieldRegistry.js';
27
28
  export { FormCodeEditor, FormTemplateEditor } from './code.js';
28
29
  export { FormMarkdownEditor } from './markdown.js';
29
30
  export { registerCodeEditorField, registerTemplateEditorField, registerAllCodeEditors, isCodeEditorRegistered, isTemplateEditorRegistered, codeEditorFieldMatcher, templateEditorFieldMatcher } from './code.js';
@@ -31,26 +32,29 @@ export { registerMarkdownEditorField, isMarkdownEditorRegistered, markdownEditor
31
32
  /**
32
33
  * Initialize all form field types including heavy editors
33
34
  *
34
- * Call this once at application startup to enable all field types.
35
- * This includes:
35
+ * Call this once at application startup to enable all field types in the
36
+ * given instance's field registry. This includes:
36
37
  * - Code/JSON editor (CodeMirror)
37
38
  * - Template editor (CodeMirror with Twig/Liquid syntax)
38
39
  * - Markdown editor (CodeMirror 6)
39
40
  *
41
+ * Registration is idempotent per registry — each `register*Field` is a no-op
42
+ * if its field type is already present (see `FieldComponentRegistry.has`).
43
+ *
44
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
45
+ *
40
46
  * @example
41
47
  * ```typescript
42
48
  * import { initializeAllFieldTypes } from "@flowdrop/flowdrop/form/full";
43
49
  *
44
50
  * // In your app's entry point
45
- * initializeAllFieldTypes();
51
+ * initializeAllFieldTypes(fd.fields);
46
52
  * ```
47
53
  */
48
- export declare function initializeAllFieldTypes(): void;
54
+ export declare function initializeAllFieldTypes(registry: FieldComponentRegistry): void;
49
55
  /**
50
- * Check if all field types have been initialized
51
- */
52
- export declare function areAllFieldTypesInitialized(): boolean;
53
- /**
54
- * Reset initialization state (useful for testing)
56
+ * Check if all heavy field types are registered in the given registry.
57
+ *
58
+ * @param registry - The instance's field registry (e.g. `fd.fields`)
55
59
  */
56
- export declare function resetFieldTypeInitialization(): void;
60
+ export declare function areAllFieldTypesInitialized(registry: FieldComponentRegistry): boolean;