@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
package/README.md CHANGED
@@ -14,6 +14,14 @@ A visual workflow editor component library built with Svelte 5 and @xyflow/svelt
14
14
  - **TypeScript Support**: Full type definitions included
15
15
  - **Docker Ready**: Production-ready Dockerfile and Docker Compose configuration
16
16
 
17
+ ### Enterprise Features (v0.0.16+)
18
+
19
+ - **Pluggable Authentication**: AuthProvider interface for OAuth, JWT, SSO integration
20
+ - **Workflow Lifecycle Events**: Hooks for save, load, change, and unmount events
21
+ - **Dirty State Tracking**: Monitor unsaved changes with reactive stores
22
+ - **Draft Auto-Save**: Automatic localStorage drafts with configurable intervals
23
+ - **Feature Flags**: Customize behavior for security and UX requirements
24
+
17
25
  ## 📦 Installation
18
26
 
19
27
  ```bash
@@ -117,6 +125,52 @@ const editor = mountWorkflowEditor(container, {
117
125
  editor.destroy();
118
126
  ```
119
127
 
128
+ #### 3. Enterprise Integration (v0.0.16+)
129
+
130
+ ```javascript
131
+ import { mountFlowDropApp, createEndpointConfig, CallbackAuthProvider } from '@d34dman/flowdrop';
132
+
133
+ const app = await mountFlowDropApp(container, {
134
+ workflow: myWorkflow,
135
+ endpointConfig: createEndpointConfig('/api/flowdrop'),
136
+
137
+ // Dynamic authentication with token refresh
138
+ authProvider: new CallbackAuthProvider({
139
+ getToken: () => authService.getAccessToken(),
140
+ onUnauthorized: () => authService.refreshToken()
141
+ }),
142
+
143
+ // Workflow lifecycle hooks
144
+ eventHandlers: {
145
+ onDirtyStateChange: (isDirty) => updateSaveButton(isDirty),
146
+ onAfterSave: (workflow) => showSuccess('Saved!'),
147
+ onBeforeUnmount: (workflow, isDirty) => {
148
+ if (isDirty) saveDraft(workflow);
149
+ }
150
+ },
151
+
152
+ // Feature configuration
153
+ features: {
154
+ autoSaveDraft: true,
155
+ autoSaveDraftInterval: 30000,
156
+ showToasts: true
157
+ }
158
+ });
159
+
160
+ // Access instance methods
161
+ if (app.isDirty()) {
162
+ await app.save();
163
+ }
164
+
165
+ // Get current workflow data
166
+ const workflow = app.getWorkflow();
167
+
168
+ // Cleanup
169
+ app.destroy();
170
+ ```
171
+
172
+ See the [Enterprise Integration Guide](./docs/enterprise-integration.md) for React, Vue, Angular, and Drupal examples.
173
+
120
174
  #### 3. Integration with Backend Frameworks
121
175
 
122
176
  ##### Drupal Example
@@ -218,6 +272,48 @@ Override CSS custom properties:
218
272
 
219
273
  ### Node Types
220
274
 
275
+ FlowDrop includes 7 built-in visual node types that control how nodes are rendered:
276
+
277
+ | Type | Description | Use Case |
278
+ | ---------- | ------------------------------------------------------- | ------------------------ |
279
+ | `default` | Full-featured workflow node with inputs/outputs display | Standard nodes |
280
+ | `simple` | Compact layout with header, icon, and description | Space-efficient nodes |
281
+ | `square` | Minimal square node showing only an icon | Icon-only representation |
282
+ | `tool` | Specialized node for agent tools with tool metadata | AI agent tools |
283
+ | `gateway` | Branching control flow with multiple output branches | Conditional logic |
284
+ | `terminal` | Circular node for workflow start/end/exit points | Workflow boundaries |
285
+ | `note` | Documentation note with markdown support | Comments/documentation |
286
+
287
+ #### Terminal Nodes
288
+
289
+ Terminal nodes are special circular nodes for workflow boundaries:
290
+
291
+ ```typescript
292
+ // Start node - output only
293
+ const startNode: NodeMetadata = {
294
+ id: 'workflow-start',
295
+ name: 'Start',
296
+ type: 'terminal',
297
+ tags: ['start'],
298
+ inputs: [],
299
+ outputs: [{ id: 'trigger', name: 'Go', type: 'output', dataType: 'trigger' }]
300
+ };
301
+
302
+ // End node - input only
303
+ const endNode: NodeMetadata = {
304
+ id: 'workflow-end',
305
+ name: 'End',
306
+ type: 'terminal',
307
+ tags: ['end'],
308
+ inputs: [{ id: 'done', name: 'Done', type: 'input', dataType: 'trigger' }],
309
+ outputs: []
310
+ };
311
+ ```
312
+
313
+ Terminal variants are auto-detected from `id`, `name`, or `tags` containing: `start`, `end`, `exit`, `abort`, `entry`, `finish`, `complete`.
314
+
315
+ #### Custom Node Types
316
+
221
317
  Define custom node types:
