@d34dman/flowdrop 0.0.16 → 0.0.18

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 (37) hide show
  1. package/README.md +106 -0
  2. package/dist/api/enhanced-client.d.ts +3 -3
  3. package/dist/api/enhanced-client.js +57 -57
  4. package/dist/components/FlowDropZone.svelte +4 -5
  5. package/dist/components/FlowDropZone.svelte.d.ts +1 -1
  6. package/dist/components/TerminalNode.svelte +565 -0
  7. package/dist/components/TerminalNode.svelte.d.ts +24 -0
  8. package/dist/components/UniversalNode.svelte +94 -34
  9. package/dist/components/WorkflowEditor.svelte +63 -3
  10. package/dist/config/runtimeConfig.d.ts +2 -2
  11. package/dist/config/runtimeConfig.js +7 -7
  12. package/dist/helpers/workflowEditorHelper.d.ts +44 -4
  13. package/dist/helpers/workflowEditorHelper.js +161 -30
  14. package/dist/index.d.ts +16 -13
  15. package/dist/index.js +19 -8
  16. package/dist/registry/builtinNodes.d.ts +77 -0
  17. package/dist/registry/builtinNodes.js +194 -0
  18. package/dist/registry/index.d.ts +7 -0
  19. package/dist/registry/index.js +10 -0
  20. package/dist/registry/nodeComponentRegistry.d.ts +307 -0
  21. package/dist/registry/nodeComponentRegistry.js +315 -0
  22. package/dist/registry/plugin.d.ts +215 -0
  23. package/dist/registry/plugin.js +249 -0
  24. package/dist/services/draftStorage.d.ts +1 -1
  25. package/dist/services/draftStorage.js +5 -5
  26. package/dist/stores/workflowStore.d.ts +2 -2
  27. package/dist/stores/workflowStore.js +16 -16
  28. package/dist/styles/base.css +15 -0
  29. package/dist/svelte-app.d.ts +6 -6
  30. package/dist/svelte-app.js +25 -25
  31. package/dist/types/auth.d.ts +2 -2
  32. package/dist/types/auth.js +7 -7
  33. package/dist/types/events.d.ts +2 -2
  34. package/dist/types/index.d.ts +38 -3
  35. package/dist/utils/nodeTypes.d.ts +76 -21
  36. package/dist/utils/nodeTypes.js +182 -32
  37. package/package.json +2 -2
