@universal-workflow/widget-react 0.1.0
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 +59 -0
- package/dist/index.css +3 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +32 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx","../src/components/WorkflowBuilder.tsx","../../widget-core/src/license/manager.ts","../../widget-core/src/api/client.ts","../../widget-core/src/io/serializer.ts","../../widget-core/src/nodes/connector.ts","../../widget-core/src/nodes/standard-library.ts","../../widget-core/src/nodes/catalog.json","../../widget-core/src/nodes/loader.ts","../../widget-core/src/nodes/registry.ts","../src/components/UniversalNode.tsx","../src/utils.ts","../src/utils/icons.ts","../src/components/Toolbar.tsx","../src/components/PropertyPanel.tsx","../src/utils/curl.ts","../src/components/NodePalette.tsx","../src/components/Toast.tsx","../src/utils/layout.ts","../src/hooks/useUndoRedo.ts","../src/utils/validation.ts","../src/components/WorkflowWidget.tsx","../src/components/EmbeddableWidget.tsx"],"sourcesContent":["export * from \"./components/WorkflowBuilder\";\nexport * from \"./components/WorkflowWidget\";\nexport * from \"./components/EmbeddableWidget\";\nexport * from \"@universal-workflow/widget-core\";\n","import React, { useEffect, useState, useCallback, useMemo, useRef } from 'react';\nimport ReactFlow, { \n Background, \n Controls, \n MiniMap,\n useNodesState,\n useEdgesState,\n addEdge,\n Connection,\n Edge,\n Node,\n BackgroundVariant\n} from 'reactflow';\nimport 'reactflow/dist/style.css';\nimport { LicenseManager, ApiClient, ApiConfig, serialize, deserialize, nodeRegistry } from '@universal-workflow/widget-core';\nimport { UniversalNode } from './UniversalNode';\nimport { Toolbar } from './Toolbar';\nimport { PropertyPanel } from './PropertyPanel';\nimport { NodePalette } from './NodePalette';\nimport { Toast } from './Toast';\n\nexport interface WorkflowBuilderProps {\n licenseKey: string;\n apiConfig: ApiConfig;\n className?: string;\n style?: React.CSSProperties;\n}\n\nconst initialNodes: Node[] = [\n { id: '1', type: 'webhook', position: { x: 100, y: 100 }, data: { method: 'POST', path: '/start' } },\n { id: '2', type: 'http-request', position: { x: 100, y: 300 }, data: { method: 'POST', url: 'https://api.example.com/data' } },\n { id: '3', type: 'slack', position: { x: 400, y: 200 }, data: { message: 'Workflow completed', webhookUrl: 'https://hooks.slack.com/...' } },\n];\nconst initialEdges: Edge[] = [\n { id: 'e1-2', source: '1', target: '2', type: 'smoothstep', animated: true, style: { stroke: '#6366f1', strokeWidth: 2 } },\n { id: 'e2-3', source: '2', target: '3', type: 'smoothstep', animated: true, style: { stroke: '#6366f1', strokeWidth: 2 } }\n];\n\nimport { ReactFlowProvider } from 'reactflow';\n\nexport const WorkflowBuilder: React.FC<WorkflowBuilderProps> = (props) => {\n return (\n <ReactFlowProvider>\n <WorkflowBuilderContent {...props} />\n </ReactFlowProvider>\n );\n};\n\nimport { getLayoutedElements } from '../utils/layout';\nimport { useUndoRedo } from '../hooks/useUndoRedo';\nimport { defaultEdgeOptions } from '../utils/edges';\nimport { validateWorkflow } from '../utils/validation';\n\n// ... other code ...\n\nconst WorkflowBuilderContent: React.FC<WorkflowBuilderProps> = ({ licenseKey, apiConfig, className, style }) => {\n const [isValid, setIsValid] = useState<boolean | null>(null);\n const [errorMsg, setErrorMsg] = useState<string>('');\n \n // Initialize License Manager\n const [manager] = useState(() => new LicenseManager({ \n licenseKey, \n widgetVersion: '1.0.0',\n validationEndpoint: 'http://localhost:3000/api/v1/license/validate' \n }));\n\n // Lifting state up for undo/redo is tricky with useNodesState because it manages internal state too.\n // Actually useNodesState returns a setter that we can use.\n const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);\n const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);\n const [isSaving, setIsSaving] = useState(false);\n const [isRunning, setIsRunning] = useState(false);\n const [toast, setToast] = useState<{message: string, type: 'success'|'error'} | null>(null);\n\n // History Hook\n const { takeSnapshot, undo, redo, canUndo, canRedo } = useUndoRedo(initialNodes, initialEdges, \n (nds) => setNodes([...nds]), \n (eds) => setEdges([...eds])\n );\n \n // Snapshot wrapper\n const snapshot = useCallback(() => {\n takeSnapshot(nodes, edges);\n }, [nodes, edges, takeSnapshot]);\n\n const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null);\n\n // Register custom node types\n const nodeTypes = useMemo(() => {\n const types: Record<string, any> = {\n 'custom': UniversalNode \n };\n Object.keys(nodeRegistry).forEach(key => {\n types[key] = UniversalNode; \n });\n return types;\n }, []);\n\n useEffect(() => {\n async function validate() {\n const status = await manager.validate();\n setIsValid(status.valid);\n if (!status.valid) setErrorMsg(status.reason || 'Invalid License');\n }\n validate();\n }, [manager]);\n\n const onConnect = useCallback((params: Connection) => {\n setEdges((eds) => {\n const newEdges = addEdge({ ...params, type: 'smoothstep', animated: true, style: { stroke: '#6366f1', strokeWidth: 2 } }, eds);\n takeSnapshot(nodes, newEdges); // Snap\n return newEdges;\n });\n }, [setEdges, nodes, takeSnapshot]); \n\n const onNodeClick = useCallback((event: React.MouseEvent, node: Node) => {\n setSelectedNodeId(node.id);\n }, []);\n\n const onPaneClick = useCallback(() => {\n setSelectedNodeId(null);\n }, []);\n\n const reactFlowWrapper = useRef<HTMLDivElement>(null);\n const [rfInstance, setRfInstance] = useState<any>(null);\n const [isPaletteOpen, setIsPaletteOpen] = useState(false);\n\n const handleAddNode = useCallback((type: string) => {\n const id = `node-${Date.now()}`;\n let pos = { x: 250, y: 250 };\n if (rfInstance) {\n // Add some randomness to avoid perfect stacking\n pos = { x: 100 + Math.random() * 200, y: 100 + Math.random() * 200 };\n }\n const newNode: Node = { id, type, position: pos, data: {} };\n \n const newNodes = nodes.concat(newNode);\n setNodes(newNodes);\n takeSnapshot(newNodes, edges);\n \n setIsPaletteOpen(false);\n setSelectedNodeId(id); \n }, [rfInstance, nodes, edges, takeSnapshot, setNodes]);\n\n const handleAutoLayout = useCallback(() => {\n const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(\n nodes,\n edges\n );\n setNodes([...layoutedNodes]);\n setEdges([...layoutedEdges]);\n takeSnapshot([...layoutedNodes], [...layoutedEdges]);\n setTimeout(() => rfInstance?.fitView(), 100);\n }, [nodes, edges, setNodes, setEdges, takeSnapshot, rfInstance]);\n\n const handleClear = useCallback(() => {\n if (confirm('Are you sure you want to clear the canvas?')) {\n setNodes([]);\n setEdges([]);\n takeSnapshot([], []);\n }\n }, [setNodes, setEdges, takeSnapshot]);\n\n const handleRunTest = useCallback(async () => {\n if (isRunning) return;\n setIsRunning(true);\n setToast(null); // Clear previous\n \n // Reset all nodes to default state\n const resetNodes = nodes.map(n => ({\n ...n,\n data: { ...n.data, executionStatus: undefined }\n }));\n setNodes(resetNodes);\n\n // Helper to update status\n const updateStatus = (id: string, status: 'running' | 'success' | 'error') => {\n setNodes(nds => nds.map(n => n.id === id ? { ...n, data: { ...n.data, executionStatus: status } } : n));\n };\n\n try {\n // Find start nodes (no targets)\n const successors: Record<string, string[]> = {};\n edges.forEach(e => {\n if(!successors[e.source]) successors[e.source] = [];\n successors[e.source].push(e.target);\n });\n\n // Simple BFS simulation\n const queue = nodes.filter(n => ['webhook', 'schedule', 'connector'].includes(n.type || '') || edges.every(e => e.target !== n.id) ).map(n => n.id);\n \n if (queue.length === 0 && nodes.length > 0) queue.push(nodes[0].id);\n\n if (queue.length === 0) {\n throw new Error(\"No start node found\");\n }\n\n // Process\n for (const nodeId of queue) {\n updateStatus(nodeId, 'running');\n await new Promise(r => setTimeout(r, 800)); // Simulate work\n \n // Simulation: If node is empty customized (no data), maybe warn?\n // For now, let's keep it simple.\n \n updateStatus(nodeId, 'success');\n \n const children = successors[nodeId] || [];\n for(const childId of children) {\n updateStatus(childId, 'running');\n await new Promise(r => setTimeout(r, 800));\n \n // Random failure simulation for demo purposes if it's a specific node?\n // Nah, let's just run success for now unless user asks.\n updateStatus(childId, 'success');\n }\n }\n setToast({ message: 'Execution completed successfully', type: 'success' });\n } catch (err: any) {\n setToast({ message: err.message || 'Execution Success', type: 'success' }); // Fallback\n } finally {\n setIsRunning(false);\n }\n\n }, [nodes, edges, isRunning, setNodes]);\n\n\n const handleSave = async () => {\n // Validate\n const issues = validateWorkflow(nodes, edges);\n const errors = issues.filter(i => i.severity === 'error');\n \n if (errors.length > 0) {\n setToast({ message: `Cannot save: ${errors[0].message}`, type: 'error' });\n return;\n }\n \n if (issues.length > 0) {\n setToast({ message: `Saved with warnings: ${issues[0].message}`, type: 'success' });\n }\n\n setIsSaving(true);\n const client = new ApiClient(apiConfig);\n const workflow = { nodes, edges };\n // For this demo, we just create new. Ideally we'd have ID state.\n const res = await client.createWorkflow(workflow);\n const success = !!res;\n setIsSaving(false);\n if (!success) {\n setToast({ message: 'Failed to save workflow', type: 'error' });\n } else {\n setToast({ message: 'Workflow saved successfully', type: 'success' });\n }\n };\n\n const handleExport = () => {\n const json = serialize(nodes, edges);\n const blob = new Blob([json], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = `workflow-${Date.now()}.json`;\n document.body.appendChild(link);\n link.click();\n document.body.removeChild(link);\n };\n\n const handleImport = async (file: File) => {\n try {\n const text = await file.text();\n const { nodes: newNodes, edges: newEdges } = deserialize(text);\n setNodes(newNodes);\n setEdges(newEdges);\n takeSnapshot(newNodes, newEdges); \n setTimeout(() => {\n rfInstance?.fitView({ padding: 0.2 });\n }, 50);\n } catch (e) {\n alert(\"Failed to import workflow. Invalid file.\");\n console.error(e);\n }\n };\n\n if (isValid === null) {\n return (\n <div className=\"flex items-center justify-center h-[600px] w-full bg-zinc-50 rounded-xl border border-zinc-200\">\n <div className=\"flex flex-col items-center gap-3\">\n <div className=\"w-6 h-6 border-2 border-indigo-600 border-t-transparent rounded-full animate-spin\" />\n <p className=\"text-zinc-500 text-sm font-medium\">Verifying License...</p>\n </div>\n </div>\n );\n }\n\n return (\n <div style={style} className={`relative w-full h-[800px] rounded-xl border border-zinc-200 shadow-sm overflow-hidden bg-zinc-50/50 group ${className || ''}`}>\n \n {/* License Block Overlay */}\n {!isValid && (\n <div className=\"absolute inset-0 z-50 bg-white/80 backdrop-blur-md flex flex-col items-center justify-center p-8 text-center\">\n <div className=\"w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mb-4\">\n <div className=\"w-8 h-8 text-red-600\">⚠️</div>\n </div>\n <h2 className=\"text-2xl font-bold text-zinc-900 mb-2\">License Verification Failed</h2>\n <p className=\"text-zinc-600 max-w-md\">{errorMsg}. Please update your license key to access the builder.</p>\n </div>\n )}\n\n {/* Toolbar */}\n <Toolbar \n onSave={handleSave} \n onExport={handleExport}\n onImport={handleImport}\n onAddNode={() => setIsPaletteOpen(true)}\n onAutoLayout={handleAutoLayout}\n onClear={handleClear}\n onRun={handleRunTest}\n isSaving={isSaving} \n isRunning={isRunning}\n canUndo={canUndo}\n canRedo={canRedo}\n onUndo={undo}\n onRedo={redo}\n />\n\n {/* Property Panel */}\n <PropertyPanel \n selectedNodeId={selectedNodeId || undefined} \n onClose={() => setSelectedNodeId(null)} \n />\n\n <NodePalette \n isOpen={isPaletteOpen}\n onClose={() => setIsPaletteOpen(false)}\n onSelect={handleAddNode}\n />\n \n <Toast \n message={toast?.message || ''}\n type={toast?.type || 'success'}\n isVisible={!!toast}\n onClose={() => setToast(null)}\n />\n\n <div className=\"w-full h-full\" ref={reactFlowWrapper}>\n <ReactFlow\n nodes={nodes}\n edges={edges}\n onNodesChange={onNodesChange}\n onEdgesChange={onEdgesChange}\n onConnect={onConnect}\n onNodeClick={onNodeClick}\n onPaneClick={onPaneClick}\n onInit={setRfInstance}\n nodeTypes={nodeTypes}\n fitView\n className=\"bg-zinc-50\"\n >\n <Background \n variant={BackgroundVariant.Dots} \n gap={20} \n size={1} \n color=\"#94a3b8\" \n className=\"bg-slate-50\"\n />\n <Controls className=\"!bg-white !border-slate-200 !shadow-xl !rounded-lg overflow-hidden [&>button]:!border-b-slate-100 [&>button]:!text-slate-600 hover:[&>button]:!bg-indigo-50 hover:[&>button]:!text-indigo-600 transition-colors\" />\n <MiniMap \n className=\"!bg-white !border-slate-200 !shadow-xl !rounded-lg !mb-8 !mr-8\" \n maskColor=\"rgba(241, 245, 249, 0.7)\" \n nodeColor={(n) => {\n // Dynamic node colors based on type\n if (n.type?.includes('trigger') || n.type === 'webhook') return '#818cf8'; // indigo\n if (n.type === 'action') return '#34d399'; // emerald\n return '#cbd5e1'; // slate\n }}\n zoomable \n pannable \n />\n </ReactFlow>\n </div>\n </div>\n );\n};\n","export interface LicenseConfig {\n licenseKey: string;\n widgetVersion: string;\n validationEndpoint?: string; // Defaults to our SaaS\n}\n\ninterface ValidationResult {\n valid: boolean;\n plan?: string;\n features?: Record<string, any>;\n reason?: string;\n}\n\nconst DEFAULT_VALIDATION_URL = 'http://localhost:3000/api/v1/license/validate';\n\nexport class LicenseManager {\n private validationResult: ValidationResult | null = null;\n\n constructor(private config: LicenseConfig) {}\n\n async validate(): Promise<ValidationResult> {\n if (this.validationResult) return this.validationResult;\n\n try {\n const endpoint = this.config.validationEndpoint || DEFAULT_VALIDATION_URL;\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n licenseKey: this.config.licenseKey,\n widgetVersion: this.config.widgetVersion,\n originUrl: typeof window !== 'undefined' ? window.location.origin : '',\n }),\n });\n\n const data = await response.json();\n this.validationResult = data;\n return data;\n\n } catch (error) {\n console.error('License validation failed', error);\n // Fail open or closed? Strict requirement implies validation is key.\n return { valid: false, reason: 'Network Error' };\n }\n }\n\n isFeatureEnabled(featureName: string): boolean {\n if (!this.validationResult?.valid) return false;\n return !!this.validationResult.features?.[featureName];\n }\n}\n","export interface ApiConfig {\n baseUrl: string;\n endpoints: {\n create: string; // POST\n update: string; // PUT\n get: string; // GET\n list?: string; // GET\n };\n headers?: Record<string, string>;\n}\n\nexport class ApiClient {\n constructor(private config: ApiConfig) {}\n\n private async request<T>(url: string, method: string, body?: any): Promise<T> {\n const headers = {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n };\n\n const response = await fetch(url, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new Error(`API Request failed: ${response.statusText}`);\n }\n\n return response.json();\n }\n\n async getWorkflow(id: string): Promise<any> {\n const url = `${this.config.baseUrl}${this.config.endpoints.get.replace(':id', id)}`;\n return this.request(url, 'GET');\n }\n\n async createWorkflow(workflow: any): Promise<{ id: string }> {\n const url = `${this.config.baseUrl}${this.config.endpoints.create}`;\n return this.request(url, 'POST', workflow);\n }\n\n async updateWorkflow(id: string, workflow: any): Promise<void> {\n const url = `${this.config.baseUrl}${this.config.endpoints.update.replace(':id', id)}`;\n return this.request(url, 'PUT', workflow);\n }\n}\n","\nexport interface WorkflowData {\n nodes: any[];\n edges: any[];\n viewport?: { x: number; y: number; zoom: number };\n}\n\nexport class WorkflowSerializer {\n static serialize(nodes: any[], edges: any[], viewport?: any): string {\n const data: WorkflowData = { nodes, edges, viewport };\n return JSON.stringify(data);\n }\n\n static deserialize(json: string): { nodes: any[], edges: any[], viewport?: any } {\n try {\n const data = JSON.parse(json);\n return {\n nodes: data.nodes || [],\n edges: data.edges || [],\n viewport: data.viewport\n };\n } catch(e) {\n return { nodes: [], edges: [] };\n }\n }\n}\n\nexport const serialize = WorkflowSerializer.serialize;\nexport const deserialize = WorkflowSerializer.deserialize;\n","import { NodeField, NodeCategory, NodeTypeDefinition } from './registry';\n\nexport interface ConnectorOperation {\n id: string; // e.g., 'create_issue'\n label: string;\n description?: string;\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n path: string; // e.g., '/repos/{owner}/{repo}/issues'\n inputs: NodeField[]; // Arguments specific to this operation\n}\n\nexport interface ConnectorDefinition {\n id: string; // e.g., 'github'\n label: string;\n category: NodeCategory;\n icon: string;\n color: string;\n baseUrl: string; // e.g., 'https://api.github.com'\n auth: {\n type: 'bearer' | 'header' | 'query' | 'none';\n key?: string; // e.g., 'Authorization' or 'api_key'\n placeholder?: string; // User instruction\n };\n operations: ConnectorOperation[];\n}\n\n// Factory function to convert a ConnectorDefinition into a regular NodeTypeDefinition\n// The idea is: The node type will be set to 'connector' internally, but we register it as 'github', 'slack', etc.\n// The PROPERTY PANEL will handle the dynamic rendering of operations.\n\nexport function createConnectorNode(def: ConnectorDefinition): NodeTypeDefinition {\n return {\n type: def.id,\n label: def.label,\n description: `Integration with ${def.label}`,\n category: def.category,\n icon: def.icon,\n color: def.color,\n handles: [\n { id: 'in', type: 'target' },\n { id: 'out', type: 'source' }\n ],\n // The inputs shown to the user initially\n inputs: [\n // Auth Config (usually a saved connection ID, but here raw text for simplicity)\n { \n key: 'auth_token', \n label: 'API Key / Token', \n type: 'text', \n placeholder: def.auth.placeholder || 'Enter API Key'\n },\n // Operation Selector\n {\n key: 'operation',\n label: 'Action',\n type: 'select',\n options: def.operations.map(op => ({ label: op.label, value: op.id }))\n },\n // We can't dynamically render the *rest* of the inputs here statically.\n // The PropertyPanel component needs to see 'operation' and append the inputs from that operation.\n // We can store the definition in a special property or look it up.\n ]\n };\n}\n","// This list represents the \"Essential Pack\" of integrations.\nimport { ConnectorDefinition } from './connector';\n\nexport const standardConnectors: ConnectorDefinition[] = [\n // ... existing ...\n {\n id: 'google-sheets',\n label: 'Google Sheets',\n category: 'utility',\n icon: 'Sheet',\n color: 'emerald',\n baseUrl: 'https://sheets.googleapis.com/v4/spreadsheets',\n auth: { type: 'bearer', placeholder: 'OAuth Token' },\n operations: [\n {\n id: 'append_row',\n label: 'Append Row',\n method: 'POST',\n path: '/{spreadsheetId}/values/{range}:append',\n inputs: [\n { key: 'spreadsheetId', label: 'Spreadsheet ID', type: 'text' },\n { key: 'range', label: 'Range (Sheet1!A1)', type: 'text' },\n { key: 'values', label: 'Row Values (JSON Array)', type: 'json' }\n ]\n },\n {\n id: 'get_values',\n label: 'Get Row(s)',\n method: 'GET',\n path: '/{spreadsheetId}/values/{range}',\n inputs: [\n { key: 'spreadsheetId', label: 'Spreadsheet ID', type: 'text' },\n { key: 'range', label: 'Range', type: 'text' }\n ]\n }\n ]\n },\n {\n id: 'slack-connector', \n label: 'Slack API',\n category: 'action',\n icon: 'MessageSquare',\n color: 'blue',\n baseUrl: 'https://slack.com/api',\n auth: { type: 'bearer', placeholder: 'xoxb-...' },\n operations: [\n {\n id: 'post_message',\n label: 'Post Message',\n method: 'POST',\n path: '/chat.postMessage',\n inputs: [\n { key: 'channel', label: 'Channel ID', type: 'text' },\n { key: 'text', label: 'Message Text', type: 'text' }\n ]\n }\n ]\n },\n {\n id: 'openai',\n label: 'OpenAI',\n category: 'action',\n icon: 'Bot',\n color: 'zinc',\n baseUrl: 'https://api.openai.com/v1',\n auth: { type: 'bearer', placeholder: 'sk-...' },\n operations: [\n {\n id: 'chat_completion',\n label: 'Chat Completion',\n method: 'POST',\n path: '/chat/completions',\n inputs: [\n { key: 'model', label: 'Model', type: 'select', options: [{label: 'GPT-4o', value: 'gpt-4o'}, {label: 'GPT-3.5', value: 'gpt-3.5-turbo'}] },\n { key: 'messages', label: 'Messages (JSON)', type: 'json' }\n ]\n }\n ]\n }\n];\n\nexport function registerConnector(def: ConnectorDefinition) {\n standardConnectors.push(def);\n}\n","[\n {\n \"id\": \"triggers\",\n \"nodes\": [\n {\n \"type\": \"manual-trigger\",\n \"label\": \"Manual Trigger\",\n \"description\": \"Start flow on button click\",\n \"category\": \"trigger\",\n \"icon\": \"Play\",\n \"color\": \"emerald\",\n \"inputs\": []\n },\n {\n \"type\": \"cron-trigger\",\n \"label\": \"Cron Schedule\",\n \"description\": \"Trigger on a schedule\",\n \"category\": \"trigger\",\n \"icon\": \"Clock\",\n \"color\": \"emerald\",\n \"inputs\": [\n { \"key\": \"expression\", \"label\": \"Cron Expression\", \"type\": \"text\", \"placeholder\": \"0 9 * * 1 (Every Mon at 9am)\" }\n ]\n },\n {\n \"id\": \"github-trigger\",\n \"label\": \"GitHub Trigger\",\n \"category\": \"trigger\",\n \"icon\": \"Github\",\n \"color\": \"zinc\",\n \"baseUrl\": \"https://api.github.com\",\n \"auth\": { \"type\": \"header\", \"key\": \"X-GitHub-Token\" },\n \"operations\": [\n { \"id\": \"on_push\", \"label\": \"On Push\", \"method\": \"POST\", \"path\": \"/repos/{owner}/{repo}/hooks\", \"inputs\": [{\"key\": \"owner\", \"label\": \"Owner\", \"type\": \"text\"}, {\"key\": \"repo\", \"label\": \"Repository\", \"type\": \"text\"}] },\n { \"id\": \"on_star\", \"label\": \"On New Star\", \"method\": \"POST\", \"path\": \"/repos/{owner}/{repo}/hooks\", \"inputs\": [{\"key\": \"owner\", \"label\": \"Owner\", \"type\": \"text\"}, {\"key\": \"repo\", \"label\": \"Repository\", \"type\": \"text\"}] }\n ]\n }\n ]\n },\n {\n \"id\": \"logic\",\n \"nodes\": [\n {\n \"type\": \"switch\",\n \"label\": \"Switch / Router\",\n \"description\": \"Route based on value\",\n \"category\": \"logic\",\n \"icon\": \"GitFork\",\n \"color\": \"orange\",\n \"inputs\": [\n { \"key\": \"property\", \"label\": \"Property to Check\", \"type\": \"text\" },\n { \"key\": \"cases\", \"label\": \"Cases (comma sep)\", \"type\": \"text\", \"placeholder\": \"marketing, sales, support\" }\n ]\n },\n {\n \"type\": \"ab-split\",\n \"label\": \"A/B Split\",\n \"description\": \"Randomly split traffic\",\n \"category\": \"logic\",\n \"icon\": \"Percent\",\n \"color\": \"orange\",\n \"inputs\": [\n { \"key\": \"percentA\", \"label\": \"Percentage for A\", \"type\": \"text\", \"placeholder\": \"50\" }\n ]\n },\n {\n \"type\": \"wait\",\n \"label\": \"Wait / Delay\",\n \"description\": \"Pause execution\",\n \"category\": \"logic\",\n \"icon\": \"Timer\",\n \"color\": \"orange\",\n \"inputs\": [\n { \"key\": \"duration\", \"label\": \"Duration\", \"type\": \"text\", \"placeholder\": \"5000\" },\n { \"key\": \"unit\", \"label\": \"Unit\", \"type\": \"select\", \"options\": [{\"label\": \"Milliseconds\", \"value\": \"ms\"}, {\"label\": \"Seconds\", \"value\": \"s\"}] }\n ]\n }\n ]\n },\n {\n \"id\": \"utilities\",\n \"nodes\": [\n {\n \"type\": \"text-transform\",\n \"label\": \"Text Transform\",\n \"description\": \"Modify text strings\",\n \"category\": \"utility\",\n \"icon\": \"Type\",\n \"color\": \"zinc\",\n \"inputs\": [\n {\n \"key\": \"action\",\n \"label\": \"Action\",\n \"type\": \"select\",\n \"options\": [\n { \"label\": \"To Upper Case\", \"value\": \"upper\" },\n { \"label\": \"To Lower Case\", \"value\": \"lower\" },\n { \"label\": \"Trim\", \"value\": \"trim\" },\n { \"label\": \"Replace\", \"value\": \"replace\" }\n ]\n },\n { \"key\": \"input\", \"label\": \"Input Text\", \"type\": \"text\" }\n ]\n },\n {\n \"type\": \"json-parser\",\n \"label\": \"JSON Helper\",\n \"description\": \"Parse or stringify JSON\",\n \"category\": \"utility\",\n \"icon\": \"Code\",\n \"color\": \"zinc\",\n \"inputs\": [\n {\n \"key\": \"action\",\n \"label\": \"Action\",\n \"type\": \"select\",\n \"options\": [\n { \"label\": \"Parse (String to JSON)\", \"value\": \"parse\" },\n { \"label\": \"Stringify (JSON to String)\", \"value\": \"stringify\" }\n ]\n },\n { \"key\": \"data\", \"label\": \"Data\", \"type\": \"json\" }\n ]\n },\n {\n \"type\": \"math-calc\",\n \"label\": \"Math Calculator\",\n \"description\": \"Perform calculations\",\n \"category\": \"utility\",\n \"icon\": \"Calculator\",\n \"color\": \"zinc\",\n \"inputs\": [\n {\n \"key\": \"operation\",\n \"label\": \"Operation\",\n \"type\": \"select\",\n \"options\": [\n { \"label\": \"Add\", \"value\": \"add\" },\n { \"label\": \"Subtract\", \"value\": \"sub\" },\n { \"label\": \"Multiply\", \"value\": \"mul\" },\n { \"label\": \"Divide\", \"value\": \"div\" },\n { \"label\": \"Random Number\", \"value\": \"random\" }\n ]\n },\n { \"key\": \"a\", \"label\": \"Value A\", \"type\": \"text\" },\n { \"key\": \"b\", \"label\": \"Value B\", \"type\": \"text\" }\n ]\n },\n {\n \"type\": \"crypto\",\n \"label\": \"Cryptography\",\n \"description\": \"Hash or Encrypt data\",\n \"category\": \"utility\",\n \"icon\": \"Lock\",\n \"color\": \"zinc\",\n \"inputs\": [\n { \"key\": \"algo\", \"label\": \"Algorithm\", \"type\": \"select\", \"options\": [{\"label\": \"MD5\", \"value\": \"md5\"}, {\"label\": \"SHA-256\", \"value\": \"sha256\"}, {\"label\": \"Base64 Encode\", \"value\": \"base64_enc\"}, {\"label\": \"Base64 Decode\", \"value\": \"base64_dec\"}] },\n { \"key\": \"input\", \"label\": \"value\", \"type\": \"text\" }\n ]\n },\n {\n \"type\": \"date-time\",\n \"label\": \"Date & Time\",\n \"description\": \"Format or manipulate dates\",\n \"category\": \"utility\",\n \"icon\": \"Calendar\",\n \"color\": \"zinc\",\n \"inputs\": [\n { \"key\": \"operation\", \"label\": \"Action\", \"type\": \"select\", \"options\": [{\"label\": \"Now (ISO)\", \"value\": \"now\"}, {\"label\": \"Format Date\", \"value\": \"format\"}, {\"label\": \"Add Time\", \"value\": \"add\"}] },\n { \"key\": \"date\", \"label\": \"Date String\", \"type\": \"text\" },\n { \"key\": \"format\", \"label\": \"Format Pattern\", \"type\": \"text\", \"placeholder\": \"YYYY-MM-DD\" }\n ]\n }\n\n ]\n },\n {\n \"id\": \"integrations-productivity\",\n \"nodes\": [\n {\n \"id\": \"google-drive\",\n \"label\": \"Google Drive\",\n \"icon\": \"HardDrive\",\n \"color\": \"blue\",\n \"category\": \"action\",\n \"baseUrl\": \"https://www.googleapis.com/drive/v3\",\n \"auth\": { \"type\": \"bearer\", \"placeholder\": \"OAuth Token\" },\n \"operations\": [\n { \"id\": \"list\", \"label\": \"List Files\", \"method\": \"GET\", \"path\": \"/files\", \"inputs\": [{\"key\": \"q\", \"label\": \"Query\", \"type\": \"text\"}] },\n { \"id\": \"upload\", \"label\": \"Upload File\", \"method\": \"POST\", \"path\": \"/files\", \"inputs\": [{\"key\": \"name\", \"label\": \"Name\", \"type\": \"text\"}, {\"key\": \"content\", \"label\": \"Content\", \"type\": \"text\"}] }\n ]\n },\n {\n \"id\": \"notion\",\n \"label\": \"Notion\",\n \"icon\": \"FileText\",\n \"color\": \"zinc\",\n \"category\": \"action\",\n \"baseUrl\": \"https://api.notion.com/v1\",\n \"auth\": { \"type\": \"header\", \"key\": \"Authorization\", \"placeholder\": \"Bearer secret_...\" },\n \"operations\": [\n { \"id\": \"create_page\", \"label\": \"Create Page\", \"method\": \"POST\", \"path\": \"/pages\", \"inputs\": [{\"key\": \"parent_id\", \"label\": \"Parent DB ID\", \"type\": \"text\"}, {\"key\": \"properties\", \"label\": \"Properties JSON\", \"type\": \"json\"}] },\n { \"id\": \"query_db\", \"label\": \"Query Database\", \"method\": \"POST\", \"path\": \"/databases/{id}/query\", \"inputs\": [{\"key\": \"id\", \"label\": \"Database ID\", \"type\": \"text\"}] }\n ]\n },\n {\n \"id\": \"airtable\",\n \"label\": \"Airtable\",\n \"icon\": \"Database\",\n \"color\": \"amber\",\n \"category\": \"action\",\n \"baseUrl\": \"https://api.airtable.com/v0\",\n \"auth\": { \"type\": \"bearer\", \"placeholder\": \"pat_...\" },\n \"operations\": [\n { \"id\": \"create_record\", \"label\": \"Create Record\", \"method\": \"POST\", \"path\": \"/{baseId}/{tableId}\", \"inputs\": [{\"key\": \"baseId\", \"label\": \"Base ID\", \"type\": \"text\"}, {\"key\": \"tableId\", \"label\": \"Table Name\", \"type\": \"text\"}, {\"key\": \"fields\", \"label\": \"Fields JSON\", \"type\": \"json\"}] },\n { \"id\": \"list_records\", \"label\": \"List Records\", \"method\": \"GET\", \"path\": \"/{baseId}/{tableId}\", \"inputs\": [{\"key\": \"baseId\", \"label\": \"Base ID\", \"type\": \"text\"}, {\"key\": \"tableId\", \"label\": \"Table Name\", \"type\": \"text\"}] }\n ]\n }\n ]\n },\n {\n \"id\": \"integrations-crm-marketing\",\n \"nodes\": [\n {\n \"id\": \"salesforce\",\n \"label\": \"Salesforce\",\n \"icon\": \"Cloud\",\n \"color\": \"blue\",\n \"category\": \"action\",\n \"baseUrl\": \"https://{instance}.salesforce.com/services/data/vXX.X\",\n \"auth\": { \"type\": \"bearer\" },\n \"operations\": [\n { \"id\": \"create_lead\", \"label\": \"Create Lead\", \"method\": \"POST\", \"path\": \"/sobjects/Lead\", \"inputs\": [{\"key\": \"instance\", \"label\": \"Instance URL\", \"type\": \"text\"}, {\"key\": \"LastName\", \"label\": \"Last Name\", \"type\": \"text\"}, {\"key\": \"Company\", \"label\": \"Company\", \"type\": \"text\"}] }\n ]\n },\n {\n \"id\": \"hubspot\",\n \"label\": \"HubSpot\",\n \"icon\": \"Users\",\n \"color\": \"orange\",\n \"category\": \"action\",\n \"baseUrl\": \"https://api.hubapi.com\",\n \"auth\": { \"type\": \"bearer\" },\n \"operations\": [\n { \"id\": \"create_contact\", \"label\": \"Create Contact\", \"method\": \"POST\", \"path\": \"/crm/v3/objects/contacts\", \"inputs\": [{\"key\": \"properties\", \"label\": \"Properties JSON\", \"type\": \"json\"}] }\n ]\n },\n {\n \"id\": \"mailchimp\",\n \"label\": \"Mailchimp\",\n \"icon\": \"Mail\",\n \"color\": \"yellow\",\n \"category\": \"action\",\n \"baseUrl\": \"https://{dc}.api.mailchimp.com/3.0\",\n \"auth\": { \"type\": \"bearer\" },\n \"operations\": [\n { \"id\": \"add_member\", \"label\": \"Add Subscriber\", \"method\": \"POST\", \"path\": \"/lists/{list_id}/members\", \"inputs\": [{\"key\": \"dc\", \"label\": \"Data Center (usX)\", \"type\": \"text\"}, {\"key\": \"list_id\", \"label\": \"List ID\", \"type\": \"text\"}, {\"key\": \"email_address\", \"label\": \"Email\", \"type\": \"text\"}, {\"key\": \"status\", \"label\": \"Status\", \"type\": \"select\", \"options\": [{\"label\":\"subscribed\",\"value\":\"subscribed\"}]}] }\n ]\n }\n ]\n },\n {\n \"id\": \"integrations-commerce\",\n \"nodes\": [\n {\n \"id\": \"shopify\",\n \"label\": \"Shopify\",\n \"icon\": \"ShoppingBag\",\n \"color\": \"emerald\",\n \"category\": \"action\",\n \"baseUrl\": \"https://{shop}.myshopify.com/admin/api/2023-10\",\n \"auth\": { \"type\": \"header\", \"key\": \"X-Shopify-Access-Token\" },\n \"operations\": [\n { \"id\": \"get_products\", \"label\": \"Get Products\", \"method\": \"GET\", \"path\": \"/products.json\", \"inputs\": [{\"key\": \"shop\", \"label\": \"Shop Name\", \"type\": \"text\"}] },\n { \"id\": \"create_order\", \"label\": \"Create Order\", \"method\": \"POST\", \"path\": \"/orders.json\", \"inputs\": [{\"key\": \"shop\", \"label\": \"Shop Name\", \"type\": \"text\"}, {\"key\": \"order\", \"label\": \"Order JSON\", \"type\": \"json\"}] }\n ]\n },\n {\n \"id\": \"stripe\",\n \"label\": \"Stripe\",\n \"icon\": \"CreditCard\",\n \"color\": \"indigo\",\n \"category\": \"action\",\n \"baseUrl\": \"https://api.stripe.com/v1\",\n \"auth\": { \"type\": \"bearer\" },\n \"operations\": [\n { \"id\": \"create_customer\", \"label\": \"Create Customer\", \"method\": \"POST\", \"path\": \"/customers\", \"inputs\": [{\"key\": \"email\", \"label\": \"Email\", \"type\": \"text\"}] },\n { \"id\": \"list_charges\", \"label\": \"List Charges\", \"method\": \"GET\", \"path\": \"/charges\", \"inputs\": [{\"key\": \"limit\", \"label\": \"Limit\", \"type\": \"text\"}] }\n ]\n }\n ]\n }\n]\n","import { NodeTypeDefinition, nodeRegistry } from './registry';\nimport { createConnectorNode, ConnectorDefinition } from './connector';\nimport catalogData from './catalog.json';\n\n// Helper to convert catalog entries to registry definitions\nexport function loadCatalog() {\n catalogData.forEach((group: any) => {\n group.nodes.forEach((node: any) => {\n // Check if it's a connector (has operations) or a native node\n if (node.operations) {\n // It's a connector\n const connector: ConnectorDefinition = {\n id: node.id,\n label: node.label,\n category: node.category,\n icon: node.icon,\n color: node.color,\n baseUrl: node.baseUrl,\n auth: node.auth,\n operations: node.operations\n };\n // Register it\n nodeRegistry[connector.id] = createConnectorNode(connector);\n // We also need to add it to generic connector lookups if we used a separate array.\n // But createConnectorNode returns a definition that we put in registry.\n // However, for PropertyPanel execution logic to find operations, we need it in a lookup.\n // Let's attach the connector definition to the registry entry metadata if possible, \n // OR extending the look up function.\n // HACK: We will push to standardConnectors array in standard-library if we want `getConnectorDetails` to find it.\n } else {\n // It's a standard simple node\n const def: NodeTypeDefinition = {\n type: node.type,\n label: node.label,\n description: node.description,\n category: node.category,\n icon: node.icon,\n color: node.color,\n handles: node.handles || [ { id: 'in', type: 'target' }, { id: 'out', type: 'source' } ],\n inputs: node.inputs\n };\n nodeRegistry[def.type] = def;\n }\n });\n });\n}\n","export type NodeCategory = 'trigger' | 'action' | 'logic' | 'utility';\n\nexport interface NodeHandle {\n id: string;\n type: 'source' | 'target';\n label?: string;\n}\n\nexport interface NodeField {\n key: string;\n label: string;\n type: 'text' | 'number' | 'select' | 'boolean' | 'json' | 'code';\n options?: { label: string; value: string }[];\n placeholder?: string;\n description?: string;\n}\n\nexport interface NodeTypeDefinition {\n type: string;\n label: string;\n description: string;\n category: NodeCategory;\n icon: string; \n color: string; // Tailwind class component for border/bg\n handles: NodeHandle[];\n inputs: NodeField[];\n}\n\nimport { createConnectorNode, ConnectorDefinition } from './connector';\nimport { standardConnectors } from './standard-library';\n\n// ... existing definitions ...\nexport const nodeRegistry: Record<string, NodeTypeDefinition> = {\n // ... existing static nodes ...\n 'webhook': {\n type: 'webhook',\n label: 'Webhook',\n description: 'Triggers when a URL is called',\n category: 'trigger',\n icon: 'Webhook',\n color: 'emerald',\n handles: [{ id: 'out', type: 'source' }],\n inputs: [\n { key: 'method', label: 'HTTP Method', type: 'select', options: [{ label: 'GET', value: 'GET'}, { label: 'POST', value: 'POST'}] },\n { key: 'path', label: 'Path', type: 'text', placeholder: '/webhook/...' }\n ]\n },\n 'schedule': {\n type: 'schedule',\n label: 'Schedule',\n description: 'Triggers on a specific interval',\n category: 'trigger',\n icon: 'Clock',\n color: 'emerald',\n handles: [{ id: 'out', type: 'source' }],\n inputs: [\n { key: 'interval', label: 'Interval', type: 'select', options: [{ label: 'Every Minute', value: '1m'}, { label: 'Every Hour', value: '1h'}, { label: 'Every Day', value: '1d'}] },\n { key: 'cron', label: 'Cron Expression', type: 'text', placeholder: '* * * * *' }\n ]\n },\n 'http-request': {\n type: 'http-request',\n label: 'HTTP Request',\n description: 'Make an external API call',\n category: 'action',\n icon: 'Globe',\n color: 'blue',\n handles: [{ id: 'in', type: 'target' }, { id: 'out', type: 'source' }],\n inputs: [\n { key: 'url', label: 'URL', type: 'text', placeholder: 'https://api.example.com' },\n { key: 'method', label: 'Method', type: 'select', options: [{ label: 'GET', value: 'GET'}, { label: 'POST', value: 'POST'}, { label: 'PUT', value: 'PUT'}, { label: 'DELETE', value: 'DELETE'}] },\n { key: 'headers', label: 'Headers', type: 'json' },\n { key: 'body', label: 'Body', type: 'json' }\n ]\n },\n 'email': {\n type: 'email',\n label: 'Send Email',\n description: 'Send an email to a recipient',\n category: 'action',\n icon: 'Mail',\n color: 'blue',\n handles: [{ id: 'in', type: 'target' }, { id: 'out', type: 'source' }],\n inputs: [\n { key: 'to', label: 'To', type: 'text' },\n { key: 'subject', label: 'Subject', type: 'text' },\n { key: 'body', label: 'Body', type: 'text' } \n ]\n },\n 'slack': {\n type: 'slack',\n label: 'Slack (Simple)',\n description: 'Send a message to a channel',\n category: 'action',\n icon: 'MessageSquare',\n color: 'blue',\n handles: [{ id: 'in', type: 'target' }, { id: 'out', type: 'source' }],\n inputs: [\n { key: 'webhookUrl', label: 'Webhook URL', type: 'text' },\n { key: 'message', label: 'Message', type: 'text' }\n ]\n },\n 'if-else': {\n type: 'if-else',\n label: 'If / Else',\n description: 'Branch flow based on condition',\n category: 'logic',\n icon: 'Split',\n color: 'orange',\n handles: [\n { id: 'in', type: 'target' },\n { id: 'true', type: 'source', label: 'True' },\n { id: 'false', type: 'source', label: 'False' }\n ],\n inputs: [\n { key: 'condition', label: 'Condition', type: 'code', description: 'Javascript expression returning true/false' }\n ]\n },\n 'merge': {\n type: 'merge',\n label: 'Merge',\n description: 'Combine multiple branches',\n category: 'logic',\n icon: 'GitMerge',\n color: 'orange',\n handles: [\n { id: 'in-a', type: 'target', label: 'A' },\n { id: 'in-b', type: 'target', label: 'B' },\n { id: 'out', type: 'source' }\n ],\n inputs: []\n }\n};\n\n// Inject Standard Connectors\nstandardConnectors.forEach(conn => {\n nodeRegistry[conn.id] = createConnectorNode(conn);\n});\n\nimport { loadCatalog } from './loader';\n// Initialize Catalog\nloadCatalog();\n\n// Helper to get definition details if it is a connector\nexport function getConnectorDetails(typeId: string): ConnectorDefinition | undefined {\n return standardConnectors.find(c => c.id === typeId);\n}\n","import React, { memo } from 'react';\nimport { Handle, Position, NodeProps } from 'reactflow';\nimport { \n Webhook, \n Clock, \n Globe, \n Mail, \n MessageSquare, \n Split, \n GitMerge, \n MoreHorizontal, \n Zap, \n type LucideIcon\n} from 'lucide-react';\nimport { cn } from '../utils';\nimport { nodeRegistry, NodeTypeDefinition } from '@universal-workflow/widget-core';\n\nimport { extendedIconMap } from '../utils/icons';\n\nconst iconMap: Record<string, LucideIcon> = {\n Webhook,\n Clock,\n Globe,\n Mail,\n MessageSquare,\n Split,\n GitMerge,\n Zap,\n ...extendedIconMap\n};\n\n// Map color names to Tailwind types\nconst colorMap: Record<string, string> = {\n emerald: 'text-emerald-600 bg-emerald-50 border-emerald-200',\n blue: 'text-blue-600 bg-blue-50 border-blue-200',\n orange: 'text-orange-600 bg-orange-50 border-orange-200',\n zinc: 'text-zinc-600 bg-zinc-50 border-zinc-200',\n};\n\nconst borderMap: Record<string, string> = {\n emerald: 'ring-emerald-500/20',\n blue: 'ring-blue-500/20',\n orange: 'ring-orange-500/20',\n zinc: 'ring-zinc-500/20',\n};\n\nexport const UniversalNode = memo(({ data, selected, type }: NodeProps) => {\n // 1. Look up definition\n const def = nodeRegistry[data.type || type] || nodeRegistry['webhook']; // Fallback\n \n if (!def) {\n return <div className=\"p-2 border border-red-500 rounded bg-red-50 text-red-600\">Unknown Node Type: {type}</div>\n }\n\n const Icon = iconMap[def.icon] || Zap;\n const colorClass = colorMap[def.color] || colorMap['zinc'];\n const ringClass = borderMap[def.color] || borderMap['zinc'];\n\n // Execution Status Styles\n const status = data.executionStatus; // 'running' | 'success' | 'error'\n let statusBorder = \"\";\n if (status === 'running') statusBorder = \"ring-4 ring-indigo-500/30 border-indigo-500 shadow-lg shadow-indigo-200 animate-pulse\";\n else if (status === 'success') statusBorder = \"ring-4 ring-emerald-500/40 border-emerald-500 shadow-lg shadow-emerald-200\";\n else if (status === 'error') statusBorder = \"ring-4 ring-red-500/40 border-red-500 shadow-lg shadow-red-200\";\n\n return (\n <div className={cn(\n \"min-w-[240px] bg-white rounded-lg shadow-sm border-2 transition-all duration-300\", \n selected ? `border-indigo-500 shadow-xl ring-2 ${ringClass}` : \"border-zinc-200 hover:border-zinc-300\",\n statusBorder\n )}>\n {/* Header */}\n <div className={cn(\"flex items-center justify-between p-3 border-b border-zinc-100/50 rounded-t-md bg-zinc-50/50\")}>\n <div className=\"flex items-center gap-3\">\n <div className={cn(\"p-1.5 rounded-md border shadow-sm\", colorClass)}>\n <Icon size={16} strokeWidth={2.5} />\n </div>\n <div>\n <span className=\"block text-xs font-bold uppercase tracking-wider text-zinc-500\">{def.category}</span>\n <span className=\"block text-sm font-semibold text-zinc-900 leading-none mt-0.5\">{def.label}</span>\n </div>\n </div>\n <button className=\"text-zinc-400 hover:text-zinc-600 transition-colors\">\n <MoreHorizontal size={16} />\n </button>\n </div>\n\n {/* Body / Summary */}\n <div className=\"p-4 bg-white rounded-b-lg\">\n {/* Dynamic Summary based on important fields */}\n {def.type === 'http-request' && (\n <div className=\"flex items-center gap-2 font-mono text-xs text-zinc-600 bg-zinc-50 p-2 rounded border border-zinc-100\">\n <span className=\"font-bold text-blue-600\">{data.method || 'GET'}</span>\n <span className=\"truncate max-w-[140px]\">{data.url || 'https://...'}</span>\n </div>\n )}\n {def.type === 'webhook' && (\n <div className=\"flex items-center gap-2 font-mono text-xs text-zinc-600\">\n <span className=\"font-bold text-emerald-600\">{data.method || 'POST'}</span>\n <span>{data.path || '/webhook/...'}</span>\n </div>\n )}\n {def.type === 'if-else' && (\n <div className=\"text-xs font-mono text-orange-600 bg-orange-50 p-2 rounded border border-orange-100 truncate\">\n {data.condition || 'x > 0'}\n </div>\n )}\n {!['http-request', 'webhook', 'if-else'].includes(def.type) && (\n <p className=\"text-sm text-zinc-500\">{def.description}</p>\n )}\n </div>\n\n {/* Dynamic Handles */}\n {def.handles.map((handle) => {\n // Logic for positioning handles? \n // For now, let's stick to standard Left=Target, Right=Source, but If/Else has multiple sources.\n \n let position = handle.type === 'target' ? Position.Left : Position.Right;\n let style = {};\n \n // Special case for Logic nodes which might fan out\n if (def.type === 'if-else' && handle.type === 'source') {\n // Spread logic: If it's the 'true' handle, go top-right? Or just stack them?\n // Let's stack them on the right for now with labels.\n }\n\n // We need to offset handles if there are multiple.\n // Simple strategy: Just render them. React Flow handles multiple handles on same side fine if positioned manually via style, \n // but default stack is tricky without absolute positioning.\n // Let's use flexbox helper or hardcoded styles for now.\n \n const isRight = handle.type === 'source';\n const offset = def.handles.filter(h => h.type === handle.type).indexOf(handle);\n const total = def.handles.filter(h => h.type === handle.type).length;\n \n // If multiple sources, distribute them vertically?\n const topPos = total > 1 ? `${((offset + 1) * 100) / (total + 1)}%` : '50%';\n \n return (\n <Handle \n key={handle.id}\n id={handle.id}\n type={handle.type} \n position={isRight ? Position.Right : Position.Left}\n style={{ top: topPos, ...style }}\n className={cn(\n \"!w-3 !h-3 !border-2 !border-white transition-all duration-200 bg-zinc-400 group-hover:bg-indigo-500\",\n isRight ? \"-right-1.5\" : \"-left-1.5\",\n // Color code handles?\n handle.id === 'true' ? '!bg-emerald-500' : \n handle.id === 'false' ? '!bg-red-500' : ''\n )}\n >\n {/* Handle Label tooltip */}\n {handle.label && (\n <span className={cn(\n \"absolute text-[10px] uppercase font-bold text-zinc-500 pointer-events-none w-max block mb-1\",\n isRight ? \"right-4 mr-1 text-right\" : \"left-4 ml-1 text-left\",\n \"top-1/2 -translate-y-1/2\"\n )}>\n {handle.label}\n </span>\n )}\n </Handle>\n );\n })}\n </div>\n );\n});\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","import { LucideIcon, Sheet, Bot, Type, Code, Calculator, Timer, GitFork, Percent, HardDrive, Calendar, Play, Github, Lock, FileText, Database, Cloud, Users, ShoppingBag, CreditCard } from 'lucide-react';\n\nexport const extendedIconMap: Record<string, LucideIcon | any> = {\n Sheet,\n Bot,\n Type,\n Code,\n Calculator,\n Timer,\n GitFork,\n Percent,\n HardDrive,\n Calendar,\n Play,\n Github, \n Lock,\n FileText, // Notion\n Database, // Airtable\n Cloud, // Salesforce\n Users, // HubSpot\n ShoppingBag, // Shopify\n CreditCard // Stripe\n};\n","import React, { useRef } from 'react';\nimport { MousePointer2, Save, Undo2, Redo2, Plus, Download, Upload, Layout, Trash2, Play } from 'lucide-react';\nimport { cn } from '../utils';\n\ninterface ToolbarProps {\n onSave: () => void;\n onExport: () => void;\n onImport: (file: File) => void;\n onAddNode: () => void;\n onAutoLayout: () => void;\n onClear: () => void;\n onRun: () => void;\n isSaving: boolean;\n isRunning: boolean;\n canUndo: boolean;\n canRedo: boolean;\n onUndo: () => void;\n onRedo: () => void;\n}\n\nexport function Toolbar({ \n onSave, onExport, onImport, onAddNode, \n onAutoLayout, onClear, onRun,\n isSaving, isRunning,\n canUndo, canRedo, onUndo, onRedo \n}: ToolbarProps) {\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n if (file) {\n onImport(file);\n }\n // Reset so same file can be selected again\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n };\n\n return (\n <div className=\"absolute top-4 left-1/2 -translate-x-1/2 z-50 flex items-center gap-1 p-1 bg-white/90 backdrop-blur-md border border-zinc-200/50 shadow-xl rounded-full\">\n <input \n type=\"file\" \n ref={fileInputRef} \n onChange={handleFileChange} \n accept=\".json\" \n className=\"hidden\" \n />\n\n <div className=\"flex items-center gap-1 px-1 border-r border-zinc-200\">\n <button className=\"p-2 text-zinc-500 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all\" title=\"Select\">\n <MousePointer2 size={18} />\n </button>\n <button onClick={onAddNode} className=\"p-2 text-zinc-500 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all\" title=\"Add Node\">\n <Plus size={18} />\n </button>\n </div>\n \n <div className=\"flex items-center gap-1 px-1 border-r border-zinc-200\">\n <button \n onClick={onUndo} \n disabled={!canUndo}\n className=\"p-2 text-zinc-400 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all disabled:opacity-30 disabled:cursor-not-allowed\" \n title=\"Undo\"\n >\n <Undo2 size={18} />\n </button>\n <button \n onClick={onRedo}\n disabled={!canRedo}\n className=\"p-2 text-zinc-400 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all disabled:opacity-30 disabled:cursor-not-allowed\" \n title=\"Redo\"\n >\n <Redo2 size={18} />\n </button>\n </div>\n\n <div className=\"flex items-center gap-1 px-1 border-r border-zinc-200\">\n <button onClick={onAutoLayout} className=\"p-2 text-zinc-600 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all\" title=\"Auto Layout\">\n <Layout size={18} />\n </button>\n <button onClick={onClear} className=\"p-2 text-zinc-600 hover:text-red-600 hover:bg-red-50 rounded-full transition-all\" title=\"Clear Canvas\">\n <Trash2 size={18} />\n </button>\n </div>\n \n <div className=\"flex items-center gap-1 px-1 border-r border-zinc-200\">\n <button onClick={onExport} className=\"p-2 text-zinc-600 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all\" title=\"Export JSON\">\n <Download size={18} />\n </button>\n <button onClick={() => fileInputRef.current?.click()} className=\"p-2 text-zinc-600 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all\" title=\"Import JSON\">\n <Upload size={18} />\n </button>\n </div>\n\n <div className=\"flex items-center gap-1 px-1\">\n <button \n className=\"flex items-center gap-2 px-3 py-2 bg-emerald-500 text-white rounded-full font-medium text-sm hover:bg-emerald-600 shadow-md shadow-emerald-200 transition-all mr-1\"\n onClick={onRun}\n disabled={isRunning}\n >\n {isRunning ? <div className=\"w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin\" /> : <Play size={16} fill=\"currentColor\" />}\n </button>\n\n <button \n className=\"flex items-center gap-2 px-4 py-2 bg-indigo-600 text-white rounded-full font-medium text-sm hover:bg-indigo-700 shadow-md shadow-indigo-200 transition-all disabled:opacity-70 disabled:cursor-not-allowed\"\n onClick={onSave}\n disabled={isSaving}\n >\n {isSaving ? <div className=\"w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin\" /> : <Save size={16} />}\n <span>Save</span>\n </button>\n </div>\n </div>\n );\n}\n","import React from 'react';\nimport { Settings2, X, AlertCircle, Trash2, Import } from 'lucide-react';\nimport { useReactFlow } from 'reactflow';\nimport { nodeRegistry, getConnectorDetails, ConnectorDefinition } from '@universal-workflow/widget-core';\nimport { parseCurl } from '../utils/curl';\n\n\ninterface PropertyPanelProps {\n selectedNodeId?: string;\n selectedNodeType?: string;\n onClose: () => void;\n}\n\nexport function PropertyPanel({ selectedNodeId, selectedNodeType, onClose }: PropertyPanelProps) {\n const { setNodes, getNodes, deleteElements } = useReactFlow();\n\n if (!selectedNodeId) return null;\n\n const node = getNodes().find(n => n.id === selectedNodeId);\n if (!node) return null;\n \n // Resolve type directly or from data\n // Note: custom node types usually store their identifier in `type` prop or `data.type`. \n // Our UniversalNode logic uses `data.type` as primary if available.\n const typeKey = node.data?.type || node.type || selectedNodeType; \n let def = nodeRegistry[typeKey];\n\n // Dynamic Logic: If it's a connector, we might need to expand the inputs based on the selected operation\n const connectorDef = getConnectorDetails(typeKey);\n \n if (connectorDef) {\n // Deep copy def so we don't mutate registry\n def = JSON.parse(JSON.stringify(def)); \n const currentOpId = node.data['operation'];\n if (currentOpId) {\n const op = connectorDef.operations.find(o => o.id === currentOpId);\n if (op) {\n // Append operation inputs\n def.inputs = [...def.inputs, ...op.inputs];\n }\n }\n }\n\n if (!def) {\n return (\n <div className=\"absolute top-4 right-4 w-80 bg-white p-4 rounded shadow border border-red-200 z-50\">\n <div className=\"flex items-center justify-between text-red-600 mb-2\">\n <div className=\"flex items-center gap-2\">\n <AlertCircle size={16} />\n <span className=\"font-bold\">Unknown Node Type</span>\n </div>\n <button onClick={onClose}><X size={16}/></button>\n </div>\n <p className=\"text-xs text-zinc-500 mt-1\">ID: {typeKey}</p>\n </div>\n );\n }\n\n const handleUpdate = (key: string, value: any) => {\n setNodes((nds) => \n nds.map((n) => {\n if (n.id === selectedNodeId) {\n return {\n ...n,\n data: { ...n.data, [key]: value }\n };\n }\n return n;\n })\n );\n };\n\n const handleDelete = () => {\n deleteElements({ nodes: [{ id: selectedNodeId }] });\n onClose();\n };\n\n return (\n <div className=\"absolute top-4 right-4 bottom-4 w-80 bg-white/95 backdrop-blur-md border border-zinc-200 shadow-2xl rounded-xl z-50 flex flex-col overflow-hidden animate-in slide-in-from-right duration-200\">\n <div className=\"p-4 border-b border-zinc-100 flex items-center justify-between bg-zinc-50/50\">\n <div className=\"flex items-center gap-2 text-zinc-700 font-semibold\">\n <Settings2 size={16} />\n <span>{def.label} Properties</span>\n </div>\n <div className=\"flex items-center gap-1\">\n {typeKey === 'http-request' && (\n <button \n onClick={() => {\n const curl = prompt(\"Paste your cURL command here:\");\n if (curl) {\n const parsed = parseCurl(curl);\n if (parsed) {\n setNodes((nds) => \n nds.map((n) => {\n if (n.id === selectedNodeId) {\n return {\n ...n,\n data: { \n ...n.data, \n method: parsed.method,\n url: parsed.url,\n headers: JSON.stringify(parsed.headers, null, 2),\n body: parsed.body || '{}'\n }\n };\n }\n return n;\n })\n );\n } else {\n alert(\"Could not parse cURL command.\");\n }\n }\n }}\n className=\"p-1.5 text-indigo-500 hover:text-indigo-700 hover:bg-indigo-50 rounded-md transition-colors flex items-center gap-1 text-xs font-medium mr-1\"\n title=\"Import cURL\"\n >\n <Import size={14} />\n <span>Import cURL</span>\n </button>\n )}\n <button \n onClick={handleDelete} \n className=\"p-1.5 text-red-400 hover:text-red-600 hover:bg-red-50 rounded-md transition-colors\"\n title=\"Delete Node\"\n >\n <Trash2 size={16} />\n </button>\n <button onClick={onClose} className=\"p-1.5 text-zinc-400 hover:text-zinc-700 hover:bg-zinc-100 rounded-md transition-colors\">\n <X size={16} />\n </button>\n </div>\n </div>\n \n <div className=\"p-4 space-y-5 flex-1 overflow-y-auto\">\n \n <div className=\"space-y-1 pb-4 border-b border-zinc-100\">\n <label className=\"text-xs font-bold uppercase tracking-wider text-zinc-400\">Description</label>\n <p className=\"text-sm text-zinc-600\">{def.description}</p>\n </div>\n\n {def.inputs.map((field) => (\n <div key={field.key} className=\"space-y-2\">\n <label className=\"block text-xs font-bold uppercase tracking-wider text-zinc-500\">\n {field.label}\n </label>\n \n {field.type === 'text' && (\n <input \n type=\"text\" \n value={node.data[field.key] || ''}\n onChange={(e) => handleUpdate(field.key, e.target.value)}\n placeholder={field.placeholder}\n className=\"w-full px-3 py-2 bg-white border border-zinc-200 rounded-md text-sm text-zinc-800 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-500 transition-all\"\n />\n )}\n\n {field.type === 'select' && (\n <select\n value={node.data[field.key] || ''}\n onChange={(e) => handleUpdate(field.key, e.target.value)}\n className=\"w-full px-3 py-2 bg-white border border-zinc-200 rounded-md text-sm text-zinc-800 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-500 transition-all\"\n >\n <option value=\"\" disabled>Select...</option>\n {field.options?.map(opt => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n )}\n\n {(field.type === 'json' || field.type === 'code') && (\n <textarea \n value={typeof node.data[field.key] === 'object' ? JSON.stringify(node.data[field.key], null, 2) : (node.data[field.key] || '')}\n onChange={(e) => handleUpdate(field.key, e.target.value)}\n rows={5}\n className=\"w-full px-3 py-2 bg-white border border-zinc-200 rounded-md text-sm font-mono text-zinc-800 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-500 transition-all resize-y\"\n />\n )}\n </div>\n ))}\n\n </div>\n </div>\n );\n}\n","\n/**\n * Simple cURL parser to extract method, url, headers, and body\n */\nexport interface CurlRequest {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n url: string;\n headers: Record<string, string>;\n body?: string;\n}\n\nexport function parseCurl(curlCommand: string): CurlRequest | null {\n if (!curlCommand.trim().toLowerCase().startsWith('curl')) return null;\n\n let method: any = 'GET';\n const headers: Record<string, string> = {};\n let body: string | undefined = undefined;\n let url = '';\n\n // Remove newlines and backslashes for multi-line commands\n const cleanCommand = curlCommand.replace(/\\\\\\n/g, ' ').replace(/\\n/g, ' ');\n\n // Extract URL (simplistic: first string starting with http)\n const urlMatch = cleanCommand.match(/'(http[^']*)'|\"(http[^\"]*)\"|(http\\S+)/);\n if (urlMatch) {\n url = urlMatch[1] || urlMatch[2] || urlMatch[3];\n }\n\n // Extract Method (-X POST)\n const methodMatch = cleanCommand.match(/-X\\s+([A-Z]+)/);\n if (methodMatch) {\n method = methodMatch[1];\n }\n\n // Extract Headers (-H \"Key: Value\")\n // Regex global match\n const headerRegex = /-H\\s+['\"]([^'\"]+)['\"]/g;\n let match;\n while ((match = headerRegex.exec(cleanCommand)) !== null) {\n const [key, value] = match[1].split(/:\\s?(.+)/);\n if (key && value) {\n headers[key] = value;\n }\n }\n\n // Extract Body (-d \"data\" or --data \"data\")\n const dataMatch = cleanCommand.match(/(-d|--data|--data-raw)\\s+['\"]([^'\"]+)['\"]/);\n if (dataMatch) {\n body = dataMatch[2];\n // If method wasn't set, default to POST when data is present\n if (method === 'GET') method = 'POST';\n }\n\n return { method, url, headers, body };\n}\n","import React, { useState, useMemo } from 'react';\nimport { Search, X, Zap, Globe, MessageSquare, Split, GitMerge, Clock, Mail, Sheet, Bot } from 'lucide-react';\nimport { nodeRegistry, NodeTypeDefinition } from '@universal-workflow/widget-core';\nimport { cn } from '../utils';\nimport { extendedIconMap } from '../utils/icons';\n\ninterface NodePaletteProps {\n isOpen: boolean;\n onClose: () => void;\n onSelect: (type: string) => void;\n}\n\nconst iconMap: Record<string, any> = {\n Webhook: Zap,\n Clock: Clock,\n Globe: Globe,\n Mail: Mail,\n MessageSquare: MessageSquare,\n Split: Split,\n GitMerge: GitMerge,\n Zap: Zap,\n ...extendedIconMap\n};\n\nexport function NodePalette({ isOpen, onClose, onSelect }: NodePaletteProps) {\n const [search, setSearch] = useState('');\n\n const groupedNodes = useMemo(() => {\n const groups: Record<string, NodeTypeDefinition[]> = {};\n\n Object.values(nodeRegistry).forEach(node => {\n const matchesSearch = \n node.label.toLowerCase().includes(search.toLowerCase()) || \n (node.description && node.description.toLowerCase().includes(search.toLowerCase()));\n\n if (matchesSearch) {\n const cat = node.category || 'other';\n if (!groups[cat]) groups[cat] = [];\n groups[cat].push(node);\n }\n });\n\n // Sort categories explicitly if needed, or just rely on insertion order.\n // Let's force a specific order for main ones, then others.\n const order = ['trigger', 'logic', 'action', 'utility', 'integration'];\n const sortedGroups: Record<string, NodeTypeDefinition[]> = {};\n order.forEach(key => {\n if (groups[key]) sortedGroups[key] = groups[key];\n });\n // Add remaining\n Object.keys(groups).forEach(key => {\n if (!order.includes(key)) sortedGroups[key] = groups[key];\n });\n\n return sortedGroups;\n }, [search]);\n\n if (!isOpen) return null;\n\n return (\n <div className=\"absolute inset-0 z-[100] bg-black/20 backdrop-blur-sm flex items-start justify-center pt-20 animate-in fade-in duration-200\">\n <div className=\"w-[600px] bg-white rounded-xl shadow-2xl border border-zinc-200 overflow-hidden flex flex-col max-h-[70vh] animate-in slide-in-from-bottom-4 duration-300\">\n \n {/* Header / Search */}\n <div className=\"p-4 border-b border-zinc-100 flex items-center gap-3 bg-zinc-50/50\">\n <Search className=\"text-zinc-400\" size={20} />\n <input \n autoFocus\n type=\"text\" \n placeholder=\"Search nodes...\" \n className=\"flex-1 bg-transparent border-none outline-none text-zinc-900 placeholder:text-zinc-400 text-lg\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n />\n <div className=\"px-2 py-1 bg-zinc-100 border border-zinc-200 rounded text-xs text-zinc-500 font-medium\">ESC</div>\n <button onClick={onClose} className=\"text-zinc-400 hover:text-zinc-700\">\n <X size={20} />\n </button>\n </div>\n\n {/* Content */}\n <div className=\"overflow-y-auto p-4 space-y-2\">\n {Object.entries(groupedNodes).map(([category, nodes]) => {\n if (nodes.length === 0) return null;\n \n // If searching, always expand. If not, maybe collapse? \n // Let's keep them expanded for now as <details> open by default or controlled.\n // Actually, with search, we want to see everything.\n const isSearchActive = search.length > 0;\n \n return (\n <details \n key={category} \n open={true} // Default to open\n className=\"group border border-zinc-200 rounded-lg bg-zinc-50/30 open:bg-white transition-all duration-200\"\n >\n <summary className=\"flex items-center justify-between p-3 cursor-pointer list-none text-zinc-600 font-medium hover:bg-zinc-50 select-none\">\n <div className=\"flex items-center gap-2\">\n <span className=\"uppercase tracking-wider text-xs font-bold text-zinc-500\">{category}</span>\n <span className=\"text-xs bg-zinc-100 text-zinc-400 px-1.5 py-0.5 rounded-full\">{nodes.length}</span>\n </div>\n <div className=\"text-zinc-400 group-open:rotate-180 transition-transform\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"m6 9 6 6 6-6\"/></svg>\n </div>\n </summary>\n \n <div className=\"p-3 pt-0 border-t border-transparent group-open:border-zinc-100\">\n <div className=\"grid grid-cols-2 gap-3 pt-2\">\n {nodes.map(node => {\n const Icon = iconMap[node.icon] || extendedIconMap[node.icon] || Zap;\n return (\n <button \n key={node.type}\n onClick={() => onSelect(node.type)}\n className=\"flex items-start gap-3 p-3 rounded-lg border border-zinc-100 bg-white hover:border-indigo-200 hover:shadow-md hover:bg-indigo-50/30 transition-all text-left group/btn\"\n >\n <div className={cn(\n \"p-2 rounded-md transition-colors\", \n `bg-${node.color}-50 text-${node.color}-600 group-hover/btn:bg-white`\n )}>\n <Icon size={20} />\n </div>\n <div>\n <div className=\"font-semibold text-zinc-900 text-sm\">{node.label}</div>\n <div className=\"text-xs text-zinc-500 line-clamp-2 leading-relaxed\">{node.description}</div>\n </div>\n </button>\n );\n })}\n </div>\n </div>\n </details>\n );\n })}\n\n {Object.values(groupedNodes).every(g => g.length === 0) && (\n <div className=\"text-center py-12 text-zinc-400\">\n <p>No nodes found matching \"{search}\"</p>\n </div>\n )}\n </div>\n\n </div>\n \n {/* Close on click outside */}\n <div className=\"absolute inset-0 -z-10\" onClick={onClose} />\n </div>\n );\n}\n","import React, { useEffect, useState } from 'react';\nimport { CheckCircle2, AlertCircle, X } from 'lucide-react';\nimport { cn } from '../utils';\n\nexport type ToastType = 'success' | 'error';\n\nexport interface ToastProps {\n message: string;\n type: 'success' | 'error';\n isVisible: boolean;\n onClose: () => void;\n}\n\nexport function Toast({ message, type, isVisible, onClose }: ToastProps) {\n const [show, setShow] = useState(false);\n\n useEffect(() => {\n if (isVisible) {\n setShow(true);\n const timer = setTimeout(() => {\n onClose();\n }, 4000);\n return () => clearTimeout(timer);\n } else {\n setTimeout(() => setShow(false), 300); // Wait for exit animation\n }\n }, [isVisible, onClose]);\n\n if (!show && !isVisible) return null;\n\n return (\n <div className={cn(\n \"absolute bottom-6 left-1/2 -translate-x-1/2 z-[100] flex items-center gap-3 px-4 py-3 rounded-lg shadow-xl border transition-all duration-300 transform\",\n type === 'success' ? \"bg-white border-emerald-100 text-emerald-800\" : \"bg-white border-red-100 text-red-800\",\n isVisible ? \"translate-y-0 opacity-100 scale-100\" : \"translate-y-4 opacity-0 scale-95\"\n )}>\n {type === 'success' ? <CheckCircle2 size={20} className=\"text-emerald-500\"/> : <AlertCircle size={20} className=\"text-red-500\"/>}\n <span className=\"font-medium text-sm\">{message}</span>\n <button onClick={onClose} className=\"ml-2 hover:opacity-70\">\n <X size={16} className=\"text-zinc-400\" />\n </button>\n </div>\n );\n}\n","import dagre from 'dagre';\nimport { Node, Edge, Position } from 'reactflow';\n\nconst dagreGraph = new dagre.graphlib.Graph();\ndagreGraph.setDefaultEdgeLabel(() => ({}));\n\nconst nodeWidth = 240;\nconst nodeHeight = 150; // Approximated UniversalNode height\n\nexport const getLayoutedElements = (nodes: Node[], edges: Edge[], direction = 'LR') => {\n const isHorizontal = direction === 'LR';\n dagreGraph.setGraph({ rankdir: direction });\n\n nodes.forEach((node) => {\n dagreGraph.setNode(node.id, { width: nodeWidth, height: nodeHeight });\n });\n\n edges.forEach((edge) => {\n dagreGraph.setEdge(edge.source, edge.target);\n });\n\n dagre.layout(dagreGraph);\n\n const layoutedNodes = nodes.map((node) => {\n const nodeWithPosition = dagreGraph.node(node.id);\n node.targetPosition = isHorizontal ? Position.Left : Position.Top;\n node.sourcePosition = isHorizontal ? Position.Right : Position.Bottom;\n\n // We intend to shift the dagre node position (anchor=center center) to the top left\n // so it matches the React Flow node anchor point (top left).\n node.position = {\n x: nodeWithPosition.x - nodeWidth / 2,\n y: nodeWithPosition.y - nodeHeight / 2,\n };\n\n return node;\n });\n\n return { nodes: layoutedNodes, edges };\n};\n","import { useState, useCallback, useRef } from 'react';\nimport { Node, Edge } from 'reactflow';\n\nexport interface HistoryState {\n nodes: Node[];\n edges: Edge[];\n}\n\n// Simple history hook for nodes and edges\nexport function useUndoRedo(initialNodes: Node[], initialEdges: Edge[], setNodes: (nds: Node[]) => void, setEdges: (eds: Edge[]) => void) {\n const [history, setHistory] = useState<HistoryState[]>([{ nodes: initialNodes, edges: initialEdges }]);\n const [index, setIndex] = useState(0);\n\n const takeSnapshot = useCallback((nodes: Node[], edges: Edge[]) => {\n setHistory(prev => {\n const newHistory = prev.slice(0, index + 1);\n newHistory.push({ nodes, edges });\n // Limit history size to 50\n if (newHistory.length > 50) newHistory.shift();\n return newHistory;\n });\n setIndex(prev => Math.min(prev + 1, 50));\n }, [index]);\n\n const undo = useCallback(() => {\n if (index > 0) {\n const newIndex = index - 1;\n const state = history[newIndex];\n setNodes(state.nodes);\n setEdges(state.edges);\n setIndex(newIndex);\n }\n }, [index, history, setNodes, setEdges]);\n\n const redo = useCallback(() => {\n if (index < history.length - 1) {\n const newIndex = index + 1;\n const state = history[newIndex];\n setNodes(state.nodes);\n setEdges(state.edges);\n setIndex(newIndex);\n }\n }, [index, history, setNodes, setEdges]);\n\n return {\n takeSnapshot,\n undo,\n redo,\n canUndo: index > 0,\n canRedo: index < history.length - 1\n };\n}\n","\nexport interface ValidationIssue {\n nodeId: string;\n field?: string;\n message: string;\n severity: 'error' | 'warning';\n}\n\nexport function validateWorkflow(nodes: any[], edges: any[]): ValidationIssue[] {\n const issues: ValidationIssue[] = [];\n\n // 1. Check for disconnected nodes (except unconnected triggers)\n if (nodes.length === 0) {\n issues.push({ nodeId: 'root', message: 'Workflow is empty', severity: 'warning' });\n return issues;\n }\n\n const connectedNodeIds = new Set<string>();\n edges.forEach(e => {\n connectedNodeIds.add(e.source);\n connectedNodeIds.add(e.target);\n });\n\n nodes.forEach(node => {\n // Triggers often don't have incoming connections, so we skip checking them as \"disconnected target\"\n // But if a node is not connected at all...\n if (!connectedNodeIds.has(node.id) && nodes.length > 1) {\n issues.push({ nodeId: node.id, message: 'Node is disconnected', severity: 'warning' });\n }\n\n // 2. Connector Validation\n // If it's a connector with operations, check if operation is selected\n if (node.type && nodeRegistry[node.type]) {\n // Basic empty field checks could go here if we had schema definitions handy\n }\n \n // Check required fields (simplistic)\n if (node.type === 'http-request') {\n if (!node.data.url) issues.push({ nodeId: node.id, field: 'url', message: 'URL is required', severity: 'error'});\n }\n if (node.type === 'webhook') {\n // Webhooks are usually fine\n }\n });\n\n return issues;\n}\n\nimport { nodeRegistry } from '@universal-workflow/widget-core';\n","import React from 'react';\nimport { WorkflowBuilder, WorkflowBuilderProps } from './WorkflowBuilder';\nimport { ApiConfig } from '@universal-workflow/widget-core';\n\nexport type { WorkflowBuilderProps as WorkflowWidgetProps };\n\nexport function WorkflowWidget(props: WorkflowBuilderProps) {\n return <WorkflowBuilder {...props} />;\n}\n","\nimport React, { useState } from 'react';\nimport { Settings, X, Maximize2, Minimize2 } from 'lucide-react';\nimport { WorkflowWidget, WorkflowWidgetProps } from './WorkflowWidget';\n// We need to export props to use them here, but WorkflowWidgetProps is not exported in the previous file view. \n// I will assume I can import it or I will redefine a similar interface extending it.\n// Actually, looking at the previous file content, it WAS NOT exported.\n// I should probably update WorkflowWidget.tsx to export the interface first, but I can just rely on 'typeof WorkflowWidget' props or redefine for now to save a turn. \n// Better: I will Update WorkflowWidget.tsx to export the interface.\n\ninterface EmbeddableWidgetProps {\n licenseKey: string;\n apiConfig: {\n baseUrl: string;\n endpoints: {\n create: string;\n update: string;\n get: string;\n list?: string;\n };\n };\n position?: 'bottom-left' | 'bottom-right';\n themeColor?: string;\n}\n\nexport function EmbeddableWidget({ \n licenseKey, \n apiConfig, \n position = 'bottom-right', \n themeColor = '#2563eb' \n}: EmbeddableWidgetProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [isExpanded, setIsExpanded] = useState(false); // Fullscreen mode\n\n const toggleOpen = () => setIsOpen(!isOpen);\n const toggleExpand = () => setIsExpanded(!isExpanded);\n\n const positionStyles: React.CSSProperties = {\n position: 'fixed',\n bottom: '20px',\n [position === 'bottom-right' ? 'right' : 'left']: '20px',\n zIndex: 9999,\n display: 'flex',\n flexDirection: 'column',\n alignItems: position === 'bottom-right' ? 'flex-end' : 'flex-start',\n gap: '10px',\n };\n\n const containerStyles: React.CSSProperties = isExpanded \n ? {\n position: 'fixed',\n top: 0,\n left: 0,\n width: '100vw',\n height: '100vh',\n backgroundColor: 'white',\n zIndex: 10000,\n boxShadow: '0 0 20px rgba(0,0,0,0.2)',\n display: 'flex',\n flexDirection: 'column',\n }\n : {\n width: '800px',\n height: '600px',\n backgroundColor: 'white',\n borderRadius: '12px',\n boxShadow: '0 4px 20px rgba(0,0,0,0.15)',\n border: '1px solid #e5e7eb',\n display: 'flex',\n flexDirection: 'column',\n overflow: 'hidden',\n // Transition for smooth open check? Not prioritizing animation yet.\n };\n\n if (!isOpen) {\n return (\n <div style={positionStyles}>\n <button\n onClick={toggleOpen}\n style={{\n width: '60px',\n height: '60px',\n borderRadius: '50%',\n backgroundColor: themeColor,\n color: 'white',\n border: 'none',\n cursor: 'pointer',\n boxShadow: '0 4px 12px rgba(0,0,0,0.2)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n transition: 'transform 0.2s',\n }}\n onMouseEnter={(e) => e.currentTarget.style.transform = 'scale(1.05)'}\n onMouseLeave={(e) => e.currentTarget.style.transform = 'scale(1)'}\n >\n <Settings size={28} />\n </button>\n </div>\n );\n }\n\n return (\n <div style={isExpanded ? { position: 'fixed', top: 0, left: 0, zIndex: 10000 } : positionStyles}>\n {/* Main Widget Container */}\n <div style={containerStyles}>\n {/* Header */}\n <div style={{\n padding: '12px 16px',\n borderBottom: '1px solid #eee',\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n backgroundColor: '#f9fafb',\n color:'black'\n }}>\n <h3 style={{ margin: 0, fontSize: '16px', fontWeight: 600 }}>Workflow Builder</h3>\n <div style={{ display: 'flex', gap: '8px' }}>\n <button \n onClick={toggleExpand}\n style={{ background: 'none', border: 'none', cursor: 'pointer', padding: 4 }}\n >\n {isExpanded ? <Minimize2 size={18} /> : <Maximize2 size={18} />}\n </button>\n <button \n onClick={toggleOpen}\n style={{ background: 'none', border: 'none', cursor: 'pointer', padding: 4 }}\n >\n <X size={18} />\n </button>\n </div>\n </div>\n \n {/* Widget Content */}\n <div style={{ flex: 1, position: 'relative' }}>\n <WorkflowWidget \n licenseKey={licenseKey} \n apiConfig={apiConfig} \n />\n </div>\n </div>\n \n {/* Logic to hide the launcher button when open? Or keep it? kept hidden via return early */}\n </div>\n );\n}\n"],"mappings":"0kBAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,eAAAE,GAAA,qBAAAC,GAAA,mBAAAC,GAAA,oBAAAC,GAAA,uBAAAC,GAAA,mBAAAC,GAAA,wBAAAC,GAAA,gBAAAC,GAAA,wBAAAC,GAAA,iBAAAC,EAAA,sBAAAC,GAAA,cAAAC,GAAA,uBAAAC,KAAA,eAAAC,GAAAf,ICAA,IAAAgB,EAAyE,iBACzEC,EAWO,yBACPC,GAAO,oCCAP,IAAMC,GAAyB,gDAElBC,GAAN,KAAqB,CAG1B,YAAoBC,EAAuB,CAAvB,KAAA,OAAAA,EAFpB,KAAQ,iBAA4C,IAER,CAE5C,MAAM,UAAsC,CAC1C,GAAI,KAAK,iBAAkB,OAAO,KAAK,iBAEvC,GAAI,CACF,IAAMC,EAAW,KAAK,OAAO,oBAAsBH,GAW7CI,EAAO,MAVI,MAAM,MAAMD,EAAU,CACrC,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,UAAU,CACnB,WAAY,KAAK,OAAO,WACxB,cAAe,KAAK,OAAO,cAC3B,UAAW,OAAO,QAAW,YAAc,OAAO,SAAS,OAAS,EACtE,CAAC,CACH,CAAC,GAE2B,KAAK,EACjC,OAAA,KAAK,iBAAmBC,EACjBA,CAET,OAASC,EAAO,CACd,OAAA,QAAQ,MAAM,4BAA6BA,CAAK,EAEzC,CAAE,MAAO,GAAO,OAAQ,eAAgB,CACjD,CACF,CAEA,iBAAiBC,EAA8B,CA9CjD,IAAAC,EAAAC,EA+CI,OAAKD,EAAA,KAAK,mBAAL,MAAAA,EAAuB,MACrB,CAAC,GAACC,EAAA,KAAK,iBAAiB,WAAtB,MAAAA,EAAiCF,CAAAA,GADA,EAE5C,CACF,ECvCaG,GAAN,KAAgB,CACrB,YAAoBP,EAAmB,CAAnB,KAAA,OAAAA,CAAoB,CAExC,MAAc,QAAWQ,EAAaC,EAAgBC,EAAwB,CAC5E,IAAMC,EAAU,CACd,eAAgB,mBAChB,GAAG,KAAK,OAAO,OACjB,EAEMC,EAAW,MAAM,MAAMJ,EAAK,CAChC,OAAAC,EACA,QAAAE,EACA,KAAMD,EAAO,KAAK,UAAUA,CAAI,EAAI,MACtC,CAAC,EAED,GAAI,CAACE,EAAS,GACZ,MAAM,IAAI,MAAM,uBAAuBA,EAAS,UAAU,EAAE,EAG9D,OAAOA,EAAS,KAAK,CACvB,CAEA,MAAM,YAAYC,EAA0B,CAC1C,IAAML,EAAM,GAAG,KAAK,OAAO,OAAO,GAAG,KAAK,OAAO,UAAU,IAAI,QAAQ,MAAOK,CAAE,CAAC,GACjF,OAAO,KAAK,QAAQL,EAAK,KAAK,CAChC,CAEA,MAAM,eAAeM,EAAwC,CAC3D,IAAMN,EAAM,GAAG,KAAK,OAAO,OAAO,GAAG,KAAK,OAAO,UAAU,MAAM,GACjE,OAAO,KAAK,QAAQA,EAAK,OAAQM,CAAQ,CAC3C,CAEA,MAAM,eAAeD,EAAYC,EAA8B,CAC7D,IAAMN,EAAM,GAAG,KAAK,OAAO,OAAO,GAAG,KAAK,OAAO,UAAU,OAAO,QAAQ,MAAOK,CAAE,CAAC,GACpF,OAAO,KAAK,QAAQL,EAAK,MAAOM,CAAQ,CAC1C,CACF,ECxCaC,GAAN,KAAyB,CAC9B,OAAO,UAAUC,EAAcC,EAAcC,EAAwB,CAElE,OAAO,KAAK,UADe,CAAE,MAAAF,EAAO,MAAAC,EAAO,SAAAC,CAAS,CAC1B,CAC7B,CAEA,OAAO,YAAYC,EAA8D,CAC/E,GAAI,CACF,IAAMjB,EAAO,KAAK,MAAMiB,CAAI,EAC5B,MAAO,CACL,MAAOjB,EAAK,OAAS,CAAC,EACtB,MAAOA,EAAK,OAAS,CAAC,EACtB,SAAUA,EAAK,QACjB,CACF,MAAW,CACT,MAAO,CAAE,MAAO,CAAC,EAAG,MAAO,CAAC,CAAE,CAChC,CACF,CACF,EAEakB,GAAYL,GAAmB,UAC/BM,GAAcN,GAAmB,YCEvC,SAASO,GAAoBC,EAA8C,CAC9E,MAAO,CACH,KAAMA,EAAI,GACV,MAAOA,EAAI,MACX,YAAa,oBAAoBA,EAAI,KAAK,GAC1C,SAAUA,EAAI,SACd,KAAMA,EAAI,KACV,MAAOA,EAAI,MACX,QAAS,CACL,CAAE,GAAI,KAAM,KAAM,QAAS,EAC3B,CAAE,GAAI,MAAO,KAAM,QAAS,CAChC,EAEA,OAAQ,CAEJ,CACI,IAAK,aACL,MAAO,kBACP,KAAM,OACN,YAAaA,EAAI,KAAK,aAAe,eACzC,EAEA,CACI,IAAK,YACL,MAAO,SACP,KAAM,SACN,QAASA,EAAI,WAAW,IAAIC,IAAO,CAAE,MAAOA,EAAG,MAAO,MAAOA,EAAG,EAAG,EAAE,CACzE,CAIJ,CACJ,CACJ,CC5DO,IAAMC,GAA4C,CAErD,CACI,GAAI,gBACJ,MAAO,gBACP,SAAU,UACV,KAAM,QACN,MAAO,UACP,QAAS,gDACT,KAAM,CAAE,KAAM,SAAU,YAAa,aAAc,EACnD,WAAY,CACR,CACI,GAAI,aACJ,MAAO,aACP,OAAQ,OACR,KAAM,yCACN,OAAQ,CACJ,CAAE,IAAK,gBAAiB,MAAO,iBAAkB,KAAM,MAAO,EAC9D,CAAE,IAAK,QAAS,MAAO,oBAAqB,KAAM,MAAO,EACzD,CAAE,IAAK,SAAU,MAAO,0BAA2B,KAAM,MAAO,CACpE,CACJ,EACA,CACI,GAAI,aACJ,MAAO,aACP,OAAQ,MACR,KAAM,kCACN,OAAQ,CACJ,CAAE,IAAK,gBAAiB,MAAO,iBAAkB,KAAM,MAAO,EAC9D,CAAE,IAAK,QAAS,MAAO,QAAS,KAAM,MAAO,CACjD,CACJ,CACJ,CACJ,EACA,CACI,GAAI,kBACJ,MAAO,YACP,SAAU,SACV,KAAM,gBACN,MAAO,OACP,QAAS,wBACT,KAAM,CAAE,KAAM,SAAU,YAAa,UAAW,EAChD,WAAY,CACR,CACI,GAAI,eACJ,MAAO,eACP,OAAQ,OACR,KAAM,oBACN,OAAQ,CACJ,CAAE,IAAK,UAAW,MAAO,aAAc,KAAM,MAAO,EACpD,CAAE,IAAK,OAAQ,MAAO,eAAgB,KAAM,MAAO,CACvD,CACJ,CACJ,CACJ,EACA,CACI,GAAI,SACJ,MAAO,SACP,SAAU,SACV,KAAM,MACN,MAAO,OACP,QAAS,4BACT,KAAM,CAAE,KAAM,SAAU,YAAa,QAAS,EAC9C,WAAY,CACR,CACI,GAAI,kBACJ,MAAO,kBACP,OAAQ,OACR,KAAM,oBACN,OAAQ,CACJ,CAAE,IAAK,QAAS,MAAO,QAAS,KAAM,SAAU,QAAS,CAAC,CAAC,MAAO,SAAU,MAAO,QAAQ,EAAG,CAAC,MAAO,UAAW,MAAO,eAAe,CAAC,CAAE,EAC1I,CAAE,IAAK,WAAY,MAAO,kBAAmB,KAAM,MAAO,CAC9D,CACJ,CACJ,CACJ,CACJ,EAEO,SAASC,GAAkBH,EAA0B,CACxDE,GAAmB,KAAKF,CAAG,CAC/B,CCnFA,IAAAI,GAAA,CACE,CACE,GAAM,WACN,MAAS,CACP,CACE,KAAQ,iBACR,MAAS,iBACT,YAAe,6BACf,SAAY,UACZ,KAAQ,OACR,MAAS,UACT,OAAU,CAAC,CACb,EACA,CACE,KAAQ,eACR,MAAS,gBACT,YAAe,wBACf,SAAY,UACZ,KAAQ,QACR,MAAS,UACT,OAAU,CACP,CAAE,IAAO,aAAc,MAAS,kBAAmB,KAAQ,OAAQ,YAAe,8BAA+B,CACpH,CACF,EACA,CACE,GAAM,iBACN,MAAS,iBACT,SAAY,UACZ,KAAQ,SACR,MAAS,OACT,QAAW,yBACX,KAAQ,CAAE,KAAQ,SAAU,IAAO,gBAAiB,EACpD,WAAc,CACX,CAAE,GAAM,UAAW,MAAS,UAAW,OAAU,OAAQ,KAAQ,8BAA+B,OAAU,CAAC,CAAC,IAAO,QAAS,MAAS,QAAS,KAAQ,MAAM,EAAG,CAAC,IAAO,OAAQ,MAAS,aAAc,KAAQ,MAAM,CAAC,CAAE,EACvN,CAAE,GAAM,UAAW,MAAS,cAAe,OAAU,OAAQ,KAAQ,8BAA+B,OAAU,CAAC,CAAC,IAAO,QAAS,MAAS,QAAS,KAAQ,MAAM,EAAG,CAAC,IAAO,OAAQ,MAAS,aAAc,KAAQ,MAAM,CAAC,CAAE,CAC9N,CACF,CACF,CACF,EACA,CACE,GAAM,QACN,MAAS,CACP,CACE,KAAQ,SACR,MAAS,kBACT,YAAe,uBACf,SAAY,QACZ,KAAQ,UACR,MAAS,SACT,OAAU,CACR,CAAE,IAAO,WAAY,MAAS,oBAAqB,KAAQ,MAAO,EAClE,CAAE,IAAO,QAAS,MAAS,oBAAqB,KAAQ,OAAQ,YAAe,2BAA4B,CAC7G,CACF,EACA,CACE,KAAQ,WACR,MAAS,YACT,YAAe,yBACf,SAAY,QACZ,KAAQ,UACR,MAAS,SACT,OAAU,CACR,CAAE,IAAO,WAAY,MAAS,mBAAoB,KAAQ,OAAQ,YAAe,IAAK,CACxF,CACF,EACA,CACE,KAAQ,OACR,MAAS,eACT,YAAe,kBACf,SAAY,QACZ,KAAQ,QACR,MAAS,SACT,OAAU,CACR,CAAE,IAAO,WAAY,MAAS,WAAY,KAAQ,OAAQ,YAAe,MAAO,EAChF,CAAE,IAAO,OAAQ,MAAS,OAAQ,KAAQ,SAAU,QAAW,CAAC,CAAC,MAAS,eAAgB,MAAS,IAAI,EAAG,CAAC,MAAS,UAAW,MAAS,GAAG,CAAC,CAAE,CAChJ,CACF,CACF,CACF,EACA,CACE,GAAM,YACN,MAAS,CACP,CACE,KAAQ,iBACR,MAAS,iBACT,YAAe,sBACf,SAAY,UACZ,KAAQ,OACR,MAAS,OACT,OAAU,CACR,CACE,IAAO,SACP,MAAS,SACT,KAAQ,SACR,QAAW,CACT,CAAE,MAAS,gBAAiB,MAAS,OAAQ,EAC7C,CAAE,MAAS,gBAAiB,MAAS,OAAQ,EAC7C,CAAE,MAAS,OAAQ,MAAS,MAAO,EACnC,CAAE,MAAS,UAAW,MAAS,SAAU,CAC3C,CACF,EACA,CAAE,IAAO,QAAS,MAAS,aAAc,KAAQ,MAAO,CAC1D,CACF,EACA,CACE,KAAQ,cACR,MAAS,cACT,YAAe,0BACf,SAAY,UACZ,KAAQ,OACR,MAAS,OACT,OAAU,CACR,CACE,IAAO,SACP,MAAS,SACT,KAAQ,SACR,QAAW,CACT,CAAE,MAAS,yBAA0B,MAAS,OAAQ,EACtD,CAAE,MAAS,6BAA8B,MAAS,WAAY,CAChE,CACF,EACA,CAAE,IAAO,OAAQ,MAAS,OAAQ,KAAQ,MAAO,CACnD,CACF,EACA,CACE,KAAQ,YACR,MAAS,kBACT,YAAe,uBACf,SAAY,UACZ,KAAQ,aACR,MAAS,OACT,OAAU,CACR,CACE,IAAO,YACP,MAAS,YACT,KAAQ,SACR,QAAW,CACT,CAAE,MAAS,MAAO,MAAS,KAAM,EACjC,CAAE,MAAS,WAAY,MAAS,KAAM,EACtC,CAAE,MAAS,WAAY,MAAS,KAAM,EACtC,CAAE,MAAS,SAAU,MAAS,KAAM,EACpC,CAAE,MAAS,gBAAiB,MAAS,QAAS,CAChD,CACF,EACA,CAAE,IAAO,IAAK,MAAS,UAAW,KAAQ,MAAO,EACjD,CAAE,IAAO,IAAK,MAAS,UAAW,KAAQ,MAAO,CACnD,CACF,EACA,CACE,KAAQ,SACR,MAAS,eACT,YAAe,uBACf,SAAY,UACZ,KAAQ,OACR,MAAS,OACT,OAAU,CACP,CAAE,IAAO,OAAQ,MAAS,YAAa,KAAQ,SAAU,QAAW,CAAC,CAAC,MAAS,MAAO,MAAS,KAAK,EAAG,CAAC,MAAS,UAAW,MAAS,QAAQ,EAAG,CAAC,MAAS,gBAAiB,MAAS,YAAY,EAAG,CAAC,MAAS,gBAAiB,MAAS,YAAY,CAAC,CAAE,EACtP,CAAE,IAAO,QAAS,MAAS,QAAS,KAAQ,MAAO,CACtD,CACF,EACA,CACE,KAAQ,YACR,MAAS,cACT,YAAe,6BACf,SAAY,UACZ,KAAQ,WACR,MAAS,OACT,OAAU,CACR,CAAE,IAAO,YAAa,MAAS,SAAU,KAAQ,SAAU,QAAW,CAAC,CAAC,MAAS,YAAa,MAAS,KAAK,EAAG,CAAC,MAAS,cAAe,MAAS,QAAQ,EAAG,CAAC,MAAS,WAAY,MAAS,KAAK,CAAC,CAAE,EACnM,CAAE,IAAO,OAAQ,MAAS,cAAe,KAAQ,MAAO,EACxD,CAAE,IAAO,SAAU,MAAS,iBAAkB,KAAQ,OAAQ,YAAe,YAAa,CAC5F,CACF,CAEF,CACF,EACA,CACE,GAAM,4BACN,MAAS,CACP,CACE,GAAM,eACN,MAAS,eACT,KAAQ,YACR,MAAS,OACT,SAAY,SACZ,QAAW,sCACX,KAAQ,CAAE,KAAQ,SAAU,YAAe,aAAc,EACzD,WAAc,CACX,CAAE,GAAM,OAAQ,MAAS,aAAc,OAAU,MAAO,KAAQ,SAAU,OAAU,CAAC,CAAC,IAAO,IAAK,MAAS,QAAS,KAAQ,MAAM,CAAC,CAAE,EACrI,CAAE,GAAM,SAAU,MAAS,cAAe,OAAU,OAAQ,KAAQ,SAAU,OAAU,CAAC,CAAC,IAAO,OAAQ,MAAS,OAAQ,KAAQ,MAAM,EAAG,CAAC,IAAO,UAAW,MAAS,UAAW,KAAQ,MAAM,CAAC,CAAE,CACtM,CACF,EACA,CACE,GAAM,SACN,MAAS,SACT,KAAQ,WACR,MAAS,OACT,SAAY,SACZ,QAAW,4BACX,KAAQ,CAAE,KAAQ,SAAU,IAAO,gBAAiB,YAAe,mBAAoB,EACvF,WAAc,CACX,CAAE,GAAM,cAAe,MAAS,cAAe,OAAU,OAAQ,KAAQ,SAAU,OAAU,CAAC,CAAC,IAAO,YAAa,MAAS,eAAgB,KAAQ,MAAM,EAAG,CAAC,IAAO,aAAc,MAAS,kBAAmB,KAAQ,MAAM,CAAC,CAAE,EAChO,CAAE,GAAM,WAAY,MAAS,iBAAkB,OAAU,OAAQ,KAAQ,wBAAyB,OAAU,CAAC,CAAC,IAAO,KAAM,MAAS,cAAe,KAAQ,MAAM,CAAC,CAAE,CACvK,CACF,EACA,CACE,GAAM,WACN,MAAS,WACT,KAAQ,WACR,MAAS,QACT,SAAY,SACZ,QAAW,8BACX,KAAQ,CAAE,KAAQ,SAAU,YAAe,SAAU,EACrD,WAAc,CACX,CAAE,GAAM,gBAAiB,MAAS,gBAAiB,OAAU,OAAQ,KAAQ,sBAAuB,OAAU,CAAC,CAAC,IAAO,SAAU,MAAS,UAAW,KAAQ,MAAM,EAAG,CAAC,IAAO,UAAW,MAAS,aAAc,KAAQ,MAAM,EAAG,CAAC,IAAO,SAAU,MAAS,cAAe,KAAQ,MAAM,CAAC,CAAE,EAC5R,CAAE,GAAM,eAAgB,MAAS,eAAgB,OAAU,MAAO,KAAQ,sBAAuB,OAAU,CAAC,CAAC,IAAO,SAAU,MAAS,UAAW,KAAQ,MAAM,EAAG,CAAC,IAAO,UAAW,MAAS,aAAc,KAAQ,MAAM,CAAC,CAAE,CACjO,CACF,CACF,CACF,EACA,CACE,GAAM,6BACN,MAAS,CACP,CACE,GAAM,aACN,MAAS,aACT,KAAQ,QACR,MAAS,OACT,SAAY,SACZ,QAAW,wDACX,KAAQ,CAAE,KAAQ,QAAS,EAC3B,WAAc,CACX,CAAE,GAAM,cAAe,MAAS,cAAe,OAAU,OAAQ,KAAQ,iBAAkB,OAAU,CAAC,CAAC,IAAO,WAAY,MAAS,eAAgB,KAAQ,MAAM,EAAG,CAAC,IAAO,WAAY,MAAS,YAAa,KAAQ,MAAM,EAAG,CAAC,IAAO,UAAW,MAAS,UAAW,KAAQ,MAAM,CAAC,CAAE,CAC1R,CACF,EACA,CACE,GAAM,UACN,MAAS,UACT,KAAQ,QACR,MAAS,SACT,SAAY,SACZ,QAAW,yBACX,KAAQ,CAAE,KAAQ,QAAS,EAC3B,WAAc,CACX,CAAE,GAAM,iBAAkB,MAAS,iBAAkB,OAAU,OAAQ,KAAQ,2BAA4B,OAAU,CAAC,CAAC,IAAO,aAAc,MAAS,kBAAmB,KAAQ,MAAM,CAAC,CAAE,CAC5L,CACF,EACA,CACE,GAAM,YACN,MAAS,YACT,KAAQ,OACR,MAAS,SACT,SAAY,SACZ,QAAW,qCACX,KAAQ,CAAE,KAAQ,QAAS,EAC3B,WAAc,CACX,CAAE,GAAM,aAAc,MAAS,iBAAkB,OAAU,OAAQ,KAAQ,2BAA4B,OAAU,CAAC,CAAC,IAAO,KAAM,MAAS,oBAAqB,KAAQ,MAAM,EAAG,CAAC,IAAO,UAAW,MAAS,UAAW,KAAQ,MAAM,EAAG,CAAC,IAAO,gBAAiB,MAAS,QAAS,KAAQ,MAAM,EAAG,CAAC,IAAO,SAAU,MAAS,SAAU,KAAQ,SAAU,QAAW,CAAC,CAAC,MAAQ,aAAa,MAAQ,YAAY,CAAC,CAAC,CAAC,CAAE,CACxZ,CACF,CACF,CACF,EACA,CACG,GAAM,wBACN,MAAS,CACR,CACE,GAAM,UACN,MAAS,UACT,KAAQ,cACR,MAAS,UACT,SAAY,SACZ,QAAW,iDACX,KAAQ,CAAE,KAAQ,SAAU,IAAO,wBAAyB,EAC5D,WAAc,CACX,CAAE,GAAM,eAAgB,MAAS,eAAgB,OAAU,MAAO,KAAQ,iBAAkB,OAAU,CAAC,CAAC,IAAO,OAAQ,MAAS,YAAa,KAAQ,MAAM,CAAC,CAAE,EAC9J,CAAE,GAAM,eAAgB,MAAS,eAAgB,OAAU,OAAQ,KAAQ,eAAgB,OAAU,CAAC,CAAC,IAAO,OAAQ,MAAS,YAAa,KAAQ,MAAM,EAAG,CAAC,IAAO,QAAS,MAAS,aAAc,KAAQ,MAAM,CAAC,CAAE,CACzN,CACF,EACA,CACE,GAAM,SACN,MAAS,SACT,KAAQ,aACR,MAAS,SACT,SAAY,SACZ,QAAW,4BACX,KAAQ,CAAE,KAAQ,QAAS,EAC3B,WAAc,CACX,CAAE,GAAM,kBAAmB,MAAS,kBAAmB,OAAU,OAAQ,KAAQ,aAAc,OAAU,CAAC,CAAC,IAAO,QAAS,MAAS,QAAS,KAAQ,MAAM,CAAC,CAAE,EAC9J,CAAE,GAAM,eAAgB,MAAS,eAAgB,OAAU,MAAO,KAAQ,WAAY,OAAU,CAAC,CAAC,IAAO,QAAS,MAAS,QAAS,KAAQ,MAAM,CAAC,CAAE,CACxJ,CACF,CACD,CACH,CACF,EC/RO,SAASC,IAAc,CAC1BD,GAAY,QAASE,GAAe,CAChCA,EAAM,MAAM,QAASC,GAAc,CAE/B,GAAIA,EAAK,WAAY,CAEjB,IAAMC,EAAiC,CACnC,GAAID,EAAK,GACT,MAAOA,EAAK,MACZ,SAAUA,EAAK,SACf,KAAMA,EAAK,KACX,MAAOA,EAAK,MACZ,QAASA,EAAK,QACd,KAAMA,EAAK,KACX,WAAYA,EAAK,UACrB,EAEAE,EAAaD,EAAU,EAAE,EAAIT,GAAoBS,CAAS,CAO9D,KAAO,CAEH,IAAMR,EAA0B,CAC5B,KAAMO,EAAK,KACX,MAAOA,EAAK,MACZ,YAAaA,EAAK,YAClB,SAAUA,EAAK,SACf,KAAMA,EAAK,KACX,MAAOA,EAAK,MACZ,QAASA,EAAK,SAAW,CAAE,CAAE,GAAI,KAAM,KAAM,QAAS,EAAG,CAAE,GAAI,MAAO,KAAM,QAAS,CAAE,EACvF,OAAQA,EAAK,MACjB,EACAE,EAAaT,EAAI,IAAI,EAAIA,CAC7B,CACJ,CAAC,CACL,CAAC,CACL,CCbO,IAAMS,EAAmD,CAE5D,QAAW,CACP,KAAM,UACN,MAAO,UACP,YAAa,gCACb,SAAU,UACV,KAAM,UACN,MAAO,UACP,QAAS,CAAC,CAAE,GAAI,MAAO,KAAM,QAAS,CAAC,EACvC,OAAQ,CACR,CAAE,IAAK,SAAU,MAAO,cAAe,KAAM,SAAU,QAAS,CAAC,CAAE,MAAO,MAAO,MAAO,KAAK,EAAG,CAAE,MAAO,OAAQ,MAAO,MAAM,CAAC,CAAE,EACjI,CAAE,IAAK,OAAQ,MAAO,OAAQ,KAAM,OAAQ,YAAa,cAAe,CACxE,CACJ,EACA,SAAY,CACR,KAAM,WACN,MAAO,WACP,YAAa,kCACb,SAAU,UACV,KAAM,QACN,MAAO,UACP,QAAS,CAAC,CAAE,GAAI,MAAO,KAAM,QAAS,CAAC,EACvC,OAAQ,CACR,CAAE,IAAK,WAAY,MAAO,WAAY,KAAM,SAAU,QAAS,CAAC,CAAE,MAAO,eAAgB,MAAO,IAAI,EAAG,CAAE,MAAO,aAAc,MAAO,IAAI,EAAG,CAAE,MAAO,YAAa,MAAO,IAAI,CAAC,CAAE,EAChL,CAAE,IAAK,OAAQ,MAAO,kBAAmB,KAAM,OAAQ,YAAa,WAAY,CAChF,CACJ,EACA,eAAgB,CACZ,KAAM,eACN,MAAO,eACP,YAAa,4BACb,SAAU,SACV,KAAM,QACN,MAAO,OACP,QAAS,CAAC,CAAE,GAAI,KAAM,KAAM,QAAS,EAAG,CAAE,GAAI,MAAO,KAAM,QAAS,CAAC,EACrE,OAAQ,CACR,CAAE,IAAK,MAAO,MAAO,MAAO,KAAM,OAAQ,YAAa,yBAA0B,EACjF,CAAE,IAAK,SAAU,MAAO,SAAU,KAAM,SAAU,QAAS,CAAC,CAAE,MAAO,MAAO,MAAO,KAAK,EAAG,CAAE,MAAO,OAAQ,MAAO,MAAM,EAAG,CAAE,MAAO,MAAO,MAAO,KAAK,EAAG,CAAE,MAAO,SAAU,MAAO,QAAQ,CAAC,CAAE,EAChM,CAAE,IAAK,UAAW,MAAO,UAAW,KAAM,MAAO,EACjD,CAAE,IAAK,OAAQ,MAAO,OAAQ,KAAM,MAAO,CAC3C,CACJ,EACA,MAAS,CACL,KAAM,QACN,MAAO,aACP,YAAa,+BACb,SAAU,SACV,KAAM,OACN,MAAO,OACP,QAAS,CAAC,CAAE,GAAI,KAAM,KAAM,QAAS,EAAG,CAAE,GAAI,MAAO,KAAM,QAAS,CAAC,EACrE,OAAQ,CACR,CAAE,IAAK,KAAM,MAAO,KAAM,KAAM,MAAO,EACvC,CAAE,IAAK,UAAW,MAAO,UAAW,KAAM,MAAO,EACjD,CAAE,IAAK,OAAQ,MAAO,OAAQ,KAAM,MAAO,CAC3C,CACJ,EACA,MAAS,CACL,KAAM,QACN,MAAO,iBACP,YAAa,8BACb,SAAU,SACV,KAAM,gBACN,MAAO,OACP,QAAS,CAAC,CAAE,GAAI,KAAM,KAAM,QAAS,EAAG,CAAE,GAAI,MAAO,KAAM,QAAS,CAAC,EACrE,OAAQ,CACR,CAAE,IAAK,aAAc,MAAO,cAAe,KAAM,MAAO,EACxD,CAAE,IAAK,UAAW,MAAO,UAAW,KAAM,MAAO,CACjD,CACJ,EACA,UAAW,CACP,KAAM,UACN,MAAO,YACP,YAAa,iCACb,SAAU,QACV,KAAM,QACN,MAAO,SACP,QAAS,CACT,CAAE,GAAI,KAAM,KAAM,QAAS,EAC3B,CAAE,GAAI,OAAQ,KAAM,SAAU,MAAO,MAAO,EAC5C,CAAE,GAAI,QAAS,KAAM,SAAU,MAAO,OAAQ,CAC9C,EACA,OAAQ,CACR,CAAE,IAAK,YAAa,MAAO,YAAa,KAAM,OAAQ,YAAa,4CAA6C,CAChH,CACJ,EACA,MAAS,CACL,KAAM,QACN,MAAO,QACP,YAAa,4BACb,SAAU,QACV,KAAM,WACN,MAAO,SACP,QAAS,CACT,CAAE,GAAI,OAAQ,KAAM,SAAU,MAAO,GAAI,EACzC,CAAE,GAAI,OAAQ,KAAM,SAAU,MAAO,GAAI,EACzC,CAAE,GAAI,MAAO,KAAM,QAAS,CAC5B,EACA,OAAQ,CAAC,CACb,CACJ,EAGAP,GAAmB,QAAQQ,GAAQ,CAC/BD,EAAaC,EAAK,EAAE,EAAIX,GAAoBW,CAAI,CACpD,CAAC,EAIDL,GAAY,EAGL,SAASM,GAAoBC,EAAiD,CACjF,OAAOV,GAAmB,KAAKW,GAAKA,EAAE,KAAOD,CAAM,CACvD,CClJA,IAAAE,GAA4B,iBAC5BC,EAA4C,qBAC5CC,EAWO,wBCbP,IAAAC,GAAsC,gBACtCC,GAAwB,0BAEjB,SAASC,KAAMC,EAAsB,CAC1C,SAAO,eAAQ,SAAKA,CAAM,CAAC,CAC7B,CCLA,IAAAC,EAA4L,wBAE/KC,EAAoD,CAC/D,cACA,UACA,YACA,YACA,wBACA,cACA,kBACA,kBACA,sBACA,oBACA,YACA,gBACA,YACA,oBACA,oBACA,cACA,cACA,0BACA,uBACF,EF6Ba,IAAAC,EAAA,6BAhCPC,GAAsC,CAC1C,kBACA,cACA,cACA,YACA,8BACA,cACA,oBACA,UACA,GAAGC,CACL,EAGMC,GAAmC,CACvC,QAAS,oDACT,KAAM,2CACN,OAAQ,iDACR,KAAM,0CACR,EAEMC,GAAoC,CACxC,QAAS,sBACT,KAAM,mBACN,OAAQ,qBACR,KAAM,kBACR,EAEaC,MAAgB,SAAK,CAAC,CAAE,KAAAC,EAAM,SAAAC,EAAU,KAAAC,CAAK,IAAiB,CAEzE,IAAMC,EAAMC,EAAaJ,EAAK,MAAQE,CAAI,GAAKE,EAAa,QAE5D,GAAI,CAACD,EACD,SAAO,QAAC,OAAI,UAAU,2DAA2D,gCAAoBD,GAAK,EAG9G,IAAMG,EAAOV,GAAQQ,EAAI,IAAI,GAAK,MAC5BG,EAAaT,GAASM,EAAI,KAAK,GAAKN,GAAS,KAC7CU,EAAYT,GAAUK,EAAI,KAAK,GAAKL,GAAU,KAG9CU,EAASR,EAAK,gBAChBS,EAAe,GACnB,OAAID,IAAW,UAAWC,EAAe,wFAChCD,IAAW,UAAWC,EAAe,6EACrCD,IAAW,UAASC,EAAe,qEAG1C,QAAC,OAAI,UAAWC,EACd,mFACAT,EAAW,sCAAsCM,CAAS,GAAK,wCAC/DE,CACF,EAEE,qBAAC,OAAI,UAAWC,EAAG,8FAA8F,EAC/G,qBAAC,OAAI,UAAU,0BACZ,oBAAC,OAAI,UAAWA,EAAG,oCAAqCJ,CAAU,EAChE,mBAACD,EAAA,CAAK,KAAM,GAAI,YAAa,IAAK,EACpC,KACA,QAAC,OACE,oBAAC,QAAK,UAAU,iEAAkE,SAAAF,EAAI,SAAS,KAC/F,OAAC,QAAK,UAAU,gEAAiE,SAAAA,EAAI,MAAM,GAC9F,GACH,KACA,OAAC,UAAO,UAAU,sDACd,mBAAC,kBAAe,KAAM,GAAI,EAC9B,GACF,KAGA,QAAC,OAAI,UAAU,4BAEV,UAAAA,EAAI,OAAS,mBACX,QAAC,OAAI,UAAU,wGACZ,oBAAC,QAAK,UAAU,0BAA2B,SAAAH,EAAK,QAAU,MAAM,KAChE,OAAC,QAAK,UAAU,yBAA0B,SAAAA,EAAK,KAAO,cAAc,GACvE,EAEFG,EAAI,OAAS,cACX,QAAC,OAAI,UAAU,0DACZ,oBAAC,QAAK,UAAU,6BAA8B,SAAAH,EAAK,QAAU,OAAO,KACpE,OAAC,QAAM,SAAAA,EAAK,MAAQ,eAAe,GACtC,EAEFG,EAAI,OAAS,cACX,OAAC,OAAI,UAAU,+FACX,SAAAH,EAAK,WAAa,QACtB,EAED,CAAC,CAAC,eAAgB,UAAW,SAAS,EAAE,SAASG,EAAI,IAAI,MACvD,OAAC,KAAE,UAAU,wBAAyB,SAAAA,EAAI,YAAY,GAE9D,EAGCA,EAAI,QAAQ,IAAKQ,GAAW,CAI1B,IAAIC,EAAWD,EAAO,OAAS,SAAW,WAAS,KAAO,WAAS,MAC/DE,EAAQ,CAAC,EAGTV,EAAI,OAAS,WAAaQ,EAAO,KAUrC,IAAMG,EAAUH,EAAO,OAAS,SAC1BI,EAASZ,EAAI,QAAQ,OAAOa,GAAKA,EAAE,OAASL,EAAO,IAAI,EAAE,QAAQA,CAAM,EACvEM,EAAQd,EAAI,QAAQ,OAAOa,GAAKA,EAAE,OAASL,EAAO,IAAI,EAAE,OAGxDO,EAASD,EAAQ,EAAI,IAAKF,EAAS,GAAK,KAAQE,EAAQ,EAAE,IAAM,MAEtE,SACI,OAAC,UAEE,GAAIN,EAAO,GACX,KAAMA,EAAO,KACb,SAAUG,EAAU,WAAS,MAAQ,WAAS,KAC9C,MAAO,CAAE,IAAKI,EAAQ,GAAGL,CAAM,EAC/B,UAAWH,EACP,sGACAI,EAAU,aAAe,YAEzBH,EAAO,KAAO,OAAS,kBACvBA,EAAO,KAAO,QAAU,cAAgB,EAC5C,EAGC,SAAAA,EAAO,UACL,OAAC,QAAK,UAAWD,EACb,8FACAI,EAAU,0BAA4B,wBACtC,0BACJ,EACK,SAAAH,EAAO,MACZ,GArBEA,EAAO,EAuBf,CAEP,CAAC,GACH,CAEJ,CAAC,EGxKD,IAAAQ,GAA8B,iBAC9BC,EAAgG,wBAwCzFC,EAAA,6BArBA,SAASC,GAAQ,CACtB,OAAAC,EAAQ,SAAAC,EAAU,SAAAC,EAAU,UAAAC,EAC5B,aAAAC,EAAc,QAAAC,EAAS,MAAAC,EACvB,SAAAC,EAAU,UAAAC,EACV,QAAAC,EAAS,QAAAC,EAAS,OAAAC,EAAQ,OAAAC,CAC5B,EAAiB,CACf,IAAMC,KAAe,WAAyB,IAAI,EAalD,SACE,QAAC,OAAI,UAAU,0JACZ,oBAAC,SACC,KAAK,OACL,IAAKA,EACL,SAhBmBC,GAA2C,CA5BvE,IAAAC,EA6BI,IAAMC,GAAOD,EAAAD,EAAE,OAAO,QAAT,YAAAC,EAAiB,GAC1BC,GACFd,EAASc,CAAI,EAGXH,EAAa,UACfA,EAAa,QAAQ,MAAQ,GAEjC,EAQO,OAAO,QACP,UAAU,SACZ,KAEA,QAAC,OAAI,UAAU,wDACb,oBAAC,UAAO,UAAU,sFAAsF,MAAM,SAC3G,mBAAC,iBAAc,KAAM,GAAI,EAC5B,KACA,OAAC,UAAO,QAASV,EAAW,UAAU,sFAAsF,MAAM,WAC/H,mBAAC,QAAK,KAAM,GAAI,EACnB,GACF,KAEA,QAAC,OAAI,UAAU,wDACb,oBAAC,UACE,QAASQ,EACT,SAAU,CAACF,EACX,UAAU,sIACV,MAAM,OAEN,mBAAC,SAAM,KAAM,GAAI,EACpB,KACA,OAAC,UACE,QAASG,EACT,SAAU,CAACF,EACX,UAAU,sIACV,MAAM,OAEN,mBAAC,SAAM,KAAM,GAAI,EACpB,GACF,KAEA,QAAC,OAAI,UAAU,wDACZ,oBAAC,UAAO,QAASN,EAAc,UAAU,sFAAsF,MAAM,cAClI,mBAAC,UAAO,KAAM,GAAI,EACrB,KACA,OAAC,UAAO,QAASC,EAAS,UAAU,mFAAmF,MAAM,eAC1H,mBAAC,UAAO,KAAM,GAAI,EACrB,GACH,KAEA,QAAC,OAAI,UAAU,wDACZ,oBAAC,UAAO,QAASJ,EAAU,UAAU,sFAAsF,MAAM,cAC9H,mBAAC,YAAS,KAAM,GAAI,EACvB,KACA,OAAC,UAAO,QAAS,IAAG,CA1F9B,IAAAc,EA0FiC,OAAAA,EAAAF,EAAa,UAAb,YAAAE,EAAsB,SAAS,UAAU,sFAAsF,MAAM,cACzJ,mBAAC,UAAO,KAAM,GAAI,EACrB,GACH,KAEA,QAAC,OAAI,UAAU,+BACZ,oBAAC,UACE,UAAU,qKACV,QAAST,EACT,SAAUE,EAET,SAAAA,KAAY,OAAC,OAAI,UAAU,4EAA4E,KAAK,OAAC,QAAK,KAAM,GAAI,KAAK,eAAe,EACpJ,KAEA,QAAC,UACE,UAAU,6MACV,QAASR,EACT,SAAUO,EAET,UAAAA,KAAW,OAAC,OAAI,UAAU,4EAA4E,KAAK,OAAC,QAAK,KAAM,GAAI,KAC5H,OAAC,QAAK,gBAAI,GACb,GACH,GACH,CAEJ,CClHA,IAAAU,EAA0D,wBAC1DC,GAA6B,qBCStB,SAASC,GAAUC,EAAyC,CAC/D,GAAI,CAACA,EAAY,KAAK,EAAE,YAAY,EAAE,WAAW,MAAM,EAAG,OAAO,KAEjE,IAAIC,EAAc,MACZC,EAAkC,CAAC,EACrCC,EACAC,EAAM,GAGJC,EAAeL,EAAY,QAAQ,QAAS,GAAG,EAAE,QAAQ,MAAO,GAAG,EAGnEM,EAAWD,EAAa,MAAM,uCAAuC,EACvEC,IACDF,EAAME,EAAS,CAAC,GAAKA,EAAS,CAAC,GAAKA,EAAS,CAAC,GAIjD,IAAMC,EAAcF,EAAa,MAAM,eAAe,EAClDE,IACAN,EAASM,EAAY,CAAC,GAK1B,IAAMC,EAAc,yBAChBC,EACJ,MAAQA,EAAQD,EAAY,KAAKH,CAAY,KAAO,MAAM,CACtD,GAAM,CAACK,EAAKC,CAAK,EAAIF,EAAM,CAAC,EAAE,MAAM,UAAU,EAC1CC,GAAOC,IACPT,EAAQQ,CAAG,EAAIC,EAEvB,CAGA,IAAMC,EAAYP,EAAa,MAAM,2CAA2C,EAChF,OAAIO,IACAT,EAAOS,EAAU,CAAC,EAEdX,IAAW,QAAOA,EAAS,SAG5B,CAAE,OAAAA,EAAQ,IAAAG,EAAK,QAAAF,EAAS,KAAAC,CAAK,CACxC,CDPgB,IAAAU,EAAA,6BAlCT,SAASC,GAAc,CAAE,eAAAC,EAAgB,iBAAAC,EAAkB,QAAAC,CAAQ,EAAuB,CAbjG,IAAAC,EAcE,GAAM,CAAE,SAAAC,EAAU,SAAAC,EAAU,eAAAC,CAAe,KAAI,iBAAa,EAE5D,GAAI,CAACN,EAAgB,OAAO,KAE5B,IAAMO,EAAOF,EAAS,EAAE,KAAKG,GAAKA,EAAE,KAAOR,CAAc,EACzD,GAAI,CAACO,EAAM,OAAO,KAKlB,IAAME,IAAUN,EAAAI,EAAK,OAAL,YAAAJ,EAAW,OAAQI,EAAK,MAAQN,EAC5CS,EAAMF,EAAaC,CAAO,EAGxBE,EAAeC,GAAoBH,CAAO,EAEhD,GAAIE,EAAc,CAEbD,EAAM,KAAK,MAAM,KAAK,UAAUA,CAAG,CAAC,EACpC,IAAMG,EAAcN,EAAK,KAAK,UAC9B,GAAIM,EAAa,CACb,IAAMC,EAAKH,EAAa,WAAW,KAAKI,GAAKA,EAAE,KAAOF,CAAW,EAC7DC,IAEAJ,EAAI,OAAS,CAAC,GAAGA,EAAI,OAAQ,GAAGI,EAAG,MAAM,EAEjD,CACL,CAEA,GAAI,CAACJ,EACF,SACG,QAAC,OAAI,UAAU,qFACX,qBAAC,OAAI,UAAU,sDACX,qBAAC,OAAI,UAAU,0BACX,oBAAC,eAAY,KAAM,GAAI,KACvB,OAAC,QAAK,UAAU,YAAY,6BAAiB,GACjD,KACA,OAAC,UAAO,QAASR,EAAS,mBAAC,KAAE,KAAM,GAAG,EAAE,GAC5C,KACA,QAAC,KAAE,UAAU,6BAA6B,iBAAKO,GAAQ,GAC3D,EAIN,IAAMO,EAAe,CAACC,EAAaC,IAAe,CAC/Cd,EAAUe,GACPA,EAAI,IAAKX,GACFA,EAAE,KAAOR,EACH,CACJ,GAAGQ,EACH,KAAM,CAAE,GAAGA,EAAE,KAAM,CAACS,CAAG,EAAGC,CAAM,CACnC,EAEIV,CACT,CACJ,CACH,EAEMY,EAAe,IAAM,CACxBd,EAAe,CAAE,MAAO,CAAC,CAAE,GAAIN,CAAe,CAAC,CAAE,CAAC,EAClDE,EAAQ,CACX,EAEA,SACE,QAAC,OAAI,UAAU,gMACb,qBAAC,OAAI,UAAU,+EACZ,qBAAC,OAAI,UAAU,sDACb,oBAAC,aAAU,KAAM,GAAI,KACrB,QAAC,QAAM,UAAAQ,EAAI,MAAM,eAAW,GAC9B,KACA,QAAC,OAAI,UAAU,0BACV,UAAAD,IAAY,mBACT,QAAC,UACA,QAAS,IAAM,CACX,IAAMY,EAAO,OAAO,+BAA+B,EACnD,GAAIA,EAAM,CACN,IAAMC,EAASC,GAAUF,CAAI,EACzBC,EACAlB,EAAUe,GACRA,EAAI,IAAKX,GACHA,EAAE,KAAOR,EACF,CACH,GAAGQ,EACH,KAAM,CACF,GAAGA,EAAE,KACL,OAAQc,EAAO,OACf,IAAKA,EAAO,IACZ,QAAS,KAAK,UAAUA,EAAO,QAAS,KAAM,CAAC,EAC/C,KAAMA,EAAO,MAAQ,IACzB,CACJ,EAEGd,CACR,CACH,EAEA,MAAM,+BAA+B,CAE7C,CACJ,EACA,UAAU,+IACV,MAAM,cAEL,oBAAC,UAAO,KAAM,GAAI,KAClB,OAAC,QAAK,uBAAW,GACnB,KAEJ,OAAC,UACE,QAASY,EACT,UAAU,qFACV,MAAM,cAEP,mBAAC,UAAO,KAAM,GAAI,EACpB,KACA,OAAC,UAAO,QAASlB,EAAS,UAAU,yFAClC,mBAAC,KAAE,KAAM,GAAI,EACf,GACJ,GACH,KAEA,QAAC,OAAI,UAAU,uCAEZ,qBAAC,OAAI,UAAU,0CACX,oBAAC,SAAM,UAAU,2DAA2D,uBAAW,KACvF,OAAC,KAAE,UAAU,wBAAyB,SAAAQ,EAAI,YAAY,GAC1D,EAECA,EAAI,OAAO,IAAKc,GAAO,CA7IjC,IAAArB,EA8IY,iBAAC,OAAoB,UAAU,YAC3B,oBAAC,SAAM,UAAU,iEACZ,SAAAqB,EAAM,MACX,EAECA,EAAM,OAAS,WACZ,OAAC,SACC,KAAK,OACL,MAAOjB,EAAK,KAAKiB,EAAM,GAAG,GAAK,GAC/B,SAAWC,GAAMT,EAAaQ,EAAM,IAAKC,EAAE,OAAO,KAAK,EACvD,YAAaD,EAAM,YACnB,UAAU,oLACZ,EAGHA,EAAM,OAAS,aACZ,QAAC,UACC,MAAOjB,EAAK,KAAKiB,EAAM,GAAG,GAAK,GAC/B,SAAWC,GAAMT,EAAaQ,EAAM,IAAKC,EAAE,OAAO,KAAK,EACvD,UAAU,oLAER,oBAAC,UAAO,MAAM,GAAG,SAAQ,GAAC,qBAAS,GAClCtB,EAAAqB,EAAM,UAAN,YAAArB,EAAe,IAAIuB,MAChB,OAAC,UAAuB,MAAOA,EAAI,MAAQ,SAAAA,EAAI,OAAlCA,EAAI,KAAoC,IAE7D,GAGFF,EAAM,OAAS,QAAUA,EAAM,OAAS,YACtC,OAAC,YACC,MAAO,OAAOjB,EAAK,KAAKiB,EAAM,GAAG,GAAM,SAAW,KAAK,UAAUjB,EAAK,KAAKiB,EAAM,GAAG,EAAG,KAAM,CAAC,EAAKjB,EAAK,KAAKiB,EAAM,GAAG,GAAK,GAC3H,SAAWC,GAAMT,EAAaQ,EAAM,IAAKC,EAAE,OAAO,KAAK,EACvD,KAAM,EACN,UAAU,uMACZ,IAlCED,EAAM,GAoChB,EACF,GAEJ,GACF,CAEJ,CExLA,IAAAG,GAAyC,iBACzCC,EAA+F,wBA+DvF,IAAAC,EAAA,6BApDFC,GAA+B,CACnC,QAAS,MACT,MAAO,QACP,MAAO,QACP,KAAM,OACN,cAAe,gBACf,MAAO,QACP,SAAU,WACV,IAAK,MACL,GAAGC,CACL,EAEO,SAASC,GAAY,CAAE,OAAAC,EAAQ,QAAAC,EAAS,SAAAC,CAAS,EAAqB,CAC3E,GAAM,CAACC,EAAQC,CAAS,KAAI,aAAS,EAAE,EAEjCC,KAAe,YAAQ,IAAM,CACjC,IAAMC,EAA+C,CAAC,EAEtD,OAAO,OAAOC,CAAY,EAAE,QAAQC,GAAQ,CAK1C,GAHEA,EAAK,MAAM,YAAY,EAAE,SAASL,EAAO,YAAY,CAAC,GACrDK,EAAK,aAAeA,EAAK,YAAY,YAAY,EAAE,SAASL,EAAO,YAAY,CAAC,EAEhE,CACjB,IAAMM,EAAMD,EAAK,UAAY,QACxBF,EAAOG,CAAG,IAAGH,EAAOG,CAAG,EAAI,CAAC,GACjCH,EAAOG,CAAG,EAAE,KAAKD,CAAI,CACvB,CACF,CAAC,EAID,IAAME,EAAQ,CAAC,UAAW,QAAS,SAAU,UAAW,aAAa,EAC/DC,EAAqD,CAAC,EAC5D,OAAAD,EAAM,QAAQE,GAAO,CACbN,EAAOM,CAAG,IAAGD,EAAaC,CAAG,EAAIN,EAAOM,CAAG,EACnD,CAAC,EAED,OAAO,KAAKN,CAAM,EAAE,QAAQM,GAAO,CAC1BF,EAAM,SAASE,CAAG,IAAGD,EAAaC,CAAG,EAAIN,EAAOM,CAAG,EAC5D,CAAC,EAEMD,CACT,EAAG,CAACR,CAAM,CAAC,EAEX,OAAKH,KAGH,QAAC,OAAI,UAAU,8HACb,qBAAC,OAAI,UAAU,4JAGb,qBAAC,OAAI,UAAU,qEACZ,oBAAC,UAAO,UAAU,gBAAgB,KAAM,GAAI,KAC5C,OAAC,SACC,UAAS,GACT,KAAK,OACL,YAAY,kBACZ,UAAU,iGACV,MAAOG,EACP,SAAWU,GAAMT,EAAUS,EAAE,OAAO,KAAK,EAC3C,KACA,OAAC,OAAI,UAAU,yFAAyF,eAAG,KAC3G,OAAC,UAAO,QAASZ,EAAS,UAAU,oCAClC,mBAAC,KAAE,KAAM,GAAI,EACf,GACH,KAGA,QAAC,OAAI,UAAU,gCACX,iBAAO,QAAQI,CAAY,EAAE,IAAI,CAAC,CAACS,EAAUC,CAAK,IAAM,CACvD,GAAIA,EAAM,SAAW,EAAG,OAAO,KAK/B,IAAMC,EAAiBb,EAAO,OAAS,EAEvC,SACE,QAAC,WAEC,KAAM,GACN,UAAU,kGAEV,qBAAC,WAAQ,UAAU,wHAChB,qBAAC,OAAI,UAAU,0BACX,oBAAC,QAAK,UAAU,2DAA4D,SAAAW,EAAS,KACrF,OAAC,QAAK,UAAU,+DAAgE,SAAAC,EAAM,OAAO,GACjG,KACA,OAAC,OAAI,UAAU,2DACX,mBAAC,OAAI,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OAAO,OAAO,eAAe,YAAY,IAAI,cAAc,QAAQ,eAAe,QAAQ,mBAAC,QAAK,EAAE,eAAc,EAAE,EAC3K,GACH,KAEA,OAAC,OAAI,UAAU,kEACZ,mBAAC,OAAI,UAAU,8BACV,SAAAA,EAAM,IAAIP,GAAQ,CACnB,IAAMS,EAAOpB,GAAQW,EAAK,IAAI,GAAKV,EAAgBU,EAAK,IAAI,GAAK,MACjE,SACI,QAAC,UAED,QAAS,IAAMN,EAASM,EAAK,IAAI,EACjC,UAAU,yKAEN,oBAAC,OAAI,UAAWU,EAChB,mCACA,MAAMV,EAAK,KAAK,YAAYA,EAAK,KAAK,+BACtC,EACA,mBAACS,EAAA,CAAK,KAAM,GAAI,EAChB,KACA,QAAC,OACD,oBAAC,OAAI,UAAU,sCAAuC,SAAAT,EAAK,MAAM,KACjE,OAAC,OAAI,UAAU,qDAAsD,SAAAA,EAAK,YAAY,GACtF,IAbCA,EAAK,IAcV,CAEJ,CAAC,EACL,EACH,IAtCKM,CAuCP,CAEJ,CAAC,EAEA,OAAO,OAAOT,CAAY,EAAE,MAAMc,GAAKA,EAAE,SAAW,CAAC,MACnD,OAAC,OAAI,UAAU,kCACb,oBAAC,KAAE,sCAA0BhB,EAAO,KAAC,EACvC,GAEN,GAEF,KAGA,OAAC,OAAI,UAAU,yBAAyB,QAASF,EAAS,GAC5D,EAzFkB,IA2FtB,CCpJA,IAAAmB,GAA2C,iBAC3CC,EAA6C,wBA8BzC,IAAAC,EAAA,6BAlBG,SAASC,GAAM,CAAE,QAAAC,EAAS,KAAAC,EAAM,UAAAC,EAAW,QAAAC,CAAQ,EAAe,CACvE,GAAM,CAACC,EAAMC,CAAO,KAAI,aAAS,EAAK,EActC,SAZA,cAAU,IAAM,CACd,GAAIH,EAAW,CACbG,EAAQ,EAAI,EACZ,IAAMC,EAAQ,WAAW,IAAM,CAC7BH,EAAQ,CACV,EAAG,GAAI,EACP,MAAO,IAAM,aAAaG,CAAK,CACjC,MACE,WAAW,IAAMD,EAAQ,EAAK,EAAG,GAAG,CAExC,EAAG,CAACH,EAAWC,CAAO,CAAC,EAEnB,CAACC,GAAQ,CAACF,EAAkB,QAG9B,QAAC,OAAI,UAAWK,EACd,0JACAN,IAAS,UAAY,+CAAiD,uCACtEC,EAAY,sCAAwC,kCACtD,EACI,UAAAD,IAAS,aAAY,OAAC,gBAAa,KAAM,GAAI,UAAU,mBAAkB,KAAK,OAAC,eAAY,KAAM,GAAI,UAAU,eAAc,KAC9H,OAAC,QAAK,UAAU,sBAAuB,SAAAD,EAAQ,KAC/C,OAAC,UAAO,QAASG,EAAS,UAAU,wBAClC,mBAAC,KAAE,KAAM,GAAI,UAAU,gBAAgB,EACzC,GACH,CAEJ,ChBLA,IAAAK,GAAkC,qBiBtClC,IAAAC,GAAkB,qBAClBC,EAAqC,qBAE/BC,EAAa,IAAI,GAAAC,QAAM,SAAS,MACtCD,EAAW,oBAAoB,KAAO,CAAC,EAAE,EAEzC,IAAME,GAAY,IACZC,GAAa,IAENC,GAAsB,CAACC,EAAeC,EAAeC,EAAY,OAAS,CACrF,IAAMC,EAAeD,IAAc,KACnC,OAAAP,EAAW,SAAS,CAAE,QAASO,CAAU,CAAC,EAE1CF,EAAM,QAASI,GAAS,CACtBT,EAAW,QAAQS,EAAK,GAAI,CAAE,MAAOP,GAAW,OAAQC,EAAW,CAAC,CACtE,CAAC,EAEDG,EAAM,QAASI,GAAS,CACtBV,EAAW,QAAQU,EAAK,OAAQA,EAAK,MAAM,CAC7C,CAAC,EAED,GAAAT,QAAM,OAAOD,CAAU,EAiBhB,CAAE,MAfaK,EAAM,IAAKI,GAAS,CACxC,IAAME,EAAmBX,EAAW,KAAKS,EAAK,EAAE,EAChD,OAAAA,EAAK,eAAiBD,EAAe,WAAS,KAAO,WAAS,IAC9DC,EAAK,eAAiBD,EAAe,WAAS,MAAQ,WAAS,OAI/DC,EAAK,SAAW,CACd,EAAGE,EAAiB,EAAIT,GAAY,EACpC,EAAGS,EAAiB,EAAIR,GAAa,CACvC,EAEOM,CACT,CAAC,EAE8B,MAAAH,CAAM,CACvC,ECvCA,IAAAM,EAA8C,iBASvC,SAASC,GAAYC,EAAsBC,EAAsBC,EAAiCC,EAAiC,CACtI,GAAM,CAACC,EAASC,CAAU,KAAI,YAAyB,CAAC,CAAE,MAAOL,EAAc,MAAOC,CAAa,CAAC,CAAC,EAC/F,CAACK,EAAOC,CAAQ,KAAI,YAAS,CAAC,EAE9BC,KAAe,eAAY,CAACC,EAAeC,IAAkB,CAC/DL,EAAWM,GAAQ,CACf,IAAMC,EAAaD,EAAK,MAAM,EAAGL,EAAQ,CAAC,EAC1C,OAAAM,EAAW,KAAK,CAAE,MAAAH,EAAO,MAAAC,CAAM,CAAC,EAE5BE,EAAW,OAAS,IAAIA,EAAW,MAAM,EACtCA,CACX,CAAC,EACDL,EAASI,GAAQ,KAAK,IAAIA,EAAO,EAAG,EAAE,CAAC,CAC3C,EAAG,CAACL,CAAK,CAAC,EAEJO,KAAO,eAAY,IAAM,CAC3B,GAAIP,EAAQ,EAAG,CACX,IAAMQ,EAAWR,EAAQ,EACnBS,EAAQX,EAAQU,CAAQ,EAC9BZ,EAASa,EAAM,KAAK,EACpBZ,EAASY,EAAM,KAAK,EACpBR,EAASO,CAAQ,CACrB,CACJ,EAAG,CAACR,EAAOF,EAASF,EAAUC,CAAQ,CAAC,EAEjCa,KAAO,eAAY,IAAM,CAC3B,GAAIV,EAAQF,EAAQ,OAAS,EAAG,CAC5B,IAAMU,EAAWR,EAAQ,EACnBS,EAAQX,EAAQU,CAAQ,EAC9BZ,EAASa,EAAM,KAAK,EACpBZ,EAASY,EAAM,KAAK,EACpBR,EAASO,CAAQ,CACrB,CACJ,EAAG,CAACR,EAAOF,EAASF,EAAUC,CAAQ,CAAC,EAEvC,MAAO,CACH,aAAAK,EACA,KAAAK,EACA,KAAAG,EACA,QAASV,EAAQ,EACjB,QAASA,EAAQF,EAAQ,OAAS,CACtC,CACJ,CC3CO,SAASa,GAAiBC,EAAcC,EAAiC,CAC5E,IAAMC,EAA4B,CAAC,EAGnC,GAAIF,EAAM,SAAW,EACjB,OAAAE,EAAO,KAAK,CAAE,OAAQ,OAAQ,QAAS,oBAAqB,SAAU,SAAU,CAAC,EAC1EA,EAGX,IAAMC,EAAmB,IAAI,IAC7B,OAAAF,EAAM,QAAQG,GAAK,CACfD,EAAiB,IAAIC,EAAE,MAAM,EAC7BD,EAAiB,IAAIC,EAAE,MAAM,CACjC,CAAC,EAEDJ,EAAM,QAAQK,GAAQ,CAGd,CAACF,EAAiB,IAAIE,EAAK,EAAE,GAAKL,EAAM,OAAS,GACjDE,EAAO,KAAK,CAAE,OAAQG,EAAK,GAAI,QAAS,uBAAwB,SAAU,SAAU,CAAC,EAKrFA,EAAK,MAAQC,EAAaD,EAAK,IAAI,EAKnCA,EAAK,OAAS,iBACTA,EAAK,KAAK,KAAKH,EAAO,KAAK,CAAE,OAAQG,EAAK,GAAI,MAAO,MAAO,QAAS,kBAAmB,SAAU,OAAO,CAAC,GAE/GA,EAAK,IAGb,CAAC,EAEMH,CACX,CnBHS,IAAAK,EAAA,6BAfHC,GAAuB,CAC3B,CAAE,GAAI,IAAK,KAAM,UAAW,SAAU,CAAE,EAAG,IAAK,EAAG,GAAI,EAAG,KAAM,CAAE,OAAQ,OAAQ,KAAM,QAAS,CAAE,EACnG,CAAE,GAAI,IAAK,KAAM,eAAgB,SAAU,CAAE,EAAG,IAAK,EAAG,GAAI,EAAG,KAAM,CAAE,OAAQ,OAAQ,IAAK,8BAA+B,CAAE,EAC7H,CAAE,GAAI,IAAK,KAAM,QAAS,SAAU,CAAE,EAAG,IAAK,EAAG,GAAI,EAAG,KAAM,CAAE,QAAS,qBAAsB,WAAY,6BAA8B,CAAE,CAC7I,EACMC,GAAuB,CACzB,CAAE,GAAI,OAAQ,OAAQ,IAAK,OAAQ,IAAK,KAAM,aAAc,SAAU,GAAM,MAAO,CAAE,OAAQ,UAAW,YAAa,CAAE,CAAE,EACzH,CAAE,GAAI,OAAQ,OAAQ,IAAK,OAAQ,IAAK,KAAM,aAAc,SAAU,GAAM,MAAO,CAAE,OAAQ,UAAW,YAAa,CAAE,CAAE,CAC7H,EAIaC,GAAmDC,MAE1D,OAAC,sBACE,mBAACC,GAAA,CAAwB,GAAGD,EAAO,EACtC,EAWAC,GAAyD,CAAC,CAAE,WAAAC,EAAY,UAAAC,EAAW,UAAAC,EAAW,MAAAC,CAAM,IAAM,CAC9G,GAAM,CAACC,EAASC,CAAU,KAAI,YAAyB,IAAI,EACrD,CAACC,EAAUC,CAAW,KAAI,YAAiB,EAAE,EAG7C,CAACC,CAAO,KAAI,YAAS,IAAM,IAAIC,GAAe,CAClD,WAAAT,EACA,cAAe,QACf,mBAAoB,+CACtB,CAAC,CAAC,EAII,CAACU,EAAOC,EAAUC,CAAa,KAAI,iBAAcjB,EAAY,EAC7D,CAACkB,EAAOC,EAAUC,CAAa,KAAI,iBAAcnB,EAAY,EAC7D,CAACoB,EAAUC,CAAW,KAAI,YAAS,EAAK,EACxC,CAACC,EAAWC,EAAY,KAAI,YAAS,EAAK,EAC1C,CAACC,EAAOC,CAAQ,KAAI,YAA4D,IAAI,EAGpF,CAAE,aAAAC,EAAc,KAAAC,GAAM,KAAAC,GAAM,QAAAC,GAAS,QAAAC,EAAQ,EAAIC,GAAYhC,GAAcC,GAC5EgC,GAAQjB,EAAS,CAAC,GAAGiB,CAAG,CAAC,EACzBC,GAAQf,EAAS,CAAC,GAAGe,CAAG,CAAC,CAC9B,EAGMC,MAAW,eAAY,IAAM,CAChCR,EAAaZ,EAAOG,CAAK,CAC5B,EAAG,CAACH,EAAOG,EAAOS,CAAY,CAAC,EAEzB,CAACS,GAAgBC,CAAiB,KAAI,YAAwB,IAAI,EAGlEC,MAAY,WAAQ,IAAM,CAC7B,IAAMC,EAA6B,CAC/B,OAAUC,EACd,EACA,cAAO,KAAKC,CAAY,EAAE,QAAQC,GAAO,CACrCH,EAAMG,CAAG,EAAIF,EACjB,CAAC,EACMD,CACV,EAAG,CAAC,CAAC,KAEL,aAAU,IAAM,CACd,eAAeI,GAAW,CACxB,IAAMC,EAAS,MAAM/B,EAAQ,SAAS,EACtCH,EAAWkC,EAAO,KAAK,EAClBA,EAAO,OAAOhC,EAAYgC,EAAO,QAAU,iBAAiB,CACnE,CACAD,EAAS,CACX,EAAG,CAAC9B,CAAO,CAAC,EAEZ,IAAMgC,MAAY,eAAaC,GAAuB,CAClD3B,EAAUe,GAAQ,CACd,IAAMa,KAAW,WAAQ,CAAE,GAAGD,EAAQ,KAAM,aAAc,SAAU,GAAM,MAAO,CAAE,OAAQ,UAAW,YAAa,CAAE,CAAE,EAAGZ,CAAG,EAC7H,OAAAP,EAAaZ,EAAOgC,CAAQ,EACrBA,CACX,CAAC,CACL,EAAG,CAAC5B,EAAUJ,EAAOY,CAAY,CAAC,EAE5BqB,MAAc,eAAY,CAACC,EAAyBC,IAAe,CACrEb,EAAkBa,EAAK,EAAE,CAC7B,EAAG,CAAC,CAAC,EAECC,MAAc,eAAY,IAAM,CAClCd,EAAkB,IAAI,CAC1B,EAAG,CAAC,CAAC,EAECe,MAAmB,UAAuB,IAAI,EAC9C,CAACC,EAAYC,EAAa,KAAI,YAAc,IAAI,EAChD,CAACC,GAAeC,EAAgB,KAAI,YAAS,EAAK,EAElDC,MAAgB,eAAaC,GAAiB,CAChD,IAAMC,EAAK,QAAQ,KAAK,IAAI,CAAC,GACzBC,EAAM,CAAE,EAAG,IAAK,EAAG,GAAI,EACvBP,IAEAO,EAAM,CAAE,EAAG,IAAM,KAAK,OAAO,EAAI,IAAK,EAAG,IAAM,KAAK,OAAO,EAAI,GAAI,GAEvE,IAAMC,EAAgB,CAAE,GAAAF,EAAI,KAAAD,EAAM,SAAUE,EAAK,KAAM,CAAC,CAAE,EAEpDE,EAAW/C,EAAM,OAAO8C,CAAO,EACrC7C,EAAS8C,CAAQ,EACjBnC,EAAamC,EAAU5C,CAAK,EAE5BsC,GAAiB,EAAK,EACtBnB,EAAkBsB,CAAE,CACxB,EAAG,CAACN,EAAYtC,EAAOG,EAAOS,EAAcX,CAAQ,CAAC,EAE/C+C,MAAmB,eAAY,IAAM,CACvC,GAAM,CAAE,MAAOC,EAAe,MAAOC,CAAc,EAAIC,GACrDnD,EACAG,CACF,EACAF,EAAS,CAAC,GAAGgD,CAAa,CAAC,EAC3B7C,EAAS,CAAC,GAAG8C,CAAa,CAAC,EAC3BtC,EAAa,CAAC,GAAGqC,CAAa,EAAG,CAAC,GAAGC,CAAa,CAAC,EACnD,WAAW,IAAMZ,GAAA,YAAAA,EAAY,UAAW,GAAG,CAC/C,EAAG,CAACtC,EAAOG,EAAOF,EAAUG,EAAUQ,EAAc0B,CAAU,CAAC,EAEzDc,MAAc,eAAY,IAAM,CAC9B,QAAQ,4CAA4C,IACpDnD,EAAS,CAAC,CAAC,EACXG,EAAS,CAAC,CAAC,EACXQ,EAAa,CAAC,EAAG,CAAC,CAAC,EAE3B,EAAG,CAACX,EAAUG,EAAUQ,CAAY,CAAC,EAE/ByC,MAAgB,eAAY,SAAY,CAC5C,GAAI7C,EAAW,OACfC,GAAa,EAAI,EACjBE,EAAS,IAAI,EAGb,IAAM2C,EAAatD,EAAM,IAAI0B,IAAM,CAC/B,GAAGA,EACH,KAAM,CAAE,GAAGA,EAAE,KAAM,gBAAiB,MAAU,CAClD,EAAE,EACFzB,EAASqD,CAAU,EAGnB,IAAMC,EAAe,CAACX,EAAYf,IAA4C,CAC1E5B,EAASiB,GAAOA,EAAI,IAAIQ,GAAKA,EAAE,KAAOkB,EAAK,CAAE,GAAGlB,EAAG,KAAM,CAAE,GAAGA,EAAE,KAAM,gBAAiBG,CAAO,CAAE,EAAIH,CAAC,CAAC,CAC1G,EAEA,GAAI,CAEA,IAAM8B,EAAuC,CAAC,EAC9CrD,EAAM,QAAQsD,GAAK,CACXD,EAAWC,EAAE,MAAM,IAAGD,EAAWC,EAAE,MAAM,EAAI,CAAC,GAClDD,EAAWC,EAAE,MAAM,EAAE,KAAKA,EAAE,MAAM,CACtC,CAAC,EAGD,IAAMC,EAAQ1D,EAAM,OAAO0B,GAAK,CAAC,UAAW,WAAY,WAAW,EAAE,SAASA,EAAE,MAAQ,EAAE,GAAKvB,EAAM,MAAMsD,GAAKA,EAAE,SAAW/B,EAAE,EAAE,CAAE,EAAE,IAAIA,GAAKA,EAAE,EAAE,EAIlJ,GAFIgC,EAAM,SAAW,GAAK1D,EAAM,OAAS,GAAG0D,EAAM,KAAK1D,EAAM,CAAC,EAAE,EAAE,EAE9D0D,EAAM,SAAW,EAChB,MAAM,IAAI,MAAM,qBAAqB,EAI1C,QAAWC,KAAUD,EAAO,CACxBH,EAAaI,EAAQ,SAAS,EAC9B,MAAM,IAAI,QAAQC,GAAK,WAAWA,EAAG,GAAG,CAAC,EAKzCL,EAAaI,EAAQ,SAAS,EAE9B,IAAME,EAAWL,EAAWG,CAAM,GAAK,CAAC,EACxC,QAAUG,KAAWD,EACjBN,EAAaO,EAAS,SAAS,EAC/B,MAAM,IAAI,QAAQF,IAAK,WAAWA,GAAG,GAAG,CAAC,EAIzCL,EAAaO,EAAS,SAAS,CAEvC,CACAnD,EAAS,CAAE,QAAS,mCAAoC,KAAM,SAAU,CAAC,CAC7E,OAASoD,EAAU,CACfpD,EAAS,CAAE,QAASoD,EAAI,SAAW,oBAAqB,KAAM,SAAU,CAAC,CAC7E,QAAE,CACEtD,GAAa,EAAK,CACtB,CAEF,EAAG,CAACT,EAAOG,EAAOK,EAAWP,CAAQ,CAAC,EAGhC+D,GAAa,SAAY,CAE3B,IAAMC,EAASC,GAAiBlE,EAAOG,CAAK,EACtCgE,EAASF,EAAO,OAAOG,GAAKA,EAAE,WAAa,OAAO,EAExD,GAAID,EAAO,OAAS,EAAG,CACnBxD,EAAS,CAAE,QAAS,gBAAgBwD,EAAO,CAAC,EAAE,OAAO,GAAI,KAAM,OAAQ,CAAC,EACxE,MACJ,CAEIF,EAAO,OAAS,GACftD,EAAS,CAAE,QAAS,wBAAwBsD,EAAO,CAAC,EAAE,OAAO,GAAI,KAAM,SAAU,CAAC,EAGvF1D,EAAY,EAAI,EAChB,IAAM8D,EAAS,IAAIC,GAAU/E,CAAS,EAChCgF,EAAW,CAAE,MAAAvE,EAAO,MAAAG,CAAM,EAG1BqE,EAAU,CAAC,CADL,MAAMH,EAAO,eAAeE,CAAQ,EAEhDhE,EAAY,EAAK,EAIbI,EAHC6D,EAGQ,CAAE,QAAS,8BAA+B,KAAM,SAAU,EAF1D,CAAE,QAAS,0BAA2B,KAAM,OAAQ,CAEO,CAE5E,EAEMC,GAAe,IAAM,CACzB,IAAMC,EAAOC,GAAU3E,EAAOG,CAAK,EAC7ByE,EAAO,IAAI,KAAK,CAACF,CAAI,EAAG,CAAE,KAAM,kBAAmB,CAAC,EACpDG,EAAM,IAAI,gBAAgBD,CAAI,EAC9BE,EAAO,SAAS,cAAc,GAAG,EACvCA,EAAK,KAAOD,EACZC,EAAK,SAAW,YAAY,KAAK,IAAI,CAAC,QACtC,SAAS,KAAK,YAAYA,CAAI,EAC9BA,EAAK,MAAM,EACX,SAAS,KAAK,YAAYA,CAAI,CAChC,EAEMC,GAAe,MAAOC,GAAe,CACzC,GAAI,CACF,IAAMC,EAAO,MAAMD,EAAK,KAAK,EACvB,CAAE,MAAOjC,EAAU,MAAOf,CAAS,EAAIkD,GAAYD,CAAI,EAC7DhF,EAAS8C,CAAQ,EACjB3C,EAAS4B,CAAQ,EACjBpB,EAAamC,EAAUf,CAAQ,EAC/B,WAAW,IAAM,CACfM,GAAA,MAAAA,EAAY,QAAQ,CAAE,QAAS,EAAI,EACrC,EAAG,EAAE,CACP,OAASmB,EAAG,CACV,MAAM,0CAA0C,EAChD,QAAQ,MAAMA,CAAC,CACjB,CACF,EAEA,OAAI/D,IAAY,QAEV,OAAC,OAAI,UAAU,iGACZ,oBAAC,OAAI,UAAU,mCACZ,oBAAC,OAAI,UAAU,oFAAoF,KACnG,OAAC,KAAE,UAAU,oCAAoC,gCAAoB,GACxE,EACH,KAKJ,QAAC,OAAI,MAAOD,EAAO,UAAW,6GAA6GD,GAAa,EAAE,GAGvJ,WAACE,MACA,QAAC,OAAI,UAAU,+GACX,oBAAC,OAAI,UAAU,0EACX,mBAAC,OAAI,UAAU,uBAAuB,wBAAE,EAC5C,KACA,OAAC,MAAG,UAAU,wCAAwC,uCAA2B,KACjF,QAAC,KAAE,UAAU,yBAA0B,UAAAE,EAAS,2DAAuD,GAC3G,KAIF,OAACuF,GAAA,CACC,OAAQnB,GACR,SAAUS,GACV,SAAUM,GACV,UAAW,IAAMtC,GAAiB,EAAI,EACtC,aAAcO,GACd,QAASI,GACT,MAAOC,GACP,SAAU/C,EACV,UAAWE,EACX,QAASO,GACT,QAASC,GACT,OAAQH,GACR,OAAQC,GACV,KAGA,OAACsE,GAAA,CACE,eAAgB/D,IAAkB,OAClC,QAAS,IAAMC,EAAkB,IAAI,EACxC,KAEA,OAAC+D,GAAA,CACE,OAAQ7C,GACR,QAAS,IAAMC,GAAiB,EAAK,EACrC,SAAUC,GACb,KAEA,OAAC4C,GAAA,CACE,SAAS5E,GAAA,YAAAA,EAAO,UAAW,GAC3B,MAAMA,GAAA,YAAAA,EAAO,OAAQ,UACrB,UAAW,CAAC,CAACA,EACb,QAAS,IAAMC,EAAS,IAAI,EAC/B,KAEA,OAAC,OAAI,UAAU,gBAAgB,IAAK0B,GAClC,oBAAC,EAAAkD,QAAA,CACG,MAAOvF,EACP,MAAOG,EACP,cAAeD,EACf,cAAeG,EACf,UAAWyB,GACX,YAAaG,GACb,YAAaG,GACb,OAAQG,GACR,UAAWhB,GACX,QAAO,GACP,UAAU,aAEV,oBAAC,cACG,QAAS,oBAAkB,KAC3B,IAAK,GACL,KAAM,EACN,MAAM,UACN,UAAU,cACd,KACA,OAAC,YAAS,UAAU,kNAAkN,KACtO,OAAC,WACG,UAAU,iEACV,UAAU,2BACV,UAAYG,GAAM,CAjXlC,IAAA8D,EAmXoB,OAAIA,EAAA9D,EAAE,OAAF,MAAA8D,EAAQ,SAAS,YAAc9D,EAAE,OAAS,UAAkB,UAC5DA,EAAE,OAAS,SAAiB,UACzB,SACX,EACA,SAAQ,GACR,SAAQ,GACZ,GACJ,EACF,GACF,CAEJ,EoBvXS,IAAA+D,GAAA,6BADF,SAASC,GAAeC,EAA6B,CAC1D,SAAO,QAACC,GAAA,CAAiB,GAAGD,EAAO,CACrC,CCPA,IAAAE,GAAgC,iBAChCC,EAAkD,wBA8F9B,IAAAC,EAAA,6BAvEb,SAASC,GAAiB,CAC/B,WAAAC,EACA,UAAAC,EACA,SAAAC,EAAW,eACX,WAAAC,EAAa,SACf,EAA0B,CACxB,GAAM,CAACC,EAAQC,CAAS,KAAI,aAAS,EAAK,EACpC,CAACC,EAAYC,CAAa,KAAI,aAAS,EAAK,EAE5CC,EAAa,IAAMH,EAAU,CAACD,CAAM,EACpCK,EAAe,IAAMF,EAAc,CAACD,CAAU,EAE9CI,EAAsC,CAC1C,SAAU,QACV,OAAQ,OACR,CAACR,IAAa,eAAiB,QAAU,MAAM,EAAG,OAClD,OAAQ,KACR,QAAS,OACT,cAAe,SACf,WAAYA,IAAa,eAAiB,WAAa,aACvD,IAAK,MACP,EAEMS,EAAuCL,EACzC,CACE,SAAU,QACV,IAAK,EACL,KAAM,EACN,MAAO,QACP,OAAQ,QACR,gBAAiB,QACjB,OAAQ,IACR,UAAW,2BACX,QAAS,OACT,cAAe,QACjB,EACA,CACE,MAAO,QACP,OAAQ,QACR,gBAAiB,QACjB,aAAc,OACd,UAAW,8BACX,OAAQ,oBACR,QAAS,OACT,cAAe,SACf,SAAU,QAEZ,EAEF,OAAKF,KA6BD,OAAC,OAAI,MAAOE,EAAa,CAAE,SAAU,QAAS,IAAK,EAAG,KAAM,EAAG,OAAQ,GAAM,EAAII,EAE5E,oBAAC,OAAI,MAAOC,EAET,qBAAC,OAAI,MAAO,CACR,QAAS,YACT,aAAc,iBACd,QAAS,OACT,eAAgB,gBAChB,WAAY,SACZ,gBAAiB,UACjB,MAAM,OACV,EACI,oBAAC,MAAG,MAAO,CAAE,OAAQ,EAAG,SAAU,OAAQ,WAAY,GAAI,EAAG,4BAAgB,KAC7E,QAAC,OAAI,MAAO,CAAE,QAAS,OAAQ,IAAK,KAAM,EACtC,oBAAC,UACG,QAASF,EACT,MAAO,CAAE,WAAY,OAAQ,OAAQ,OAAQ,OAAQ,UAAW,QAAS,CAAE,EAE1E,SAAAH,KAAa,OAAC,aAAU,KAAM,GAAI,KAAK,OAAC,aAAU,KAAM,GAAI,EACjE,KACA,OAAC,UACG,QAASE,EACT,MAAO,CAAE,WAAY,OAAQ,OAAQ,OAAQ,OAAQ,UAAW,QAAS,CAAE,EAE3E,mBAAC,KAAE,KAAM,GAAI,EACjB,GACJ,GACJ,KAGA,OAAC,OAAI,MAAO,CAAE,KAAM,EAAG,SAAU,UAAW,EACxC,mBAACI,GAAA,CACG,WAAYZ,EACZ,UAAWC,EACf,EACJ,GACH,EAGL,KAnEI,OAAC,OAAI,MAAOS,EACR,mBAAC,UACG,QAASF,EACT,MAAO,CACH,MAAO,OACP,OAAQ,OACR,aAAc,MACd,gBAAiBL,EACjB,MAAO,QACP,OAAQ,OACR,OAAQ,UACR,UAAW,6BACX,QAAS,OACT,WAAY,SACZ,eAAgB,SAChB,WAAY,gBAChB,EACA,aAAeU,GAAMA,EAAE,cAAc,MAAM,UAAY,cACvD,aAAeA,GAAMA,EAAE,cAAc,MAAM,UAAY,WAEvD,mBAAC,YAAS,KAAM,GAAI,EACxB,EACJ,CA+CZ","names":["index_exports","__export","d","EmbeddableWidget","c","WorkflowBuilder","i","WorkflowWidget","l","S","j","n","w","T","r","__toCommonJS","import_react","import_reactflow","import_style","DEFAULT_VALIDATION_URL","LicenseManager","config","endpoint","data","error","featureName","_a","_b","ApiClient","url","method","body","headers","response","id","workflow","WorkflowSerializer","nodes","edges","viewport","json","serialize","deserialize","createConnectorNode","def","op","standardConnectors","registerConnector","catalog_default","loadCatalog","group","node","connector","nodeRegistry","conn","getConnectorDetails","typeId","c","import_react","import_reactflow","import_lucide_react","import_clsx","import_tailwind_merge","cn","inputs","import_lucide_react","extendedIconMap","import_jsx_runtime","iconMap","extendedIconMap","colorMap","borderMap","UniversalNode","data","selected","type","def","n","Icon","colorClass","ringClass","status","statusBorder","cn","handle","position","style","isRight","offset","h","total","topPos","import_react","import_lucide_react","import_jsx_runtime","Toolbar","onSave","onExport","onImport","onAddNode","onAutoLayout","onClear","onRun","isSaving","isRunning","canUndo","canRedo","onUndo","onRedo","fileInputRef","e","_a","file","import_lucide_react","import_reactflow","parseCurl","curlCommand","method","headers","body","url","cleanCommand","urlMatch","methodMatch","headerRegex","match","key","value","dataMatch","import_jsx_runtime","PropertyPanel","selectedNodeId","selectedNodeType","onClose","_a","setNodes","getNodes","deleteElements","node","n","typeKey","def","connectorDef","j","currentOpId","op","o","handleUpdate","key","value","nds","handleDelete","curl","parsed","parseCurl","field","e","opt","import_react","import_lucide_react","import_jsx_runtime","iconMap","extendedIconMap","NodePalette","isOpen","onClose","onSelect","search","setSearch","groupedNodes","groups","n","node","cat","order","sortedGroups","key","e","category","nodes","isSearchActive","Icon","cn","g","import_react","import_lucide_react","import_jsx_runtime","Toast","message","type","isVisible","onClose","show","setShow","timer","cn","import_reactflow","import_dagre","import_reactflow","dagreGraph","dagre","nodeWidth","nodeHeight","getLayoutedElements","nodes","edges","direction","isHorizontal","node","edge","nodeWithPosition","import_react","useUndoRedo","initialNodes","initialEdges","setNodes","setEdges","history","setHistory","index","setIndex","takeSnapshot","nodes","edges","prev","newHistory","undo","newIndex","state","redo","validateWorkflow","nodes","edges","issues","connectedNodeIds","e","node","n","import_jsx_runtime","initialNodes","initialEdges","WorkflowBuilder","props","WorkflowBuilderContent","licenseKey","apiConfig","className","style","isValid","setIsValid","errorMsg","setErrorMsg","manager","c","nodes","setNodes","onNodesChange","edges","setEdges","onEdgesChange","isSaving","setIsSaving","isRunning","setIsRunning","toast","setToast","takeSnapshot","undo","redo","canUndo","canRedo","useUndoRedo","nds","eds","snapshot","selectedNodeId","setSelectedNodeId","nodeTypes","types","UniversalNode","n","key","validate","status","onConnect","params","newEdges","onNodeClick","event","node","onPaneClick","reactFlowWrapper","rfInstance","setRfInstance","isPaletteOpen","setIsPaletteOpen","handleAddNode","type","id","pos","newNode","newNodes","handleAutoLayout","layoutedNodes","layoutedEdges","getLayoutedElements","handleClear","handleRunTest","resetNodes","updateStatus","successors","e","queue","nodeId","r","children","childId","err","handleSave","issues","validateWorkflow","errors","i","client","d","workflow","success","handleExport","json","T","blob","url","link","handleImport","file","text","S","Toolbar","PropertyPanel","NodePalette","Toast","ReactFlow","_a","import_jsx_runtime","WorkflowWidget","props","WorkflowBuilder","import_react","import_lucide_react","import_jsx_runtime","EmbeddableWidget","licenseKey","apiConfig","position","themeColor","isOpen","setIsOpen","isExpanded","setIsExpanded","toggleOpen","toggleExpand","positionStyles","containerStyles","WorkflowWidget","e"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{useEffect as uo,useState as U,useCallback as W,useMemo as bo,useRef as mo}from"react";import go,{Background as yo,Controls as ho,MiniMap as fo,useNodesState as xo,useEdgesState as vo,addEdge as wo,BackgroundVariant as ko}from"reactflow";import"reactflow/dist/style.css";var Ye="http://localhost:3000/api/v1/license/validate",ae=class{constructor(e){this.config=e,this.validationResult=null}async validate(){if(this.validationResult)return this.validationResult;try{let e=this.config.validationEndpoint||Ye,t=await(await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({licenseKey:this.config.licenseKey,widgetVersion:this.config.widgetVersion,originUrl:typeof window!="undefined"?window.location.origin:""})})).json();return this.validationResult=t,t}catch(e){return console.error("License validation failed",e),{valid:!1,reason:"Network Error"}}}isFeatureEnabled(e){var t,r;return(t=this.validationResult)!=null&&t.valid?!!((r=this.validationResult.features)!=null&&r[e]):!1}},re=class{constructor(e){this.config=e}async request(e,t,r){let i={"Content-Type":"application/json",...this.config.headers},s=await fetch(e,{method:t,headers:i,body:r?JSON.stringify(r):void 0});if(!s.ok)throw new Error(`API Request failed: ${s.statusText}`);return s.json()}async getWorkflow(e){let t=`${this.config.baseUrl}${this.config.endpoints.get.replace(":id",e)}`;return this.request(t,"GET")}async createWorkflow(e){let t=`${this.config.baseUrl}${this.config.endpoints.create}`;return this.request(t,"POST",e)}async updateWorkflow(e,t){let r=`${this.config.baseUrl}${this.config.endpoints.update.replace(":id",e)}`;return this.request(r,"PUT",t)}},ie=class{static serialize(e,t,r){return JSON.stringify({nodes:e,edges:t,viewport:r})}static deserialize(e){try{let t=JSON.parse(e);return{nodes:t.nodes||[],edges:t.edges||[],viewport:t.viewport}}catch{return{nodes:[],edges:[]}}}},ne=ie.serialize,se=ie.deserialize;function le(e){return{type:e.id,label:e.label,description:`Integration with ${e.label}`,category:e.category,icon:e.icon,color:e.color,handles:[{id:"in",type:"target"},{id:"out",type:"source"}],inputs:[{key:"auth_token",label:"API Key / Token",type:"text",placeholder:e.auth.placeholder||"Enter API Key"},{key:"operation",label:"Action",type:"select",options:e.operations.map(t=>({label:t.label,value:t.id}))}]}}var Y=[{id:"google-sheets",label:"Google Sheets",category:"utility",icon:"Sheet",color:"emerald",baseUrl:"https://sheets.googleapis.com/v4/spreadsheets",auth:{type:"bearer",placeholder:"OAuth Token"},operations:[{id:"append_row",label:"Append Row",method:"POST",path:"/{spreadsheetId}/values/{range}:append",inputs:[{key:"spreadsheetId",label:"Spreadsheet ID",type:"text"},{key:"range",label:"Range (Sheet1!A1)",type:"text"},{key:"values",label:"Row Values (JSON Array)",type:"json"}]},{id:"get_values",label:"Get Row(s)",method:"GET",path:"/{spreadsheetId}/values/{range}",inputs:[{key:"spreadsheetId",label:"Spreadsheet ID",type:"text"},{key:"range",label:"Range",type:"text"}]}]},{id:"slack-connector",label:"Slack API",category:"action",icon:"MessageSquare",color:"blue",baseUrl:"https://slack.com/api",auth:{type:"bearer",placeholder:"xoxb-..."},operations:[{id:"post_message",label:"Post Message",method:"POST",path:"/chat.postMessage",inputs:[{key:"channel",label:"Channel ID",type:"text"},{key:"text",label:"Message Text",type:"text"}]}]},{id:"openai",label:"OpenAI",category:"action",icon:"Bot",color:"zinc",baseUrl:"https://api.openai.com/v1",auth:{type:"bearer",placeholder:"sk-..."},operations:[{id:"chat_completion",label:"Chat Completion",method:"POST",path:"/chat/completions",inputs:[{key:"model",label:"Model",type:"select",options:[{label:"GPT-4o",value:"gpt-4o"},{label:"GPT-3.5",value:"gpt-3.5-turbo"}]},{key:"messages",label:"Messages (JSON)",type:"json"}]}]}];function Io(e){Y.push(e)}var Ze=[{id:"triggers",nodes:[{type:"manual-trigger",label:"Manual Trigger",description:"Start flow on button click",category:"trigger",icon:"Play",color:"emerald",inputs:[]},{type:"cron-trigger",label:"Cron Schedule",description:"Trigger on a schedule",category:"trigger",icon:"Clock",color:"emerald",inputs:[{key:"expression",label:"Cron Expression",type:"text",placeholder:"0 9 * * 1 (Every Mon at 9am)"}]},{id:"github-trigger",label:"GitHub Trigger",category:"trigger",icon:"Github",color:"zinc",baseUrl:"https://api.github.com",auth:{type:"header",key:"X-GitHub-Token"},operations:[{id:"on_push",label:"On Push",method:"POST",path:"/repos/{owner}/{repo}/hooks",inputs:[{key:"owner",label:"Owner",type:"text"},{key:"repo",label:"Repository",type:"text"}]},{id:"on_star",label:"On New Star",method:"POST",path:"/repos/{owner}/{repo}/hooks",inputs:[{key:"owner",label:"Owner",type:"text"},{key:"repo",label:"Repository",type:"text"}]}]}]},{id:"logic",nodes:[{type:"switch",label:"Switch / Router",description:"Route based on value",category:"logic",icon:"GitFork",color:"orange",inputs:[{key:"property",label:"Property to Check",type:"text"},{key:"cases",label:"Cases (comma sep)",type:"text",placeholder:"marketing, sales, support"}]},{type:"ab-split",label:"A/B Split",description:"Randomly split traffic",category:"logic",icon:"Percent",color:"orange",inputs:[{key:"percentA",label:"Percentage for A",type:"text",placeholder:"50"}]},{type:"wait",label:"Wait / Delay",description:"Pause execution",category:"logic",icon:"Timer",color:"orange",inputs:[{key:"duration",label:"Duration",type:"text",placeholder:"5000"},{key:"unit",label:"Unit",type:"select",options:[{label:"Milliseconds",value:"ms"},{label:"Seconds",value:"s"}]}]}]},{id:"utilities",nodes:[{type:"text-transform",label:"Text Transform",description:"Modify text strings",category:"utility",icon:"Type",color:"zinc",inputs:[{key:"action",label:"Action",type:"select",options:[{label:"To Upper Case",value:"upper"},{label:"To Lower Case",value:"lower"},{label:"Trim",value:"trim"},{label:"Replace",value:"replace"}]},{key:"input",label:"Input Text",type:"text"}]},{type:"json-parser",label:"JSON Helper",description:"Parse or stringify JSON",category:"utility",icon:"Code",color:"zinc",inputs:[{key:"action",label:"Action",type:"select",options:[{label:"Parse (String to JSON)",value:"parse"},{label:"Stringify (JSON to String)",value:"stringify"}]},{key:"data",label:"Data",type:"json"}]},{type:"math-calc",label:"Math Calculator",description:"Perform calculations",category:"utility",icon:"Calculator",color:"zinc",inputs:[{key:"operation",label:"Operation",type:"select",options:[{label:"Add",value:"add"},{label:"Subtract",value:"sub"},{label:"Multiply",value:"mul"},{label:"Divide",value:"div"},{label:"Random Number",value:"random"}]},{key:"a",label:"Value A",type:"text"},{key:"b",label:"Value B",type:"text"}]},{type:"crypto",label:"Cryptography",description:"Hash or Encrypt data",category:"utility",icon:"Lock",color:"zinc",inputs:[{key:"algo",label:"Algorithm",type:"select",options:[{label:"MD5",value:"md5"},{label:"SHA-256",value:"sha256"},{label:"Base64 Encode",value:"base64_enc"},{label:"Base64 Decode",value:"base64_dec"}]},{key:"input",label:"value",type:"text"}]},{type:"date-time",label:"Date & Time",description:"Format or manipulate dates",category:"utility",icon:"Calendar",color:"zinc",inputs:[{key:"operation",label:"Action",type:"select",options:[{label:"Now (ISO)",value:"now"},{label:"Format Date",value:"format"},{label:"Add Time",value:"add"}]},{key:"date",label:"Date String",type:"text"},{key:"format",label:"Format Pattern",type:"text",placeholder:"YYYY-MM-DD"}]}]},{id:"integrations-productivity",nodes:[{id:"google-drive",label:"Google Drive",icon:"HardDrive",color:"blue",category:"action",baseUrl:"https://www.googleapis.com/drive/v3",auth:{type:"bearer",placeholder:"OAuth Token"},operations:[{id:"list",label:"List Files",method:"GET",path:"/files",inputs:[{key:"q",label:"Query",type:"text"}]},{id:"upload",label:"Upload File",method:"POST",path:"/files",inputs:[{key:"name",label:"Name",type:"text"},{key:"content",label:"Content",type:"text"}]}]},{id:"notion",label:"Notion",icon:"FileText",color:"zinc",category:"action",baseUrl:"https://api.notion.com/v1",auth:{type:"header",key:"Authorization",placeholder:"Bearer secret_..."},operations:[{id:"create_page",label:"Create Page",method:"POST",path:"/pages",inputs:[{key:"parent_id",label:"Parent DB ID",type:"text"},{key:"properties",label:"Properties JSON",type:"json"}]},{id:"query_db",label:"Query Database",method:"POST",path:"/databases/{id}/query",inputs:[{key:"id",label:"Database ID",type:"text"}]}]},{id:"airtable",label:"Airtable",icon:"Database",color:"amber",category:"action",baseUrl:"https://api.airtable.com/v0",auth:{type:"bearer",placeholder:"pat_..."},operations:[{id:"create_record",label:"Create Record",method:"POST",path:"/{baseId}/{tableId}",inputs:[{key:"baseId",label:"Base ID",type:"text"},{key:"tableId",label:"Table Name",type:"text"},{key:"fields",label:"Fields JSON",type:"json"}]},{id:"list_records",label:"List Records",method:"GET",path:"/{baseId}/{tableId}",inputs:[{key:"baseId",label:"Base ID",type:"text"},{key:"tableId",label:"Table Name",type:"text"}]}]}]},{id:"integrations-crm-marketing",nodes:[{id:"salesforce",label:"Salesforce",icon:"Cloud",color:"blue",category:"action",baseUrl:"https://{instance}.salesforce.com/services/data/vXX.X",auth:{type:"bearer"},operations:[{id:"create_lead",label:"Create Lead",method:"POST",path:"/sobjects/Lead",inputs:[{key:"instance",label:"Instance URL",type:"text"},{key:"LastName",label:"Last Name",type:"text"},{key:"Company",label:"Company",type:"text"}]}]},{id:"hubspot",label:"HubSpot",icon:"Users",color:"orange",category:"action",baseUrl:"https://api.hubapi.com",auth:{type:"bearer"},operations:[{id:"create_contact",label:"Create Contact",method:"POST",path:"/crm/v3/objects/contacts",inputs:[{key:"properties",label:"Properties JSON",type:"json"}]}]},{id:"mailchimp",label:"Mailchimp",icon:"Mail",color:"yellow",category:"action",baseUrl:"https://{dc}.api.mailchimp.com/3.0",auth:{type:"bearer"},operations:[{id:"add_member",label:"Add Subscriber",method:"POST",path:"/lists/{list_id}/members",inputs:[{key:"dc",label:"Data Center (usX)",type:"text"},{key:"list_id",label:"List ID",type:"text"},{key:"email_address",label:"Email",type:"text"},{key:"status",label:"Status",type:"select",options:[{label:"subscribed",value:"subscribed"}]}]}]}]},{id:"integrations-commerce",nodes:[{id:"shopify",label:"Shopify",icon:"ShoppingBag",color:"emerald",category:"action",baseUrl:"https://{shop}.myshopify.com/admin/api/2023-10",auth:{type:"header",key:"X-Shopify-Access-Token"},operations:[{id:"get_products",label:"Get Products",method:"GET",path:"/products.json",inputs:[{key:"shop",label:"Shop Name",type:"text"}]},{id:"create_order",label:"Create Order",method:"POST",path:"/orders.json",inputs:[{key:"shop",label:"Shop Name",type:"text"},{key:"order",label:"Order JSON",type:"json"}]}]},{id:"stripe",label:"Stripe",icon:"CreditCard",color:"indigo",category:"action",baseUrl:"https://api.stripe.com/v1",auth:{type:"bearer"},operations:[{id:"create_customer",label:"Create Customer",method:"POST",path:"/customers",inputs:[{key:"email",label:"Email",type:"text"}]},{id:"list_charges",label:"List Charges",method:"GET",path:"/charges",inputs:[{key:"limit",label:"Limit",type:"text"}]}]}]}];function Qe(){Ze.forEach(e=>{e.nodes.forEach(t=>{if(t.operations){let r={id:t.id,label:t.label,category:t.category,icon:t.icon,color:t.color,baseUrl:t.baseUrl,auth:t.auth,operations:t.operations};S[r.id]=le(r)}else{let r={type:t.type,label:t.label,description:t.description,category:t.category,icon:t.icon,color:t.color,handles:t.handles||[{id:"in",type:"target"},{id:"out",type:"source"}],inputs:t.inputs};S[r.type]=r}})})}var S={webhook:{type:"webhook",label:"Webhook",description:"Triggers when a URL is called",category:"trigger",icon:"Webhook",color:"emerald",handles:[{id:"out",type:"source"}],inputs:[{key:"method",label:"HTTP Method",type:"select",options:[{label:"GET",value:"GET"},{label:"POST",value:"POST"}]},{key:"path",label:"Path",type:"text",placeholder:"/webhook/..."}]},schedule:{type:"schedule",label:"Schedule",description:"Triggers on a specific interval",category:"trigger",icon:"Clock",color:"emerald",handles:[{id:"out",type:"source"}],inputs:[{key:"interval",label:"Interval",type:"select",options:[{label:"Every Minute",value:"1m"},{label:"Every Hour",value:"1h"},{label:"Every Day",value:"1d"}]},{key:"cron",label:"Cron Expression",type:"text",placeholder:"* * * * *"}]},"http-request":{type:"http-request",label:"HTTP Request",description:"Make an external API call",category:"action",icon:"Globe",color:"blue",handles:[{id:"in",type:"target"},{id:"out",type:"source"}],inputs:[{key:"url",label:"URL",type:"text",placeholder:"https://api.example.com"},{key:"method",label:"Method",type:"select",options:[{label:"GET",value:"GET"},{label:"POST",value:"POST"},{label:"PUT",value:"PUT"},{label:"DELETE",value:"DELETE"}]},{key:"headers",label:"Headers",type:"json"},{key:"body",label:"Body",type:"json"}]},email:{type:"email",label:"Send Email",description:"Send an email to a recipient",category:"action",icon:"Mail",color:"blue",handles:[{id:"in",type:"target"},{id:"out",type:"source"}],inputs:[{key:"to",label:"To",type:"text"},{key:"subject",label:"Subject",type:"text"},{key:"body",label:"Body",type:"text"}]},slack:{type:"slack",label:"Slack (Simple)",description:"Send a message to a channel",category:"action",icon:"MessageSquare",color:"blue",handles:[{id:"in",type:"target"},{id:"out",type:"source"}],inputs:[{key:"webhookUrl",label:"Webhook URL",type:"text"},{key:"message",label:"Message",type:"text"}]},"if-else":{type:"if-else",label:"If / Else",description:"Branch flow based on condition",category:"logic",icon:"Split",color:"orange",handles:[{id:"in",type:"target"},{id:"true",type:"source",label:"True"},{id:"false",type:"source",label:"False"}],inputs:[{key:"condition",label:"Condition",type:"code",description:"Javascript expression returning true/false"}]},merge:{type:"merge",label:"Merge",description:"Combine multiple branches",category:"logic",icon:"GitMerge",color:"orange",handles:[{id:"in-a",type:"target",label:"A"},{id:"in-b",type:"target",label:"B"},{id:"out",type:"source"}],inputs:[]}};Y.forEach(e=>{S[e.id]=le(e)});Qe();function de(e){return Y.find(t=>t.id===e)}import{memo as wt}from"react";import{Handle as kt,Position as $}from"reactflow";import{Webhook as Nt,Clock as zt,Globe as Ct,Mail as St,MessageSquare as Tt,Split as Pt,GitMerge as Rt,MoreHorizontal as Et,Zap as ue}from"lucide-react";import{clsx as et}from"clsx";import{twMerge as tt}from"tailwind-merge";function O(...e){return tt(et(e))}import{Sheet as ot,Bot as at,Type as rt,Code as it,Calculator as nt,Timer as st,GitFork as lt,Percent as dt,HardDrive as ct,Calendar as pt,Play as ut,Github as bt,Lock as mt,FileText as gt,Database as yt,Cloud as ht,Users as ft,ShoppingBag as xt,CreditCard as vt}from"lucide-react";var _={Sheet:ot,Bot:at,Type:rt,Code:it,Calculator:nt,Timer:st,GitFork:lt,Percent:dt,HardDrive:ct,Calendar:pt,Play:ut,Github:bt,Lock:mt,FileText:gt,Database:yt,Cloud:ht,Users:ft,ShoppingBag:xt,CreditCard:vt};import{jsx as T,jsxs as A}from"react/jsx-runtime";var It={Webhook:Nt,Clock:zt,Globe:Ct,Mail:St,MessageSquare:Tt,Split:Pt,GitMerge:Rt,Zap:ue,..._},ce={emerald:"text-emerald-600 bg-emerald-50 border-emerald-200",blue:"text-blue-600 bg-blue-50 border-blue-200",orange:"text-orange-600 bg-orange-50 border-orange-200",zinc:"text-zinc-600 bg-zinc-50 border-zinc-200"},pe={emerald:"ring-emerald-500/20",blue:"ring-blue-500/20",orange:"ring-orange-500/20",zinc:"ring-zinc-500/20"},Z=wt(({data:e,selected:t,type:r})=>{let i=S[e.type||r]||S.webhook;if(!i)return A("div",{className:"p-2 border border-red-500 rounded bg-red-50 text-red-600",children:["Unknown Node Type: ",r]});let s=It[i.icon]||ue,d=ce[i.color]||ce.zinc,a=pe[i.color]||pe.zinc,b=e.executionStatus,p="";return b==="running"?p="ring-4 ring-indigo-500/30 border-indigo-500 shadow-lg shadow-indigo-200 animate-pulse":b==="success"?p="ring-4 ring-emerald-500/40 border-emerald-500 shadow-lg shadow-emerald-200":b==="error"&&(p="ring-4 ring-red-500/40 border-red-500 shadow-lg shadow-red-200"),A("div",{className:O("min-w-[240px] bg-white rounded-lg shadow-sm border-2 transition-all duration-300",t?`border-indigo-500 shadow-xl ring-2 ${a}`:"border-zinc-200 hover:border-zinc-300",p),children:[A("div",{className:O("flex items-center justify-between p-3 border-b border-zinc-100/50 rounded-t-md bg-zinc-50/50"),children:[A("div",{className:"flex items-center gap-3",children:[T("div",{className:O("p-1.5 rounded-md border shadow-sm",d),children:T(s,{size:16,strokeWidth:2.5})}),A("div",{children:[T("span",{className:"block text-xs font-bold uppercase tracking-wider text-zinc-500",children:i.category}),T("span",{className:"block text-sm font-semibold text-zinc-900 leading-none mt-0.5",children:i.label})]})]}),T("button",{className:"text-zinc-400 hover:text-zinc-600 transition-colors",children:T(Et,{size:16})})]}),A("div",{className:"p-4 bg-white rounded-b-lg",children:[i.type==="http-request"&&A("div",{className:"flex items-center gap-2 font-mono text-xs text-zinc-600 bg-zinc-50 p-2 rounded border border-zinc-100",children:[T("span",{className:"font-bold text-blue-600",children:e.method||"GET"}),T("span",{className:"truncate max-w-[140px]",children:e.url||"https://..."})]}),i.type==="webhook"&&A("div",{className:"flex items-center gap-2 font-mono text-xs text-zinc-600",children:[T("span",{className:"font-bold text-emerald-600",children:e.method||"POST"}),T("span",{children:e.path||"/webhook/..."})]}),i.type==="if-else"&&T("div",{className:"text-xs font-mono text-orange-600 bg-orange-50 p-2 rounded border border-orange-100 truncate",children:e.condition||"x > 0"}),!["http-request","webhook","if-else"].includes(i.type)&&T("p",{className:"text-sm text-zinc-500",children:i.description})]}),i.handles.map(o=>{let m=o.type==="target"?$.Left:$.Right,g={};i.type==="if-else"&&o.type;let l=o.type==="source",n=i.handles.filter(v=>v.type===o.type).indexOf(o),y=i.handles.filter(v=>v.type===o.type).length,h=y>1?`${(n+1)*100/(y+1)}%`:"50%";return T(kt,{id:o.id,type:o.type,position:l?$.Right:$.Left,style:{top:h,...g},className:O("!w-3 !h-3 !border-2 !border-white transition-all duration-200 bg-zinc-400 group-hover:bg-indigo-500",l?"-right-1.5":"-left-1.5",o.id==="true"?"!bg-emerald-500":o.id==="false"?"!bg-red-500":""),children:o.label&&T("span",{className:O("absolute text-[10px] uppercase font-bold text-zinc-500 pointer-events-none w-max block mb-1",l?"right-4 mr-1 text-right":"left-4 ml-1 text-left","top-1/2 -translate-y-1/2"),children:o.label})},o.id)})]})});import{useRef as Ot}from"react";import{MousePointer2 as Mt,Save as Lt,Undo2 as Ut,Redo2 as Dt,Plus as At,Download as Wt,Upload as Gt,Layout as jt,Trash2 as Bt,Play as Ft}from"lucide-react";import{jsx as x,jsxs as j}from"react/jsx-runtime";function be({onSave:e,onExport:t,onImport:r,onAddNode:i,onAutoLayout:s,onClear:d,onRun:a,isSaving:b,isRunning:p,canUndo:o,canRedo:m,onUndo:g,onRedo:l}){let n=Ot(null);return j("div",{className:"absolute top-4 left-1/2 -translate-x-1/2 z-50 flex items-center gap-1 p-1 bg-white/90 backdrop-blur-md border border-zinc-200/50 shadow-xl rounded-full",children:[x("input",{type:"file",ref:n,onChange:h=>{var B;let v=(B=h.target.files)==null?void 0:B[0];v&&r(v),n.current&&(n.current.value="")},accept:".json",className:"hidden"}),j("div",{className:"flex items-center gap-1 px-1 border-r border-zinc-200",children:[x("button",{className:"p-2 text-zinc-500 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all",title:"Select",children:x(Mt,{size:18})}),x("button",{onClick:i,className:"p-2 text-zinc-500 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all",title:"Add Node",children:x(At,{size:18})})]}),j("div",{className:"flex items-center gap-1 px-1 border-r border-zinc-200",children:[x("button",{onClick:g,disabled:!o,className:"p-2 text-zinc-400 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all disabled:opacity-30 disabled:cursor-not-allowed",title:"Undo",children:x(Ut,{size:18})}),x("button",{onClick:l,disabled:!m,className:"p-2 text-zinc-400 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all disabled:opacity-30 disabled:cursor-not-allowed",title:"Redo",children:x(Dt,{size:18})})]}),j("div",{className:"flex items-center gap-1 px-1 border-r border-zinc-200",children:[x("button",{onClick:s,className:"p-2 text-zinc-600 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all",title:"Auto Layout",children:x(jt,{size:18})}),x("button",{onClick:d,className:"p-2 text-zinc-600 hover:text-red-600 hover:bg-red-50 rounded-full transition-all",title:"Clear Canvas",children:x(Bt,{size:18})})]}),j("div",{className:"flex items-center gap-1 px-1 border-r border-zinc-200",children:[x("button",{onClick:t,className:"p-2 text-zinc-600 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all",title:"Export JSON",children:x(Wt,{size:18})}),x("button",{onClick:()=>{var h;return(h=n.current)==null?void 0:h.click()},className:"p-2 text-zinc-600 hover:text-zinc-900 hover:bg-zinc-100 rounded-full transition-all",title:"Import JSON",children:x(Gt,{size:18})})]}),j("div",{className:"flex items-center gap-1 px-1",children:[x("button",{className:"flex items-center gap-2 px-3 py-2 bg-emerald-500 text-white rounded-full font-medium text-sm hover:bg-emerald-600 shadow-md shadow-emerald-200 transition-all mr-1",onClick:a,disabled:p,children:p?x("div",{className:"w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin"}):x(Ft,{size:16,fill:"currentColor"})}),j("button",{className:"flex items-center gap-2 px-4 py-2 bg-indigo-600 text-white rounded-full font-medium text-sm hover:bg-indigo-700 shadow-md shadow-indigo-200 transition-all disabled:opacity-70 disabled:cursor-not-allowed",onClick:e,disabled:b,children:[b?x("div",{className:"w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin"}):x(Lt,{size:16}),x("span",{children:"Save"})]})]})]})}import{Settings2 as Ht,X as ge,AlertCircle as _t,Trash2 as qt,Import as Jt}from"lucide-react";import{useReactFlow as Vt}from"reactflow";function me(e){if(!e.trim().toLowerCase().startsWith("curl"))return null;let t="GET",r={},i,s="",d=e.replace(/\\\n/g," ").replace(/\n/g," "),a=d.match(/'(http[^']*)'|"(http[^"]*)"|(http\S+)/);a&&(s=a[1]||a[2]||a[3]);let b=d.match(/-X\s+([A-Z]+)/);b&&(t=b[1]);let p=/-H\s+['"]([^'"]+)['"]/g,o;for(;(o=p.exec(d))!==null;){let[g,l]=o[1].split(/:\s?(.+)/);g&&l&&(r[g]=l)}let m=d.match(/(-d|--data|--data-raw)\s+['"]([^'"]+)['"]/);return m&&(i=m[2],t==="GET"&&(t="POST")),{method:t,url:s,headers:r,body:i}}import{jsx as N,jsxs as P}from"react/jsx-runtime";function ye({selectedNodeId:e,selectedNodeType:t,onClose:r}){var l;let{setNodes:i,getNodes:s,deleteElements:d}=Vt();if(!e)return null;let a=s().find(n=>n.id===e);if(!a)return null;let b=((l=a.data)==null?void 0:l.type)||a.type||t,p=S[b],o=de(b);if(o){p=JSON.parse(JSON.stringify(p));let n=a.data.operation;if(n){let y=o.operations.find(h=>h.id===n);y&&(p.inputs=[...p.inputs,...y.inputs])}}if(!p)return P("div",{className:"absolute top-4 right-4 w-80 bg-white p-4 rounded shadow border border-red-200 z-50",children:[P("div",{className:"flex items-center justify-between text-red-600 mb-2",children:[P("div",{className:"flex items-center gap-2",children:[N(_t,{size:16}),N("span",{className:"font-bold",children:"Unknown Node Type"})]}),N("button",{onClick:r,children:N(ge,{size:16})})]}),P("p",{className:"text-xs text-zinc-500 mt-1",children:["ID: ",b]})]});let m=(n,y)=>{i(h=>h.map(v=>v.id===e?{...v,data:{...v.data,[n]:y}}:v))},g=()=>{d({nodes:[{id:e}]}),r()};return P("div",{className:"absolute top-4 right-4 bottom-4 w-80 bg-white/95 backdrop-blur-md border border-zinc-200 shadow-2xl rounded-xl z-50 flex flex-col overflow-hidden animate-in slide-in-from-right duration-200",children:[P("div",{className:"p-4 border-b border-zinc-100 flex items-center justify-between bg-zinc-50/50",children:[P("div",{className:"flex items-center gap-2 text-zinc-700 font-semibold",children:[N(Ht,{size:16}),P("span",{children:[p.label," Properties"]})]}),P("div",{className:"flex items-center gap-1",children:[b==="http-request"&&P("button",{onClick:()=>{let n=prompt("Paste your cURL command here:");if(n){let y=me(n);y?i(h=>h.map(v=>v.id===e?{...v,data:{...v.data,method:y.method,url:y.url,headers:JSON.stringify(y.headers,null,2),body:y.body||"{}"}}:v)):alert("Could not parse cURL command.")}},className:"p-1.5 text-indigo-500 hover:text-indigo-700 hover:bg-indigo-50 rounded-md transition-colors flex items-center gap-1 text-xs font-medium mr-1",title:"Import cURL",children:[N(Jt,{size:14}),N("span",{children:"Import cURL"})]}),N("button",{onClick:g,className:"p-1.5 text-red-400 hover:text-red-600 hover:bg-red-50 rounded-md transition-colors",title:"Delete Node",children:N(qt,{size:16})}),N("button",{onClick:r,className:"p-1.5 text-zinc-400 hover:text-zinc-700 hover:bg-zinc-100 rounded-md transition-colors",children:N(ge,{size:16})})]})]}),P("div",{className:"p-4 space-y-5 flex-1 overflow-y-auto",children:[P("div",{className:"space-y-1 pb-4 border-b border-zinc-100",children:[N("label",{className:"text-xs font-bold uppercase tracking-wider text-zinc-400",children:"Description"}),N("p",{className:"text-sm text-zinc-600",children:p.description})]}),p.inputs.map(n=>{var y;return P("div",{className:"space-y-2",children:[N("label",{className:"block text-xs font-bold uppercase tracking-wider text-zinc-500",children:n.label}),n.type==="text"&&N("input",{type:"text",value:a.data[n.key]||"",onChange:h=>m(n.key,h.target.value),placeholder:n.placeholder,className:"w-full px-3 py-2 bg-white border border-zinc-200 rounded-md text-sm text-zinc-800 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-500 transition-all"}),n.type==="select"&&P("select",{value:a.data[n.key]||"",onChange:h=>m(n.key,h.target.value),className:"w-full px-3 py-2 bg-white border border-zinc-200 rounded-md text-sm text-zinc-800 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-500 transition-all",children:[N("option",{value:"",disabled:!0,children:"Select..."}),(y=n.options)==null?void 0:y.map(h=>N("option",{value:h.value,children:h.label},h.value))]}),(n.type==="json"||n.type==="code")&&N("textarea",{value:typeof a.data[n.key]=="object"?JSON.stringify(a.data[n.key],null,2):a.data[n.key]||"",onChange:h=>m(n.key,h.target.value),rows:5,className:"w-full px-3 py-2 bg-white border border-zinc-200 rounded-md text-sm font-mono text-zinc-800 focus:outline-none focus:ring-2 focus:ring-indigo-500/20 focus:border-indigo-500 transition-all resize-y"})]},n.key)})]})]})}import{useState as $t,useMemo as Xt}from"react";import{Search as Kt,X as Yt,Zap as Q,Globe as Zt,MessageSquare as Qt,Split as eo,GitMerge as to,Clock as oo,Mail as ao}from"lucide-react";import{jsx as z,jsxs as M}from"react/jsx-runtime";var ro={Webhook:Q,Clock:oo,Globe:Zt,Mail:ao,MessageSquare:Qt,Split:eo,GitMerge:to,Zap:Q,..._};function he({isOpen:e,onClose:t,onSelect:r}){let[i,s]=$t(""),d=Xt(()=>{let a={};Object.values(S).forEach(o=>{if(o.label.toLowerCase().includes(i.toLowerCase())||o.description&&o.description.toLowerCase().includes(i.toLowerCase())){let g=o.category||"other";a[g]||(a[g]=[]),a[g].push(o)}});let b=["trigger","logic","action","utility","integration"],p={};return b.forEach(o=>{a[o]&&(p[o]=a[o])}),Object.keys(a).forEach(o=>{b.includes(o)||(p[o]=a[o])}),p},[i]);return e?M("div",{className:"absolute inset-0 z-[100] bg-black/20 backdrop-blur-sm flex items-start justify-center pt-20 animate-in fade-in duration-200",children:[M("div",{className:"w-[600px] bg-white rounded-xl shadow-2xl border border-zinc-200 overflow-hidden flex flex-col max-h-[70vh] animate-in slide-in-from-bottom-4 duration-300",children:[M("div",{className:"p-4 border-b border-zinc-100 flex items-center gap-3 bg-zinc-50/50",children:[z(Kt,{className:"text-zinc-400",size:20}),z("input",{autoFocus:!0,type:"text",placeholder:"Search nodes...",className:"flex-1 bg-transparent border-none outline-none text-zinc-900 placeholder:text-zinc-400 text-lg",value:i,onChange:a=>s(a.target.value)}),z("div",{className:"px-2 py-1 bg-zinc-100 border border-zinc-200 rounded text-xs text-zinc-500 font-medium",children:"ESC"}),z("button",{onClick:t,className:"text-zinc-400 hover:text-zinc-700",children:z(Yt,{size:20})})]}),M("div",{className:"overflow-y-auto p-4 space-y-2",children:[Object.entries(d).map(([a,b])=>{if(b.length===0)return null;let p=i.length>0;return M("details",{open:!0,className:"group border border-zinc-200 rounded-lg bg-zinc-50/30 open:bg-white transition-all duration-200",children:[M("summary",{className:"flex items-center justify-between p-3 cursor-pointer list-none text-zinc-600 font-medium hover:bg-zinc-50 select-none",children:[M("div",{className:"flex items-center gap-2",children:[z("span",{className:"uppercase tracking-wider text-xs font-bold text-zinc-500",children:a}),z("span",{className:"text-xs bg-zinc-100 text-zinc-400 px-1.5 py-0.5 rounded-full",children:b.length})]}),z("div",{className:"text-zinc-400 group-open:rotate-180 transition-transform",children:z("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:z("path",{d:"m6 9 6 6 6-6"})})})]}),z("div",{className:"p-3 pt-0 border-t border-transparent group-open:border-zinc-100",children:z("div",{className:"grid grid-cols-2 gap-3 pt-2",children:b.map(o=>{let m=ro[o.icon]||_[o.icon]||Q;return M("button",{onClick:()=>r(o.type),className:"flex items-start gap-3 p-3 rounded-lg border border-zinc-100 bg-white hover:border-indigo-200 hover:shadow-md hover:bg-indigo-50/30 transition-all text-left group/btn",children:[z("div",{className:O("p-2 rounded-md transition-colors",`bg-${o.color}-50 text-${o.color}-600 group-hover/btn:bg-white`),children:z(m,{size:20})}),M("div",{children:[z("div",{className:"font-semibold text-zinc-900 text-sm",children:o.label}),z("div",{className:"text-xs text-zinc-500 line-clamp-2 leading-relaxed",children:o.description})]})]},o.type)})})})]},a)}),Object.values(d).every(a=>a.length===0)&&z("div",{className:"text-center py-12 text-zinc-400",children:M("p",{children:['No nodes found matching "',i,'"']})})]})]}),z("div",{className:"absolute inset-0 -z-10",onClick:t})]}):null}import{useEffect as io,useState as no}from"react";import{CheckCircle2 as so,AlertCircle as lo,X as co}from"lucide-react";import{jsx as q,jsxs as po}from"react/jsx-runtime";function fe({message:e,type:t,isVisible:r,onClose:i}){let[s,d]=no(!1);return io(()=>{if(r){d(!0);let a=setTimeout(()=>{i()},4e3);return()=>clearTimeout(a)}else setTimeout(()=>d(!1),300)},[r,i]),!s&&!r?null:po("div",{className:O("absolute bottom-6 left-1/2 -translate-x-1/2 z-[100] flex items-center gap-3 px-4 py-3 rounded-lg shadow-xl border transition-all duration-300 transform",t==="success"?"bg-white border-emerald-100 text-emerald-800":"bg-white border-red-100 text-red-800",r?"translate-y-0 opacity-100 scale-100":"translate-y-4 opacity-0 scale-95"),children:[t==="success"?q(so,{size:20,className:"text-emerald-500"}):q(lo,{size:20,className:"text-red-500"}),q("span",{className:"font-medium text-sm",children:e}),q("button",{onClick:i,className:"ml-2 hover:opacity-70",children:q(co,{size:16,className:"text-zinc-400"})})]})}import{ReactFlowProvider as No}from"reactflow";import we from"dagre";import{Position as X}from"reactflow";var H=new we.graphlib.Graph;H.setDefaultEdgeLabel(()=>({}));var xe=240,ve=150,ke=(e,t,r="LR")=>{let i=r==="LR";return H.setGraph({rankdir:r}),e.forEach(d=>{H.setNode(d.id,{width:xe,height:ve})}),t.forEach(d=>{H.setEdge(d.source,d.target)}),we.layout(H),{nodes:e.map(d=>{let a=H.node(d.id);return d.targetPosition=i?X.Left:X.Top,d.sourcePosition=i?X.Right:X.Bottom,d.position={x:a.x-xe/2,y:a.y-ve/2},d}),edges:t}};import{useState as Ne,useCallback as ee}from"react";function ze(e,t,r,i){let[s,d]=Ne([{nodes:e,edges:t}]),[a,b]=Ne(0),p=ee((g,l)=>{d(n=>{let y=n.slice(0,a+1);return y.push({nodes:g,edges:l}),y.length>50&&y.shift(),y}),b(n=>Math.min(n+1,50))},[a]),o=ee(()=>{if(a>0){let g=a-1,l=s[g];r(l.nodes),i(l.edges),b(g)}},[a,s,r,i]),m=ee(()=>{if(a<s.length-1){let g=a+1,l=s[g];r(l.nodes),i(l.edges),b(g)}},[a,s,r,i]);return{takeSnapshot:p,undo:o,redo:m,canUndo:a>0,canRedo:a<s.length-1}}function Ce(e,t){let r=[];if(e.length===0)return r.push({nodeId:"root",message:"Workflow is empty",severity:"warning"}),r;let i=new Set;return t.forEach(s=>{i.add(s.source),i.add(s.target)}),e.forEach(s=>{!i.has(s.id)&&e.length>1&&r.push({nodeId:s.id,message:"Node is disconnected",severity:"warning"}),s.type&&S[s.type],s.type==="http-request"&&(s.data.url||r.push({nodeId:s.id,field:"url",message:"URL is required",severity:"error"})),s.type}),r}import{jsx as C,jsxs as J}from"react/jsx-runtime";var Se=[{id:"1",type:"webhook",position:{x:100,y:100},data:{method:"POST",path:"/start"}},{id:"2",type:"http-request",position:{x:100,y:300},data:{method:"POST",url:"https://api.example.com/data"}},{id:"3",type:"slack",position:{x:400,y:200},data:{message:"Workflow completed",webhookUrl:"https://hooks.slack.com/..."}}],Te=[{id:"e1-2",source:"1",target:"2",type:"smoothstep",animated:!0,style:{stroke:"#6366f1",strokeWidth:2}},{id:"e2-3",source:"2",target:"3",type:"smoothstep",animated:!0,style:{stroke:"#6366f1",strokeWidth:2}}],Pe=e=>C(No,{children:C(zo,{...e})}),zo=({licenseKey:e,apiConfig:t,className:r,style:i})=>{let[s,d]=U(null),[a,b]=U(""),[p]=U(()=>new ae({licenseKey:e,widgetVersion:"1.0.0",validationEndpoint:"http://localhost:3000/api/v1/license/validate"})),[o,m,g]=xo(Se),[l,n,y]=vo(Te),[h,v]=U(!1),[B,oe]=U(!1),[G,D]=U(null),{takeSnapshot:E,undo:Ie,redo:Oe,canUndo:Me,canRedo:Le}=ze(Se,Te,u=>m([...u]),u=>n([...u])),Eo=W(()=>{E(o,l)},[o,l,E]),[Ue,V]=U(null),De=bo(()=>{let u={custom:Z};return Object.keys(S).forEach(c=>{u[c]=Z}),u},[]);uo(()=>{async function u(){let c=await p.validate();d(c.valid),c.valid||b(c.reason||"Invalid License")}u()},[p]);let Ae=W(u=>{n(c=>{let f=wo({...u,type:"smoothstep",animated:!0,style:{stroke:"#6366f1",strokeWidth:2}},c);return E(o,f),f})},[n,o,E]),We=W((u,c)=>{V(c.id)},[]),Ge=W(()=>{V(null)},[]),je=mo(null),[L,Be]=U(null),[Fe,K]=U(!1),He=W(u=>{let c=`node-${Date.now()}`,f={x:250,y:250};L&&(f={x:100+Math.random()*200,y:100+Math.random()*200});let w={id:c,type:u,position:f,data:{}},k=o.concat(w);m(k),E(k,l),K(!1),V(c)},[L,o,l,E,m]),_e=W(()=>{let{nodes:u,edges:c}=ke(o,l);m([...u]),n([...c]),E([...u],[...c]),setTimeout(()=>L==null?void 0:L.fitView(),100)},[o,l,m,n,E,L]),qe=W(()=>{confirm("Are you sure you want to clear the canvas?")&&(m([]),n([]),E([],[]))},[m,n,E]),Je=W(async()=>{if(B)return;oe(!0),D(null);let u=o.map(f=>({...f,data:{...f.data,executionStatus:void 0}}));m(u);let c=(f,w)=>{m(k=>k.map(I=>I.id===f?{...I,data:{...I.data,executionStatus:w}}:I))};try{let f={};l.forEach(k=>{f[k.source]||(f[k.source]=[]),f[k.source].push(k.target)});let w=o.filter(k=>["webhook","schedule","connector"].includes(k.type||"")||l.every(I=>I.target!==k.id)).map(k=>k.id);if(w.length===0&&o.length>0&&w.push(o[0].id),w.length===0)throw new Error("No start node found");for(let k of w){c(k,"running"),await new Promise(F=>setTimeout(F,800)),c(k,"success");let I=f[k]||[];for(let F of I)c(F,"running"),await new Promise(Ke=>setTimeout(Ke,800)),c(F,"success")}D({message:"Execution completed successfully",type:"success"})}catch(f){D({message:f.message||"Execution Success",type:"success"})}finally{oe(!1)}},[o,l,B,m]),Ve=async()=>{let u=Ce(o,l),c=u.filter(F=>F.severity==="error");if(c.length>0){D({message:`Cannot save: ${c[0].message}`,type:"error"});return}u.length>0&&D({message:`Saved with warnings: ${u[0].message}`,type:"success"}),v(!0);let f=new re(t),w={nodes:o,edges:l},I=!!await f.createWorkflow(w);v(!1),D(I?{message:"Workflow saved successfully",type:"success"}:{message:"Failed to save workflow",type:"error"})},$e=()=>{let u=ne(o,l),c=new Blob([u],{type:"application/json"}),f=URL.createObjectURL(c),w=document.createElement("a");w.href=f,w.download=`workflow-${Date.now()}.json`,document.body.appendChild(w),w.click(),document.body.removeChild(w)},Xe=async u=>{try{let c=await u.text(),{nodes:f,edges:w}=se(c);m(f),n(w),E(f,w),setTimeout(()=>{L==null||L.fitView({padding:.2})},50)}catch(c){alert("Failed to import workflow. Invalid file."),console.error(c)}};return s===null?C("div",{className:"flex items-center justify-center h-[600px] w-full bg-zinc-50 rounded-xl border border-zinc-200",children:J("div",{className:"flex flex-col items-center gap-3",children:[C("div",{className:"w-6 h-6 border-2 border-indigo-600 border-t-transparent rounded-full animate-spin"}),C("p",{className:"text-zinc-500 text-sm font-medium",children:"Verifying License..."})]})}):J("div",{style:i,className:`relative w-full h-[800px] rounded-xl border border-zinc-200 shadow-sm overflow-hidden bg-zinc-50/50 group ${r||""}`,children:[!s&&J("div",{className:"absolute inset-0 z-50 bg-white/80 backdrop-blur-md flex flex-col items-center justify-center p-8 text-center",children:[C("div",{className:"w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mb-4",children:C("div",{className:"w-8 h-8 text-red-600",children:"\u26A0\uFE0F"})}),C("h2",{className:"text-2xl font-bold text-zinc-900 mb-2",children:"License Verification Failed"}),J("p",{className:"text-zinc-600 max-w-md",children:[a,". Please update your license key to access the builder."]})]}),C(be,{onSave:Ve,onExport:$e,onImport:Xe,onAddNode:()=>K(!0),onAutoLayout:_e,onClear:qe,onRun:Je,isSaving:h,isRunning:B,canUndo:Me,canRedo:Le,onUndo:Ie,onRedo:Oe}),C(ye,{selectedNodeId:Ue||void 0,onClose:()=>V(null)}),C(he,{isOpen:Fe,onClose:()=>K(!1),onSelect:He}),C(fe,{message:(G==null?void 0:G.message)||"",type:(G==null?void 0:G.type)||"success",isVisible:!!G,onClose:()=>D(null)}),C("div",{className:"w-full h-full",ref:je,children:J(go,{nodes:o,edges:l,onNodesChange:g,onEdgesChange:y,onConnect:Ae,onNodeClick:We,onPaneClick:Ge,onInit:Be,nodeTypes:De,fitView:!0,className:"bg-zinc-50",children:[C(yo,{variant:ko.Dots,gap:20,size:1,color:"#94a3b8",className:"bg-slate-50"}),C(ho,{className:"!bg-white !border-slate-200 !shadow-xl !rounded-lg overflow-hidden [&>button]:!border-b-slate-100 [&>button]:!text-slate-600 hover:[&>button]:!bg-indigo-50 hover:[&>button]:!text-indigo-600 transition-colors"}),C(fo,{className:"!bg-white !border-slate-200 !shadow-xl !rounded-lg !mb-8 !mr-8",maskColor:"rgba(241, 245, 249, 0.7)",nodeColor:u=>{var c;return(c=u.type)!=null&&c.includes("trigger")||u.type==="webhook"?"#818cf8":u.type==="action"?"#34d399":"#cbd5e1"},zoomable:!0,pannable:!0})]})})]})};import{jsx as Co}from"react/jsx-runtime";function Re(e){return Co(Pe,{...e})}import{useState as Ee}from"react";import{Settings as So,X as To,Maximize2 as Po,Minimize2 as Ro}from"lucide-react";import{jsx as R,jsxs as te}from"react/jsx-runtime";function mr({licenseKey:e,apiConfig:t,position:r="bottom-right",themeColor:i="#2563eb"}){let[s,d]=Ee(!1),[a,b]=Ee(!1),p=()=>d(!s),o=()=>b(!a),m={position:"fixed",bottom:"20px",[r==="bottom-right"?"right":"left"]:"20px",zIndex:9999,display:"flex",flexDirection:"column",alignItems:r==="bottom-right"?"flex-end":"flex-start",gap:"10px"},g=a?{position:"fixed",top:0,left:0,width:"100vw",height:"100vh",backgroundColor:"white",zIndex:1e4,boxShadow:"0 0 20px rgba(0,0,0,0.2)",display:"flex",flexDirection:"column"}:{width:"800px",height:"600px",backgroundColor:"white",borderRadius:"12px",boxShadow:"0 4px 20px rgba(0,0,0,0.15)",border:"1px solid #e5e7eb",display:"flex",flexDirection:"column",overflow:"hidden"};return s?R("div",{style:a?{position:"fixed",top:0,left:0,zIndex:1e4}:m,children:te("div",{style:g,children:[te("div",{style:{padding:"12px 16px",borderBottom:"1px solid #eee",display:"flex",justifyContent:"space-between",alignItems:"center",backgroundColor:"#f9fafb",color:"black"},children:[R("h3",{style:{margin:0,fontSize:"16px",fontWeight:600},children:"Workflow Builder"}),te("div",{style:{display:"flex",gap:"8px"},children:[R("button",{onClick:o,style:{background:"none",border:"none",cursor:"pointer",padding:4},children:a?R(Ro,{size:18}):R(Po,{size:18})}),R("button",{onClick:p,style:{background:"none",border:"none",cursor:"pointer",padding:4},children:R(To,{size:18})})]})]}),R("div",{style:{flex:1,position:"relative"},children:R(Re,{licenseKey:e,apiConfig:t})})]})}):R("div",{style:m,children:R("button",{onClick:p,style:{width:"60px",height:"60px",borderRadius:"50%",backgroundColor:i,color:"white",border:"none",cursor:"pointer",boxShadow:"0 4px 12px rgba(0,0,0,0.2)",display:"flex",alignItems:"center",justifyContent:"center",transition:"transform 0.2s"},onMouseEnter:l=>l.currentTarget.style.transform="scale(1.05)",onMouseLeave:l=>l.currentTarget.style.transform="scale(1)",children:R(So,{size:28})})})}export{re as ApiClient,mr as EmbeddableWidget,ae as LicenseManager,Pe as WorkflowBuilder,ie as WorkflowSerializer,Re as WorkflowWidget,le as createConnectorNode,se as deserialize,de as getConnectorDetails,S as nodeRegistry,Io as registerConnector,ne as serialize,Y as standardConnectors};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|