@d34dman/flowdrop 0.0.47 → 0.0.49

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 (36) hide show
  1. package/dist/components/App.svelte +11 -0
  2. package/dist/components/App.svelte.d.ts +2 -0
  3. package/dist/components/ConfigForm.svelte +31 -5
  4. package/dist/components/ConfigForm.svelte.d.ts +3 -1
  5. package/dist/components/NodeSidebar.svelte +1 -0
  6. package/dist/components/SchemaForm.svelte +4 -2
  7. package/dist/components/SettingsPanel.svelte +3 -3
  8. package/dist/components/form/FormAutocomplete.svelte +9 -4
  9. package/dist/components/form/FormCodeEditor.svelte +17 -15
  10. package/dist/components/form/FormField.svelte +32 -4
  11. package/dist/components/form/FormField.svelte.d.ts +11 -0
  12. package/dist/components/form/FormFieldLight.svelte +0 -1
  13. package/dist/components/form/FormTemplateEditor.svelte +300 -79
  14. package/dist/components/form/FormTemplateEditor.svelte.d.ts +11 -7
  15. package/dist/components/form/index.d.ts +1 -1
  16. package/dist/components/form/index.js +1 -1
  17. package/dist/components/form/templateAutocomplete.d.ts +2 -11
  18. package/dist/components/form/templateAutocomplete.js +49 -104
  19. package/dist/components/form/types.d.ts +0 -6
  20. package/dist/components/nodes/TerminalNode.svelte +27 -15
  21. package/dist/components/nodes/ToolNode.svelte +4 -6
  22. package/dist/services/apiVariableService.d.ts +116 -0
  23. package/dist/services/apiVariableService.js +338 -0
  24. package/dist/services/globalSave.js +6 -0
  25. package/dist/services/variableService.d.ts +50 -9
  26. package/dist/services/variableService.js +139 -44
  27. package/dist/svelte-app.d.ts +5 -0
  28. package/dist/svelte-app.js +7 -1
  29. package/dist/types/index.d.ts +138 -1
  30. package/dist/types/settings.js +4 -4
  31. package/dist/utils/colors.js +1 -0
  32. package/dist/utils/handlePositioning.d.ts +31 -0
  33. package/dist/utils/handlePositioning.js +35 -0
  34. package/dist/utils/icons.js +1 -0
  35. package/dist/utils/nodeTypes.js +3 -3
  36. package/package.json +8 -4
@@ -10,6 +10,7 @@ import type { Workflow, NodeMetadata, PortConfig } from './types/index.js';
10
10
  import type { EndpointConfig } from './config/endpoints.js';
11
11
  import type { AuthProvider } from './types/auth.js';
12
12
  import type { FlowDropEventHandlers, FlowDropFeatures } from './types/events.js';