@@ -0,0 +1,315 @@
1
+ /**
2
+ * Node Component Registry
3
+ * Central registry for node component types that allows built-in and third-party
4
+ * components to be registered and resolved at runtime.
5
+ *
6
+ * This enables:
7
+ * - Custom node components to be registered by users
8
+ * - External libraries to contribute node types via plugins
9
+ * - Runtime switching between different node visualizations
10
+ */
11
+ /**
12
+ * Central registry for node component types.
13
+ * Allows built-in and third-party components to be registered and resolved.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // Register a custom node
18
+ * nodeComponentRegistry.register({
19
+ * type: "myCustomNode",
20
+ * displayName: "My Custom Node",
21
+ * component: MyCustomNodeComponent,
22
+ * icon: "mdi:star",
23
+ * category: "custom"
24
+ * });
25
+ *
26
+ * // Get a component
27
+ * const component = nodeComponentRegistry.getComponent("myCustomNode");
28
+ * ```
29
+ */
30
+ class NodeComponentRegistry {
31
+ /** Map of type -> registration */
32
+ components = new Map();
33
+ /** Default type to use when requested type is not found */
34
+ defaultType = 'workflowNode';
35
+ /** Listeners for registry changes */
36
+ listeners = new Set();
37
+ /**
38
+ * Register a node component type.
39
+ *
40
+ * @param registration - The component registration details
41
+ * @param overwrite - If true, allows overwriting existing registrations
42
+ * @throws Error if type already registered and overwrite is false
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * nodeComponentRegistry.register({
47
+ * type: "fancy",
48
+ * displayName: "Fancy Node",
49
+ * component: FancyNode,
50
+ * icon: "mdi:sparkles"
51
+ * });
52
+ * ```
53
+ */
54
+ register(registration, overwrite = false) {
55
+ if (this.components.has(registration.type) && !overwrite) {
56
+ throw new Error(`Node type "${registration.type}" is already registered. ` +
57
+ `Use overwrite: true to replace it, or use a namespaced type like "mylib:${registration.type}".`);
58
+ }
59
+ this.components.set(registration.type, registration);
60
+ this.notifyListeners();
61
+ }
62
+ /**
63
+ * Register multiple components at once.
64
+ * Useful for libraries registering multiple node types.
65
+ *
66
+ * @param registrations - Array of registrations to add
67
+ * @param overwrite - If true, allows overwriting existing registrations
68
+ */
69
+ registerAll(registrations, overwrite = false) {
70
+ for (const registration of registrations) {
71
+ this.register(registration, overwrite);
72
+ }
73
+ }
74
+ /**
75
+ * Unregister a node component type.
76
+ *
77
+ * @param type - The type identifier to remove
78
+ * @returns true if the type was found and removed, false otherwise
79
+ */
80
+ unregister(type) {
81
+ const result = this.components.delete(type);
82
+ if (result) {
83
+ this.notifyListeners();
84
+ }
85
+ return result;
86
+ }
87
+ /**
88
+ * Get a registration by type.
89
+ *
90
+ * @param type - The type identifier to look up
91
+ * @returns The registration if found, undefined otherwise
92
+ */
93
+ get(type) {
94
+ return this.components.get(type);
95
+ }
96
+ /**
97
+ * Get the component for a type, with fallback to default.
98
+ *
99
+ * @param type - The type identifier to look up
100
+ * @returns The component if found, or the default component
101
+ */
102
+ getComponent(type) {
103
+ const registration = this.components.get(type) ?? this.components.get(this.defaultType);
104
+ return registration?.component;
105
+ }
106
+ /**
107
+ * Check if a type is registered.
108
+ *
109
+ * @param type - The type identifier to check
110
+ * @returns true if the type is registered
111
+ */
112
+ has(type) {
113
+ return this.components.has(type);
114
+ }
115
+ /**
116
+ * Get all registered type identifiers.
117
+ *
118
+ * @returns Array of registered type strings
119
+ */
120
+ getTypes() {
121
+ return Array.from(this.components.keys());
122
+ }
123
+ /**
124
+ * Get all registrations.
125
+ *
126
+ * @returns Array of all registered node component metadata
127
+ */
128
+ getAll() {
129
+ return Array.from(this.components.values());
130
+ }
131
+ /**
132
+ * Get registrations filtered by criteria.
133
+ *
134
+ * @param filter - Filter options
135
+ * @returns Filtered array of registrations
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * // Get all visual nodes
140
+ * const visualNodes = nodeComponentRegistry.filter({ category: "visual" });
141
+ *
142
+ * // Get nodes from a specific library
143
+ * const libNodes = nodeComponentRegistry.filter({ source: "mylib" });
144
+ * ```
145
+ */
146
+ filter(filter) {
147
+ return this.getAll().filter((reg) => {
148
+ if (filter.category && reg.category !== filter.category) {
149
+ return false;
150
+ }
151
+ if (filter.source && reg.source !== filter.source) {
152
+ return false;
153
+ }
154
+ if (filter.predicate && !filter.predicate(reg)) {
155
+ return false;
156
+ }
157
+ return true;
158
+ });
159
+ }
160
+ /**
161
+ * Get registrations filtered by category.
162
+ *
163
+ * @param category - The category to filter by
164
+ * @returns Array of registrations in that category
165
+ */
166
+ getByCategory(category) {
167
+ return this.filter({ category });
168
+ }
169
+ /**
170
+ * Get registrations filtered by source.
171
+ *
172
+ * @param source - The source identifier to filter by (e.g., "flowdrop", "mylib")
173
+ * @returns Array of registrations from that source
174
+ */
175
+ getBySource(source) {
176
+ return this.filter({ source });
177
+ }
178
+ /**
179
+ * Set the default fallback type.
180
+ *
181
+ * @param type - The type to use as default when requested type is not found
182
+ * @throws Error if the type is not registered
183
+ */
184
+ setDefaultType(type) {
185
+ if (!this.components.has(type)) {
186
+ throw new Error(`Cannot set default to unregistered type: ${type}`);
187
+ }
188
+ this.defaultType = type;
189
+ }
190
+ /**
191
+ * Get the current default type.
192
+ *
193
+ * @returns The default type identifier
194
+ */
195
+ getDefaultType() {
196
+ return this.defaultType;
197
+ }
198
+ /**
199
+ * Subscribe to registry changes.
200
+ * Called whenever components are registered or unregistered.
201
+ *
202
+ * @param listener - Callback to invoke on changes
203
+ * @returns Unsubscribe function
204
+ */
205
+ subscribe(listener) {
206
+ this.listeners.add(listener);
207
+ return () => this.listeners.delete(listener);
208
+ }
209
+ /**
210
+ * Notify all listeners of a change.
211
+ */
212
+ notifyListeners() {
213
+ for (const listener of this.listeners) {
214
+ listener();
215
+ }
216
+ }
217
+ /**
218
+ * Get enum options for config forms.
219
+ * Returns arrays suitable for JSON Schema enum/enumNames.
220
+ *
221
+ * @param filterFn - Optional filter function to limit which types are included
222
+ * @returns Object with enum (type values) and enumNames (display names)
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * const { enum: types, enumNames } = nodeComponentRegistry.getEnumOptions();
227
+ * // Use in configSchema: { type: "string", enum: types, enumNames }
228
+ * ```
229
+ */
230
+ getEnumOptions(filterFn) {
231
+ const registrations = filterFn ? this.getAll().filter(filterFn) : this.getAll();
232
+ return {
233
+ enum: registrations.map((r) => r.type),
234
+ enumNames: registrations.map((r) => r.displayName)
235
+ };
236
+ }
237
+ /**
238
+ * Get the status position for a node type.
239
+ *
240
+ * @param type - The node type
241
+ * @returns The status position, or default "top-right"
242
+ */
243
+ getStatusPosition(type) {
244
+ return this.components.get(type)?.statusPosition ?? 'top-right';
245
+ }
246
+ /**
247
+ * Get the status size for a node type.
248
+ *
249
+ * @param type - The node type
250
+ * @returns The status size, or default "md"
251
+ */
252
+ getStatusSize(type) {
253
+ return this.components.get(type)?.statusSize ?? 'md';
254
+ }
255
+ /**
256
+ * Clear all registrations.
257
+ * Primarily useful for testing.
258
+ */
259
+ clear() {
260
+ this.components.clear();
261
+ this.notifyListeners();
262
+ }
263
+ /**
264
+ * Get the count of registered components.
265
+ *
266
+ * @returns Number of registered node types
267
+ */
268
+ get size() {
269
+ return this.components.size;
270
+ }
271
+ }
272
+ /** Singleton instance of the node component registry */
273
+ export const nodeComponentRegistry = new NodeComponentRegistry();
274
+ /**
275
+ * Helper function to create a namespaced type identifier.
276
+ * Use this to avoid conflicts when registering custom nodes.
277
+ *
278
+ * @param namespace - Your library/project namespace
279
+ * @param type - The node type name
280
+ * @returns Namespaced type string (e.g., "mylib:custom")
281
+ *
282
+ * @example
283
+ * ```typescript
284
+ * const type = createNamespacedType("mylib", "fancy");
285
+ * // Returns "mylib:fancy"
286
+ * ```
287
+ */
288
+ export function createNamespacedType(namespace, type) {
289
+ return `${namespace}:${type}`;
290
+ }
291
+ /**
292
+ * Parse a namespaced type into its components.
293
+ *
294
+ * @param namespacedType - The full namespaced type (e.g., "mylib:custom")
295
+ * @returns Object with namespace and type, or null if not namespaced
296
+ *
297
+ * @example
298
+ * ```typescript
299
+ * parseNamespacedType("mylib:fancy");
300
+ * // Returns { namespace: "mylib", type: "fancy" }
301
+ *
302
+ * parseNamespacedType("simple");
303
+ * // Returns null (not namespaced)
304
+ * ```
305
+ */
306
+ export function parseNamespacedType(namespacedType) {
307
+ const colonIndex = namespacedType.indexOf(':');
308
+ if (colonIndex === -1) {
309
+ return null;
310
+ }
311
+ return {
312
+ namespace: namespacedType.slice(0, colonIndex),
313
+ type: namespacedType.slice(colonIndex + 1)
314
+ };
315
+ }
@@ -0,0 +1,215 @@
1
+ /**
2
+ * FlowDrop Plugin System
3
+ * Provides APIs for external libraries to register custom node components.
4
+ *
5
+ * This enables a plugin ecosystem where:
6
+ * - Third-party libraries can provide custom node types
7
+ * - Custom nodes are namespaced to avoid conflicts
8
+ * - Registration is simplified with a clean API
9
+ */
10
+ import { type NodeComponentProps, type NodeComponentCategory, type StatusPosition, type StatusSize } from './nodeComponentRegistry.js';
11
+ import type { Component } from 'svelte';
12
+ /**
13
+ * Plugin configuration for external libraries.
14
+ * Use this to register multiple node types from a library.
15
+ */
16
+ export interface FlowDropPluginConfig {
17
+ /**
18
+ * Unique namespace for this plugin.
19
+ * Used to prefix all node types (e.g., "mylib" -> "mylib:nodename").
20
+ * Should be lowercase, alphanumeric with optional hyphens.
21
+ */
22
+ namespace: string;
23
+ /** Display name for the plugin (for UI/debugging purposes) */
24
+ name: string;
25
+ /** Plugin version (optional, for debugging) */
26
+ version?: string;
27
+ /** Description of what this plugin provides */
28
+ description?: string;
29
+ /** Node components to register */
30
+ nodes: PluginNodeDefinition[];
31
+ }
32
+ /**
33
+ * Simplified node definition for plugins.
34
+ * Provides a cleaner API than full NodeComponentRegistration.
35
+ */
36
+ export interface PluginNodeDefinition {
37
+ /**
38
+ * Type identifier for this node.
39
+ * Will be prefixed with the plugin namespace (e.g., "fancy" -> "mylib:fancy").
40
+ */
41
+ type: string;
42
+ /** Display name shown in UI */
43
+ displayName: string;
44
+ /** Description of what this node does */
45
+ description?: string;
46
+ /** The Svelte component to render */
47
+ component: Component<NodeComponentProps>;
48
+ /** Icon in iconify format (e.g., "mdi:star") */
49
+ icon?: string;
50
+ /** Category for organizing in UI */
51
+ category?: NodeComponentCategory;
52
+ /** Status overlay position */
53
+ statusPosition?: StatusPosition;
54
+ /** Status overlay size */
55
+ statusSize?: StatusSize;
56
+ }
57
+ /**
58
+ * Result of plugin registration.
59
+ * Contains information about what was registered and any errors.
60
+ */
61
+ export interface PluginRegistrationResult {
62
+ /** Whether all nodes were registered successfully */
63
+ success: boolean;
64
+ /** The plugin namespace */
65
+ namespace: string;
66
+ /** Array of successfully registered type identifiers (namespaced) */
67
+ registeredTypes: string[];
68
+ /** Array of error messages for failed registrations */
69
+ errors: string[];
70
+ }
71
+ /**
72
+ * Register a FlowDrop plugin with custom node components.
73
+ * All node types are automatically namespaced with the plugin namespace.
74
+ *
75
+ * @param config - Plugin configuration with namespace and node definitions
76
+ * @returns Result object with registered types and any errors
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * import { registerFlowDropPlugin } from "@flowdrop/lib";
81
+ * import FancyNode from "./FancyNode.svelte";
82
+ * import GlowNode from "./GlowNode.svelte";
83
+ *
84
+ * const result = registerFlowDropPlugin({
85
+ * namespace: "awesome",
86
+ * name: "Awesome Nodes",
87
+ * version: "1.0.0",
88
+ * nodes: [
89
+ * {
90
+ * type: "fancy",
91
+ * displayName: "Fancy Node",
92
+ * component: FancyNode,
93
+ * icon: "mdi:sparkles"
94
+ * },
95
+ * {
96
+ * type: "glow",
97
+ * displayName: "Glowing Node",
98
+ * component: GlowNode,
99
+ * icon: "mdi:lightbulb"
100
+ * }
101
+ * ]
102
+ * });
103
+ *
104
+ * // Result:
105
+ * // {
106
+ * // success: true,
107
+ * // namespace: "awesome",
108
+ * // registeredTypes: ["awesome:fancy", "awesome:glow"],
109
+ * // errors: []
110
+ * // }
111
+ * ```
112
+ */
113
+ export declare function registerFlowDropPlugin(config: FlowDropPluginConfig): PluginRegistrationResult;
114
+ /**
115
+ * Unregister all nodes from a plugin by namespace.
116
+ *
117
+ * @param namespace - The plugin namespace to unregister
118
+ * @returns Array of unregistered type identifiers
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * const removed = unregisterFlowDropPlugin("awesome");
123
+ * // Returns ["awesome:fancy", "awesome:glow"]
124
+ * ```
125
+ */
126
+ export declare function unregisterFlowDropPlugin(namespace: string): string[];
127
+ /**
128
+ * Check if a namespace is valid.
129
+ * Must be lowercase alphanumeric with optional hyphens.
130
+ *
131
+ * @param namespace - The namespace to validate
132
+ * @returns true if valid
133
+ */
134
+ export declare function isValidNamespace(namespace: string): boolean;
135
+ /**
136
+ * Get all registered plugins (unique namespaces).
137
+ *
138
+ * @returns Array of namespace strings
139
+ */
140
+ export declare function getRegisteredPlugins(): string[];
141
+ /**
142
+ * Get the count of nodes registered by a plugin.
143
+ *
144
+ * @param namespace - The plugin namespace
145
+ * @returns Number of nodes registered by this plugin
146
+ */
147
+ export declare function getPluginNodeCount(namespace: string): number;
148
+ /**
149
+ * Register a single custom node without a full plugin.
150
+ * Useful for project-specific custom nodes.
151
+ *
152
+ * @param type - Type identifier (can be namespaced or plain)
153
+ * @param displayName - Display name for UI
154
+ * @param component - Svelte component
155
+ * @param options - Additional options
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * import { registerCustomNode } from "@flowdrop/lib";
160
+ * import MyNode from "./MyNode.svelte";
161
+ *
162
+ * registerCustomNode("myproject:special", "Special Node", MyNode, {
163
+ * icon: "mdi:star",
164
+ * description: "A special node for my project"
165
+ * });
166
+ * ```
167
+ */
168
+ export declare function registerCustomNode(type: string, displayName: string, component: Component<NodeComponentProps>, options?: {
169
+ description?: string;
170
+ icon?: string;
171
+ category?: NodeComponentCategory;
172
+ source?: string;
173
+ statusPosition?: StatusPosition;
174
+ statusSize?: StatusSize;
175
+ }): void;
176
+ /**
177
+ * Create a plugin builder for a fluent API experience.
178
+ *
179
+ * @param namespace - Plugin namespace
180
+ * @param name - Plugin name
181
+ * @returns Plugin builder with chainable methods
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * import { createPlugin } from "@flowdrop/lib";
186
+ *
187
+ * createPlugin("awesome", "Awesome Nodes")
188
+ * .version("1.0.0")
189
+ * .node("fancy", "Fancy Node", FancyNode)
190
+ * .node("glow", "Glowing Node", GlowNode, { icon: "mdi:lightbulb" })
191
+ * .register();
192
+ * ```
193
+ */
194
+ export declare function createPlugin(namespace: string, name: string): {
195
+ /**
196
+ * Set plugin version
197
+ */
198
+ version(v: string): /*elided*/ any;
199
+ /**
200
+ * Set plugin description
201
+ */
202
+ description(desc: string): /*elided*/ any;
203
+ /**
204
+ * Add a node to the plugin
205
+ */
206
+ node(type: string, displayName: string, component: Component<NodeComponentProps>, options?: Partial<Omit<PluginNodeDefinition, "type" | "displayName" | "component">>): /*elided*/ any;
207
+ /**
208
+ * Register the plugin
209
+ */
210
+ register(): PluginRegistrationResult;
211
+ /**
212
+ * Get the config without registering (for testing/inspection)
213
+ */
214
+ getConfig(): FlowDropPluginConfig;
215
+ };