@flowdrop/flowdrop 1.15.0 → 2.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +508 -0
- package/MIGRATION-2.0.md +629 -0
- package/README.md +23 -23
- package/dist/adapters/WorkflowAdapter.d.ts +1 -1
- package/dist/adapters/WorkflowAdapter.js +14 -8
- package/dist/adapters/agentspec/AgentSpecAdapter.js +7 -7
- package/dist/api/enhanced-client.js +6 -11
- package/dist/chat/batchFeedback.d.ts +39 -0
- package/dist/chat/batchFeedback.js +51 -0
- package/dist/commands/executor.js +15 -1
- package/dist/commands/storeIntegration.svelte.d.ts +4 -1
- package/dist/commands/storeIntegration.svelte.js +26 -21
- package/dist/commands/types.d.ts +2 -0
- package/dist/components/App.svelte +163 -192
- package/dist/components/App.svelte.d.ts +47 -8
- package/dist/components/ConfigForm.svelte +77 -49
- package/dist/components/ConfigModal.svelte +7 -2
- package/dist/components/ConnectionLine.svelte +4 -2
- package/dist/components/Navbar.svelte +61 -1
- package/dist/components/NodeSidebar.svelte +27 -45
- package/dist/components/NodeStatusOverlay.svelte +94 -6
- package/dist/components/NodeSwapPicker.svelte +10 -8
- package/dist/components/PipelineStatus.svelte +22 -68
- package/dist/components/PipelineStatus.svelte.d.ts +3 -0
- package/dist/components/PortCoordinateTracker.svelte +5 -6
- package/dist/components/SchemaForm.stories.svelte +1 -3
- package/dist/components/SchemaForm.svelte +22 -27
- package/dist/components/SchemaForm.svelte.d.ts +0 -8
- package/dist/components/SettingsModal.svelte +8 -3
- package/dist/components/SettingsPanel.svelte +20 -4
- package/dist/components/SwapMappingEditor.svelte +67 -49
- package/dist/components/SwapMappingEditor.svelte.d.ts +0 -2
- package/dist/components/UniversalNode.svelte +9 -7
- package/dist/components/WorkflowEditor.svelte +121 -111
- package/dist/components/WorkflowEditor.svelte.d.ts +21 -10
- package/dist/components/chat/AIChatPanel.svelte +98 -89
- package/dist/components/chat/AIChatPanel.svelte.d.ts +0 -4
- package/dist/components/chat/CommandPreview.svelte +2 -1
- package/dist/components/console/CommandConsole.svelte +7 -5
- package/dist/components/console/ConsoleAutocomplete.svelte +10 -11
- package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +6 -0
- package/dist/components/console/ConsoleInput.svelte +15 -6
- package/dist/components/console/ConsoleOutput.svelte +2 -1
- package/dist/components/form/FormArray.svelte +5 -9
- package/dist/components/form/FormArray.svelte.d.ts +2 -1
- package/dist/components/form/FormAutocomplete.svelte +16 -15
- package/dist/components/form/FormField.svelte +4 -2
- package/dist/components/form/FormFieldLight.svelte +34 -3
- package/dist/components/form/FormFieldLight.svelte.d.ts +12 -0
- package/dist/components/form/FormMarkdownEditor.svelte +9 -4
- package/dist/components/form/FormRangeField.svelte +1 -0
- package/dist/components/form/FormTemplateEditor.svelte +11 -3
- package/dist/components/form/FormToggle.svelte +5 -12
- package/dist/components/form/FormToggle.svelte.d.ts +4 -2
- package/dist/components/form/FormUISchemaRenderer.svelte +3 -1
- package/dist/components/form/templateAutocomplete.js +1 -5
- package/dist/components/form/types.d.ts +1 -14
- package/dist/components/interrupt/FormPrompt.svelte +3 -2
- package/dist/components/interrupt/InterruptBubble.svelte +25 -17
- package/dist/components/interrupt/ReviewPrompt.svelte +10 -3
- package/dist/components/interrupt/TextInputPrompt.svelte +2 -1
- package/dist/components/layouts/MainLayout.svelte +20 -13
- package/dist/components/layouts/MainLayout.svelte.d.ts +4 -0
- package/dist/components/nodes/AtomNode.svelte +17 -5
- package/dist/components/nodes/GatewayNode.svelte +19 -10
- package/dist/components/nodes/IdeaNode.svelte +7 -0
- package/dist/components/nodes/SimpleNode.svelte +11 -6
- package/dist/components/nodes/SquareNode.svelte +15 -8
- package/dist/components/nodes/TerminalNode.svelte +9 -4
- package/dist/components/nodes/ToolNode.svelte +7 -1
- package/dist/components/nodes/WorkflowNode.svelte +16 -7
- package/dist/components/playground/ChatInput.svelte +11 -14
- package/dist/components/playground/ChatPanel.svelte +6 -49
- package/dist/components/playground/ChatPanel.svelte.d.ts +0 -14
- package/dist/components/playground/ControlPanel.svelte +134 -123
- package/dist/components/playground/ControlPanel.svelte.d.ts +3 -0
- package/dist/components/playground/ExecutionLogs.svelte +11 -9
- package/dist/components/playground/InputCollector.svelte +11 -9
- package/dist/components/playground/MessageStream.svelte +17 -23
- package/dist/components/playground/PipelineKanbanView.svelte +69 -8
- package/dist/components/playground/PipelineKanbanView.svelte.d.ts +2 -0
- package/dist/components/playground/PipelinePanel.svelte +31 -8
- package/dist/components/playground/PipelinePanel.svelte.d.ts +2 -0
- package/dist/components/playground/PipelineTableView.svelte +188 -44
- package/dist/components/playground/PipelineTableView.svelte.d.ts +2 -0
- package/dist/components/playground/Playground.svelte +154 -105
- package/dist/components/playground/Playground.svelte.d.ts +5 -0
- package/dist/components/playground/PlaygroundApp.svelte +11 -1
- package/dist/components/playground/PlaygroundApp.svelte.d.ts +6 -0
- package/dist/components/playground/PlaygroundModal.svelte +18 -3
- package/dist/components/playground/PlaygroundModal.svelte.d.ts +6 -0
- package/dist/components/playground/PlaygroundStudio.svelte +40 -32
- package/dist/components/playground/PlaygroundStudio.svelte.d.ts +6 -0
- package/dist/components/playground/SessionManager.svelte +9 -12
- package/dist/components/playground/pipelineViewUtils.svelte.d.ts +30 -1
- package/dist/components/playground/pipelineViewUtils.svelte.js +40 -3
- package/dist/config/endpoints.d.ts +23 -7
- package/dist/config/endpoints.js +30 -10
- package/dist/core/index.d.ts +5 -6
- package/dist/core/index.js +8 -12
- package/dist/display/index.d.ts +6 -3
- package/dist/display/index.js +7 -5
- package/dist/editor/index.d.ts +20 -21
- package/dist/editor/index.js +26 -36
- package/dist/form/code.d.ts +25 -15
- package/dist/form/code.js +44 -41
- package/dist/form/fieldRegistry.d.ts +17 -13
- package/dist/form/fieldRegistry.js +32 -12
- package/dist/form/full.d.ts +19 -14
- package/dist/form/full.js +26 -28
- package/dist/form/index.d.ts +3 -4
- package/dist/form/index.js +6 -5
- package/dist/form/markdown.d.ts +13 -8
- package/dist/form/markdown.js +22 -23
- package/dist/helpers/proximityConnect.d.ts +3 -2
- package/dist/helpers/proximityConnect.js +2 -5
- package/dist/helpers/workflowEditorHelper.d.ts +14 -5
- package/dist/helpers/workflowEditorHelper.js +28 -25
- package/dist/index.d.ts +28 -24
- package/dist/index.js +27 -50
- package/dist/messages/defaults.d.ts +2 -5
- package/dist/messages/defaults.js +3 -6
- package/dist/messages/index.d.ts +0 -1
- package/dist/messages/index.js +0 -1
- package/dist/mocks/app-forms.d.ts +6 -2
- package/dist/mocks/app-forms.js +11 -4
- package/dist/openapi/v1/openapi.yaml +3 -3
- package/dist/playground/index.d.ts +4 -5
- package/dist/playground/index.js +4 -32
- package/dist/playground/mount.d.ts +25 -0
- package/dist/playground/mount.js +50 -20
- package/dist/registry/{BaseRegistry.d.ts → BaseRegistry.svelte.d.ts} +22 -1
- package/dist/registry/{BaseRegistry.js → BaseRegistry.svelte.js} +37 -1
- package/dist/registry/builtinFormats.d.ts +9 -18
- package/dist/registry/builtinFormats.js +9 -39
- package/dist/registry/builtinNodeTypes.d.ts +53 -0
- package/dist/registry/builtinNodeTypes.js +67 -0
- package/dist/registry/builtinNodes.d.ts +2 -64
- package/dist/registry/builtinNodes.js +7 -103
- package/dist/registry/index.d.ts +3 -4
- package/dist/registry/index.js +4 -6
- package/dist/registry/nodeComponentRegistry.d.ts +182 -15
- package/dist/registry/nodeComponentRegistry.js +235 -17
- package/dist/registry/workflowFormatRegistry.d.ts +14 -9
- package/dist/registry/workflowFormatRegistry.js +24 -8
- package/dist/{schema → schemas}/index.d.ts +2 -2
- package/dist/{schema → schemas}/index.js +2 -2
- package/dist/schemas/v1/workflow.schema.json +3 -3
- package/dist/services/agentSpecExecutionService.d.ts +0 -2
- package/dist/services/agentSpecExecutionService.js +0 -3
- package/dist/services/apiVariableService.d.ts +2 -1
- package/dist/services/apiVariableService.js +16 -47
- package/dist/services/autoSaveService.d.ts +7 -0
- package/dist/services/autoSaveService.js +6 -4
- package/dist/services/categoriesApi.js +3 -6
- package/dist/services/chatService.d.ts +9 -4
- package/dist/services/chatService.js +23 -28
- package/dist/services/draftStorage.d.ts +129 -13
- package/dist/services/draftStorage.js +185 -37
- package/dist/services/dynamicSchemaService.d.ts +2 -1
- package/dist/services/dynamicSchemaService.js +5 -22
- package/dist/services/globalSave.d.ts +13 -12
- package/dist/services/globalSave.js +29 -51
- package/dist/services/historyService.d.ts +9 -3
- package/dist/services/historyService.js +9 -3
- package/dist/services/interruptService.d.ts +15 -9
- package/dist/services/interruptService.js +35 -37
- package/dist/services/nodeExecutionService.d.ts +18 -3
- package/dist/services/nodeExecutionService.js +71 -45
- package/dist/services/playgroundService.d.ts +16 -10
- package/dist/services/playgroundService.js +42 -43
- package/dist/services/portConfigApi.js +3 -6
- package/dist/services/settingsService.d.ts +9 -4
- package/dist/services/settingsService.js +23 -12
- package/dist/services/variableService.d.ts +2 -1
- package/dist/services/variableService.js +2 -2
- package/dist/services/workflowStorage.js +6 -6
- package/dist/stores/apiContext.d.ts +56 -0
- package/dist/stores/apiContext.js +80 -0
- package/dist/stores/categoriesStore.svelte.d.ts +28 -23
- package/dist/stores/categoriesStore.svelte.js +69 -64
- package/dist/stores/getInstance.svelte.d.ts +39 -0
- package/dist/stores/getInstance.svelte.js +65 -0
- package/dist/stores/historyStore.svelte.d.ts +77 -93
- package/dist/stores/historyStore.svelte.js +134 -160
- package/dist/stores/instanceContainer.svelte.d.ts +111 -0
- package/dist/stores/instanceContainer.svelte.js +114 -0
- package/dist/stores/interruptStore.svelte.d.ts +112 -82
- package/dist/stores/interruptStore.svelte.js +253 -226
- package/dist/stores/pipelinePanelStore.svelte.d.ts +27 -3
- package/dist/stores/pipelinePanelStore.svelte.js +61 -14
- package/dist/stores/playgroundStore.svelte.d.ts +169 -222
- package/dist/stores/playgroundStore.svelte.js +513 -580
- package/dist/stores/portCoordinateStore.svelte.d.ts +57 -51
- package/dist/stores/portCoordinateStore.svelte.js +109 -98
- package/dist/stores/settingsStore.svelte.d.ts +4 -1
- package/dist/stores/settingsStore.svelte.js +47 -12
- package/dist/stores/workflowStore.svelte.d.ts +178 -213
- package/dist/stores/workflowStore.svelte.js +449 -501
- package/dist/stories/EdgeDecorator.svelte +5 -2
- package/dist/stories/NodeDecorator.svelte +5 -3
- package/dist/svelte-app.d.ts +60 -10
- package/dist/svelte-app.js +159 -54
- package/dist/types/auth.d.ts +9 -51
- package/dist/types/auth.js +4 -54
- package/dist/types/events.d.ts +6 -3
- package/dist/types/index.d.ts +37 -5
- package/dist/types/index.js +0 -1
- package/dist/types/navbar.d.ts +7 -0
- package/dist/types/playground.d.ts +18 -3
- package/dist/types/settings.d.ts +13 -0
- package/dist/types/settings.js +1 -0
- package/dist/utils/colors.d.ts +47 -21
- package/dist/utils/colors.js +69 -68
- package/dist/utils/connections.d.ts +9 -15
- package/dist/utils/connections.js +13 -32
- package/dist/utils/duration.d.ts +13 -0
- package/dist/utils/duration.js +45 -0
- package/dist/utils/edgeStyling.js +9 -5
- package/dist/utils/fetchWithAuth.d.ts +36 -15
- package/dist/utils/fetchWithAuth.js +53 -23
- package/dist/utils/icons.d.ts +5 -2
- package/dist/utils/icons.js +6 -5
- package/dist/utils/nodeSwap.d.ts +6 -2
- package/dist/utils/nodeSwap.js +62 -126
- package/dist/utils/nodeTypes.d.ts +17 -8
- package/dist/utils/nodeTypes.js +27 -20
- package/dist/utils/performanceUtils.js +7 -0
- package/package.json +7 -5
- package/dist/messages/deprecation.d.ts +0 -20
- package/dist/messages/deprecation.js +0 -33
- package/dist/registry/plugin.d.ts +0 -215
- package/dist/registry/plugin.js +0 -249
- package/dist/services/api.d.ts +0 -129
- package/dist/services/api.js +0 -217
|
@@ -8,7 +8,17 @@
|
|
|
8
8
|
* - External libraries to contribute node types via plugins
|
|
9
9
|
* - Runtime switching between different node visualizations
|
|
10
10
|
*/
|
|
11
|
-
import { BaseRegistry } from './BaseRegistry.js';
|
|
11
|
+
import { BaseRegistry } from './BaseRegistry.svelte.js';
|
|
12
|
+
/**
|
|
13
|
+
* Check if a namespace is valid.
|
|
14
|
+
* Must be lowercase alphanumeric with optional hyphens.
|
|
15
|
+
*
|
|
16
|
+
* @param namespace - The namespace to validate
|
|
17
|
+
* @returns true if valid
|
|
18
|
+
*/
|
|
19
|
+
export function isValidNamespace(namespace) {
|
|
20
|
+
return /^[a-z][a-z0-9-]*$/.test(namespace);
|
|
21
|
+
}
|
|
12
22
|
/**
|
|
13
23
|
* Central registry for node component types.
|
|
14
24
|
* Allows built-in and third-party components to be registered and resolved.
|
|
@@ -18,7 +28,7 @@ import { BaseRegistry } from './BaseRegistry.js';
|
|
|
18
28
|
* @example
|
|
19
29
|
* ```typescript
|
|
20
30
|
* // Register a custom node
|
|
21
|
-
*
|
|
31
|
+
* fd.nodes.register({
|
|
22
32
|
* type: "myCustomNode",
|
|
23
33
|
* displayName: "My Custom Node",
|
|
24
34
|
* component: MyCustomNodeComponent,
|
|
@@ -27,14 +37,37 @@ import { BaseRegistry } from './BaseRegistry.js';
|
|
|
27
37
|
* });
|
|
28
38
|
*
|
|
29
39
|
* // Get a component
|
|
30
|
-
* const component =
|
|
40
|
+
* const component = fd.nodes.getComponent("myCustomNode");
|
|
31
41
|
* ```
|
|
32
42
|
*/
|
|
33
|
-
class NodeComponentRegistry extends BaseRegistry {
|
|
43
|
+
export class NodeComponentRegistry extends BaseRegistry {
|
|
34
44
|
/** Default type to use when requested type is not found */
|
|
35
45
|
defaultType = 'workflowNode';
|
|
36
46
|
/** Initial default type, restored on clear() */
|
|
37
47
|
static INITIAL_DEFAULT_TYPE = 'workflowNode';
|
|
48
|
+
/**
|
|
49
|
+
* @param seed - Optional initial registrations and default type. When
|
|
50
|
+
* omitted the registry starts empty; instances created via
|
|
51
|
+
* `createFlowDropInstance` pass the built-in node components (see
|
|
52
|
+
* `builtinNodes.ts`).
|
|
53
|
+
*/
|
|
54
|
+
constructor(seed) {
|
|
55
|
+
super();
|
|
56
|
+
if (seed?.registrations) {
|
|
57
|
+
this.registerAll(seed.registrations, true);
|
|
58
|
+
}
|
|
59
|
+
if (seed?.defaultType) {
|
|
60
|
+
this.defaultType = seed.defaultType;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Clear all registrations and reset default type.
|
|
65
|
+
*/
|
|
66
|
+
clear() {
|
|
67
|
+
super.clear();
|
|
68
|
+
this.defaultType = NodeComponentRegistry.INITIAL_DEFAULT_TYPE;
|
|
69
|
+
this.touch(); // defaultType changed — invalidate getComponent/getDefaultType reads
|
|
70
|
+
}
|
|
38
71
|
/**
|
|
39
72
|
* Register a node component type.
|
|
40
73
|
*
|
|
@@ -44,7 +77,7 @@ class NodeComponentRegistry extends BaseRegistry {
|
|
|
44
77
|
*
|
|
45
78
|
* @example
|
|
46
79
|
* ```typescript
|
|
47
|
-
*
|
|
80
|
+
* fd.nodes.register({
|
|
48
81
|
* type: "fancy",
|
|
49
82
|
* displayName: "Fancy Node",
|
|
50
83
|
* component: FancyNode,
|
|
@@ -52,19 +85,13 @@ class NodeComponentRegistry extends BaseRegistry {
|
|
|
52
85
|
* });
|
|
53
86
|
* ```
|
|
54
87
|
*/
|
|
55
|
-
/**
|
|
56
|
-
* Clear all registrations and reset default type.
|
|
57
|
-
*/
|
|
58
|
-
clear() {
|
|
59
|
-
super.clear();
|
|
60
|
-
this.defaultType = NodeComponentRegistry.INITIAL_DEFAULT_TYPE;
|
|
61
|
-
}
|
|
62
88
|
register(registration, overwrite = false) {
|
|
63
89
|
if (this.items.has(registration.type) && !overwrite) {
|
|
64
90
|
throw new Error(`Node type "${registration.type}" is already registered. ` +
|
|
65
91
|
`Use overwrite: true to replace it, or use a namespaced type like "mylib:${registration.type}".`);
|
|
66
92
|
}
|
|
67
93
|
this.items.set(registration.type, registration);
|
|
94
|
+
this.touch();
|
|
68
95
|
this.notifyListeners();
|
|
69
96
|
}
|
|
70
97
|
/**
|
|
@@ -86,6 +113,7 @@ class NodeComponentRegistry extends BaseRegistry {
|
|
|
86
113
|
* @returns The component if found, or the default component
|
|
87
114
|
*/
|
|
88
115
|
getComponent(type) {
|
|
116
|
+
this.trackVersion(); // reactive dependency (reads items + defaultType directly)
|
|
89
117
|
const registration = this.items.get(type) ?? this.items.get(this.defaultType);
|
|
90
118
|
return registration?.component;
|
|
91
119
|
}
|
|
@@ -96,6 +124,7 @@ class NodeComponentRegistry extends BaseRegistry {
|
|
|
96
124
|
* @returns The metadata if found, undefined otherwise
|
|
97
125
|
*/
|
|
98
126
|
getMetadata(type) {
|
|
127
|
+
this.trackVersion(); // reactive dependency (reads items directly)
|
|
99
128
|
const reg = this.items.get(type);
|
|
100
129
|
if (!reg)
|
|
101
130
|
return undefined;
|
|
@@ -119,10 +148,10 @@ class NodeComponentRegistry extends BaseRegistry {
|
|
|
119
148
|
* @example
|
|
120
149
|
* ```typescript
|
|
121
150
|
* // Get all visual nodes
|
|
122
|
-
* const visualNodes =
|
|
151
|
+
* const visualNodes = fd.nodes.filter({ category: "visual" });
|
|
123
152
|
*
|
|
124
153
|
* // Get nodes from a specific library
|
|
125
|
-
* const libNodes =
|
|
154
|
+
* const libNodes = fd.nodes.filter({ source: "mylib" });
|
|
126
155
|
* ```
|
|
127
156
|
*/
|
|
128
157
|
filter(filter) {
|
|
@@ -168,6 +197,7 @@ class NodeComponentRegistry extends BaseRegistry {
|
|
|
168
197
|
throw new Error(`Cannot set default to unregistered type: ${type}`);
|
|
169
198
|
}
|
|
170
199
|
this.defaultType = type;
|
|
200
|
+
this.touch(); // defaultType changed — invalidate getComponent/getDefaultType reads
|
|
171
201
|
}
|
|
172
202
|
/**
|
|
173
203
|
* Get the current default type.
|
|
@@ -175,6 +205,7 @@ class NodeComponentRegistry extends BaseRegistry {
|
|
|
175
205
|
* @returns The default type identifier
|
|
176
206
|
*/
|
|
177
207
|
getDefaultType() {
|
|
208
|
+
this.trackVersion(); // reactive dependency (reads defaultType directly)
|
|
178
209
|
return this.defaultType;
|
|
179
210
|
}
|
|
180
211
|
/**
|
|
@@ -186,7 +217,7 @@ class NodeComponentRegistry extends BaseRegistry {
|
|
|
186
217
|
*
|
|
187
218
|
* @example
|
|
188
219
|
* ```typescript
|
|
189
|
-
* const oneOf =
|
|
220
|
+
* const oneOf = fd.nodes.getOneOfOptions();
|
|
190
221
|
* // Use in configSchema: { type: "string", oneOf }
|
|
191
222
|
* ```
|
|
192
223
|
*/
|
|
@@ -204,6 +235,7 @@ class NodeComponentRegistry extends BaseRegistry {
|
|
|
204
235
|
* @returns The status position, or default "top-right"
|
|
205
236
|
*/
|
|
206
237
|
getStatusPosition(type) {
|
|
238
|
+
this.trackVersion(); // reactive dependency (reads items directly)
|
|
207
239
|
return this.items.get(type)?.statusPosition ?? 'top-right';
|
|
208
240
|
}
|
|
209
241
|
/**
|
|
@@ -213,11 +245,197 @@ class NodeComponentRegistry extends BaseRegistry {
|
|
|
213
245
|
* @returns The status size, or default "md"
|
|
214
246
|
*/
|
|
215
247
|
getStatusSize(type) {
|
|
248
|
+
this.trackVersion(); // reactive dependency (reads items directly)
|
|
216
249
|
return this.items.get(type)?.statusSize ?? 'md';
|
|
217
250
|
}
|
|
251
|
+
// ==========================================================================
|
|
252
|
+
// Plugin system
|
|
253
|
+
// ==========================================================================
|
|
254
|
+
/**
|
|
255
|
+
* Register a single custom node without a full plugin.
|
|
256
|
+
* Useful for project-specific custom nodes.
|
|
257
|
+
*
|
|
258
|
+
* @param type - Type identifier (can be namespaced or plain)
|
|
259
|
+
* @param displayName - Display name for UI
|
|
260
|
+
* @param component - Svelte component
|
|
261
|
+
* @param options - Additional options
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```typescript
|
|
265
|
+
* fd.nodes.registerCustom("myproject:special", "Special Node", MyNode, {
|
|
266
|
+
* icon: "mdi:star",
|
|
267
|
+
* description: "A special node for my project"
|
|
268
|
+
* });
|
|
269
|
+
* ```
|
|
270
|
+
*/
|
|
271
|
+
registerCustom(type, displayName, component, options = {}) {
|
|
272
|
+
this.register({
|
|
273
|
+
type,
|
|
274
|
+
displayName,
|
|
275
|
+
component,
|
|
276
|
+
description: options.description,
|
|
277
|
+
icon: options.icon,
|
|
278
|
+
category: options.category ?? 'custom',
|
|
279
|
+
source: options.source ?? 'custom',
|
|
280
|
+
statusPosition: options.statusPosition,
|
|
281
|
+
statusSize: options.statusSize
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Register a FlowDrop plugin with custom node components.
|
|
286
|
+
* All node types are automatically namespaced with the plugin namespace.
|
|
287
|
+
*
|
|
288
|
+
* @param config - Plugin configuration with namespace and node definitions
|
|
289
|
+
* @returns Result object with registered types and any errors
|
|
290
|
+
*/
|
|
291
|
+
registerPlugin(config) {
|
|
292
|
+
const result = {
|
|
293
|
+
success: true,
|
|
294
|
+
namespace: config.namespace,
|
|
295
|
+
registeredTypes: [],
|
|
296
|
+
errors: []
|
|
297
|
+
};
|
|
298
|
+
// Validate namespace
|
|
299
|
+
if (!isValidNamespace(config.namespace)) {
|
|
300
|
+
result.success = false;
|
|
301
|
+
result.errors.push(`Invalid namespace "${config.namespace}". ` +
|
|
302
|
+
`Namespace must be lowercase alphanumeric with optional hyphens.`);
|
|
303
|
+
return result;
|
|
304
|
+
}
|
|
305
|
+
// Register each node
|
|
306
|
+
for (const nodeDef of config.nodes) {
|
|
307
|
+
try {
|
|
308
|
+
const namespacedType = createNamespacedType(config.namespace, nodeDef.type);
|
|
309
|
+
const registration = {
|
|
310
|
+
type: namespacedType,
|
|
311
|
+
displayName: nodeDef.displayName,
|
|
312
|
+
description: nodeDef.description,
|
|
313
|
+
component: nodeDef.component,
|
|
314
|
+
icon: nodeDef.icon,
|
|
315
|
+
category: nodeDef.category ?? 'custom',
|
|
316
|
+
source: config.namespace,
|
|
317
|
+
statusPosition: nodeDef.statusPosition,
|
|
318
|
+
statusSize: nodeDef.statusSize
|
|
319
|
+
};
|
|
320
|
+
this.register(registration);
|
|
321
|
+
result.registeredTypes.push(namespacedType);
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
result.success = false;
|
|
325
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
326
|
+
result.errors.push(`Failed to register ${config.namespace}:${nodeDef.type}: ${errorMessage}`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Unregister all nodes from a plugin by namespace.
|
|
333
|
+
*
|
|
334
|
+
* @param namespace - The plugin namespace to unregister
|
|
335
|
+
* @returns Array of unregistered type identifiers
|
|
336
|
+
*/
|
|
337
|
+
unregisterPlugin(namespace) {
|
|
338
|
+
const unregistered = [];
|
|
339
|
+
const types = this.getTypes();
|
|
340
|
+
for (const type of types) {
|
|
341
|
+
if (type.startsWith(`${namespace}:`)) {
|
|
342
|
+
if (this.unregister(type)) {
|
|
343
|
+
unregistered.push(type);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return unregistered;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Get all registered plugins (unique namespaces).
|
|
351
|
+
*
|
|
352
|
+
* @returns Array of namespace strings
|
|
353
|
+
*/
|
|
354
|
+
getRegisteredPlugins() {
|
|
355
|
+
const sources = new Set();
|
|
356
|
+
for (const reg of this.getAll()) {
|
|
357
|
+
if (reg.source && reg.source !== 'flowdrop') {
|
|
358
|
+
sources.add(reg.source);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return Array.from(sources);
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Get the count of nodes registered by a plugin.
|
|
365
|
+
*
|
|
366
|
+
* @param namespace - The plugin namespace
|
|
367
|
+
* @returns Number of nodes registered by this plugin
|
|
368
|
+
*/
|
|
369
|
+
getPluginNodeCount(namespace) {
|
|
370
|
+
return this.getBySource(namespace).length;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Create a plugin builder for a fluent API experience.
|
|
375
|
+
*
|
|
376
|
+
* @param namespace - Plugin namespace
|
|
377
|
+
* @param name - Plugin name
|
|
378
|
+
* @returns Plugin builder with chainable methods
|
|
379
|
+
*
|
|
380
|
+
* @example
|
|
381
|
+
* ```typescript
|
|
382
|
+
* import { createPlugin } from "@flowdrop/flowdrop/editor";
|
|
383
|
+
*
|
|
384
|
+
* createPlugin("awesome", "Awesome Nodes")
|
|
385
|
+
* .version("1.0.0")
|
|
386
|
+
* .node("fancy", "Fancy Node", FancyNode)
|
|
387
|
+
* .node("glow", "Glowing Node", GlowNode, { icon: "mdi:lightbulb" })
|
|
388
|
+
* .register(fd.nodes);
|
|
389
|
+
* ```
|
|
390
|
+
*/
|
|
391
|
+
export function createPlugin(namespace, name) {
|
|
392
|
+
const config = {
|
|
393
|
+
namespace,
|
|
394
|
+
name,
|
|
395
|
+
nodes: []
|
|
396
|
+
};
|
|
397
|
+
const builder = {
|
|
398
|
+
/**
|
|
399
|
+
* Set plugin version
|
|
400
|
+
*/
|
|
401
|
+
version(v) {
|
|
402
|
+
config.version = v;
|
|
403
|
+
return builder;
|
|
404
|
+
},
|
|
405
|
+
/**
|
|
406
|
+
* Set plugin description
|
|
407
|
+
*/
|
|
408
|
+
description(desc) {
|
|
409
|
+
config.description = desc;
|
|
410
|
+
return builder;
|
|
411
|
+
},
|
|
412
|
+
/**
|
|
413
|
+
* Add a node to the plugin
|
|
414
|
+
*/
|
|
415
|
+
node(type, displayName, component, options = {}) {
|
|
416
|
+
config.nodes.push({
|
|
417
|
+
type,
|
|
418
|
+
displayName,
|
|
419
|
+
component,
|
|
420
|
+
...options
|
|
421
|
+
});
|
|
422
|
+
return builder;
|
|
423
|
+
},
|
|
424
|
+
/**
|
|
425
|
+
* Register the plugin into a node component registry (e.g. `fd.nodes`).
|
|
426
|
+
*/
|
|
427
|
+
register(registry) {
|
|
428
|
+
return registry.registerPlugin(config);
|
|
429
|
+
},
|
|
430
|
+
/**
|
|
431
|
+
* Get the config without registering (for testing/inspection)
|
|
432
|
+
*/
|
|
433
|
+
getConfig() {
|
|
434
|
+
return { ...config };
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
return builder;
|
|
218
438
|
}
|
|
219
|
-
/** Singleton instance of the node component registry */
|
|
220
|
-
export const nodeComponentRegistry = new NodeComponentRegistry();
|
|
221
439
|
/**
|
|
222
440
|
* Helper function to create a namespaced type identifier.
|
|
223
441
|
* Use this to avoid conflicts when registering custom nodes.
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import type { StandardWorkflow } from '../adapters/WorkflowAdapter.js';
|
|
15
15
|
import type { NodeMetadata, WorkflowFormat } from '../types/index.js';
|
|
16
|
-
import { BaseRegistry } from './BaseRegistry.js';
|
|
16
|
+
import { BaseRegistry } from './BaseRegistry.svelte.js';
|
|
17
17
|
/**
|
|
18
18
|
* Validation result returned by format adapters.
|
|
19
19
|
*/
|
|
@@ -60,13 +60,15 @@ export interface WorkflowFormatAdapter {
|
|
|
60
60
|
validate?(workflow: StandardWorkflow): FormatValidationResult;
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
63
|
+
* Per-instance registry for workflow format adapters.
|
|
64
|
+
* Extends BaseRegistry for shared mechanics; seeded with the built-in
|
|
65
|
+
* adapters at construction (see `createFlowDropInstance`). Reach it via
|
|
66
|
+
* `fd.formats`, or supply adapters through the `formatAdapters` mount option.
|
|
65
67
|
*
|
|
66
68
|
* @example
|
|
67
69
|
* ```typescript
|
|
68
70
|
* // Register a custom format
|
|
69
|
-
*
|
|
71
|
+
* fd.formats.register({
|
|
70
72
|
* id: 'n8n',
|
|
71
73
|
* name: 'n8n Workflow',
|
|
72
74
|
* export: (workflow) => JSON.stringify(convertToN8n(workflow)),
|
|
@@ -74,10 +76,16 @@ export interface WorkflowFormatAdapter {
|
|
|
74
76
|
* });
|
|
75
77
|
*
|
|
76
78
|
* // Get an adapter
|
|
77
|
-
* const adapter =
|
|
79
|
+
* const adapter = fd.formats.get('n8n');
|
|
78
80
|
* ```
|
|
79
81
|
*/
|
|
80
|
-
declare class WorkflowFormatRegistry extends BaseRegistry<string, WorkflowFormatAdapter> {
|
|
82
|
+
export declare class WorkflowFormatRegistry extends BaseRegistry<string, WorkflowFormatAdapter> {
|
|
83
|
+
/**
|
|
84
|
+
* @param seed - Optional initial format adapters. When omitted the registry
|
|
85
|
+
* starts empty; instances created via `createFlowDropInstance` pass the
|
|
86
|
+
* built-in flowdrop + agentspec adapters (see `builtinFormats.ts`).
|
|
87
|
+
*/
|
|
88
|
+
constructor(seed?: WorkflowFormatAdapter[]);
|
|
81
89
|
/**
|
|
82
90
|
* Register a workflow format adapter.
|
|
83
91
|
*
|
|
@@ -117,6 +125,3 @@ declare class WorkflowFormatRegistry extends BaseRegistry<string, WorkflowFormat
|
|
|
117
125
|
title: string;
|
|
118
126
|
}>;
|
|
119
127
|
}
|
|
120
|
-
/** Singleton instance of the workflow format registry */
|
|
121
|
-
export declare const workflowFormatRegistry: WorkflowFormatRegistry;
|
|
122
|
-
export {};
|
|
@@ -11,15 +11,17 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Extends BaseRegistry for shared mechanics (subscribe, onClear, etc.).
|
|
13
13
|
*/
|
|
14
|
-
import { BaseRegistry } from './BaseRegistry.js';
|
|
14
|
+
import { BaseRegistry } from './BaseRegistry.svelte.js';
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* Per-instance registry for workflow format adapters.
|
|
17
|
+
* Extends BaseRegistry for shared mechanics; seeded with the built-in
|
|
18
|
+
* adapters at construction (see `createFlowDropInstance`). Reach it via
|
|
19
|
+
* `fd.formats`, or supply adapters through the `formatAdapters` mount option.
|
|
18
20
|
*
|
|
19
21
|
* @example
|
|
20
22
|
* ```typescript
|
|
21
23
|
* // Register a custom format
|
|
22
|
-
*
|
|
24
|
+
* fd.formats.register({
|
|
23
25
|
* id: 'n8n',
|
|
24
26
|
* name: 'n8n Workflow',
|
|
25
27
|
* export: (workflow) => JSON.stringify(convertToN8n(workflow)),
|
|
@@ -27,10 +29,23 @@ import { BaseRegistry } from './BaseRegistry.js';
|
|
|
27
29
|
* });
|
|
28
30
|
*
|
|
29
31
|
* // Get an adapter
|
|
30
|
-
* const adapter =
|
|
32
|
+
* const adapter = fd.formats.get('n8n');
|
|
31
33
|
* ```
|
|
32
34
|
*/
|
|
33
|
-
class WorkflowFormatRegistry extends BaseRegistry {
|
|
35
|
+
export class WorkflowFormatRegistry extends BaseRegistry {
|
|
36
|
+
/**
|
|
37
|
+
* @param seed - Optional initial format adapters. When omitted the registry
|
|
38
|
+
* starts empty; instances created via `createFlowDropInstance` pass the
|
|
39
|
+
* built-in flowdrop + agentspec adapters (see `builtinFormats.ts`).
|
|
40
|
+
*/
|
|
41
|
+
constructor(seed) {
|
|
42
|
+
super();
|
|
43
|
+
if (seed) {
|
|
44
|
+
for (const adapter of seed) {
|
|
45
|
+
this.register(adapter, true);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
34
49
|
/**
|
|
35
50
|
* Register a workflow format adapter.
|
|
36
51
|
*
|
|
@@ -44,6 +59,7 @@ class WorkflowFormatRegistry extends BaseRegistry {
|
|
|
44
59
|
`Use overwrite: true to replace it.`);
|
|
45
60
|
}
|
|
46
61
|
this.items.set(adapter.id, adapter);
|
|
62
|
+
this.touch();
|
|
47
63
|
this.notifyListeners();
|
|
48
64
|
}
|
|
49
65
|
/**
|
|
@@ -61,6 +77,7 @@ class WorkflowFormatRegistry extends BaseRegistry {
|
|
|
61
77
|
* @returns Array of NodeMetadata from all format adapters
|
|
62
78
|
*/
|
|
63
79
|
getAllFormatNodes() {
|
|
80
|
+
this.trackVersion(); // reactive dependency (reads items directly)
|
|
64
81
|
const allNodes = [];
|
|
65
82
|
for (const adapter of this.items.values()) {
|
|
66
83
|
if (adapter.nodes && adapter.nodes.length > 0) {
|
|
@@ -76,6 +93,7 @@ class WorkflowFormatRegistry extends BaseRegistry {
|
|
|
76
93
|
* @returns Array of NodeMetadata for the format, or empty array
|
|
77
94
|
*/
|
|
78
95
|
getFormatNodes(formatId) {
|
|
96
|
+
this.trackVersion(); // reactive dependency (reads items directly)
|
|
79
97
|
const adapter = this.items.get(formatId);
|
|
80
98
|
return adapter?.nodes ?? [];
|
|
81
99
|
}
|
|
@@ -92,5 +110,3 @@ class WorkflowFormatRegistry extends BaseRegistry {
|
|
|
92
110
|
}));
|
|
93
111
|
}
|
|
94
112
|
}
|
|
95
|
-
/** Singleton instance of the workflow format registry */
|
|
96
|
-
export const workflowFormatRegistry = new WorkflowFormatRegistry();
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
* const valid = validate(myWorkflow);
|
|
16
16
|
* ```
|
|
17
17
|
*
|
|
18
|
-
* @module
|
|
18
|
+
* @module schemas
|
|
19
19
|
*/
|
|
20
|
-
import workflowSchema from '
|
|
20
|
+
import workflowSchema from './v1/workflow.schema.json';
|
|
21
21
|
/** Current workflow schema format version */
|
|
22
22
|
export declare const WORKFLOW_SCHEMA_VERSION = "1.0.0";
|
|
23
23
|
export { workflowSchema };
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
* const valid = validate(myWorkflow);
|
|
16
16
|
* ```
|
|
17
17
|
*
|
|
18
|
-
* @module
|
|
18
|
+
* @module schemas
|
|
19
19
|
*/
|
|
20
|
-
import workflowSchema from '
|
|
20
|
+
import workflowSchema from './v1/workflow.schema.json';
|
|
21
21
|
/** Current workflow schema format version */
|
|
22
22
|
export const WORKFLOW_SCHEMA_VERSION = '1.0.0';
|
|
23
23
|
export { workflowSchema };
|
|
@@ -1053,9 +1053,9 @@
|
|
|
1053
1053
|
"WorkflowMetadata": {
|
|
1054
1054
|
"type": "object",
|
|
1055
1055
|
"properties": {
|
|
1056
|
-
"
|
|
1056
|
+
"schemaVersion": {
|
|
1057
1057
|
"type": "string",
|
|
1058
|
-
"description": "Workflow version"
|
|
1058
|
+
"description": "Workflow schema format version — identifies the document format, not the workflow's own revision."
|
|
1059
1059
|
},
|
|
1060
1060
|
"createdAt": {
|
|
1061
1061
|
"type": "string",
|
|
@@ -1093,7 +1093,7 @@
|
|
|
1093
1093
|
}
|
|
1094
1094
|
},
|
|
1095
1095
|
"required": [
|
|
1096
|
-
"
|
|
1096
|
+
"schemaVersion",
|
|
1097
1097
|
"createdAt",
|
|
1098
1098
|
"updatedAt"
|
|
1099
1099
|
]
|
|
@@ -227,7 +227,6 @@ export class AgentSpecExecutionService {
|
|
|
227
227
|
/** Get the config, throwing if not configured */
|
|
228
228
|
getConfig() {
|
|
229
229
|
this.ensureConfigured();
|
|
230
|
-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
231
230
|
return this.config;
|
|
232
231
|
}
|
|
233
232
|
startPolling(executionId, nameToNodeId, onNodeUpdate, onComplete, onError, intervalMs = 2000) {
|
|
@@ -333,5 +332,3 @@ export class AgentSpecExecutionService {
|
|
|
333
332
|
}
|
|
334
333
|
}
|
|
335
334
|
}
|
|
336
|
-
/** Singleton instance */
|
|
337
|
-
export const agentSpecExecutionService = AgentSpecExecutionService.getInstance();
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* @module services/apiVariableService
|
|
7
7
|
*/
|
|
8
8
|
import type { VariableSchema, ApiVariablesConfig, AuthProvider } from '../types/index.js';
|
|
9
|
+
import type { EndpointConfig } from '../config/endpoints.js';
|
|
9
10
|
/**
|
|
10
11
|
* Context for variable API requests
|
|
11
12
|
*/
|
|
@@ -71,7 +72,7 @@ export declare function resolveEndpointUrl(template: string, context: VariableCo
|
|
|
71
72
|
* }
|
|
72
73
|
* ```
|
|
73
74
|
*/
|
|
74
|
-
export declare function fetchVariableSchema(workflowId: string | undefined, nodeId: string, config: ApiVariablesConfig, authProvider?: AuthProvider): Promise<ApiVariableResult>;
|
|
75
|
+
export declare function fetchVariableSchema(endpointConfig: EndpointConfig | null, workflowId: string | undefined, nodeId: string, config: ApiVariablesConfig, authProvider?: AuthProvider): Promise<ApiVariableResult>;
|
|
75
76
|
/**
|
|
76
77
|
* Clears the variable schema cache.
|
|
77
78
|
* Can optionally clear only entries matching a specific pattern.
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @module services/apiVariableService
|
|
7
7
|
*/
|
|
8
|
-
import { getEndpointConfig } from './api.js';
|
|
9
|
-
import { logger } from '../utils/logger.js';
|
|
10
8
|
import { DEFAULT_CACHE_TTL_MS } from '../config/constants.js';
|
|
9
|
+
import { authenticatedFetch } from '../utils/fetchWithAuth.js';
|
|
11
10
|
/**
|
|
12
11
|
* Variable schema cache with TTL support
|
|
13
12
|
* Key format: `variables:{workflowId}:{nodeId}`
|
|
@@ -116,7 +115,7 @@ function resolveBodyTemplates(body, context) {
|
|
|
116
115
|
* }
|
|
117
116
|
* ```
|
|
118
117
|
*/
|
|
119
|
-
export async function fetchVariableSchema(workflowId, nodeId, config, authProvider) {
|
|
118
|
+
export async function fetchVariableSchema(endpointConfig, workflowId, nodeId, config, authProvider) {
|
|
120
119
|
const endpoint = config.endpoint;
|
|
121
120
|
const context = { workflowId, nodeId };
|
|
122
121
|
// Generate cache key
|
|
@@ -136,48 +135,16 @@ export async function fetchVariableSchema(workflowId, nodeId, config, authProvid
|
|
|
136
135
|
// Resolve the URL with template variables
|
|
137
136
|
let url = resolveEndpointUrl(endpoint.url, context);
|
|
138
137
|
// If URL is relative, prepend base URL from endpoint config
|
|
139
|
-
if (url.startsWith('/')) {
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
const baseUrl = currentConfig.baseUrl.replace(/\/$/, '');
|
|
143
|
-
url = `${baseUrl}${url}`;
|
|
144
|
-
}
|
|
138
|
+
if (url.startsWith('/') && endpointConfig?.baseUrl) {
|
|
139
|
+
const baseUrl = endpointConfig.baseUrl.replace(/\/$/, '');
|
|
140
|
+
url = `${baseUrl}${url}`;
|
|
145
141
|
}
|
|
146
142
|
// Prepare request options
|
|
147
143
|
const method = endpoint.method ?? 'GET';
|
|
148
144
|
const timeout = endpoint.timeout ?? 30000;
|
|
149
|
-
const headers = {
|
|
150
|
-
Accept: 'application/json',
|
|
151
|
-
'Content-Type': 'application/json',
|
|
152
|
-
...endpoint.headers
|
|
153
|
-
};
|
|
154
|
-
// Add auth headers from AuthProvider if available
|
|
155
|
-
if (authProvider) {
|
|
156
|
-
try {
|
|
157
|
-
const authHeaders = await authProvider.getAuthHeaders();
|
|
158
|
-
Object.assign(headers, authHeaders);
|
|
159
|
-
}
|
|
160
|
-
catch (error) {
|
|
161
|
-
logger.warn('Failed to get auth headers:', error);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
// Add auth headers from endpoint config as fallback
|
|
165
|
-
const currentConfig = getEndpointConfig();
|
|
166
|
-
if (currentConfig?.auth) {
|
|
167
|
-
if (currentConfig.auth.type === 'bearer' && currentConfig.auth.token) {
|
|
168
|
-
headers['Authorization'] = headers['Authorization'] ?? `Bearer ${currentConfig.auth.token}`;
|
|
169
|
-
}
|
|
170
|
-
else if (currentConfig.auth.type === 'api_key' && currentConfig.auth.apiKey) {
|
|
171
|
-
headers['X-API-Key'] = headers['X-API-Key'] ?? currentConfig.auth.apiKey;
|
|
172
|
-
}
|
|
173
|
-
else if (currentConfig.auth.type === 'custom' && currentConfig.auth.headers) {
|
|
174
|
-
Object.assign(headers, currentConfig.auth.headers);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
145
|
// Prepare fetch options
|
|
178
146
|
const fetchOptions = {
|
|
179
147
|
method,
|
|
180
|
-
headers,
|
|
181
148
|
signal: AbortSignal.timeout(timeout)
|
|
182
149
|
};
|
|
183
150
|
// Add body for non-GET requests
|
|
@@ -186,7 +153,16 @@ export async function fetchVariableSchema(workflowId, nodeId, config, authProvid
|
|
|
186
153
|
fetchOptions.body = JSON.stringify(resolvedBody);
|
|
187
154
|
}
|
|
188
155
|
try {
|
|
189
|
-
|
|
156
|
+
// authenticatedFetch merges auth headers and transparently refreshes +
|
|
157
|
+
// retries once on 401 via the provider's onUnauthorized hook.
|
|
158
|
+
const response = await authenticatedFetch(url, fetchOptions, {
|
|
159
|
+
authProvider,
|
|
160
|
+
baseHeaders: {
|
|
161
|
+
Accept: 'application/json',
|
|
162
|
+
'Content-Type': 'application/json',
|
|
163
|
+
...endpoint.headers
|
|
164
|
+
}
|
|
165
|
+
});
|
|
190
166
|
// Handle 404 as "no variables available"
|
|
191
167
|
if (response.status === 404) {
|
|
192
168
|
return {
|
|
@@ -196,15 +172,8 @@ export async function fetchVariableSchema(workflowId, nodeId, config, authProvid
|
|
|
196
172
|
};
|
|
197
173
|
}
|
|
198
174
|
if (!response.ok) {
|
|
199
|
-
//
|
|
175
|
+
// Auth errors remain after the provider's refresh attempt.
|
|
200
176
|
if (response.status === 401 || response.status === 403) {
|
|
201
|
-
if (authProvider?.onUnauthorized) {
|
|
202
|
-
const refreshed = await authProvider.onUnauthorized();
|
|
203
|
-
if (refreshed) {
|
|
204
|
-
// Retry with refreshed auth
|
|
205
|
-
return fetchVariableSchema(workflowId, nodeId, config, authProvider);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
177
|
return {
|
|
209
178
|
success: false,
|
|
210
179
|
error: 'Authentication failed'
|