222
318
 
223
319
  ```typescript
@@ -313,6 +409,13 @@ npm run format
313
409
  - **CHANGELOG.md** - Version history
314
410
  - **Storybook** - Component documentation (run `npm run storybook`)
315
411
 
412
+ ### Enterprise Features (v0.0.16+)
413
+
414
+ - **[Enterprise Integration Guide](./docs/enterprise-integration.md)** - Complete integration patterns for React, Vue, Angular, Drupal
415
+ - **[Authentication Guide](./docs/authentication-guide.md)** - OAuth, JWT, SSO, and custom auth providers
416
+ - **[Event Handlers](./docs/event-handlers.md)** - Workflow lifecycle events and hooks
417
+ - **[Features Configuration](./docs/features-configuration.md)** - Feature flags, draft auto-save, and customization
418
+
316
419
  ## 🤝 Contributing
317
420
 
318
421
  Not accepting contributions until the library stabilizes. Stay tuned.
@@ -347,6 +450,7 @@ docker-compose up -d
347
450
  ### Environment Variables
348
451
 
349
452
  **Production (Runtime):**
453
+
350
454
  - `FLOWDROP_API_BASE_URL` - Backend API URL
351
455
  - `FLOWDROP_THEME` - UI theme (light/dark/auto)
352
456
  - `FLOWDROP_TIMEOUT` - Request timeout in milliseconds
@@ -354,6 +458,7 @@ docker-compose up -d
354
458
  - `FLOWDROP_AUTH_TOKEN` - Authentication token
355
459
 
356
460
  **Development (Build-time):**
461
+
357
462
  - `VITE_API_BASE_URL` - Dev API URL (used only during `npm run dev`)
358
463
 
359
464
  ### Build for Production
@@ -371,6 +476,7 @@ node build
371
476
  ```
372
477
 
373
478
  For detailed deployment instructions, see:
479
+
374
480
  - [DOCKER.md](./DOCKER.md) - Docker quick start
375
481
 
376
482
  ---
@@ -5,9 +5,9 @@
5
5
  *
6
6
  * @module api/enhanced-client
7
7
  */
8
- import type { NodeMetadata, Workflow, ExecutionResult } from "../types/index.js";
9
- import type { EndpointConfig } from "../config/endpoints.js";
10
- import type { AuthProvider } from "../types/auth.js";
8
+ import type { NodeMetadata, Workflow, ExecutionResult } from '../types/index.js';
9
+ import type { EndpointConfig } from '../config/endpoints.js';
10
+ import type { AuthProvider } from '../types/auth.js';
11
11
  /**
12
12
  * API error with additional context
13
13
  */
@@ -5,8 +5,8 @@
5
5
  *
6
6
  * @module api/enhanced-client
7
7
  */
8
- import { buildEndpointUrl, getEndpointMethod, getEndpointHeaders } from "../config/endpoints.js";
9
- import { createAuthProviderFromLegacyConfig } from "../types/auth.js";
8
+ import { buildEndpointUrl, getEndpointMethod, getEndpointHeaders } from '../config/endpoints.js';
9
+ import { createAuthProviderFromLegacyConfig } from '../types/auth.js';
10
10
  /**
11
11
  * API error with additional context
12
12
  */
