@d34dman/flowdrop 0.0.30 → 0.0.31

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 (51) hide show
  1. package/dist/components/App.svelte +54 -6
  2. package/dist/components/NodeSidebar.svelte +1 -1
  3. package/dist/components/SchemaForm.svelte +14 -14
  4. package/dist/components/SchemaForm.svelte.d.ts +1 -1
  5. package/dist/components/form/FormFieldLight.svelte +66 -66
  6. package/dist/components/form/FormFieldLight.svelte.d.ts +1 -1
  7. package/dist/components/form/types.d.ts +1 -1
  8. package/dist/components/playground/ChatPanel.svelte +523 -0
  9. package/dist/components/playground/ChatPanel.svelte.d.ts +20 -0
  10. package/dist/components/playground/ExecutionLogs.svelte +486 -0
  11. package/dist/components/playground/ExecutionLogs.svelte.d.ts +14 -0
  12. package/dist/components/playground/InputCollector.svelte +444 -0
  13. package/dist/components/playground/InputCollector.svelte.d.ts +16 -0
  14. package/dist/components/playground/MessageBubble.svelte +398 -0
  15. package/dist/components/playground/MessageBubble.svelte.d.ts +15 -0
  16. package/dist/components/playground/Playground.svelte +851 -0
  17. package/dist/components/playground/Playground.svelte.d.ts +25 -0
  18. package/dist/components/playground/SessionManager.svelte +537 -0
  19. package/dist/components/playground/SessionManager.svelte.d.ts +20 -0
  20. package/dist/config/endpoints.d.ts +16 -0
  21. package/dist/config/endpoints.js +9 -0
  22. package/dist/core/index.d.ts +25 -23
  23. package/dist/core/index.js +13 -12
  24. package/dist/display/index.d.ts +2 -2
  25. package/dist/display/index.js +2 -2
  26. package/dist/editor/index.d.ts +57 -49
  27. package/dist/editor/index.js +52 -42
  28. package/dist/form/code.d.ts +4 -4
  29. package/dist/form/code.js +11 -11
  30. package/dist/form/fieldRegistry.d.ts +2 -2
  31. package/dist/form/fieldRegistry.js +8 -10
  32. package/dist/form/full.d.ts +5 -5
  33. package/dist/form/full.js +7 -7
  34. package/dist/form/index.d.ts +16 -16
  35. package/dist/form/index.js +14 -14
  36. package/dist/form/markdown.d.ts +3 -3
  37. package/dist/form/markdown.js +6 -6
  38. package/dist/index.d.ts +6 -4
  39. package/dist/index.js +9 -4
  40. package/dist/playground/index.d.ts +92 -0
  41. package/dist/playground/index.js +114 -0
  42. package/dist/playground/mount.d.ts +183 -0
  43. package/dist/playground/mount.js +178 -0
  44. package/dist/services/playgroundService.d.ts +129 -0
  45. package/dist/services/playgroundService.js +317 -0
  46. package/dist/stores/playgroundStore.d.ts +199 -0
  47. package/dist/stores/playgroundStore.js +350 -0
  48. package/dist/types/playground.d.ts +230 -0
  49. package/dist/types/playground.js +28 -0
  50. package/dist/utils/colors.js +4 -4
  51. package/package.json +6 -1
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Playground Mount Functions
3
+ *
4
+ * Provides mount/unmount functions for integrating the Playground component
5
+ * into any web application. Particularly useful for integration with
6
+ * vanilla JS, Drupal, WordPress, or other frameworks.
7
+ *
8
+ * @module playground/mount
9
+ *
10
+ * @example Basic usage in vanilla JavaScript:
11
+ * ```javascript
12
+ * const app = await FlowDrop.mountPlayground(
13
+ * document.getElementById("playground-container"),
14
+ * {
15
+ * workflowId: "wf-123",
16
+ * endpointConfig: FlowDrop.createEndpointConfig("/api/flowdrop"),
17
+ * mode: "standalone"
18
+ * }
19
+ * );
20
+ *
21
+ * // Later, to cleanup:
22
+ * app.destroy();
23
+ * ```
24
+ *
25
+ * @example Drupal integration:
26
+ * ```javascript
27
+ * (function (Drupal, FlowDrop) {
28
+ * Drupal.behaviors.flowdropPlayground = {
29
+ * attach: function (context, settings) {
30
+ * const container = document.getElementById("playground-container");
31
+ * if (!container || container.dataset.initialized) return;
32
+ * container.dataset.initialized = "true";
33
+ *
34
+ * FlowDrop.mountPlayground(container, {
35
+ * workflowId: settings.flowdrop.workflowId,
36
+ * endpointConfig: FlowDrop.createEndpointConfig(settings.flowdrop.apiBaseUrl),
37
+ * mode: "standalone"
38
+ * }).then(function (app) {
39
+ * container._flowdropApp = app;
40
+ * });
41
+ * }
42
+ * };
43
+ * })(Drupal, window.FlowDrop);
44
+ * ```
45
+ */
46
+ import { mount, unmount } from "svelte";
47
+ import Playground from "../components/playground/Playground.svelte";
48
+ import { setEndpointConfig } from "../services/api.js";
49
+ import { playgroundService } from "../services/playgroundService.js";
50
+ import { currentSession, sessions, messages, playgroundActions } from "../stores/playgroundStore.js";
51
+ import { get } from "svelte/store";
52
+ /**
53
+ * Mount the Playground component in a container
54
+ *
55
+ * This function mounts the Playground Svelte component into a DOM container,
56
+ * enabling interactive workflow testing with a chat interface.
57
+ *
58
+ * @param container - DOM element to mount the playground into
59
+ * @param options - Configuration options for the playground
60
+ * @returns Promise resolving to a MountedPlayground instance
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * import { mountPlayground, createEndpointConfig } from "@d34dman/flowdrop/playground";
65
+ *
66
+ * const app = await mountPlayground(
67
+ * document.getElementById("playground"),
68
+ * {
69
+ * workflowId: "wf-123",
70
+ * endpointConfig: createEndpointConfig("/api/flowdrop"),
71
+ * mode: "standalone",
72
+ * config: {
73
+ * showTimestamps: true,
74
+ * autoScroll: true,
75
+ * pollingInterval: 1500
76
+ * }
77
+ * }
78
+ * );
79
+ * ```
80
+ */
81
+ export async function mountPlayground(container, options) {
82
+ const { workflowId, workflow, mode = "standalone", initialSessionId, endpointConfig, config = {}, height = "100%", width = "100%", onClose } = options;
83
+ // Validate required parameters
84
+ if (!workflowId) {
85
+ throw new Error("workflowId is required for mountPlayground()");
86
+ }
87
+ if (!container) {
88
+ throw new Error("container element is required for mountPlayground()");
89
+ }
90
+ // Set endpoint configuration if provided
91
+ let finalEndpointConfig;
92
+ if (endpointConfig) {
93
+ // Merge with default configuration to ensure all required endpoints are present
94
+ const { defaultEndpointConfig } = await import("../config/endpoints.js");
95
+ finalEndpointConfig = {
96
+ ...defaultEndpointConfig,
97
+ ...endpointConfig,
98
+ endpoints: {
99
+ ...defaultEndpointConfig.endpoints,
100
+ ...endpointConfig.endpoints
101
+ }
102
+ };
103
+ setEndpointConfig(finalEndpointConfig);
104
+ }
105
+ // Apply container styling
106
+ container.style.height = height;
107
+ container.style.width = width;
108
+ // Mount the Svelte Playground component
109
+ const svelteApp = mount(Playground, {
110
+ target: container,
111
+ props: {
112
+ workflowId,
113
+ workflow,
114
+ mode,
115
+ initialSessionId,
116
+ endpointConfig: finalEndpointConfig,
117
+ config,
118
+ onClose
119
+ }
120
+ });
121
+ // Store state for cleanup
122
+ const state = {
123
+ svelteApp,
124
+ container,
125
+ workflowId
126
+ };
127
+ // Create the mounted playground interface
128
+ const mountedPlayground = {
129
+ destroy: () => {
130
+ // Stop any active polling
131
+ playgroundService.stopPolling();
132
+ // Reset playground state
133
+ playgroundActions.reset();
134
+ // Unmount Svelte component
135
+ unmount(state.svelteApp);
136
+ },
137
+ getCurrentSession: () => {
138
+ return get(currentSession);
139
+ },
140
+ getSessions: () => {
141
+ return get(sessions);
142
+ },
143
+ getMessageCount: () => {
144
+ return get(messages).length;
145
+ },
146
+ isExecuting: () => {
147
+ return playgroundService.isPolling();
148
+ },
149
+ stopPolling: () => {
150
+ playgroundService.stopPolling();
151
+ },
152
+ reset: () => {
153
+ playgroundService.stopPolling();
154
+ playgroundActions.reset();
155
+ }
156
+ };
157
+ return mountedPlayground;
158
+ }
159
+ /**
160
+ * Unmount a Playground instance
161
+ *
162
+ * Convenience function for destroying a mounted playground.
163
+ * Equivalent to calling `app.destroy()`.
164
+ *
165
+ * @param app - The mounted playground to unmount
166
+ *
167
+ * @example
168
+ * ```typescript
169
+ * const app = await mountPlayground(container, options);
170
+ * // ... later
171
+ * unmountPlayground(app);
172
+ * ```
173
+ */
174
+ export function unmountPlayground(app) {
175
+ if (app && typeof app.destroy === "function") {
176
+ app.destroy();
177
+ }
178
+ }
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Playground Service
3
+ *
4
+ * Handles API interactions for the Playground feature including
5
+ * session management, message handling, and polling for updates.
6
+ *
7
+ * @module services/playgroundService
8
+ */
9
+ import type { PlaygroundSession, PlaygroundMessage, PlaygroundMessagesApiResponse } from '../types/playground.js';
10
+ /**
11
+ * Playground Service class
12
+ *
13
+ * Provides methods to interact with the playground API endpoints
14
+ * including session management, message handling, and polling.
15
+ */
16
+ export declare class PlaygroundService {
17
+ private static instance;
18
+ private pollingInterval;
19
+ private pollingSessionId;
20
+ private currentBackoff;
21
+ private lastMessageTimestamp;
22
+ private constructor();
23
+ /**
24
+ * Get the singleton instance of PlaygroundService
25
+ *
26
+ * @returns The PlaygroundService singleton instance
27
+ */
28
+ static getInstance(): PlaygroundService;
29
+ /**
30
+ * Get the endpoint configuration
31
+ *
32
+ * @throws Error if endpoint configuration is not set
33
+ * @returns The endpoint configuration
34
+ */
35
+ private getConfig;
36
+ /**
37
+ * Generic API request helper
38
+ *
39
+ * @param url - The URL to fetch
40
+ * @param options - Fetch options
41
+ * @returns The parsed JSON response
42
+ */
43
+ private request;
44
+ /**
45
+ * List all playground sessions for a workflow
46
+ *
47
+ * @param workflowId - The workflow UUID
48
+ * @param options - Optional pagination parameters
49
+ * @returns Array of playground sessions
50
+ */
51
+ listSessions(workflowId: string, options?: {
52
+ limit?: number;
53
+ offset?: number;
54
+ }): Promise<PlaygroundSession[]>;
55
+ /**
56
+ * Create a new playground session
57
+ *
58
+ * @param workflowId - The workflow UUID
59
+ * @param name - Optional session name
60
+ * @param metadata - Optional session metadata
61
+ * @returns The created session
62
+ */
63
+ createSession(workflowId: string, name?: string, metadata?: Record<string, unknown>): Promise<PlaygroundSession>;
64
+ /**
65
+ * Get a playground session by ID
66
+ *
67
+ * @param sessionId - The session UUID
68
+ * @returns The session details
69
+ */
70
+ getSession(sessionId: string): Promise<PlaygroundSession>;
71
+ /**
72
+ * Delete a playground session
73
+ *
74
+ * @param sessionId - The session UUID
75
+ */
76
+ deleteSession(sessionId: string): Promise<void>;
77
+ /**
78
+ * Get messages from a playground session
79
+ *
80
+ * @param sessionId - The session UUID
81
+ * @param since - Optional timestamp to fetch only newer messages (ISO 8601)
82
+ * @param limit - Maximum number of messages to return
83
+ * @returns Messages and session status
84
+ */
85
+ getMessages(sessionId: string, since?: string, limit?: number): Promise<PlaygroundMessagesApiResponse>;
86
+ /**
87
+ * Send a message to a playground session
88
+ *
89
+ * @param sessionId - The session UUID
90
+ * @param content - The message content
91
+ * @param inputs - Optional additional inputs for workflow nodes
92
+ * @returns The created message
93
+ */
94
+ sendMessage(sessionId: string, content: string, inputs?: Record<string, unknown>): Promise<PlaygroundMessage>;
95
+ /**
96
+ * Stop execution in a playground session
97
+ *
98
+ * @param sessionId - The session UUID
99
+ */
100
+ stopExecution(sessionId: string): Promise<void>;
101
+ /**
102
+ * Start polling for new messages
103
+ *
104
+ * @param sessionId - The session UUID to poll
105
+ * @param callback - Callback function to handle new messages
106
+ * @param interval - Polling interval in milliseconds (default: 1500)
107
+ */
108
+ startPolling(sessionId: string, callback: (response: PlaygroundMessagesApiResponse) => void, interval?: number): void;
109
+ /**
110
+ * Stop polling for messages
111
+ */
112
+ stopPolling(): void;
113
+ /**
114
+ * Check if polling is active
115
+ *
116
+ * @returns True if polling is active
117
+ */
118
+ isPolling(): boolean;
119
+ /**
120
+ * Get the current polling session ID
121
+ *
122
+ * @returns The session ID being polled, or null
123
+ */
124
+ getPollingSessionId(): string | null;
125
+ }
126
+ /**
127
+ * Export singleton instance
128
+ */
129
+ export declare const playgroundService: PlaygroundService;
@@ -0,0 +1,317 @@
1
+ /**
2
+ * Playground Service
3
+ *
4
+ * Handles API interactions for the Playground feature including
5
+ * session management, message handling, and polling for updates.
6
+ *
7
+ * @module services/playgroundService
8
+ */
9
+ import { buildEndpointUrl, getEndpointHeaders } from '../config/endpoints.js';
10
+ import { getEndpointConfig } from './api.js';
11
+ /**
12
+ * Default polling interval in milliseconds
13
+ */
14
+ const DEFAULT_POLLING_INTERVAL = 1500;
15
+ /**
16
+ * Maximum polling backoff interval in milliseconds
17
+ */
18
+ const MAX_POLLING_BACKOFF = 10000;
19
+ /**
20
+ * Playground Service class
21
+ *
22
+ * Provides methods to interact with the playground API endpoints
23
+ * including session management, message handling, and polling.
24
+ */
25
+ export class PlaygroundService {
26
+ static instance;
27
+ pollingInterval = null;
28
+ pollingSessionId = null;
29
+ currentBackoff = DEFAULT_POLLING_INTERVAL;
30
+ lastMessageTimestamp = null;
31
+ constructor() { }
32
+ /**
33
+ * Get the singleton instance of PlaygroundService
34
+ *
35
+ * @returns The PlaygroundService singleton instance
36
+ */
37
+ static getInstance() {
38
+ if (!PlaygroundService.instance) {
39
+ PlaygroundService.instance = new PlaygroundService();
40
+ }
41
+ return PlaygroundService.instance;
42
+ }
43
+ /**
44
+ * Get the endpoint configuration
45
+ *
46
+ * @throws Error if endpoint configuration is not set
47
+ * @returns The endpoint configuration
48
+ */
49
+ getConfig() {
50
+ const config = getEndpointConfig();
51
+ if (!config) {
52
+ throw new Error('Endpoint configuration not set. Call setEndpointConfig() first.');
53
+ }
54
+ return config;
55
+ }
56
+ /**
57
+ * Generic API request helper
58
+ *
59
+ * @param url - The URL to fetch
60
+ * @param options - Fetch options
61
+ * @returns The parsed JSON response
62
+ */
63
+ async request(url, options = {}) {
64
+ const config = this.getConfig();
65
+ const headers = getEndpointHeaders(config, 'playground');
66
+ const response = await fetch(url, {
67
+ ...options,
68
+ headers: {
69
+ ...headers,
70
+ ...options.headers
71
+ }
72
+ });
73
+ if (!response.ok) {
74
+ const errorData = await response.json().catch(() => ({}));
75
+ const errorMessage = errorData.error ||
76
+ errorData.message ||
77
+ `HTTP ${response.status}: ${response.statusText}`;
78
+ throw new Error(errorMessage);
79
+ }
80
+ return response.json();
81
+ }
82
+ // =========================================================================
83
+ // Session Management
84
+ // =========================================================================
85
+ /**
86
+ * List all playground sessions for a workflow
87
+ *
88
+ * @param workflowId - The workflow UUID
89
+ * @param options - Optional pagination parameters
90
+ * @returns Array of playground sessions
91
+ */
92
+ async listSessions(workflowId, options) {
93
+ const config = this.getConfig();
94
+ let url = buildEndpointUrl(config, config.endpoints.playground.listSessions, {
95
+ id: workflowId
96
+ });
97
+ // Add query parameters
98
+ const params = new URLSearchParams();
99
+ if (options?.limit !== undefined) {
100
+ params.append('limit', options.limit.toString());
101
+ }
102
+ if (options?.offset !== undefined) {
103
+ params.append('offset', options.offset.toString());
104
+ }
105
+ const queryString = params.toString();
106
+ if (queryString) {
107
+ url = `${url}?${queryString}`;
108
+ }
109
+ const response = await this.request(url);
110
+ return response.data ?? [];
111
+ }
112
+ /**
113
+ * Create a new playground session
114
+ *
115
+ * @param workflowId - The workflow UUID
116
+ * @param name - Optional session name
117
+ * @param metadata - Optional session metadata
118
+ * @returns The created session
119
+ */
120
+ async createSession(workflowId, name, metadata) {
121
+ const config = this.getConfig();
122
+ const url = buildEndpointUrl(config, config.endpoints.playground.createSession, {
123
+ id: workflowId
124
+ });
125
+ const response = await this.request(url, {
126
+ method: 'POST',
127
+ body: JSON.stringify({ name, metadata })
128
+ });
129
+ if (!response.data) {
130
+ throw new Error('Failed to create session: No data returned');
131
+ }
132
+ return response.data;
133
+ }
134
+ /**
135
+ * Get a playground session by ID
136
+ *
137
+ * @param sessionId - The session UUID
138
+ * @returns The session details
139
+ */
140
+ async getSession(sessionId) {
141
+ const config = this.getConfig();
142
+ const url = buildEndpointUrl(config, config.endpoints.playground.getSession, {
143
+ sessionId
144
+ });
145
+ const response = await this.request(url);
146
+ if (!response.data) {
147
+ throw new Error('Session not found');
148
+ }
149
+ return response.data;
150
+ }
151
+ /**
152
+ * Delete a playground session
153
+ *
154
+ * @param sessionId - The session UUID
155
+ */
156
+ async deleteSession(sessionId) {
157
+ const config = this.getConfig();
158
+ const url = buildEndpointUrl(config, config.endpoints.playground.deleteSession, {
159
+ sessionId
160
+ });
161
+ await this.request(url, {
162
+ method: 'DELETE'
163
+ });
164
+ }
165
+ // =========================================================================
166
+ // Message Handling
167
+ // =========================================================================
168
+ /**
169
+ * Get messages from a playground session
170
+ *
171
+ * @param sessionId - The session UUID
172
+ * @param since - Optional timestamp to fetch only newer messages (ISO 8601)
173
+ * @param limit - Maximum number of messages to return
174
+ * @returns Messages and session status
175
+ */
176
+ async getMessages(sessionId, since, limit) {
177
+ const config = this.getConfig();
178
+ let url = buildEndpointUrl(config, config.endpoints.playground.getMessages, {
179
+ sessionId
180
+ });
181
+ // Add query parameters
182
+ const params = new URLSearchParams();
183
+ if (since) {
184
+ params.append('since', since);
185
+ }
186
+ if (limit !== undefined) {
187
+ params.append('limit', limit.toString());
188
+ }
189
+ const queryString = params.toString();
190
+ if (queryString) {
191
+ url = `${url}?${queryString}`;
192
+ }
193
+ return this.request(url);
194
+ }
195
+ /**
196
+ * Send a message to a playground session
197
+ *
198
+ * @param sessionId - The session UUID
199
+ * @param content - The message content
200
+ * @param inputs - Optional additional inputs for workflow nodes
201
+ * @returns The created message
202
+ */
203
+ async sendMessage(sessionId, content, inputs) {
204
+ const config = this.getConfig();
205
+ const url = buildEndpointUrl(config, config.endpoints.playground.sendMessage, {
206
+ sessionId
207
+ });
208
+ const requestBody = { content };
209
+ if (inputs) {
210
+ requestBody.inputs = inputs;
211
+ }
212
+ const response = await this.request(url, {
213
+ method: 'POST',
214
+ body: JSON.stringify(requestBody)
215
+ });
216
+ if (!response.data) {
217
+ throw new Error('Failed to send message: No data returned');
218
+ }
219
+ return response.data;
220
+ }
221
+ /**
222
+ * Stop execution in a playground session
223
+ *
224
+ * @param sessionId - The session UUID
225
+ */
226
+ async stopExecution(sessionId) {
227
+ const config = this.getConfig();
228
+ const url = buildEndpointUrl(config, config.endpoints.playground.stopExecution, {
229
+ sessionId
230
+ });
231
+ await this.request(url, {
232
+ method: 'POST'
233
+ });
234
+ }
235
+ // =========================================================================
236
+ // Polling
237
+ // =========================================================================
238
+ /**
239
+ * Start polling for new messages
240
+ *
241
+ * @param sessionId - The session UUID to poll
242
+ * @param callback - Callback function to handle new messages
243
+ * @param interval - Polling interval in milliseconds (default: 1500)
244
+ */
245
+ startPolling(sessionId, callback, interval = DEFAULT_POLLING_INTERVAL) {
246
+ // Stop any existing polling
247
+ this.stopPolling();
248
+ this.pollingSessionId = sessionId;
249
+ this.currentBackoff = interval;
250
+ this.lastMessageTimestamp = null;
251
+ const poll = async () => {
252
+ if (this.pollingSessionId !== sessionId) {
253
+ return;
254
+ }
255
+ try {
256
+ const response = await this.getMessages(sessionId, this.lastMessageTimestamp ?? undefined);
257
+ // Update last message timestamp
258
+ if (response.data && response.data.length > 0) {
259
+ const lastMessage = response.data[response.data.length - 1];
260
+ this.lastMessageTimestamp = lastMessage.timestamp;
261
+ }
262
+ // Reset backoff on successful request
263
+ this.currentBackoff = interval;
264
+ // Call the callback with new messages
265
+ callback(response);
266
+ // Stop polling if session is completed or failed
267
+ if (response.sessionStatus === 'completed' || response.sessionStatus === 'failed') {
268
+ this.stopPolling();
269
+ return;
270
+ }
271
+ }
272
+ catch (error) {
273
+ console.error('Polling error:', error);
274
+ // Exponential backoff on error
275
+ this.currentBackoff = Math.min(this.currentBackoff * 2, MAX_POLLING_BACKOFF);
276
+ }
277
+ // Schedule next poll
278
+ if (this.pollingSessionId === sessionId) {
279
+ this.pollingInterval = setTimeout(poll, this.currentBackoff);
280
+ }
281
+ };
282
+ // Start polling immediately
283
+ poll();
284
+ }
285
+ /**
286
+ * Stop polling for messages
287
+ */
288
+ stopPolling() {
289
+ if (this.pollingInterval) {
290
+ clearTimeout(this.pollingInterval);
291
+ this.pollingInterval = null;
292
+ }
293
+ this.pollingSessionId = null;
294
+ this.lastMessageTimestamp = null;
295
+ this.currentBackoff = DEFAULT_POLLING_INTERVAL;
296
+ }
297
+ /**
298
+ * Check if polling is active
299
+ *
300
+ * @returns True if polling is active
301
+ */
302
+ isPolling() {
303
+ return this.pollingSessionId !== null;
304
+ }
305
+ /**
306
+ * Get the current polling session ID
307
+ *
308
+ * @returns The session ID being polled, or null
309
+ */
310
+ getPollingSessionId() {
311
+ return this.pollingSessionId;
312
+ }
313
+ }
314
+ /**
315
+ * Export singleton instance
316
+ */
317
+ export const playgroundService = PlaygroundService.getInstance();