@d34dman/flowdrop 0.0.61 → 0.0.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/adapters/WorkflowAdapter.d.ts +1 -1
- package/dist/adapters/agentspec/AgentSpecAdapter.js +3 -1
- package/dist/api/client.d.ts +4 -0
- package/dist/api/client.js +6 -1
- package/dist/api/enhanced-client.js +7 -6
- package/dist/components/App.svelte +143 -219
- package/dist/components/CanvasBanner.stories.svelte +25 -0
- package/dist/components/CanvasBanner.stories.svelte.d.ts +27 -0
- package/dist/components/CanvasBanner.svelte +2 -2
- package/dist/components/ConfigForm.svelte +37 -36
- package/dist/components/ConfigPanel.stories.svelte +38 -0
- package/dist/components/ConfigPanel.stories.svelte.d.ts +27 -0
- package/dist/components/ConfigPanel.svelte +2 -2
- package/dist/components/ConnectionLine.svelte +2 -2
- package/dist/components/FlowDropZone.svelte +18 -2
- package/dist/components/FlowDropZone.svelte.d.ts +2 -0
- package/dist/components/LoadingSpinner.stories.svelte +30 -0
- package/dist/components/LoadingSpinner.stories.svelte.d.ts +27 -0
- package/dist/components/Logo.stories.svelte +22 -0
- package/dist/components/Logo.stories.svelte.d.ts +27 -0
- package/dist/components/Logo.svelte +33 -13
- package/dist/components/Logo.svelte.d.ts +1 -1
- package/dist/components/MarkdownDisplay.stories.svelte +21 -0
- package/dist/components/MarkdownDisplay.stories.svelte.d.ts +27 -0
- package/dist/components/MarkdownDisplay.svelte +4 -3
- package/dist/components/Navbar.stories.svelte +41 -0
- package/dist/components/Navbar.stories.svelte.d.ts +27 -0
- package/dist/components/Navbar.svelte +4 -4
- package/dist/components/NodeSidebar.svelte +12 -12
- package/dist/components/NodeStatusOverlay.stories.svelte +74 -0
- package/dist/components/NodeStatusOverlay.stories.svelte.d.ts +27 -0
- package/dist/components/PipelineStatus.svelte +11 -4
- package/dist/components/PortCoordinateTracker.svelte +1 -1
- package/dist/components/SchemaForm.stories.svelte +101 -0
- package/dist/components/SchemaForm.stories.svelte.d.ts +27 -0
- package/dist/components/SchemaForm.svelte +17 -12
- package/dist/components/SettingsModal.svelte +3 -3
- package/dist/components/SettingsPanel.svelte +23 -22
- package/dist/components/StatusIcon.stories.svelte +60 -0
- package/dist/components/StatusIcon.stories.svelte.d.ts +27 -0
- package/dist/components/StatusIcon.svelte +7 -0
- package/dist/components/StatusLabel.stories.svelte +17 -0
- package/dist/components/StatusLabel.stories.svelte.d.ts +27 -0
- package/dist/components/ThemeToggle.stories.svelte +25 -0
- package/dist/components/ThemeToggle.stories.svelte.d.ts +27 -0
- package/dist/components/ThemeToggle.svelte +8 -8
- package/dist/components/UniversalNode.svelte +1 -1
- package/dist/components/WorkflowEditor.svelte +298 -298
- package/dist/components/form/FormAutocomplete.svelte +20 -19
- package/dist/components/form/FormCheckboxGroup.stories.svelte +28 -0
- package/dist/components/form/FormCheckboxGroup.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormField.svelte +3 -3
- package/dist/components/form/FormFieldLight.svelte +2 -2
- package/dist/components/form/FormFieldWrapper.stories.svelte +31 -0
- package/dist/components/form/FormFieldWrapper.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormFieldset.svelte +7 -7
- package/dist/components/form/FormNumberField.stories.svelte +33 -0
- package/dist/components/form/FormNumberField.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormRangeField.stories.svelte +31 -0
- package/dist/components/form/FormRangeField.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormSelect.stories.svelte +50 -0
- package/dist/components/form/FormSelect.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormTemplateEditor.svelte +2 -1
- package/dist/components/form/FormTextField.stories.svelte +30 -0
- package/dist/components/form/FormTextField.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormTextarea.stories.svelte +31 -0
- package/dist/components/form/FormTextarea.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormToggle.stories.svelte +30 -0
- package/dist/components/form/FormToggle.stories.svelte.d.ts +27 -0
- package/dist/components/form/FormUISchemaRenderer.svelte +1 -1
- package/dist/components/form/types.d.ts +15 -47
- package/dist/components/interrupt/ChoicePrompt.stories.svelte +43 -0
- package/dist/components/interrupt/ChoicePrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/ChoicePrompt.svelte +24 -24
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte +49 -0
- package/dist/components/interrupt/ConfirmationPrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/ConfirmationPrompt.svelte +19 -19
- package/dist/components/interrupt/FormPrompt.svelte +15 -15
- package/dist/components/interrupt/InterruptBubble.svelte +202 -236
- package/dist/components/interrupt/InterruptBubble.svelte.d.ts +1 -1
- package/dist/components/interrupt/ReviewPrompt.stories.svelte +46 -0
- package/dist/components/interrupt/ReviewPrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/ReviewPrompt.svelte +842 -0
- package/dist/components/interrupt/ReviewPrompt.svelte.d.ts +23 -0
- package/dist/components/interrupt/TextInputPrompt.stories.svelte +34 -0
- package/dist/components/interrupt/TextInputPrompt.stories.svelte.d.ts +27 -0
- package/dist/components/interrupt/TextInputPrompt.svelte +21 -21
- package/dist/components/nodes/GatewayNode.stories.svelte +76 -0
- package/dist/components/nodes/GatewayNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/GatewayNode.svelte +19 -17
- package/dist/components/nodes/IdeaNode.stories.svelte +48 -0
- package/dist/components/nodes/IdeaNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/IdeaNode.svelte +10 -26
- package/dist/components/nodes/NotesNode.stories.svelte +69 -0
- package/dist/components/nodes/NotesNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/NotesNode.svelte +8 -8
- package/dist/components/nodes/SimpleNode.stories.svelte +101 -0
- package/dist/components/nodes/SimpleNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/SimpleNode.svelte +16 -24
- package/dist/components/nodes/SquareNode.stories.svelte +56 -0
- package/dist/components/nodes/SquareNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/SquareNode.svelte +13 -21
- package/dist/components/nodes/TerminalNode.stories.svelte +25 -0
- package/dist/components/nodes/TerminalNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/TerminalNode.svelte +7 -7
- package/dist/components/nodes/ToolNode.stories.svelte +71 -0
- package/dist/components/nodes/ToolNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/ToolNode.svelte +7 -15
- package/dist/components/nodes/WorkflowNode.stories.svelte +50 -0
- package/dist/components/nodes/WorkflowNode.stories.svelte.d.ts +26 -0
- package/dist/components/nodes/WorkflowNode.svelte +13 -13
- package/dist/components/playground/ChatPanel.svelte +48 -48
- package/dist/components/playground/ExecutionLogs.svelte +23 -23
- package/dist/components/playground/InputCollector.svelte +24 -24
- package/dist/components/playground/MessageBubble.stories.svelte +49 -0
- package/dist/components/playground/MessageBubble.stories.svelte.d.ts +27 -0
- package/dist/components/playground/MessageBubble.svelte +49 -46
- package/dist/components/playground/Playground.svelte +194 -129
- package/dist/components/playground/PlaygroundModal.svelte +5 -5
- package/dist/components/playground/SessionManager.svelte +26 -26
- package/dist/config/constants.d.ts +22 -0
- package/dist/config/constants.js +22 -0
- package/dist/config/endpoints.d.ts +19 -0
- package/dist/config/runtimeConfig.js +2 -1
- package/dist/core/index.d.ts +5 -2
- package/dist/core/index.js +9 -1
- package/dist/editor/index.d.ts +13 -9
- package/dist/editor/index.js +15 -11
- package/dist/form/code.d.ts +2 -1
- package/dist/form/code.js +1 -3
- package/dist/form/markdown.d.ts +2 -1
- package/dist/form/markdown.js +1 -3
- package/dist/helpers/workflowEditorHelper.js +18 -33
- package/dist/mocks/app-forms.js +1 -0
- package/dist/mocks/app-navigation.js +3 -1
- package/dist/mocks/app-stores.d.ts +4 -4
- package/dist/playground/index.d.ts +4 -3
- package/dist/playground/index.js +12 -10
- package/dist/playground/mount.js +6 -13
- package/dist/services/agentSpecExecutionService.js +2 -1
- package/dist/services/api.js +10 -18
- package/dist/services/apiVariableService.js +2 -1
- package/dist/services/autoSaveService.d.ts +3 -3
- package/dist/services/autoSaveService.js +21 -17
- package/dist/services/categoriesApi.js +13 -5
- package/dist/services/draftStorage.js +5 -4
- package/dist/services/dynamicSchemaService.js +4 -4
- package/dist/services/globalSave.d.ts +60 -11
- package/dist/services/globalSave.js +160 -83
- package/dist/services/historyService.d.ts +2 -1
- package/dist/services/historyService.js +7 -3
- package/dist/services/interruptService.js +9 -8
- package/dist/services/nodeExecutionService.js +14 -6
- package/dist/services/playgroundService.js +2 -1
- package/dist/services/portConfigApi.js +11 -7
- package/dist/services/toastService.d.ts +1 -1
- package/dist/services/toastService.js +6 -5
- package/dist/services/variableService.js +3 -2
- package/dist/settings/index.d.ts +1 -1
- package/dist/settings/index.js +1 -1
- package/dist/stores/{categoriesStore.d.ts → categoriesStore.svelte.d.ts} +3 -3
- package/dist/stores/{categoriesStore.js → categoriesStore.svelte.js} +15 -18
- package/dist/stores/editorStateMachine.svelte.d.ts +42 -0
- package/dist/stores/editorStateMachine.svelte.js +132 -0
- package/dist/stores/{historyStore.d.ts → historyStore.svelte.d.ts} +18 -15
- package/dist/stores/{historyStore.js → historyStore.svelte.js} +40 -21
- package/dist/stores/{interruptStore.d.ts → interruptStore.svelte.d.ts} +16 -15
- package/dist/stores/{interruptStore.js → interruptStore.svelte.js} +85 -94
- package/dist/stores/{playgroundStore.d.ts → playgroundStore.svelte.d.ts} +41 -33
- package/dist/stores/{playgroundStore.js → playgroundStore.svelte.js} +164 -84
- package/dist/stores/{portCoordinateStore.d.ts → portCoordinateStore.svelte.d.ts} +10 -4
- package/dist/stores/{portCoordinateStore.js → portCoordinateStore.svelte.js} +38 -35
- package/dist/stores/{settingsStore.d.ts → settingsStore.svelte.d.ts} +45 -28
- package/dist/stores/{settingsStore.js → settingsStore.svelte.js} +169 -128
- package/dist/stores/{workflowStore.d.ts → workflowStore.svelte.d.ts} +101 -65
- package/dist/stores/{workflowStore.js → workflowStore.svelte.js} +285 -239
- package/dist/stories/CanvasDecorator.svelte +50 -0
- package/dist/stories/CanvasDecorator.svelte.d.ts +8 -0
- package/dist/stories/NodeDecorator.svelte +74 -0
- package/dist/stories/NodeDecorator.svelte.d.ts +8 -0
- package/dist/stories/utils.d.ts +93 -0
- package/dist/stories/utils.js +122 -0
- package/dist/styles/base.css +114 -61
- package/dist/styles/toast.css +2 -2
- package/dist/styles/tokens.css +250 -185
- package/dist/svelte-app.d.ts +0 -6
- package/dist/svelte-app.js +13 -31
- package/dist/types/index.d.ts +2 -0
- package/dist/types/interrupt.d.ts +89 -5
- package/dist/types/interrupt.js +13 -1
- package/dist/types/playground.d.ts +5 -0
- package/dist/types/settings.js +1 -1
- package/dist/utils/colors.js +4 -4
- package/dist/utils/connections.js +33 -8
- package/dist/utils/icons.js +1 -1
- package/dist/utils/logger.d.ts +47 -0
- package/dist/utils/logger.js +72 -0
- package/dist/utils/nodeWrapper.js +1 -1
- package/dist/utils/sanitize.d.ts +19 -0
- package/dist/utils/sanitize.js +31 -0
- package/dist/utils/validation.d.ts +29 -0
- package/dist/utils/validation.js +39 -0
- package/package.json +243 -232
package/dist/types/index.d.ts
CHANGED
|
@@ -1158,6 +1158,8 @@ export interface NodeExecutionInfo {
|
|
|
1158
1158
|
lastError?: string;
|
|
1159
1159
|
/** Whether the node is currently being executed */
|
|
1160
1160
|
isExecuting: boolean;
|
|
1161
|
+
/** Execution output data (e.g., active branches for gateway nodes) */
|
|
1162
|
+
output?: Record<string, unknown>;
|
|
1161
1163
|
}
|
|
1162
1164
|
/**
|
|
1163
1165
|
* Workflow execution status
|
|
@@ -17,7 +17,7 @@ export { initialState, transition, isTerminalState, isSubmitting, hasError, canS
|
|
|
17
17
|
* - `text`: Free-form text input
|
|
18
18
|
* - `form`: JSON Schema-based form
|
|
19
19
|
*/
|
|
20
|
-
export type InterruptType = 'confirmation' | 'choice' | 'text' | 'form';
|
|
20
|
+
export type InterruptType = 'confirmation' | 'choice' | 'text' | 'form' | 'review';
|
|
21
21
|
/**
|
|
22
22
|
* Status of an interrupt request
|
|
23
23
|
*
|
|
@@ -101,10 +101,86 @@ export interface FormConfig {
|
|
|
101
101
|
/** Default values for form fields */
|
|
102
102
|
defaultValues?: Record<string, unknown>;
|
|
103
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* A single field change proposed for review
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* const change: ReviewChange = {
|
|
110
|
+
* field: "title",
|
|
111
|
+
* label: "Page Title",
|
|
112
|
+
* original: "About Us",
|
|
113
|
+
* proposed: "About Our Company"
|
|
114
|
+
* };
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export interface ReviewChange {
|
|
118
|
+
/** Field identifier (machine key) */
|
|
119
|
+
field: string;
|
|
120
|
+
/** Human-readable field label */
|
|
121
|
+
label: string;
|
|
122
|
+
/** Original value before the proposed change */
|
|
123
|
+
original: unknown;
|
|
124
|
+
/** Proposed new value */
|
|
125
|
+
proposed: unknown;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Configuration for review-type interrupts
|
|
129
|
+
*
|
|
130
|
+
* Displays a list of proposed field changes for the user to
|
|
131
|
+
* accept or reject individually before submitting.
|
|
132
|
+
*/
|
|
133
|
+
export interface ReviewConfig {
|
|
134
|
+
/** The prompt message to display */
|
|
135
|
+
message: string;
|
|
136
|
+
/** List of field changes to review */
|
|
137
|
+
changes: ReviewChange[];
|
|
138
|
+
/** Label for the "Accept All" button */
|
|
139
|
+
acceptAllLabel?: string;
|
|
140
|
+
/** Label for the "Reject All" button */
|
|
141
|
+
rejectAllLabel?: string;
|
|
142
|
+
/** Label for the submit button */
|
|
143
|
+
submitLabel?: string;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Per-field decision in a review resolution
|
|
147
|
+
*/
|
|
148
|
+
export interface ReviewFieldDecision {
|
|
149
|
+
/** Whether the proposed change was accepted */
|
|
150
|
+
accepted: boolean;
|
|
151
|
+
/** The effective value (proposed if accepted, original if rejected) */
|
|
152
|
+
value: unknown;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Resolution value for review-type interrupts
|
|
156
|
+
*
|
|
157
|
+
* Contains individual decisions for each field and a summary count.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* const resolution: ReviewResolution = {
|
|
162
|
+
* decisions: {
|
|
163
|
+
* title: { accepted: true, value: "About Our Company" },
|
|
164
|
+
* meta_description: { accepted: false, value: "Learn about us" }
|
|
165
|
+
* },
|
|
166
|
+
* summary: { accepted: 1, rejected: 1, total: 2 }
|
|
167
|
+
* };
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
export interface ReviewResolution {
|
|
171
|
+
/** Map of field identifier to the user's decision */
|
|
172
|
+
decisions: Record<string, ReviewFieldDecision>;
|
|
173
|
+
/** Summary counts of accepted/rejected fields */
|
|
174
|
+
summary: {
|
|
175
|
+
accepted: number;
|
|
176
|
+
rejected: number;
|
|
177
|
+
total: number;
|
|
178
|
+
};
|
|
179
|
+
}
|
|
104
180
|
/**
|
|
105
181
|
* Union type for interrupt-specific configuration
|
|
106
182
|
*/
|
|
107
|
-
export type InterruptConfig = ConfirmationConfig | ChoiceConfig | TextConfig | FormConfig;
|
|
183
|
+
export type InterruptConfig = ConfirmationConfig | ChoiceConfig | TextConfig | FormConfig | ReviewConfig;
|
|
108
184
|
/**
|
|
109
185
|
* Core interrupt data structure
|
|
110
186
|
*
|
|
@@ -268,6 +344,14 @@ export interface InterruptMessageMetadata {
|
|
|
268
344
|
resolvedByUserName?: string;
|
|
269
345
|
/** User ID of the person who resolved the interrupt */
|
|
270
346
|
resolvedByUserId?: string;
|
|
347
|
+
/** Review: list of field changes to review */
|
|
348
|
+
changes?: ReviewChange[];
|
|
349
|
+
/** Review: label for the "Accept All" button */
|
|
350
|
+
accept_all_label?: string;
|
|
351
|
+
/** Review: label for the "Reject All" button */
|
|
352
|
+
reject_all_label?: string;
|
|
353
|
+
/** Review: label for the submit button */
|
|
354
|
+
submit_label?: string;
|
|
271
355
|
}
|
|
272
356
|
/**
|
|
273
357
|
* Type guard to check if message metadata indicates an interrupt
|
|
@@ -275,7 +359,7 @@ export interface InterruptMessageMetadata {
|
|
|
275
359
|
* @param metadata - Message metadata to check
|
|
276
360
|
* @returns True if the metadata indicates an interrupt request
|
|
277
361
|
*/
|
|
278
|
-
export declare function isInterruptMetadata(metadata: Record<string, unknown> | undefined):
|
|
362
|
+
export declare function isInterruptMetadata(metadata: Record<string, unknown> | undefined): metadata is Record<string, unknown>;
|
|
279
363
|
/**
|
|
280
364
|
* Safely extract interrupt metadata from a generic record
|
|
281
365
|
*
|
|
@@ -299,9 +383,9 @@ export interface InterruptPollingConfig {
|
|
|
299
383
|
/** Whether to enable dedicated interrupt polling */
|
|
300
384
|
enabled: boolean;
|
|
301
385
|
/** Polling interval in milliseconds */
|
|
302
|
-
interval
|
|
386
|
+
interval: number;
|
|
303
387
|
/** Maximum polling backoff interval in milliseconds */
|
|
304
|
-
maxBackoff
|
|
388
|
+
maxBackoff: number;
|
|
305
389
|
}
|
|
306
390
|
/**
|
|
307
391
|
* Default interrupt polling configuration
|
package/dist/types/interrupt.js
CHANGED
|
@@ -50,7 +50,11 @@ export function extractInterruptMetadata(metadata) {
|
|
|
50
50
|
min_selections: metadata.min_selections,
|
|
51
51
|
max_selections: metadata.max_selections,
|
|
52
52
|
resolvedByUserName: metadata.resolvedByUserName,
|
|
53
|
-
resolvedByUserId: metadata.resolvedByUserId
|
|
53
|
+
resolvedByUserId: metadata.resolvedByUserId,
|
|
54
|
+
changes: metadata.changes,
|
|
55
|
+
accept_all_label: metadata.accept_all_label,
|
|
56
|
+
reject_all_label: metadata.reject_all_label,
|
|
57
|
+
submit_label: metadata.submit_label
|
|
54
58
|
};
|
|
55
59
|
}
|
|
56
60
|
/**
|
|
@@ -119,6 +123,14 @@ function buildInterruptConfig(metadata, message) {
|
|
|
119
123
|
schema: metadata.schema ?? { type: 'object', properties: {} },
|
|
120
124
|
defaultValues: metadata.default_value
|
|
121
125
|
};
|
|
126
|
+
case 'review':
|
|
127
|
+
return {
|
|
128
|
+
message,
|
|
129
|
+
changes: metadata.changes ?? [],
|
|
130
|
+
acceptAllLabel: metadata.accept_all_label,
|
|
131
|
+
rejectAllLabel: metadata.reject_all_label,
|
|
132
|
+
submitLabel: metadata.submit_label
|
|
133
|
+
};
|
|
122
134
|
default:
|
|
123
135
|
return { message };
|
|
124
136
|
}
|
|
@@ -243,6 +243,11 @@ export interface PlaygroundConfig {
|
|
|
243
243
|
* Note: Only runs once per session - subsequent runs require clicking the Run button.
|
|
244
244
|
*/
|
|
245
245
|
autoRun?: boolean;
|
|
246
|
+
/**
|
|
247
|
+
* Width of the sidebar in CSS units (default: "280px")
|
|
248
|
+
* Accepts any valid CSS width value, e.g. "300px", "20rem".
|
|
249
|
+
*/
|
|
250
|
+
sidebarWidth?: string;
|
|
246
251
|
/**
|
|
247
252
|
* Whether to show the sidebar with session list (default: true)
|
|
248
253
|
* When false, the sidebar is hidden, creating a minimal chat widget experience.
|
package/dist/types/settings.js
CHANGED
package/dist/utils/colors.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Uses BEM syntax for CSS classes
|
|
5
5
|
*/
|
|
6
6
|
import { getPortCompatibilityChecker } from './connections.js';
|
|
7
|
-
import { getCategoryColor as getCategoryColorFromStore } from '../stores/categoriesStore.js';
|
|
7
|
+
import { getCategoryColor as getCategoryColorFromStore } from '../stores/categoriesStore.svelte.js';
|
|
8
|
+
import { logger } from './logger.js';
|
|
8
9
|
/**
|
|
9
10
|
* Category color mapping to design tokens (CSS variables)
|
|
10
11
|
* Uses --fd-node-* tokens from tokens.css
|
|
@@ -83,7 +84,6 @@ export function getDataTypeColorToken(dataType) {
|
|
|
83
84
|
}
|
|
84
85
|
catch {
|
|
85
86
|
// Fallback to static color mapping if port checker not initialized
|
|
86
|
-
// console.warn("Port compatibility checker not initialized, using fallback colors");
|
|
87
87
|
}
|
|
88
88
|
return DEFAULT_DATA_TYPE_COLORS[dataType.toLowerCase()] || 'var(--fd-node-slate)';
|
|
89
89
|
}
|
|
@@ -96,7 +96,7 @@ export function getDataTypeConfig(dataType) {
|
|
|
96
96
|
return checker.getDataTypeConfig(dataType);
|
|
97
97
|
}
|
|
98
98
|
catch (error) {
|
|
99
|
-
|
|
99
|
+
logger.warn('Port compatibility checker not initialized:', error);
|
|
100
100
|
return undefined;
|
|
101
101
|
}
|
|
102
102
|
}
|
|
@@ -109,7 +109,7 @@ export function getAvailableDataTypes() {
|
|
|
109
109
|
return checker.getEnabledDataTypes();
|
|
110
110
|
}
|
|
111
111
|
catch (error) {
|
|
112
|
-
|
|
112
|
+
logger.warn('Port compatibility checker not initialized:', error);
|
|
113
113
|
return [];
|
|
114
114
|
}
|
|
115
115
|
}
|
|
@@ -266,6 +266,18 @@ export function getConnectionSuggestions(nodeId, nodes, nodeTypes) {
|
|
|
266
266
|
* @returns True if any cycle exists in the workflow
|
|
267
267
|
*/
|
|
268
268
|
export function hasCycles(nodes, edges) {
|
|
269
|
+
// Build adjacency map once (O(E)) so the DFS inner loop is O(1) per lookup
|
|
270
|
+
// instead of scanning all edges on every recursive call (which was O(V*E)).
|
|
271
|
+
const adjacencyMap = new Map();
|
|
272
|
+
for (const node of nodes) {
|
|
273
|
+
adjacencyMap.set(node.id, []);
|
|
274
|
+
}
|
|
275
|
+
for (const edge of edges) {
|
|
276
|
+
const neighbors = adjacencyMap.get(edge.source);
|
|
277
|
+
if (neighbors) {
|
|
278
|
+
neighbors.push(edge.target);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
269
281
|
const visited = new Set();
|
|
270
282
|
const recursionStack = new Set();
|
|
271
283
|
function hasCycleUtil(nodeId) {
|
|
@@ -275,10 +287,10 @@ export function hasCycles(nodes, edges) {
|
|
|
275
287
|
return false;
|
|
276
288
|
visited.add(nodeId);
|
|
277
289
|
recursionStack.add(nodeId);
|
|
278
|
-
//
|
|
279
|
-
const
|
|
280
|
-
for (const
|
|
281
|
-
if (hasCycleUtil(
|
|
290
|
+
// Use pre-built adjacency map instead of filtering all edges each call
|
|
291
|
+
const neighbors = adjacencyMap.get(nodeId) || [];
|
|
292
|
+
for (const target of neighbors) {
|
|
293
|
+
if (hasCycleUtil(target))
|
|
282
294
|
return true;
|
|
283
295
|
}
|
|
284
296
|
recursionStack.delete(nodeId);
|
|
@@ -312,6 +324,19 @@ export function hasCycles(nodes, edges) {
|
|
|
312
324
|
export function hasInvalidCycles(nodes, edges) {
|
|
313
325
|
// Filter out loopback edges - these create valid cycles for loop iteration
|
|
314
326
|
const nonLoopbackEdges = edges.filter((edge) => !isLoopbackEdge(edge));
|
|
327
|
+
// Build adjacency map from non-loopback edges once (O(E)) so the DFS inner
|
|
328
|
+
// loop is O(1) per lookup instead of scanning all edges on every recursive
|
|
329
|
+
// call (which was O(V*E)).
|
|
330
|
+
const adjacencyMap = new Map();
|
|
331
|
+
for (const node of nodes) {
|
|
332
|
+
adjacencyMap.set(node.id, []);
|
|
333
|
+
}
|
|
334
|
+
for (const edge of nonLoopbackEdges) {
|
|
335
|
+
const neighbors = adjacencyMap.get(edge.source);
|
|
336
|
+
if (neighbors) {
|
|
337
|
+
neighbors.push(edge.target);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
315
340
|
// Check for cycles using only non-loopback edges
|
|
316
341
|
const visited = new Set();
|
|
317
342
|
const recursionStack = new Set();
|
|
@@ -327,10 +352,10 @@ export function hasInvalidCycles(nodes, edges) {
|
|
|
327
352
|
return false;
|
|
328
353
|
visited.add(nodeId);
|
|
329
354
|
recursionStack.add(nodeId);
|
|
330
|
-
//
|
|
331
|
-
const
|
|
332
|
-
for (const
|
|
333
|
-
if (hasCycleUtil(
|
|
355
|
+
// Use pre-built adjacency map instead of filtering all edges each call
|
|
356
|
+
const neighbors = adjacencyMap.get(nodeId) || [];
|
|
357
|
+
for (const target of neighbors) {
|
|
358
|
+
if (hasCycleUtil(target))
|
|
334
359
|
return true;
|
|
335
360
|
}
|
|
336
361
|
recursionStack.delete(nodeId);
|
package/dist/utils/icons.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Centralized icon management for FlowDrop
|
|
3
3
|
* Ensures consistent icon usage across all components
|
|
4
4
|
*/
|
|
5
|
-
import { getCategoryIcon as getCategoryIconFromStore } from '../stores/categoriesStore.js';
|
|
5
|
+
import { getCategoryIcon as getCategoryIconFromStore } from '../stores/categoriesStore.svelte.js';
|
|
6
6
|
/**
|
|
7
7
|
* Default icons for different contexts
|
|
8
8
|
*/
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowDrop Logger
|
|
3
|
+
*
|
|
4
|
+
* Lightweight configurable logger for the FlowDrop library.
|
|
5
|
+
* Disabled by default — consumers enable it for debugging.
|
|
6
|
+
*
|
|
7
|
+
* @module utils/logger
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { setLogLevel } from '@d34dman/flowdrop/core';
|
|
12
|
+
*
|
|
13
|
+
* // Enable debug logging during development
|
|
14
|
+
* setLogLevel('debug');
|
|
15
|
+
*
|
|
16
|
+
* // Enable only warnings and errors
|
|
17
|
+
* setLogLevel('warn');
|
|
18
|
+
*
|
|
19
|
+
* // Disable all logging (default)
|
|
20
|
+
* setLogLevel('none');
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
/** Log severity levels. `'none'` disables all output. */
|
|
24
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'none';
|
|
25
|
+
/**
|
|
26
|
+
* Set the minimum log level for FlowDrop library output.
|
|
27
|
+
* Messages below this level are silently discarded.
|
|
28
|
+
*
|
|
29
|
+
* @param level - The minimum severity to display. Use `'none'` to disable all output.
|
|
30
|
+
*/
|
|
31
|
+
export declare function setLogLevel(level: LogLevel): void;
|
|
32
|
+
/**
|
|
33
|
+
* Get the current log level.
|
|
34
|
+
*/
|
|
35
|
+
export declare function getLogLevel(): LogLevel;
|
|
36
|
+
/**
|
|
37
|
+
* FlowDrop library logger.
|
|
38
|
+
*
|
|
39
|
+
* All methods are no-ops when the log level is set to `'none'` (default).
|
|
40
|
+
* Enable output by calling `setLogLevel()`.
|
|
41
|
+
*/
|
|
42
|
+
export declare const logger: {
|
|
43
|
+
debug(message: string, ...args: unknown[]): void;
|
|
44
|
+
info(message: string, ...args: unknown[]): void;
|
|
45
|
+
warn(message: string, ...args: unknown[]): void;
|
|
46
|
+
error(message: string, ...args: unknown[]): void;
|
|
47
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowDrop Logger
|
|
3
|
+
*
|
|
4
|
+
* Lightweight configurable logger for the FlowDrop library.
|
|
5
|
+
* Disabled by default — consumers enable it for debugging.
|
|
6
|
+
*
|
|
7
|
+
* @module utils/logger
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { setLogLevel } from '@d34dman/flowdrop/core';
|
|
12
|
+
*
|
|
13
|
+
* // Enable debug logging during development
|
|
14
|
+
* setLogLevel('debug');
|
|
15
|
+
*
|
|
16
|
+
* // Enable only warnings and errors
|
|
17
|
+
* setLogLevel('warn');
|
|
18
|
+
*
|
|
19
|
+
* // Disable all logging (default)
|
|
20
|
+
* setLogLevel('none');
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
const LOG_PRIORITY = {
|
|
24
|
+
debug: 0,
|
|
25
|
+
info: 1,
|
|
26
|
+
warn: 2,
|
|
27
|
+
error: 3,
|
|
28
|
+
none: 4
|
|
29
|
+
};
|
|
30
|
+
let currentLevel = 'none';
|
|
31
|
+
/**
|
|
32
|
+
* Set the minimum log level for FlowDrop library output.
|
|
33
|
+
* Messages below this level are silently discarded.
|
|
34
|
+
*
|
|
35
|
+
* @param level - The minimum severity to display. Use `'none'` to disable all output.
|
|
36
|
+
*/
|
|
37
|
+
export function setLogLevel(level) {
|
|
38
|
+
currentLevel = level;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get the current log level.
|
|
42
|
+
*/
|
|
43
|
+
export function getLogLevel() {
|
|
44
|
+
return currentLevel;
|
|
45
|
+
}
|
|
46
|
+
function shouldLog(level) {
|
|
47
|
+
return LOG_PRIORITY[level] >= LOG_PRIORITY[currentLevel];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* FlowDrop library logger.
|
|
51
|
+
*
|
|
52
|
+
* All methods are no-ops when the log level is set to `'none'` (default).
|
|
53
|
+
* Enable output by calling `setLogLevel()`.
|
|
54
|
+
*/
|
|
55
|
+
export const logger = {
|
|
56
|
+
debug(message, ...args) {
|
|
57
|
+
if (shouldLog('debug'))
|
|
58
|
+
console.debug(`[FlowDrop] ${message}`, ...args);
|
|
59
|
+
},
|
|
60
|
+
info(message, ...args) {
|
|
61
|
+
if (shouldLog('info'))
|
|
62
|
+
console.info(`[FlowDrop] ${message}`, ...args);
|
|
63
|
+
},
|
|
64
|
+
warn(message, ...args) {
|
|
65
|
+
if (shouldLog('warn'))
|
|
66
|
+
console.warn(`[FlowDrop] ${message}`, ...args);
|
|
67
|
+
},
|
|
68
|
+
error(message, ...args) {
|
|
69
|
+
if (shouldLog('error'))
|
|
70
|
+
console.error(`[FlowDrop] ${message}`, ...args);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
@@ -19,7 +19,7 @@ export function createNodeWrapperConfig(nodeId, executionInfo, config = {}) {
|
|
|
19
19
|
executionInfo,
|
|
20
20
|
statusPosition: config.position || DEFAULT_NODE_STATUS_CONFIG.position,
|
|
21
21
|
statusSize: config.size || DEFAULT_NODE_STATUS_CONFIG.size,
|
|
22
|
-
showStatusDetails: config.showDetails ?? DEFAULT_NODE_STATUS_CONFIG.showDetails
|
|
22
|
+
showStatusDetails: config.showDetails ?? DEFAULT_NODE_STATUS_CONFIG.showDetails ?? true
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitize an HTML string to prevent XSS attacks.
|
|
3
|
+
*
|
|
4
|
+
* Uses DOMPurify defaults which strip dangerous elements (script, iframe, object)
|
|
5
|
+
* and event handler attributes (onerror, onclick, etc.) while preserving safe HTML
|
|
6
|
+
* elements typically produced by markdown renderers.
|
|
7
|
+
*
|
|
8
|
+
* @param dirty - The untrusted HTML string to sanitize
|
|
9
|
+
* @returns Sanitized HTML string safe for use with {@html}
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { sanitizeHtml } from '@d34dman/flowdrop/core';
|
|
14
|
+
* import { marked } from 'marked';
|
|
15
|
+
*
|
|
16
|
+
* const safeHtml = sanitizeHtml(marked.parse(userInput) as string);
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function sanitizeHtml(dirty: string): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML Sanitization Utility
|
|
3
|
+
*
|
|
4
|
+
* Provides XSS protection for rendered HTML content using DOMPurify.
|
|
5
|
+
* Used internally by components that render user-provided or API-provided HTML
|
|
6
|
+
* (e.g., markdown output, interrupt review diffs).
|
|
7
|
+
*
|
|
8
|
+
* @module utils/sanitize
|
|
9
|
+
*/
|
|
10
|
+
import DOMPurify from 'dompurify';
|
|
11
|
+
/**
|
|
12
|
+
* Sanitize an HTML string to prevent XSS attacks.
|
|
13
|
+
*
|
|
14
|
+
* Uses DOMPurify defaults which strip dangerous elements (script, iframe, object)
|
|
15
|
+
* and event handler attributes (onerror, onclick, etc.) while preserving safe HTML
|
|
16
|
+
* elements typically produced by markdown renderers.
|
|
17
|
+
*
|
|
18
|
+
* @param dirty - The untrusted HTML string to sanitize
|
|
19
|
+
* @returns Sanitized HTML string safe for use with {@html}
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* import { sanitizeHtml } from '@d34dman/flowdrop/core';
|
|
24
|
+
* import { marked } from 'marked';
|
|
25
|
+
*
|
|
26
|
+
* const safeHtml = sanitizeHtml(marked.parse(userInput) as string);
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function sanitizeHtml(dirty) {
|
|
30
|
+
return DOMPurify.sanitize(dirty);
|
|
31
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowDrop Workflow Validation
|
|
3
|
+
*
|
|
4
|
+
* Lightweight validation utilities for workflow JSON data.
|
|
5
|
+
* Checks minimum required fields without relying on a full JSON Schema validator library.
|
|
6
|
+
*
|
|
7
|
+
* @module utils/validation
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Result of a workflow validation check.
|
|
11
|
+
*/
|
|
12
|
+
export interface WorkflowValidationResult {
|
|
13
|
+
valid: boolean;
|
|
14
|
+
/** Human-readable description of the first validation failure, or undefined if valid. */
|
|
15
|
+
error?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Validate that the given value has the minimum required fields of a FlowDrop Workflow.
|
|
19
|
+
*
|
|
20
|
+
* Required fields (matching the Workflow type and workflow.schema.json):
|
|
21
|
+
* - `id` — string
|
|
22
|
+
* - `name` — string
|
|
23
|
+
* - `nodes` — array
|
|
24
|
+
* - `edges` — array
|
|
25
|
+
*
|
|
26
|
+
* @param data - The parsed JSON value to validate.
|
|
27
|
+
* @returns A `WorkflowValidationResult` indicating whether the data is valid.
|
|
28
|
+
*/
|
|
29
|
+
export declare function validateWorkflowData(data: unknown): WorkflowValidationResult;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlowDrop Workflow Validation
|
|
3
|
+
*
|
|
4
|
+
* Lightweight validation utilities for workflow JSON data.
|
|
5
|
+
* Checks minimum required fields without relying on a full JSON Schema validator library.
|
|
6
|
+
*
|
|
7
|
+
* @module utils/validation
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Validate that the given value has the minimum required fields of a FlowDrop Workflow.
|
|
11
|
+
*
|
|
12
|
+
* Required fields (matching the Workflow type and workflow.schema.json):
|
|
13
|
+
* - `id` — string
|
|
14
|
+
* - `name` — string
|
|
15
|
+
* - `nodes` — array
|
|
16
|
+
* - `edges` — array
|
|
17
|
+
*
|
|
18
|
+
* @param data - The parsed JSON value to validate.
|
|
19
|
+
* @returns A `WorkflowValidationResult` indicating whether the data is valid.
|
|
20
|
+
*/
|
|
21
|
+
export function validateWorkflowData(data) {
|
|
22
|
+
if (data === null || typeof data !== 'object' || Array.isArray(data)) {
|
|
23
|
+
return { valid: false, error: 'Workflow must be a JSON object.' };
|
|
24
|
+
}
|
|
25
|
+
const obj = data;
|
|
26
|
+
if (typeof obj.id !== 'string' || obj.id.trim() === '') {
|
|
27
|
+
return { valid: false, error: 'Workflow JSON must contain a non-empty string "id" field.' };
|
|
28
|
+
}
|
|
29
|
+
if (typeof obj.name !== 'string' || obj.name.trim() === '') {
|
|
30
|
+
return { valid: false, error: 'Workflow JSON must contain a non-empty string "name" field.' };
|
|
31
|
+
}
|
|
32
|
+
if (!Array.isArray(obj.nodes)) {
|
|
33
|
+
return { valid: false, error: 'Workflow JSON must contain a "nodes" array.' };
|
|
34
|
+
}
|
|
35
|
+
if (!Array.isArray(obj.edges)) {
|
|
36
|
+
return { valid: false, error: 'Workflow JSON must contain an "edges" array.' };
|
|
37
|
+
}
|
|
38
|
+
return { valid: true };
|
|
39
|
+
}
|