@@ -19,7 +19,7 @@ export class ApiError extends Error {
19
19
  operation;
20
20
  constructor(message, status, operation, errorData = {}) {
21
21
  super(message);
22
- this.name = "ApiError";
22
+ this.name = 'ApiError';
23
23
  this.status = status;
24
24
  this.operation = operation;
25
25
  this.errorData = errorData;
@@ -62,7 +62,7 @@ export class EnhancedFlowDropApiClient {
62
62
  * @param options - Additional fetch options
63
63
  * @param operation - Description of the operation (for error messages)
64
64
  */
65
- async request(endpointKey, endpointPath, params, options = {}, operation = "API request") {
65
+ async request(endpointKey, endpointPath, params, options = {}, operation = 'API request') {
66
66
  const url = buildEndpointUrl(this.config, endpointPath, params);
67
67
  const method = options.method ?? getEndpointMethod(this.config, endpointKey);
68
68
  const configHeaders = getEndpointHeaders(this.config, endpointKey);
@@ -99,14 +99,14 @@ export class EnhancedFlowDropApiClient {
99
99
  continue; // Retry with new headers
100
100
  }
101
101
  }
102
- throw new ApiError("Unauthorized", 401, operation, {});
102
+ throw new ApiError('Unauthorized', 401, operation, {});
103
103
  }
104
104
  // Handle 403 Forbidden
105
105
  if (response.status === 403) {
106
106
  if (this.authProvider.onForbidden) {
107
107
  await this.authProvider.onForbidden();
108
108
  }
109
- throw new ApiError("Forbidden", 403, operation, {});
109
+ throw new ApiError('Forbidden', 403, operation, {});
110
110
  }
111
111
  // Handle other errors
112
112
  if (!response.ok) {
@@ -133,7 +133,7 @@ export class EnhancedFlowDropApiClient {
133
133
  }
134
134
  // Wait before retry
135
135
  const delay = this.config.retry?.delay ?? 1000;
136
- const backoffDelay = this.config.retry?.backoff === "exponential" ? delay * Math.pow(2, attempt - 1) : delay;
136
+ const backoffDelay = this.config.retry?.backoff === 'exponential' ? delay * Math.pow(2, attempt - 1) : delay;
137
137
  await new Promise((resolve) => setTimeout(resolve, backoffDelay));
138
138
  }
139
139
  }
@@ -166,9 +166,9 @@ export class EnhancedFlowDropApiClient {
166
166
  * Fetch all available node types
167
167
  */
168
168
  async getAvailableNodes() {
169
- const response = await this.request("nodes.list", this.config.endpoints.nodes.list, undefined, {}, "fetch available nodes");
169
+ const response = await this.request('nodes.list', this.config.endpoints.nodes.list, undefined, {}, 'fetch available nodes');
170
170
  if (!response.success || !response.data) {
171
- throw new Error(response.error ?? "Failed to fetch available nodes");
171
+ throw new Error(response.error ?? 'Failed to fetch available nodes');
172
172
  }
173
173
  return response.data;
174
174
  }
@@ -176,9 +176,9 @@ export class EnhancedFlowDropApiClient {
176
176
  * Fetch nodes filtered by category
177
177
  */
178
178
  async getNodesByCategory(category) {
179
- const response = await this.request("nodes.byCategory", this.config.endpoints.nodes.byCategory, { category }, {}, "fetch nodes by category");
179
+ const response = await this.request('nodes.byCategory', this.config.endpoints.nodes.byCategory, { category }, {}, 'fetch nodes by category');
180
180
  if (!response.success || !response.data) {
181
- throw new Error(response.error ?? "Failed to fetch nodes by category");
181
+ throw new Error(response.error ?? 'Failed to fetch nodes by category');
182
182
  }
183
183
  return response.data;
184
184
  }
@@ -186,9 +186,9 @@ export class EnhancedFlowDropApiClient {
186
186
  * Fetch metadata for a specific node type
187
187
  */
188
188
  async getNodeMetadata(nodeId) {
189
- const response = await this.request("nodes.metadata", this.config.endpoints.nodes.metadata, { id: nodeId }, {}, "fetch node metadata");
189
+ const response = await this.request('nodes.metadata', this.config.endpoints.nodes.metadata, { id: nodeId }, {}, 'fetch node metadata');
190
190
  if (!response.success || !response.data) {
191
- throw new Error(response.error ?? "Failed to fetch node metadata");
191
+ throw new Error(response.error ?? 'Failed to fetch node metadata');
192
192
  }
193
193
  return response.data;
194
194
  }
@@ -199,12 +199,12 @@ export class EnhancedFlowDropApiClient {
199
199
  * Save a new workflow
200
200
  */
201
201
  async saveWorkflow(workflow) {
202
- const response = await this.request("workflows.create", this.config.endpoints.workflows.create, undefined, {
203
- method: "POST",
202
+ const response = await this.request('workflows.create', this.config.endpoints.workflows.create, undefined, {
203
+ method: 'POST',
204
204
  body: JSON.stringify(workflow)
205
- }, "save workflow");
205
+ }, 'save workflow');
206
206
  if (!response.success || !response.data) {
207
- throw new Error(response.error ?? "Failed to save workflow");
207
+ throw new Error(response.error ?? 'Failed to save workflow');
208
208
  }
209
209
  return response.data;
210
210
  }
@@ -212,12 +212,12 @@ export class EnhancedFlowDropApiClient {
212
212
  * Update an existing workflow
213
213
  */
214
214
  async updateWorkflow(workflowId, workflow) {
215
- const response = await this.request("workflows.update", this.config.endpoints.workflows.update, { id: workflowId }, {
216
- method: "PUT",
215
+ const response = await this.request('workflows.update', this.config.endpoints.workflows.update, { id: workflowId }, {
216
+ method: 'PUT',
217
217
  body: JSON.stringify(workflow)
218
- }, "update workflow");
218
+ }, 'update workflow');
219
219
  if (!response.success || !response.data) {
220
- throw new Error(response.error ?? "Failed to update workflow");
220
+ throw new Error(response.error ?? 'Failed to update workflow');
221
221
  }
222
222
  return response.data;
223
223
  }
@@ -225,9 +225,9 @@ export class EnhancedFlowDropApiClient {
225
225
  * Load a workflow by ID
226
226
  */
227
227
  async loadWorkflow(workflowId) {
228
- const response = await this.request("workflows.get", this.config.endpoints.workflows.get, { id: workflowId }, {}, "load workflow");
228
+ const response = await this.request('workflows.get', this.config.endpoints.workflows.get, { id: workflowId }, {}, 'load workflow');
229
229
  if (!response.success || !response.data) {
230
- throw new Error(response.error ?? "Failed to load workflow");
230
+ throw new Error(response.error ?? 'Failed to load workflow');
231
231
  }
232
232
  return response.data;
233
233
  }
@@ -235,9 +235,9 @@ export class EnhancedFlowDropApiClient {
235
235
  * List all workflows
236
236
  */
237
237
  async listWorkflows() {
238
- const response = await this.request("workflows.list", this.config.endpoints.workflows.list, undefined, {}, "list workflows");
238
+ const response = await this.request('workflows.list', this.config.endpoints.workflows.list, undefined, {}, 'list workflows');
239
239
  if (!response.success || !response.data) {
240
- throw new Error(response.error ?? "Failed to list workflows");
240
+ throw new Error(response.error ?? 'Failed to list workflows');
241
241
  }
242
242
  return response.data;
243
243
  }
@@ -245,21 +245,21 @@ export class EnhancedFlowDropApiClient {
245
245
  * Delete a workflow
246
246
  */
247
247
  async deleteWorkflow(workflowId) {
248
- const response = await this.request("workflows.delete", this.config.endpoints.workflows.delete, { id: workflowId }, { method: "DELETE" }, "delete workflow");
248
+ const response = await this.request('workflows.delete', this.config.endpoints.workflows.delete, { id: workflowId }, { method: 'DELETE' }, 'delete workflow');
249
249
  if (!response.success) {
250
- throw new Error(response.error ?? "Failed to delete workflow");
250
+ throw new Error(response.error ?? 'Failed to delete workflow');
251
251
  }
252
252
  }
253
253
  /**
254
254
  * Validate a workflow
255
255
  */
256
256
  async validateWorkflow(workflow) {
257
- const response = await this.request("workflows.validate", this.config.endpoints.workflows.validate, undefined, {
258
- method: "POST",
257
+ const response = await this.request('workflows.validate', this.config.endpoints.workflows.validate, undefined, {
258
+ method: 'POST',
259
259
  body: JSON.stringify(workflow)
260
- }, "validate workflow");
260
+ }, 'validate workflow');
261
261
  if (!response.success || !response.data) {
262
- throw new Error(response.error ?? "Failed to validate workflow");
262
+ throw new Error(response.error ?? 'Failed to validate workflow');
263
263
  }
264
264
  return response.data;
265
265
  }
@@ -267,9 +267,9 @@ export class EnhancedFlowDropApiClient {
267
267
  * Export a workflow as JSON string
268
268
  */
269
269
  async exportWorkflow(workflowId) {
270
- const response = await this.request("workflows.export", this.config.endpoints.workflows.export, { id: workflowId }, {}, "export workflow");
270
+ const response = await this.request('workflows.export', this.config.endpoints.workflows.export, { id: workflowId }, {}, 'export workflow');
271
271
  if (!response.success || !response.data) {
272
- throw new Error(response.error ?? "Failed to export workflow");
272
+ throw new Error(response.error ?? 'Failed to export workflow');
273
273
  }
274
274
  return response.data;
275
275
  }
@@ -277,12 +277,12 @@ export class EnhancedFlowDropApiClient {
277
277
  * Import a workflow from JSON
278
278
  */
279
279
  async importWorkflow(workflowJson) {
280
- const response = await this.request("workflows.import", this.config.endpoints.workflows.import, undefined, {
281
- method: "POST",
280
+ const response = await this.request('workflows.import', this.config.endpoints.workflows.import, undefined, {
281
+ method: 'POST',
282
282
  body: JSON.stringify({ workflow: workflowJson })
283
- }, "import workflow");
283
+ }, 'import workflow');
284
284
  if (!response.success || !response.data) {
285
- throw new Error(response.error ?? "Failed to import workflow");
285
+ throw new Error(response.error ?? 'Failed to import workflow');
286
286
  }
287
287
  return response.data;
288
288
  }
@@ -293,12 +293,12 @@ export class EnhancedFlowDropApiClient {
293
293
  * Execute a workflow
294
294
  */
295
295
  async executeWorkflow(workflowId, inputs) {
296
- const response = await this.request("executions.execute", this.config.endpoints.executions.execute, { id: workflowId }, {
297
- method: "POST",
296
+ const response = await this.request('executions.execute', this.config.endpoints.executions.execute, { id: workflowId }, {
297
+ method: 'POST',
298
298
  body: JSON.stringify({ inputs })
299
- }, "execute workflow");
299
+ }, 'execute workflow');
300
300
  if (!response.success || !response.data) {
301
- throw new Error(response.error ?? "Failed to execute workflow");
301
+ throw new Error(response.error ?? 'Failed to execute workflow');
302
302
  }
303
303
  return response.data;
304
304
  }
@@ -306,9 +306,9 @@ export class EnhancedFlowDropApiClient {
306
306
  * Get execution status
307
307
  */
308
308
  async getExecutionStatus(executionId) {
309
- const response = await this.request("executions.status", this.config.endpoints.executions.status, { id: executionId }, {}, "get execution status");
309
+ const response = await this.request('executions.status', this.config.endpoints.executions.status, { id: executionId }, {}, 'get execution status');
310
310
  if (!response.success || !response.data) {
311
- throw new Error(response.error ?? "Failed to get execution status");
311
+ throw new Error(response.error ?? 'Failed to get execution status');
312
312
  }
313
313
  return response.data;
314
314
  }
@@ -316,18 +316,18 @@ export class EnhancedFlowDropApiClient {
316
316
  * Cancel a running execution
317
317
  */
318
318
  async cancelExecution(executionId) {
319
- const response = await this.request("executions.cancel", this.config.endpoints.executions.cancel, { id: executionId }, { method: "POST" }, "cancel execution");
319
+ const response = await this.request('executions.cancel', this.config.endpoints.executions.cancel, { id: executionId }, { method: 'POST' }, 'cancel execution');
320
320
  if (!response.success) {
321
- throw new Error(response.error ?? "Failed to cancel execution");
321
+ throw new Error(response.error ?? 'Failed to cancel execution');
322
322
  }
323
323
  }
324
324
  /**
325
325
  * Get execution logs
326
326
  */
327
327
  async getExecutionLogs(executionId) {
328
- const response = await this.request("executions.logs", this.config.endpoints.executions.logs, { id: executionId }, {}, "get execution logs");
328
+ const response = await this.request('executions.logs', this.config.endpoints.executions.logs, { id: executionId }, {}, 'get execution logs');
329
329
  if (!response.success || !response.data) {
330
- throw new Error(response.error ?? "Failed to get execution logs");
330
+ throw new Error(response.error ?? 'Failed to get execution logs');
331
331
  }
332
332
  return response.data;
333
333
  }
@@ -338,9 +338,9 @@ export class EnhancedFlowDropApiClient {
338
338
  * List available templates
339
339
  */
340
340
  async listTemplates() {
341
- const response = await this.request("templates.list", this.config.endpoints.templates.list, undefined, {}, "list templates");
341
+ const response = await this.request('templates.list', this.config.endpoints.templates.list, undefined, {}, 'list templates');
342
342
  if (!response.success || !response.data) {
343
- throw new Error(response.error ?? "Failed to list templates");
343
+ throw new Error(response.error ?? 'Failed to list templates');
344
344
  }
345
345
  return response.data;
346
346
  }
@@ -348,9 +348,9 @@ export class EnhancedFlowDropApiClient {
348
348
  * Get a template by ID
349
349
  */
350
350
  async getTemplate(templateId) {
351
- const response = await this.request("templates.get", this.config.endpoints.templates.get, { id: templateId }, {}, "get template");
351
+ const response = await this.request('templates.get', this.config.endpoints.templates.get, { id: templateId }, {}, 'get template');
352
352
  if (!response.success || !response.data) {
353
- throw new Error(response.error ?? "Failed to get template");
353
+ throw new Error(response.error ?? 'Failed to get template');
354
354
  }
355
355
  return response.data;
356
356
  }
@@ -361,9 +361,9 @@ export class EnhancedFlowDropApiClient {
361
361
  * Get system health status
362
362
  */
363
363
  async getSystemHealth() {
364
- const response = await this.request("system.health", this.config.endpoints.system.health, undefined, {}, "get system health");
364
+ const response = await this.request('system.health', this.config.endpoints.system.health, undefined, {}, 'get system health');
365
365
  if (!response.success || !response.data) {
366
- throw new Error(response.error ?? "Failed to get system health");
366
+ throw new Error(response.error ?? 'Failed to get system health');
367
367
  }
368
368
  return response.data;
369
369
  }
@@ -371,9 +371,9 @@ export class EnhancedFlowDropApiClient {
371
371
  * Get system configuration
372
372
  */
373
373
  async getSystemConfig() {
374
- const response = await this.request("system.config", this.config.endpoints.system.config, undefined, {}, "get system config");
374
+ const response = await this.request('system.config', this.config.endpoints.system.config, undefined, {}, 'get system config');
375
375
  if (!response.success || !response.data) {
376
- throw new Error(response.error ?? "Failed to get system config");
376
+ throw new Error(response.error ?? 'Failed to get system config');
377
377
  }
378
378
  return response.data;
379
379
  }
@@ -381,9 +381,9 @@ export class EnhancedFlowDropApiClient {
381
381
  * Get system version information
382
382
  */
383
383
  async getSystemVersion() {
384
- const response = await this.request("system.version", this.config.endpoints.system.version, undefined, {}, "get system version");
384
+ const response = await this.request('system.version', this.config.endpoints.system.version, undefined, {}, 'get system version');
385
385
  if (!response.success || !response.data) {
386
- throw new Error(response.error ?? "Failed to get system version");
386
+ throw new Error(response.error ?? 'Failed to get system version');
387
387
  }
388
388
  return response.data;
389
389
  }
@@ -5,8 +5,8 @@
5
5
  -->
6
6
 
7
7
  <script lang="ts">
8
- import { useSvelteFlow } from "@xyflow/svelte";
9
- import type { Snippet } from "svelte";
8
+ import { useSvelteFlow } from '@xyflow/svelte';
9
+ import type { Snippet } from 'svelte';
10
10
 
11
11
  interface Props {
12
12
  ondrop: (nodeTypeData: string, position: { x: number; y: number }) => void;
@@ -24,7 +24,7 @@
24
24
  function handleDragOver(e: DragEvent): void {
25
25
  e.preventDefault();
26
26
  if (e.dataTransfer) {
27
- e.dataTransfer.dropEffect = "copy";
27
+ e.dataTransfer.dropEffect = 'copy';
28
28
  }
29
29
  }
30
30
 
@@ -35,7 +35,7 @@
35
35
  e.preventDefault();
36
36
 
37
37
  // Get the data from the drag event
38
- const nodeTypeData = e.dataTransfer?.getData("application/json");
38
+ const nodeTypeData = e.dataTransfer?.getData('application/json');
39
39
  if (nodeTypeData) {
40
40
  // Convert screen coordinates to flow coordinates (accounts for zoom and pan)
41
41
  const position = screenToFlowPosition({
@@ -65,4 +65,3 @@
65
65
  height: 100%;
66
66
  }
67
67
  </style>
68
-
@@ -1,4 +1,4 @@
1
- import type { Snippet } from "svelte";
1
+ import type { Snippet } from 'svelte';
2
2
  interface Props {
3
3
  ondrop: (nodeTypeData: string, position: {
4
4
  x: number;