13
+ import type { PartialSettings } from './types/settings.js';
13
14
  declare global {
14
15
  interface Window {
15
16
  flowdropSave?: () => Promise<void>;
@@ -58,12 +59,16 @@ export interface FlowDropMountOptions {
58
59
  navbarTitle?: string;
59
60
  /** Custom navbar actions */
60
61
  navbarActions?: NavbarAction[];
62
+ /** Show settings gear icon in navbar */
63
+ showSettings?: boolean;
61
64
  /** Authentication provider for API requests */
62
65
  authProvider?: AuthProvider;
63
66
  /** Event handlers for workflow lifecycle */
64
67
  eventHandlers?: FlowDropEventHandlers;
65
68
  /** Feature configuration */
66
69
  features?: FlowDropFeatures;
70
+ /** Initial settings overrides (theme, behavior, editor, ui, api) */
71
+ settings?: PartialSettings;
67
72
  /** Custom storage key for localStorage drafts */
68
73
  draftStorageKey?: string;
69
74
  }
@@ -15,6 +15,7 @@ import { fetchPortConfig } from './services/portConfigApi.js';
15
15
  import { isDirty, markAsSaved, getWorkflow as getWorkflowFromStore, setOnDirtyStateChange, setOnWorkflowChange } from './stores/workflowStore.js';
16
16
  import { DraftAutoSaveManager, getDraftStorageKey } from './services/draftStorage.js';
17
17
  import { mergeFeatures } from './types/events.js';
18
+ import { initializeSettings } from './stores/settingsStore.js';
18
19
  /**
19
20
  * Mount the full FlowDrop App with navbar, sidebars, and workflow editor
20
21
  *
@@ -40,9 +41,13 @@ import { mergeFeatures } from './types/events.js';
40
41
  * ```
41
42
  */
42
43
  export async function mountFlowDropApp(container, options = {}) {
43
- const { workflow, nodes, endpointConfig, portConfig, height = '100vh', width = '100%', showNavbar = false, disableSidebar, lockWorkflow, readOnly, nodeStatuses, pipelineId, navbarTitle, navbarActions, authProvider, eventHandlers, features: userFeatures, draftStorageKey: customDraftKey } = options;
44
+ const { workflow, nodes, endpointConfig, portConfig, height = '100vh', width = '100%', showNavbar = false, disableSidebar, lockWorkflow, readOnly, nodeStatuses, pipelineId, navbarTitle, navbarActions, showSettings, authProvider, eventHandlers, features: userFeatures, settings: initialSettings, draftStorageKey: customDraftKey } = options;
44
45
  // Merge features with defaults
45
46
  const features = mergeFeatures(userFeatures);
47
+ // Apply initial settings overrides and initialize theme
48
+ await initializeSettings({
49
+ defaults: initialSettings
50
+ });
46
51
  // Create endpoint configuration
47
52
  let config;
48
53
  if (endpointConfig) {
@@ -101,6 +106,7 @@ export async function mountFlowDropApp(container, options = {}) {
101
106
  pipelineId,
102
107
  navbarTitle,
103
108
  navbarActions,
109
+ showSettings,
104
110
  endpointConfig: config,
105
111
  authProvider,
106
112
  eventHandlers,
@@ -8,7 +8,7 @@ import type { EndpointConfig } from '../config/endpoints.js';
8
8
  * Node category types for organizing nodes in the sidebar
9
9
  * Based on actual API response categories
10
10
  */
11
- export type NodeCategory = 'triggers' | 'inputs' | 'outputs' | 'prompts' | 'models' | 'processing' | 'logic' | 'data' | 'tools' | 'helpers' | 'vector stores' | 'embeddings' | 'memories' | 'agents' | 'ai' | 'bundles';
11
+ export type NodeCategory = 'triggers' | 'inputs' | 'outputs' | 'prompts' | 'models' | 'processing' | 'logic' | 'data' | 'tools' | 'helpers' | 'vector stores' | 'embeddings' | 'memories' | 'agents' | 'ai' | 'interrupts' | 'bundles';
12
12
  /**
13
13
  * Port data type configuration
14
14
  */
@@ -693,6 +693,11 @@ export interface VariableSchema {
693
693
  * Used in template fields to control which variables are available
694
694
  * and how they are derived.
695
695
  *
696
+ * Supports three modes:
697
+ * 1. **Schema-only** (existing): Variables from static schema and/or upstream ports
698
+ * 2. **API-only** (new): Variables fetched from backend endpoint
699
+ * 3. **Hybrid** (new): Merge API variables with static schema/ports
700
+ *
696
701
  * @example
697
702
  * ```json
698
703
  * {
@@ -704,6 +709,21 @@ export interface VariableSchema {
704
709
  * }
705
710
  * }
706
711
  * ```
712
+ *
713
+ * @example API Mode
714
+ * ```json
715
+ * {
716
+ * "type": "string",
717
+ * "format": "template",
718
+ * "variables": {
719
+ * "api": {
720
+ * "endpoint": {
721
+ * "url": "/api/variables/{workflowId}/{nodeId}"
722
+ * }
723
+ * }
724
+ * }
725
+ * }
726
+ * ```
707
727
  */
708
728
  export interface TemplateVariablesConfig {
709
729
  /**
@@ -731,6 +751,123 @@ export interface TemplateVariablesConfig {
731
751
  * @default true
732
752
  */
733
753
  showHints?: boolean;
754
+ /**
755
+ * API mode configuration for fetching variables from backend endpoint.
756
+ * When configured, variables will be fetched from the specified endpoint
757
+ * and can be merged with static schema and/or port-derived variables.
758
+ */
759
+ api?: ApiVariablesConfig;
760
+ }
761
+ /**
762
+ * Configuration for API-based variable fetching.
763
+ * Enables dynamic variable suggestions from backend endpoints.
764
+ *
765
+ * @example
766
+ * ```typescript
767
+ * const apiConfig: ApiVariablesConfig = {
768
+ * endpoint: {
769
+ * url: "/api/variables/{workflowId}/{nodeId}",
770
+ * method: "GET"
771
+ * },
772
+ * cacheTtl: 300000,
773
+ * mergeWithSchema: true,
774
+ * fallbackOnError: true
775
+ * };
776
+ * ```
777
+ */
778
+ export interface ApiVariablesConfig {
779
+ /**
780
+ * Endpoint configuration for fetching variable schema
781
+ */
782
+ endpoint: ApiVariablesEndpoint;
783
+ /**
784
+ * Cache TTL in milliseconds.
785
+ * Variables are cached to prevent excessive API calls during editing.
786
+ * @default 300000 (5 minutes)
787
+ */
788
+ cacheTtl?: number;
789
+ /**
790
+ * Whether to merge API variables with static schema.
791
+ * When true, variables from both API and schema are combined.
792
+ * @default true
793
+ */
794
+ mergeWithSchema?: boolean;
795
+ /**
796
+ * Whether to merge API variables with port-derived variables.
797
+ * When true, variables from both API and ports are combined.
798
+ * @default false
799
+ */
800
+ mergeWithPorts?: boolean;
801
+ /**
802
+ * Whether to fallback to schema/ports on API error.
803
+ * When true, gracefully degrades to static variables if API fails.
804
+ * When false, shows error message to user.
805
+ * @default true
806
+ */
807
+ fallbackOnError?: boolean;
808
+ }
809
+ /**
810
+ * Endpoint configuration for fetching variable schemas from backend API.
811
+ * Supports template variables in URL (e.g., {workflowId}, {nodeId})
812
+ * which are resolved at runtime from node context.
813
+ *
814
+ * @example GET Request
815
+ * ```typescript
816
+ * const endpoint: ApiVariablesEndpoint = {
817
+ * url: "/api/variables/{workflowId}/{nodeId}",
818
+ * method: "GET"
819
+ * };
820
+ * ```
821
+ *
822
+ * @example POST Request with Body
823
+ * ```typescript
824
+ * const endpoint: ApiVariablesEndpoint = {
825
+ * url: "/api/variables",
826
+ * method: "POST",
827
+ * body: {
828
+ * workflowId: "{workflowId}",
829
+ * nodeId: "{nodeId}"
830
+ * }
831
+ * };
832
+ * ```
833
+ */
834
+ export interface ApiVariablesEndpoint {
835
+ /**
836
+ * URL to fetch variables from.
837
+ * Supports template placeholders:
838
+ * - `{workflowId}` - Resolved from workflow ID
839
+ * - `{nodeId}` - Resolved from node instance ID
840
+ *
841
+ * @example "/api/variables/{workflowId}/{nodeId}"
842
+ * @example "https://api.example.com/variables?workflow={workflowId}&node={nodeId}"
843
+ */
844
+ url: string;
845
+ /**
846
+ * HTTP method for the request.
847
+ * @default "GET"
848
+ */
849
+ method?: HttpMethod;
850
+ /**
851
+ * Custom headers to include in the request.
852
+ * Note: Authentication headers are automatically added via AuthProvider.
853
+ */
854
+ headers?: Record<string, string>;
855
+ /**
856
+ * Request body for POST/PUT/PATCH methods.
857
+ * Supports template variables like the URL.
858
+ */
859
+ body?: Record<string, unknown>;
860
+ /**
861
+ * Request timeout in milliseconds.
862
+ * @default 30000 (30 seconds)
863
+ */
864
+ timeout?: number;
865
+ /**
866
+ * Whether to cache the fetched schema.
867
+ * When false, schema is fetched on every editor load.
868
+ * @default true
869
+ */
870
+ cacheEnabled?: boolean;
734
871
  }
735
872
  /**
736
873
  * Union type for all schema types
@@ -37,7 +37,7 @@ export const SETTINGS_CATEGORY_ICONS = {
37
37
  * Default theme settings
38
38
  */
39
39
  export const DEFAULT_THEME_SETTINGS = {
40
- preference: 'auto'
40
+ preference: 'light'
41
41
  };
42
42
  /**
43
43
  * Default editor settings
@@ -64,8 +64,8 @@ export const DEFAULT_UI_SETTINGS = {
64
64
  export const DEFAULT_BEHAVIOR_SETTINGS = {
65
65
  autoSave: false,
66
66
  autoSaveInterval: 30000,
67
- undoHistoryLimit: 50,
68
- confirmDelete: true
67
+ undoHistoryLimit: 0,
68
+ confirmDelete: false
69
69
  };
70
70
  /**
71
71
  * Default API settings
@@ -74,7 +74,7 @@ export const DEFAULT_API_SETTINGS = {
74
74
  timeout: 30000,
75
75
  retryEnabled: true,
76
76
  retryAttempts: 3,
77
- cacheEnabled: true
77
+ cacheEnabled: false
78
78
  };
79
79
  /**
80
80
  * Complete default settings object
@@ -24,6 +24,7 @@ export const CATEGORY_COLOR_TOKENS = {
24
24
  memories: 'var(--fd-node-blue)',
25
25
  agents: 'var(--fd-node-teal)',
26
26
  ai: 'var(--fd-node-purple)',
27
+ interrupts: 'var(--fd-node-red)',
27
28
  bundles: 'var(--fd-node-slate)'
28
29
  };
29
30
  /**
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Utility functions for calculating handle positions on nodes
3
+ */
4
+ export interface HandlePosition {
5
+ left: number;
6
+ top: number;
7
+ }
8
+ /**
9
+ * Calculate handle position along a circle arc using cos/sin
10
+ *
11
+ * Distributes handles evenly along an arc on the left or right side of a circle.
12
+ * For N handles, they are positioned at angles calculated as:
13
+ * angle = centerAngle - arcSpan/2 + arcSpan * (index + 1) / (count + 1)
14
+ *
15
+ * @param index - The index of the handle (0-based)
16
+ * @param count - Total number of handles on this side
17
+ * @param side - 'left' for inputs, 'right' for outputs
18
+ * @param radius - The radius of the circle (default: 40px for 80px diameter)
19
+ * @param arcSpan - The arc span in radians (default: 5π/6 = 150°)
20
+ * @returns Object with left and top pixel values relative to the circle's bounding box
21
+ *
22
+ * @example
23
+ * // Single handle on left side - positioned at center (180°)
24
+ * getCircleHandlePosition(0, 1, 'left') // { left: 0, top: 36 }
25
+ *
26
+ * @example
27
+ * // Two handles on left side - positioned at 150° and 210°
28
+ * getCircleHandlePosition(0, 2, 'left') // { left: ~4.8, top: ~18 }
29
+ * getCircleHandlePosition(1, 2, 'left') // { left: ~4.8, top: ~54 }
30
+ */
31
+ export declare function getCircleHandlePosition(index: number, count: number, side: 'left' | 'right', radius?: number, arcSpan?: number): HandlePosition;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Utility functions for calculating handle positions on nodes
3
+ */
4
+ /**
5
+ * Calculate handle position along a circle arc using cos/sin
6
+ *
7
+ * Distributes handles evenly along an arc on the left or right side of a circle.
8
+ * For N handles, they are positioned at angles calculated as:
9
+ * angle = centerAngle - arcSpan/2 + arcSpan * (index + 1) / (count + 1)
10
+ *
11
+ * @param index - The index of the handle (0-based)
12
+ * @param count - Total number of handles on this side
13
+ * @param side - 'left' for inputs, 'right' for outputs
14
+ * @param radius - The radius of the circle (default: 40px for 80px diameter)
15
+ * @param arcSpan - The arc span in radians (default: 5π/6 = 150°)
16
+ * @returns Object with left and top pixel values relative to the circle's bounding box
17
+ *
18
+ * @example
19
+ * // Single handle on left side - positioned at center (180°)
20
+ * getCircleHandlePosition(0, 1, 'left') // { left: 0, top: 36 }
21
+ *
22
+ * @example
23
+ * // Two handles on left side - positioned at 150° and 210°
24
+ * getCircleHandlePosition(0, 2, 'left') // { left: ~4.8, top: ~18 }
25
+ * getCircleHandlePosition(1, 2, 'left') // { left: ~4.8, top: ~54 }
26
+ */
27
+ export function getCircleHandlePosition(index, count, side, radius = 40, arcSpan = (Math.PI * 5) / 6) {
28
+ const centerAngle = side === 'left' ? Math.PI : 0; // 180° for left, 0° for right
29
+ const angle = centerAngle - arcSpan / 2 + (arcSpan * (index + 1)) / (count + 1);
30
+ const centerOffset = radius; // center of the circle (assuming square bounding box)
31
+ return {
32
+ left: centerOffset + radius * Math.cos(angle),
33
+ top: centerOffset + radius * Math.sin(angle)
34
+ };
35
+ }
@@ -95,6 +95,7 @@ export const CATEGORY_ICONS = {
95
95
  memories: 'mdi:brain',
96
96
  agents: 'mdi:account-cog',
97
97
  ai: 'mdi:shimmer',
98
+ interrupts: 'mdi:hand-back-left',
98
99
  bundles: 'mdi:package-variant'
99
100
  };
100
101
  /**
@@ -194,9 +194,9 @@ export function createNodeTypeConfigProperty(metadata, defaultType) {
194
194
  const oneOf = getNodeTypeOneOfOptions(metadata);
195
195
  const primaryType = defaultType ?? getPrimaryNodeType(metadata);
196
196
  return {
197
- type: "string",
198
- title: "Node Type",
199
- description: "Choose the visual representation for this node",
197
+ type: 'string',
198
+ title: 'Node Type',
199
+ description: 'Choose the visual representation for this node',
200
200
  default: primaryType,
201
201
  oneOf
202
202
  };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@d34dman/flowdrop",
3
3
  "license": "MIT",
4
4
  "private": false,
5
- "version": "0.0.47",
5
+ "version": "0.0.49",
6
6
  "scripts": {
7
7
  "dev": "vite dev",
8
8
  "build": "vite build && npm run prepack",
@@ -12,7 +12,7 @@
12
12
  "watch:build:production": "npm-watch build:production",
13
13
  "watch:build": "npm-watch build",
14
14
  "preview": "vite preview",
15
- "prepare": "svelte-kit sync || echo ''",
15
+ "prepare": "svelte-kit sync || echo '' && husky",
16
16
  "prepack": "svelte-kit sync && svelte-package && publint",
17
17
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
18
18
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
@@ -30,6 +30,7 @@
30
30
  "build-storybook": "storybook build",
31
31
  "api:lint": "redocly lint api/openapi.yaml --config api/redocly.yaml",
32
32
  "api:bundle": "redocly bundle api/openapi.yaml -o api/bundled.yaml --config api/redocly.yaml",
33
+ "api:watch": "nodemon --watch api --ext yaml --ignore api/bundled.yaml --exec 'npm run api:bundle'",
33
34
  "api:preview": "redocly preview-docs api/openapi.yaml --config api/redocly.yaml",
34
35
  "api:docs": "redocly build-docs api/bundled.yaml -o api-docs/index.html"
35
36
  },
@@ -172,8 +173,10 @@
172
173
  "eslint-plugin-svelte": "^3.0.0",
173
174
  "globals": "^16.0.0",
174
175
  "happy-dom": "^20.0.11",
176
+ "husky": "^9.1.7",
175
177
  "msw": "^2.12.7",
176
178
  "npm-watch": "^0.13.0",
179
+ "picomatch": "^4.0.3",
177
180
  "playwright": "^1.53.0",
178
181
  "prettier": "^3.4.2",
179
182
  "prettier-plugin-svelte": "^3.3.3",
@@ -187,7 +190,8 @@
187
190
  "vite": "^6.2.6",
188
191
  "vite-plugin-devtools-json": "^0.2.1",
189
192
  "vitest": "^3.2.3",
190
- "vitest-browser-svelte": "^0.1.0"
193
+ "vitest-browser-svelte": "^0.1.0",
194
+ "yaml": "^2.8.2"
191
195
  },
192
196
  "overrides": {
193
197
  "@sveltejs/kit": {
@@ -214,4 +218,4 @@
214
218
  "static"
215
219
  ]
216
220
  }
217
- }
221
+ }