Repository: FlowiseAI/Flowise Branch: main Commit: 03a0cf6b3fbd Files: 1790 Total size: 14.3 MB Directory structure: gitextract_ry1pyiq_/ ├── .dockerignore ├── .eslintrc.js ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yml │ │ └── feature_request.yml │ └── workflows/ │ ├── docker-image-dockerhub.yml │ ├── docker-image-ecr.yml │ ├── main.yml │ ├── proprietary-path-guard.yml │ ├── publish-agentflow.yml │ └── test_docker_build.yml ├── .gitignore ├── .husky/ │ ├── pre-commit │ └── pre-push ├── .npmrc ├── .nvmrc ├── .prettierignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE.md ├── README.md ├── SECURITY.md ├── artillery-load-test.yml ├── docker/ │ ├── Dockerfile │ ├── README.md │ ├── docker-compose-queue-prebuilt.yml │ ├── docker-compose-queue-source.yml │ ├── docker-compose.yml │ └── worker/ │ ├── Dockerfile │ ├── README.md │ ├── docker-compose.yml │ └── healthcheck/ │ ├── healthcheck.js │ └── package.json ├── i18n/ │ ├── CODE_OF_CONDUCT-ZH.md │ ├── CONTRIBUTING-ZH.md │ ├── README-JA.md │ ├── README-KR.md │ ├── README-TW.md │ └── README-ZH.md ├── metrics/ │ ├── grafana/ │ │ ├── grafana.dashboard.app.json.txt │ │ └── grafana.dashboard.server.json.txt │ ├── otel/ │ │ ├── compose.yaml │ │ └── otel.config.yml │ └── prometheus/ │ └── prometheus.config.yml ├── package.json ├── packages/ │ ├── agentflow/ │ │ ├── .eslintignore │ │ ├── .eslintrc.js │ │ ├── .npmignore │ │ ├── .prettierignore │ │ ├── .prettierrc │ │ ├── ARCHITECTURE.md │ │ ├── README.md │ │ ├── TESTS.md │ │ ├── examples/ │ │ │ ├── README.md │ │ │ ├── index.html │ │ │ ├── package-lock.json │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── App.tsx │ │ │ │ ├── FlowStatePanel.tsx │ │ │ │ ├── PropsDisplay.tsx │ │ │ │ ├── config.ts │ │ │ │ ├── demos/ │ │ │ │ │ ├── AllNodeTypesExample.tsx │ │ │ │ │ ├── BasicExample.tsx │ │ │ │ │ ├── CustomNodeExample.tsx │ │ │ │ │ ├── CustomUIExample.tsx │ │ │ │ │ ├── DarkModeExample.tsx │ │ │ │ │ ├── FilteredComponentsExample.tsx │ │ │ │ │ ├── MultiNodeFlow.tsx │ │ │ │ │ ├── StatusIndicatorsExample.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── main.tsx │ │ │ │ └── vite-env.d.ts │ │ │ ├── tsconfig.json │ │ │ └── vite.config.ts │ │ ├── jest.config.js │ │ ├── package.json │ │ ├── src/ │ │ │ ├── Agentflow.test.tsx │ │ │ ├── Agentflow.tsx │ │ │ ├── AgentflowProvider.tsx │ │ │ ├── __mocks__/ │ │ │ │ ├── @tiptap/ │ │ │ │ │ ├── extension-code-block-lowlight.ts │ │ │ │ │ ├── extension-placeholder.ts │ │ │ │ │ ├── react.ts │ │ │ │ │ └── starter-kit.ts │ │ │ │ ├── axios.ts │ │ │ │ ├── lowlight.ts │ │ │ │ ├── reactflow.tsx │ │ │ │ └── styleMock.js │ │ │ ├── __test_utils__/ │ │ │ │ ├── factories.ts │ │ │ │ └── jest-environment-jsdom.js │ │ │ ├── atoms/ │ │ │ │ ├── ArrayInput.test.tsx │ │ │ │ ├── ArrayInput.tsx │ │ │ │ ├── CodeInput.test.tsx │ │ │ │ ├── CodeInput.tsx │ │ │ │ ├── ConditionBuilder.test.tsx │ │ │ │ ├── ConditionBuilder.tsx │ │ │ │ ├── ExpandTextDialog.test.tsx │ │ │ │ ├── ExpandTextDialog.tsx │ │ │ │ ├── JsonInput.test.tsx │ │ │ │ ├── JsonInput.tsx │ │ │ │ ├── MainCard.tsx │ │ │ │ ├── MessagesInput.test.tsx │ │ │ │ ├── MessagesInput.tsx │ │ │ │ ├── NodeInputHandler.test.tsx │ │ │ │ ├── NodeInputHandler.tsx │ │ │ │ ├── RichTextEditor.lazy.tsx │ │ │ │ ├── RichTextEditor.test.tsx │ │ │ │ ├── RichTextEditor.tsx │ │ │ │ ├── ScenariosInput.test.tsx │ │ │ │ ├── ScenariosInput.tsx │ │ │ │ ├── SelectVariable.test.tsx │ │ │ │ ├── SelectVariable.tsx │ │ │ │ ├── StructuredOutputBuilder.test.tsx │ │ │ │ ├── StructuredOutputBuilder.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── useStableKeys.test.tsx │ │ │ │ └── useStableKeys.ts │ │ │ ├── core/ │ │ │ │ ├── index.ts │ │ │ │ ├── node-catalog/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── nodeFilters.test.ts │ │ │ │ │ └── nodeFilters.ts │ │ │ │ ├── node-config/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── nodeIconUtils.test.ts │ │ │ │ │ ├── nodeIconUtils.ts │ │ │ │ │ └── nodeIcons.ts │ │ │ │ ├── theme/ │ │ │ │ │ ├── createAgentflowTheme.test.ts │ │ │ │ │ ├── createAgentflowTheme.ts │ │ │ │ │ ├── cssVariables.test.ts │ │ │ │ │ ├── cssVariables.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── tokens.test.ts │ │ │ │ │ ├── tokens.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── types/ │ │ │ │ │ ├── agentflow.ts │ │ │ │ │ ├── api.ts │ │ │ │ │ ├── context.ts │ │ │ │ │ ├── flow.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── node.ts │ │ │ │ │ └── validation.ts │ │ │ │ ├── utils/ │ │ │ │ │ ├── dynamicOutputAnchors.test.ts │ │ │ │ │ ├── dynamicOutputAnchors.ts │ │ │ │ │ ├── fieldVisibility.test.ts │ │ │ │ │ ├── fieldVisibility.ts │ │ │ │ │ ├── flowExport.test.ts │ │ │ │ │ ├── flowExport.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── nodeFactory.test.ts │ │ │ │ │ └── nodeFactory.ts │ │ │ │ └── validation/ │ │ │ │ ├── connectionValidation.test.ts │ │ │ │ ├── connectionValidation.ts │ │ │ │ ├── constraintValidation.test.ts │ │ │ │ ├── constraintValidation.ts │ │ │ │ ├── flowValidation.test.ts │ │ │ │ ├── flowValidation.ts │ │ │ │ └── index.ts │ │ │ ├── features/ │ │ │ │ ├── canvas/ │ │ │ │ │ ├── canvas.css │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── AgentflowHeader.tsx │ │ │ │ │ │ ├── ConnectionLine.test.tsx │ │ │ │ │ │ ├── ConnectionLine.tsx │ │ │ │ │ │ ├── NodeIcon.tsx │ │ │ │ │ │ ├── NodeInfoDialog.tsx │ │ │ │ │ │ ├── NodeInputHandle.tsx │ │ │ │ │ │ ├── NodeModelConfigs.tsx │ │ │ │ │ │ ├── NodeOutputHandles.test.ts │ │ │ │ │ │ ├── NodeOutputHandles.tsx │ │ │ │ │ │ ├── NodeStatusIndicator.tsx │ │ │ │ │ │ ├── NodeToolbarActions.tsx │ │ │ │ │ │ ├── ValidationFeedback.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── containers/ │ │ │ │ │ │ ├── AgentFlowEdge.tsx │ │ │ │ │ │ ├── AgentFlowNode.tsx │ │ │ │ │ │ ├── IterationNode.tsx │ │ │ │ │ │ ├── StickyNote.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── useDragAndDrop.test.tsx │ │ │ │ │ │ ├── useDragAndDrop.ts │ │ │ │ │ │ ├── useFlowHandlers.test.tsx │ │ │ │ │ │ ├── useFlowHandlers.ts │ │ │ │ │ │ ├── useFlowNodes.test.tsx │ │ │ │ │ │ ├── useFlowNodes.ts │ │ │ │ │ │ ├── useNodeColors.test.tsx │ │ │ │ │ │ ├── useNodeColors.ts │ │ │ │ │ │ ├── useOpenNodeEditor.test.tsx │ │ │ │ │ │ └── useOpenNodeEditor.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── nodeIcons.tsx │ │ │ │ │ └── styled.ts │ │ │ │ ├── generator/ │ │ │ │ │ ├── GenerateFlowDialog.test.tsx │ │ │ │ │ ├── GenerateFlowDialog.tsx │ │ │ │ │ ├── SuggestionChips.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── node-editor/ │ │ │ │ │ ├── AsyncInput.test.tsx │ │ │ │ │ ├── AsyncInput.tsx │ │ │ │ │ ├── ConfigInput.test.tsx │ │ │ │ │ ├── ConfigInput.tsx │ │ │ │ │ ├── EditNodeDialog.test.tsx │ │ │ │ │ ├── EditNodeDialog.tsx │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── useAvailableVariables.test.tsx │ │ │ │ │ ├── useAvailableVariables.ts │ │ │ │ │ ├── useDynamicOutputPorts.test.tsx │ │ │ │ │ └── useDynamicOutputPorts.ts │ │ │ │ └── node-palette/ │ │ │ │ ├── AddNodesDrawer.tsx │ │ │ │ ├── NodeListItem.tsx │ │ │ │ ├── StyledFab.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── search.test.ts │ │ │ │ ├── search.ts │ │ │ │ └── useDrawerMaxHeight.ts │ │ │ ├── index.ts │ │ │ ├── infrastructure/ │ │ │ │ ├── api/ │ │ │ │ │ ├── chatflows.test.ts │ │ │ │ │ ├── chatflows.ts │ │ │ │ │ ├── client.test.ts │ │ │ │ │ ├── client.ts │ │ │ │ │ ├── credentials.test.ts │ │ │ │ │ ├── credentials.ts │ │ │ │ │ ├── deduplicatedClient.test.ts │ │ │ │ │ ├── deduplicatedClient.ts │ │ │ │ │ ├── embeddings.ts │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── useAsyncOptions.test.tsx │ │ │ │ │ │ └── useAsyncOptions.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── loadMethodRegistry.test.ts │ │ │ │ │ ├── loadMethodRegistry.ts │ │ │ │ │ ├── models.test.ts │ │ │ │ │ ├── models.ts │ │ │ │ │ ├── nodes.test.ts │ │ │ │ │ ├── nodes.ts │ │ │ │ │ ├── runtimeState.ts │ │ │ │ │ ├── stores.ts │ │ │ │ │ ├── tools.test.ts │ │ │ │ │ └── tools.ts │ │ │ │ └── store/ │ │ │ │ ├── AgentflowContext.e2e.test.tsx │ │ │ │ ├── AgentflowContext.test.tsx │ │ │ │ ├── AgentflowContext.tsx │ │ │ │ ├── ApiContext.test.tsx │ │ │ │ ├── ApiContext.tsx │ │ │ │ ├── ConfigContext.test.tsx │ │ │ │ ├── ConfigContext.tsx │ │ │ │ ├── agentflowReducer.test.ts │ │ │ │ ├── agentflowReducer.ts │ │ │ │ └── index.ts │ │ │ ├── useAgentflow.test.tsx │ │ │ ├── useAgentflow.ts │ │ │ └── vite-env.d.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── api-documentation/ │ │ ├── README-ZH.md │ │ ├── README.md │ │ ├── nodemon.json │ │ ├── package.json │ │ ├── src/ │ │ │ ├── configs/ │ │ │ │ └── swagger.config.ts │ │ │ ├── index.ts │ │ │ └── yml/ │ │ │ └── swagger.yml │ │ └── tsconfig.json │ ├── components/ │ │ ├── README-ZH.md │ │ ├── README.md │ │ ├── __mocks__/ │ │ │ └── esm-stub.js │ │ ├── credentials/ │ │ │ ├── AWSCredential.credential.ts │ │ │ ├── AgentflowApi.credential.ts │ │ │ ├── AirtableApi.credential.ts │ │ │ ├── AlibabaApi.credential.ts │ │ │ ├── AnthropicApi.credential.ts │ │ │ ├── ApifyApi.credential.ts │ │ │ ├── ArizeApi.credential.ts │ │ │ ├── AssemblyAI.credential.ts │ │ │ ├── AstraApi.credential.ts │ │ │ ├── AzureCognitiveServices.credential.ts │ │ │ ├── AzureOpenAIApi.credential.ts │ │ │ ├── AzureRerankerApi.credential.ts │ │ │ ├── BaiduApi.credential.ts │ │ │ ├── BraveSearchApi.credential.ts │ │ │ ├── CerebrasApi.credential.ts │ │ │ ├── ChatflowApi.credential.ts │ │ │ ├── ChromaApi.credential.ts │ │ │ ├── CloudflareApi.credential.ts │ │ │ ├── CohereApi.credential.ts │ │ │ ├── CometApi.credential.ts │ │ │ ├── ComposioApi.credential.ts │ │ │ ├── ConfluenceCloudApi.credential.ts │ │ │ ├── ConfluenceServerDCApi.credential.ts │ │ │ ├── CouchbaseApi.credential.ts │ │ │ ├── DeepseekApi.credential.ts │ │ │ ├── DynamodbMemoryApi.credential.ts │ │ │ ├── E2B.credential.ts │ │ │ ├── ElasticsearchAPI.credential.ts │ │ │ ├── ElectricsearchUserPassword.credential.ts │ │ │ ├── ElevenLabsApi.credential.ts │ │ │ ├── ExaSearchApi.credential.ts │ │ │ ├── FigmaApi.credential.ts │ │ │ ├── FireCrawlApi.credential.ts │ │ │ ├── FireworksApi.credential.ts │ │ │ ├── GithubApi.credential.ts │ │ │ ├── GmailOAuth2.credential.ts │ │ │ ├── GoogleAuth.credential.ts │ │ │ ├── GoogleCalendarOAuth2.credential.ts │ │ │ ├── GoogleDocsOAuth2.credential.ts │ │ │ ├── GoogleDriveOAuth2.credential.ts │ │ │ ├── GoogleGenerativeAI.credential.ts │ │ │ ├── GoogleMakerSuite.credential.ts │ │ │ ├── GoogleSearchApi.credential.ts │ │ │ ├── GoogleSheetsOAuth2.credential.ts │ │ │ ├── GroqApi.credential.ts │ │ │ ├── HTTPApiKey.credential.ts │ │ │ ├── HTTPBasicAuth.credential.ts │ │ │ ├── HTTPBearerToken.credential.ts │ │ │ ├── HuggingFaceApi.credential.ts │ │ │ ├── IBMWatsonx.credential.ts │ │ │ ├── JinaApi.credential.ts │ │ │ ├── JiraApi.credential.ts │ │ │ ├── JiraApiBearerToken.credential.ts │ │ │ ├── LangWatchApi.credential.ts │ │ │ ├── LangfuseApi.credential.ts │ │ │ ├── LangsmithApi.credential.ts │ │ │ ├── LitellmApi.credential.ts │ │ │ ├── LocalAIApi.credential.ts │ │ │ ├── LunaryApi.credential.ts │ │ │ ├── MeilisearchApi.credential.ts │ │ │ ├── Mem0MemoryApi.credential.ts │ │ │ ├── MicrosoftOutlookOAuth2.credential.ts │ │ │ ├── MicrosoftTeamsOAuth2.credential.ts │ │ │ ├── MilvusAuth.credential.ts │ │ │ ├── MistralApi.credential.ts │ │ │ ├── MomentoCacheApi.credential.ts │ │ │ ├── MongoDBUrlApi.credential.ts │ │ │ ├── MySQLApi.credential.ts │ │ │ ├── Neo4jApi.credential.ts │ │ │ ├── NotionApi.credential.ts │ │ │ ├── NvdiaNIMApi.credential.ts │ │ │ ├── Ollama.credential.ts │ │ │ ├── OpenAIApi.credential.ts │ │ │ ├── OpenRouterApi.credential.ts │ │ │ ├── OpenSearchUrl.credential.ts │ │ │ ├── OpikApi.credential.ts │ │ │ ├── OxylabsApi.credential.ts │ │ │ ├── PerplexityApi.credential.ts │ │ │ ├── PhoenixApi.credential.ts │ │ │ ├── PineconeApi.credential.ts │ │ │ ├── PostgresApi.credential.ts │ │ │ ├── PostgresUrl.credential.ts │ │ │ ├── QdrantApi.credential.ts │ │ │ ├── RedisCacheApi.credential.ts │ │ │ ├── RedisCacheUrlApi.credential.ts │ │ │ ├── ReplicateApi.credential.ts │ │ │ ├── SambanovaApi.credential.ts │ │ │ ├── SearchApi.credential.ts │ │ │ ├── SerpApi.credential.ts │ │ │ ├── SerperApi.credential.ts │ │ │ ├── SingleStoreApi.credential.ts │ │ │ ├── SlackApi.credential.ts │ │ │ ├── SpiderApi.credential.ts │ │ │ ├── StripeApi.credential.ts │ │ │ ├── SupabaseApi.credential.ts │ │ │ ├── TavilyApi.credential.ts │ │ │ ├── TeradataBearerToken.credential.ts │ │ │ ├── TeradataTD2.credential.ts │ │ │ ├── TeradataVectorStoreApi.credential.ts │ │ │ ├── TogetherAIApi.credential.ts │ │ │ ├── UnstructuredApi.credential.ts │ │ │ ├── UpstashRedisApi.credential.ts │ │ │ ├── UpstashRedisMemoryApi.credential.ts │ │ │ ├── UpstashVectorApi.credential.ts │ │ │ ├── VectaraApi.credential.ts │ │ │ ├── VoyageAIApi.credential.ts │ │ │ ├── WeaviateApi.credential.ts │ │ │ ├── WolframAlphaApp.credential.ts │ │ │ ├── XaiApi.credential.ts │ │ │ └── ZepMemoryApi.credential.ts │ │ ├── evaluation/ │ │ │ ├── EvaluationRunTracer.ts │ │ │ ├── EvaluationRunTracerLlama.ts │ │ │ └── EvaluationRunner.ts │ │ ├── gulpfile.ts │ │ ├── jest.config.js │ │ ├── models.json │ │ ├── nodes/ │ │ │ ├── agentflow/ │ │ │ │ ├── Agent/ │ │ │ │ │ └── Agent.ts │ │ │ │ ├── Condition/ │ │ │ │ │ └── Condition.ts │ │ │ │ ├── ConditionAgent/ │ │ │ │ │ ├── ConditionAgent.ts │ │ │ │ │ ├── matchScenario.test.ts │ │ │ │ │ └── matchScenario.ts │ │ │ │ ├── CustomFunction/ │ │ │ │ │ └── CustomFunction.ts │ │ │ │ ├── DirectReply/ │ │ │ │ │ └── DirectReply.ts │ │ │ │ ├── ExecuteFlow/ │ │ │ │ │ └── ExecuteFlow.ts │ │ │ │ ├── HTTP/ │ │ │ │ │ └── HTTP.ts │ │ │ │ ├── HumanInput/ │ │ │ │ │ └── HumanInput.ts │ │ │ │ ├── Interface.Agentflow.ts │ │ │ │ ├── Iteration/ │ │ │ │ │ └── Iteration.ts │ │ │ │ ├── LLM/ │ │ │ │ │ └── LLM.ts │ │ │ │ ├── Loop/ │ │ │ │ │ └── Loop.ts │ │ │ │ ├── Retriever/ │ │ │ │ │ └── Retriever.ts │ │ │ │ ├── Start/ │ │ │ │ │ └── Start.ts │ │ │ │ ├── StickyNote/ │ │ │ │ │ └── StickyNote.ts │ │ │ │ ├── Tool/ │ │ │ │ │ └── Tool.ts │ │ │ │ ├── prompt.ts │ │ │ │ ├── utils.test.ts │ │ │ │ └── utils.ts │ │ │ ├── agents/ │ │ │ │ ├── AirtableAgent/ │ │ │ │ │ ├── AirtableAgent.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── CSVAgent/ │ │ │ │ │ ├── CSVAgent.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── ConversationalAgent/ │ │ │ │ │ └── ConversationalAgent.ts │ │ │ │ ├── ConversationalRetrievalToolAgent/ │ │ │ │ │ └── ConversationalRetrievalToolAgent.ts │ │ │ │ ├── LlamaIndexAgents/ │ │ │ │ │ ├── AnthropicAgent/ │ │ │ │ │ │ └── AnthropicAgent_LlamaIndex.ts │ │ │ │ │ └── OpenAIToolAgent/ │ │ │ │ │ └── OpenAIToolAgent_LlamaIndex.ts │ │ │ │ ├── OpenAIAssistant/ │ │ │ │ │ └── OpenAIAssistant.ts │ │ │ │ ├── ReActAgentChat/ │ │ │ │ │ └── ReActAgentChat.ts │ │ │ │ ├── ReActAgentLLM/ │ │ │ │ │ └── ReActAgentLLM.ts │ │ │ │ ├── ToolAgent/ │ │ │ │ │ └── ToolAgent.ts │ │ │ │ └── XMLAgent/ │ │ │ │ └── XMLAgent.ts │ │ │ ├── analytic/ │ │ │ │ ├── Arize/ │ │ │ │ │ └── Arize.ts │ │ │ │ ├── LangFuse/ │ │ │ │ │ └── LangFuse.ts │ │ │ │ ├── LangSmith/ │ │ │ │ │ └── LangSmith.ts │ │ │ │ ├── LangWatch/ │ │ │ │ │ └── LangWatch.ts │ │ │ │ ├── Lunary/ │ │ │ │ │ └── Lunary.ts │ │ │ │ ├── Opik/ │ │ │ │ │ └── Opik.ts │ │ │ │ └── Phoenix/ │ │ │ │ └── Phoenix.ts │ │ │ ├── cache/ │ │ │ │ ├── InMemoryCache/ │ │ │ │ │ ├── InMemoryCache.ts │ │ │ │ │ └── InMemoryEmbeddingCache.ts │ │ │ │ ├── MomentoCache/ │ │ │ │ │ └── MomentoCache.ts │ │ │ │ ├── RedisCache/ │ │ │ │ │ ├── RedisCache.ts │ │ │ │ │ └── RedisEmbeddingsCache.ts │ │ │ │ └── UpstashRedisCache/ │ │ │ │ └── UpstashRedisCache.ts │ │ │ ├── chains/ │ │ │ │ ├── ApiChain/ │ │ │ │ │ ├── GETApiChain.ts │ │ │ │ │ ├── OpenAPIChain.ts │ │ │ │ │ ├── POSTApiChain.ts │ │ │ │ │ └── postCore.ts │ │ │ │ ├── ConversationChain/ │ │ │ │ │ └── ConversationChain.ts │ │ │ │ ├── ConversationalRetrievalQAChain/ │ │ │ │ │ ├── ConversationalRetrievalQAChain.ts │ │ │ │ │ └── prompts.ts │ │ │ │ ├── GraphCypherQAChain/ │ │ │ │ │ ├── GraphCypherQAChain.test.ts │ │ │ │ │ └── GraphCypherQAChain.ts │ │ │ │ ├── LLMChain/ │ │ │ │ │ └── LLMChain.ts │ │ │ │ ├── MultiPromptChain/ │ │ │ │ │ └── MultiPromptChain.ts │ │ │ │ ├── MultiRetrievalQAChain/ │ │ │ │ │ └── MultiRetrievalQAChain.ts │ │ │ │ ├── RetrievalQAChain/ │ │ │ │ │ └── RetrievalQAChain.ts │ │ │ │ ├── SqlDatabaseChain/ │ │ │ │ │ └── SqlDatabaseChain.ts │ │ │ │ ├── VectaraChain/ │ │ │ │ │ └── VectaraChain.ts │ │ │ │ └── VectorDBQAChain/ │ │ │ │ └── VectorDBQAChain.ts │ │ │ ├── chatmodels/ │ │ │ │ ├── AWSBedrock/ │ │ │ │ │ ├── AWSChatBedrock.ts │ │ │ │ │ └── FlowiseAWSChatBedrock.ts │ │ │ │ ├── AzureChatOpenAI/ │ │ │ │ │ ├── AzureChatOpenAI.ts │ │ │ │ │ ├── AzureChatOpenAI_LlamaIndex.ts │ │ │ │ │ ├── FlowiseAzureChatOpenAI.ts │ │ │ │ │ └── README.md │ │ │ │ ├── ChatAlibabaTongyi/ │ │ │ │ │ └── ChatAlibabaTongyi.ts │ │ │ │ ├── ChatAnthropic/ │ │ │ │ │ ├── ChatAnthropic.ts │ │ │ │ │ ├── ChatAnthropic_LlamaIndex.ts │ │ │ │ │ └── FlowiseChatAnthropic.ts │ │ │ │ ├── ChatBaiduWenxin/ │ │ │ │ │ └── ChatBaiduWenxin.ts │ │ │ │ ├── ChatCerebras/ │ │ │ │ │ └── ChatCerebras.ts │ │ │ │ ├── ChatCloudflareWorkersAI/ │ │ │ │ │ └── ChatCloudflareWorkersAI.ts │ │ │ │ ├── ChatCohere/ │ │ │ │ │ └── ChatCohere.ts │ │ │ │ ├── ChatCometAPI/ │ │ │ │ │ └── ChatCometAPI.ts │ │ │ │ ├── ChatFireworks/ │ │ │ │ │ ├── ChatFireworks.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── ChatGoogleGenerativeAI/ │ │ │ │ │ ├── ChatGoogleGenerativeAI.ts │ │ │ │ │ └── FlowiseChatGoogleGenerativeAI.ts │ │ │ │ ├── ChatGoogleVertexAI/ │ │ │ │ │ └── ChatGoogleVertexAI.ts │ │ │ │ ├── ChatHuggingFace/ │ │ │ │ │ ├── ChatHuggingFace.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── ChatIBMWatsonx/ │ │ │ │ │ └── ChatIBMWatsonx.ts │ │ │ │ ├── ChatLitellm/ │ │ │ │ │ └── ChatLitellm.ts │ │ │ │ ├── ChatLocalAI/ │ │ │ │ │ └── ChatLocalAI.ts │ │ │ │ ├── ChatMistral/ │ │ │ │ │ ├── ChatMistral.ts │ │ │ │ │ └── ChatMistral_LlamaIndex.ts │ │ │ │ ├── ChatNemoGuardrails/ │ │ │ │ │ ├── ChatNemoGuardrails.ts │ │ │ │ │ ├── NemoClient.ts │ │ │ │ │ └── readme.md │ │ │ │ ├── ChatNvdiaNIM/ │ │ │ │ │ └── ChatNvdiaNIM.ts │ │ │ │ ├── ChatOllama/ │ │ │ │ │ ├── ChatOllama.ts │ │ │ │ │ ├── ChatOllama_LlamaIndex.ts │ │ │ │ │ └── FlowiseChatOllama.ts │ │ │ │ ├── ChatOpenAI/ │ │ │ │ │ ├── ChatOpenAI.ts │ │ │ │ │ ├── ChatOpenAI_LlamaIndex.ts │ │ │ │ │ └── FlowiseChatOpenAI.ts │ │ │ │ ├── ChatOpenAICustom/ │ │ │ │ │ └── ChatOpenAICustom.ts │ │ │ │ ├── ChatOpenRouter/ │ │ │ │ │ ├── ChatOpenRouter.ts │ │ │ │ │ └── FlowiseChatOpenRouter.ts │ │ │ │ ├── ChatPerplexity/ │ │ │ │ │ ├── ChatPerplexity.ts │ │ │ │ │ └── FlowiseChatPerplexity.ts │ │ │ │ ├── ChatSambanova/ │ │ │ │ │ └── ChatSambanova.ts │ │ │ │ ├── ChatTogetherAI/ │ │ │ │ │ ├── ChatTogetherAI.ts │ │ │ │ │ └── ChatTogether_LlamaIndex.ts │ │ │ │ ├── ChatXAI/ │ │ │ │ │ ├── ChatXAI.ts │ │ │ │ │ └── FlowiseChatXAI.ts │ │ │ │ ├── Deepseek/ │ │ │ │ │ └── Deepseek.ts │ │ │ │ └── Groq/ │ │ │ │ ├── ChatGroq_LlamaIndex.ts │ │ │ │ └── Groq.ts │ │ │ ├── documentloaders/ │ │ │ │ ├── API/ │ │ │ │ │ └── APILoader.ts │ │ │ │ ├── Airtable/ │ │ │ │ │ └── Airtable.ts │ │ │ │ ├── ApifyWebsiteContentCrawler/ │ │ │ │ │ └── ApifyWebsiteContentCrawler.ts │ │ │ │ ├── BraveSearchAPI/ │ │ │ │ │ └── BraveSearchAPI.ts │ │ │ │ ├── Cheerio/ │ │ │ │ │ └── Cheerio.ts │ │ │ │ ├── Confluence/ │ │ │ │ │ └── Confluence.ts │ │ │ │ ├── Csv/ │ │ │ │ │ ├── Csv.ts │ │ │ │ │ └── CsvLoader.ts │ │ │ │ ├── CustomDocumentLoader/ │ │ │ │ │ └── CustomDocumentLoader.ts │ │ │ │ ├── DocumentStore/ │ │ │ │ │ └── DocStoreLoader.ts │ │ │ │ ├── Docx/ │ │ │ │ │ └── Docx.ts │ │ │ │ ├── Epub/ │ │ │ │ │ └── Epub.ts │ │ │ │ ├── Figma/ │ │ │ │ │ └── Figma.ts │ │ │ │ ├── File/ │ │ │ │ │ └── File.ts │ │ │ │ ├── FireCrawl/ │ │ │ │ │ └── FireCrawl.ts │ │ │ │ ├── Folder/ │ │ │ │ │ └── Folder.ts │ │ │ │ ├── Gitbook/ │ │ │ │ │ └── Gitbook.ts │ │ │ │ ├── Github/ │ │ │ │ │ └── Github.ts │ │ │ │ ├── GoogleDrive/ │ │ │ │ │ └── GoogleDrive.ts │ │ │ │ ├── GoogleSheets/ │ │ │ │ │ └── GoogleSheets.ts │ │ │ │ ├── Jira/ │ │ │ │ │ └── Jira.ts │ │ │ │ ├── Json/ │ │ │ │ │ └── Json.ts │ │ │ │ ├── Jsonlines/ │ │ │ │ │ └── Jsonlines.ts │ │ │ │ ├── MicrosoftExcel/ │ │ │ │ │ ├── ExcelLoader.ts │ │ │ │ │ └── MicrosoftExcel.ts │ │ │ │ ├── MicrosoftPowerpoint/ │ │ │ │ │ ├── MicrosoftPowerpoint.ts │ │ │ │ │ └── PowerpointLoader.ts │ │ │ │ ├── MicrosoftWord/ │ │ │ │ │ ├── MicrosoftWord.ts │ │ │ │ │ └── WordLoader.ts │ │ │ │ ├── Notion/ │ │ │ │ │ ├── NotionDB.ts │ │ │ │ │ ├── NotionFolder.ts │ │ │ │ │ └── NotionPage.ts │ │ │ │ ├── Oxylabs/ │ │ │ │ │ └── Oxylabs.ts │ │ │ │ ├── Pdf/ │ │ │ │ │ └── Pdf.ts │ │ │ │ ├── PlainText/ │ │ │ │ │ └── PlainText.ts │ │ │ │ ├── Playwright/ │ │ │ │ │ └── Playwright.ts │ │ │ │ ├── Puppeteer/ │ │ │ │ │ └── Puppeteer.ts │ │ │ │ ├── S3Directory/ │ │ │ │ │ └── S3Directory.ts │ │ │ │ ├── S3File/ │ │ │ │ │ ├── README.md │ │ │ │ │ └── S3File.ts │ │ │ │ ├── SearchApi/ │ │ │ │ │ └── SearchAPI.ts │ │ │ │ ├── SerpApi/ │ │ │ │ │ └── SerpAPI.ts │ │ │ │ ├── Spider/ │ │ │ │ │ ├── Spider.ts │ │ │ │ │ └── SpiderApp.ts │ │ │ │ ├── Text/ │ │ │ │ │ └── Text.ts │ │ │ │ ├── Unstructured/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── Unstructured.ts │ │ │ │ │ └── UnstructuredFile.ts │ │ │ │ └── VectorStoreToDocument/ │ │ │ │ └── VectorStoreToDocument.ts │ │ │ ├── embeddings/ │ │ │ │ ├── AWSBedrockEmbedding/ │ │ │ │ │ └── AWSBedrockEmbedding.ts │ │ │ │ ├── AzureOpenAIEmbedding/ │ │ │ │ │ ├── AzureOpenAIEmbedding.ts │ │ │ │ │ ├── AzureOpenAIEmbedding_LlamaIndex.ts │ │ │ │ │ └── README.md │ │ │ │ ├── CohereEmbedding/ │ │ │ │ │ └── CohereEmbedding.ts │ │ │ │ ├── GoogleGenerativeAIEmbedding/ │ │ │ │ │ └── GoogleGenerativeAIEmbedding.ts │ │ │ │ ├── GoogleVertexAIEmbedding/ │ │ │ │ │ └── GoogleVertexAIEmbedding.ts │ │ │ │ ├── HuggingFaceInferenceEmbedding/ │ │ │ │ │ ├── HuggingFaceInferenceEmbedding.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── IBMWatsonxEmbedding/ │ │ │ │ │ └── IBMWatsonxEmbedding.ts │ │ │ │ ├── JinaAIEmbedding/ │ │ │ │ │ └── JinaAIEmbedding.ts │ │ │ │ ├── LocalAIEmbedding/ │ │ │ │ │ └── LocalAIEmbedding.ts │ │ │ │ ├── MistralEmbedding/ │ │ │ │ │ └── MistralEmbedding.ts │ │ │ │ ├── OllamaEmbedding/ │ │ │ │ │ └── OllamaEmbedding.ts │ │ │ │ ├── OpenAIEmbedding/ │ │ │ │ │ ├── OpenAIEmbedding.ts │ │ │ │ │ └── OpenAIEmbedding_LlamaIndex.ts │ │ │ │ ├── OpenAIEmbeddingCustom/ │ │ │ │ │ └── OpenAIEmbeddingCustom.ts │ │ │ │ ├── TogetherAIEmbedding/ │ │ │ │ │ └── TogetherAIEmbedding.ts │ │ │ │ └── VoyageAIEmbedding/ │ │ │ │ └── VoyageAIEmbedding.ts │ │ │ ├── engine/ │ │ │ │ ├── ChatEngine/ │ │ │ │ │ ├── ContextChatEngine.ts │ │ │ │ │ └── SimpleChatEngine.ts │ │ │ │ ├── EngineUtils.ts │ │ │ │ ├── QueryEngine/ │ │ │ │ │ └── QueryEngine.ts │ │ │ │ └── SubQuestionQueryEngine/ │ │ │ │ └── SubQuestionQueryEngine.ts │ │ │ ├── graphs/ │ │ │ │ └── Neo4j/ │ │ │ │ └── Neo4j.ts │ │ │ ├── llms/ │ │ │ │ ├── AWSBedrock/ │ │ │ │ │ └── AWSBedrock.ts │ │ │ │ ├── Azure OpenAI/ │ │ │ │ │ ├── AzureOpenAI.ts │ │ │ │ │ └── README.md │ │ │ │ ├── Cohere/ │ │ │ │ │ └── Cohere.ts │ │ │ │ ├── Fireworks/ │ │ │ │ │ └── Fireworks.ts │ │ │ │ ├── GoogleVertexAI/ │ │ │ │ │ └── GoogleVertexAI.ts │ │ │ │ ├── HuggingFaceInference/ │ │ │ │ │ ├── HuggingFaceInference.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── IBMWatsonx/ │ │ │ │ │ └── IBMWatsonx.ts │ │ │ │ ├── Ollama/ │ │ │ │ │ └── Ollama.ts │ │ │ │ ├── OpenAI/ │ │ │ │ │ └── OpenAI.ts │ │ │ │ ├── Replicate/ │ │ │ │ │ ├── Replicate.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── SambaNova/ │ │ │ │ │ └── Sambanova.ts │ │ │ │ └── TogetherAI/ │ │ │ │ └── TogetherAI.ts │ │ │ ├── memory/ │ │ │ │ ├── AgentMemory/ │ │ │ │ │ ├── AgentMemory.ts │ │ │ │ │ ├── MySQLAgentMemory/ │ │ │ │ │ │ ├── MySQLAgentMemory.ts │ │ │ │ │ │ └── mysqlSaver.ts │ │ │ │ │ ├── PostgresAgentMemory/ │ │ │ │ │ │ ├── PostgresAgentMemory.ts │ │ │ │ │ │ └── pgSaver.ts │ │ │ │ │ ├── SQLiteAgentMemory/ │ │ │ │ │ │ ├── SQLiteAgentMemory.ts │ │ │ │ │ │ └── sqliteSaver.ts │ │ │ │ │ └── interface.ts │ │ │ │ ├── BufferMemory/ │ │ │ │ │ └── BufferMemory.ts │ │ │ │ ├── BufferWindowMemory/ │ │ │ │ │ └── BufferWindowMemory.ts │ │ │ │ ├── ConversationSummaryBufferMemory/ │ │ │ │ │ └── ConversationSummaryBufferMemory.ts │ │ │ │ ├── ConversationSummaryMemory/ │ │ │ │ │ └── ConversationSummaryMemory.ts │ │ │ │ ├── DynamoDb/ │ │ │ │ │ └── DynamoDb.ts │ │ │ │ ├── Mem0/ │ │ │ │ │ └── Mem0.ts │ │ │ │ ├── MongoDBMemory/ │ │ │ │ │ └── MongoDBMemory.ts │ │ │ │ ├── RedisBackedChatMemory/ │ │ │ │ │ └── RedisBackedChatMemory.ts │ │ │ │ ├── UpstashRedisBackedChatMemory/ │ │ │ │ │ └── UpstashRedisBackedChatMemory.ts │ │ │ │ ├── ZepMemory/ │ │ │ │ │ └── ZepMemory.ts │ │ │ │ └── ZepMemoryCloud/ │ │ │ │ └── ZepMemoryCloud.ts │ │ │ ├── moderation/ │ │ │ │ ├── Moderation.ts │ │ │ │ ├── OpenAIModeration/ │ │ │ │ │ ├── OpenAIModeration.ts │ │ │ │ │ └── OpenAIModerationRunner.ts │ │ │ │ └── SimplePromptModeration/ │ │ │ │ ├── SimplePromptModeration.ts │ │ │ │ └── SimplePromptModerationRunner.ts │ │ │ ├── multiagents/ │ │ │ │ ├── Supervisor/ │ │ │ │ │ └── Supervisor.ts │ │ │ │ └── Worker/ │ │ │ │ └── Worker.ts │ │ │ ├── outputparsers/ │ │ │ │ ├── CSVListOutputParser/ │ │ │ │ │ └── CSVListOutputParser.ts │ │ │ │ ├── CustomListOutputParser/ │ │ │ │ │ └── CustomListOutputParser.ts │ │ │ │ ├── OutputParserHelpers.ts │ │ │ │ ├── StructuredOutputParser/ │ │ │ │ │ └── StructuredOutputParser.ts │ │ │ │ └── StructuredOutputParserAdvanced/ │ │ │ │ └── StructuredOutputParserAdvanced.ts │ │ │ ├── prompts/ │ │ │ │ ├── ChatPromptTemplate/ │ │ │ │ │ └── ChatPromptTemplate.ts │ │ │ │ ├── FewShotPromptTemplate/ │ │ │ │ │ └── FewShotPromptTemplate.ts │ │ │ │ ├── PromptLangfuse/ │ │ │ │ │ └── PromptLangfuse.ts │ │ │ │ └── PromptTemplate/ │ │ │ │ └── PromptTemplate.ts │ │ │ ├── recordmanager/ │ │ │ │ ├── MySQLRecordManager/ │ │ │ │ │ └── MySQLrecordManager.ts │ │ │ │ ├── PostgresRecordManager/ │ │ │ │ │ ├── PostgresRecordManager.ts │ │ │ │ │ ├── README.md │ │ │ │ │ └── utils.ts │ │ │ │ └── SQLiteRecordManager/ │ │ │ │ └── SQLiteRecordManager.ts │ │ │ ├── responsesynthesizer/ │ │ │ │ ├── CompactRefine/ │ │ │ │ │ └── CompactRefine.ts │ │ │ │ ├── Refine/ │ │ │ │ │ └── Refine.ts │ │ │ │ ├── SimpleResponseBuilder/ │ │ │ │ │ └── SimpleResponseBuilder.ts │ │ │ │ ├── TreeSummarize/ │ │ │ │ │ └── TreeSummarize.ts │ │ │ │ └── base.ts │ │ │ ├── retrievers/ │ │ │ │ ├── AWSBedrockKBRetriever/ │ │ │ │ │ └── AWSBedrockKBRetriever.ts │ │ │ │ ├── AzureRerankRetriever/ │ │ │ │ │ ├── AzureRerank.ts │ │ │ │ │ └── AzureRerankRetriever.ts │ │ │ │ ├── CohereRerankRetriever/ │ │ │ │ │ ├── CohereRerank.ts │ │ │ │ │ └── CohereRerankRetriever.ts │ │ │ │ ├── CustomRetriever/ │ │ │ │ │ └── CustomRetriever.ts │ │ │ │ ├── EmbeddingsFilterRetriever/ │ │ │ │ │ └── EmbeddingsFilterRetriever.ts │ │ │ │ ├── ExtractMetadataRetriever/ │ │ │ │ │ └── ExtractMetadataRetriever.ts │ │ │ │ ├── HydeRetriever/ │ │ │ │ │ └── HydeRetriever.ts │ │ │ │ ├── JinaRerankRetriever/ │ │ │ │ │ ├── JinaRerank.ts │ │ │ │ │ └── JinaRerankRetriever.ts │ │ │ │ ├── LLMFilterRetriever/ │ │ │ │ │ └── LLMFilterCompressionRetriever.ts │ │ │ │ ├── MultiQueryRetriever/ │ │ │ │ │ └── MultiQueryRetriever.ts │ │ │ │ ├── PromptRetriever/ │ │ │ │ │ └── PromptRetriever.ts │ │ │ │ ├── RRFRetriever/ │ │ │ │ │ ├── RRFRetriever.ts │ │ │ │ │ └── ReciprocalRankFusion.ts │ │ │ │ ├── SimilarityThresholdRetriever/ │ │ │ │ │ └── SimilarityThresholdRetriever.ts │ │ │ │ ├── VectorStoreRetriever/ │ │ │ │ │ └── VectorStoreRetriever.ts │ │ │ │ └── VoyageAIRetriever/ │ │ │ │ ├── VoyageAIRerank.ts │ │ │ │ └── VoyageAIRerankRetriever.ts │ │ │ ├── sequentialagents/ │ │ │ │ ├── Agent/ │ │ │ │ │ └── Agent.ts │ │ │ │ ├── Condition/ │ │ │ │ │ └── Condition.ts │ │ │ │ ├── ConditionAgent/ │ │ │ │ │ └── ConditionAgent.ts │ │ │ │ ├── CustomFunction/ │ │ │ │ │ └── CustomFunction.ts │ │ │ │ ├── End/ │ │ │ │ │ └── End.ts │ │ │ │ ├── ExecuteFlow/ │ │ │ │ │ └── ExecuteFlow.ts │ │ │ │ ├── LLMNode/ │ │ │ │ │ └── LLMNode.ts │ │ │ │ ├── Loop/ │ │ │ │ │ └── Loop.ts │ │ │ │ ├── Start/ │ │ │ │ │ └── Start.ts │ │ │ │ ├── State/ │ │ │ │ │ └── State.ts │ │ │ │ ├── ToolNode/ │ │ │ │ │ └── ToolNode.ts │ │ │ │ └── commonUtils.ts │ │ │ ├── speechtotext/ │ │ │ │ └── assemblyai/ │ │ │ │ └── AssemblyAI.ts │ │ │ ├── textsplitters/ │ │ │ │ ├── CharacterTextSplitter/ │ │ │ │ │ └── CharacterTextSplitter.ts │ │ │ │ ├── CodeTextSplitter/ │ │ │ │ │ └── CodeTextSplitter.ts │ │ │ │ ├── HtmlToMarkdownTextSplitter/ │ │ │ │ │ └── HtmlToMarkdownTextSplitter.ts │ │ │ │ ├── MarkdownTextSplitter/ │ │ │ │ │ └── MarkdownTextSplitter.ts │ │ │ │ ├── RecursiveCharacterTextSplitter/ │ │ │ │ │ └── RecursiveCharacterTextSplitter.ts │ │ │ │ └── TokenTextSplitter/ │ │ │ │ └── TokenTextSplitter.ts │ │ │ ├── tools/ │ │ │ │ ├── AWSDynamoDBKVStorage/ │ │ │ │ │ ├── AWSDynamoDBKVStorage.test.ts │ │ │ │ │ └── AWSDynamoDBKVStorage.ts │ │ │ │ ├── AWSSNS/ │ │ │ │ │ └── AWSSNS.ts │ │ │ │ ├── AgentAsTool/ │ │ │ │ │ └── AgentAsTool.ts │ │ │ │ ├── Arxiv/ │ │ │ │ │ ├── Arxiv.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── BraveSearchAPI/ │ │ │ │ │ └── BraveSearchAPI.ts │ │ │ │ ├── Calculator/ │ │ │ │ │ └── Calculator.ts │ │ │ │ ├── ChainTool/ │ │ │ │ │ ├── ChainTool.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── ChatflowTool/ │ │ │ │ │ └── ChatflowTool.ts │ │ │ │ ├── CodeInterpreterE2B/ │ │ │ │ │ └── CodeInterpreterE2B.ts │ │ │ │ ├── Composio/ │ │ │ │ │ └── Composio.ts │ │ │ │ ├── CurrentDateTime/ │ │ │ │ │ └── CurrentDateTime.ts │ │ │ │ ├── CustomTool/ │ │ │ │ │ ├── CustomTool.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── ExaSearch/ │ │ │ │ │ └── ExaSearch.ts │ │ │ │ ├── Gmail/ │ │ │ │ │ ├── Gmail.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── GoogleCalendar/ │ │ │ │ │ ├── GoogleCalendar.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── GoogleDocs/ │ │ │ │ │ ├── GoogleDocs.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── GoogleDrive/ │ │ │ │ │ ├── GoogleDrive.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── GoogleSearchAPI/ │ │ │ │ │ └── GoogleSearchAPI.ts │ │ │ │ ├── GoogleSheets/ │ │ │ │ │ ├── GoogleSheets.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── JSONPathExtractor/ │ │ │ │ │ ├── JSONPathExtractor.test.ts │ │ │ │ │ └── JSONPathExtractor.ts │ │ │ │ ├── Jira/ │ │ │ │ │ ├── Jira.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── MCP/ │ │ │ │ │ ├── BraveSearch/ │ │ │ │ │ │ └── BraveSearchMCP.ts │ │ │ │ │ ├── CustomMCP/ │ │ │ │ │ │ └── CustomMCP.ts │ │ │ │ │ ├── Github/ │ │ │ │ │ │ └── GithubMCP.ts │ │ │ │ │ ├── PostgreSQL/ │ │ │ │ │ │ └── PostgreSQLMCP.ts │ │ │ │ │ ├── SequentialThinking/ │ │ │ │ │ │ └── SequentialThinkingMCP.ts │ │ │ │ │ ├── Slack/ │ │ │ │ │ │ └── SlackMCP.ts │ │ │ │ │ ├── Supergateway/ │ │ │ │ │ │ └── SupergatewayMCP.ts │ │ │ │ │ ├── Teradata/ │ │ │ │ │ │ └── TeradataMCP.ts │ │ │ │ │ ├── core.test.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── MicrosoftOutlook/ │ │ │ │ │ ├── MicrosoftOutlook.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── MicrosoftTeams/ │ │ │ │ │ ├── MicrosoftTeams.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── OpenAPIToolkit/ │ │ │ │ │ ├── OpenAPIToolkit.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── QueryEngineTool/ │ │ │ │ │ └── QueryEngineTool.ts │ │ │ │ ├── RequestsDelete/ │ │ │ │ │ ├── RequestsDelete.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── RequestsGet/ │ │ │ │ │ ├── RequestsGet.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── RequestsPost/ │ │ │ │ │ ├── RequestsPost.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── RequestsPut/ │ │ │ │ │ ├── RequestsPut.ts │ │ │ │ │ └── core.ts │ │ │ │ ├── RetrieverTool/ │ │ │ │ │ └── RetrieverTool.ts │ │ │ │ ├── SearchApi/ │ │ │ │ │ └── SearchAPI.ts │ │ │ │ ├── Searxng/ │ │ │ │ │ └── Searxng.ts │ │ │ │ ├── SerpAPI/ │ │ │ │ │ └── SerpAPI.ts │ │ │ │ ├── Serper/ │ │ │ │ │ └── Serper.ts │ │ │ │ ├── StripeTool/ │ │ │ │ │ └── StripeTool.ts │ │ │ │ ├── TavilyAPI/ │ │ │ │ │ └── TavilyAPI.ts │ │ │ │ ├── WebBrowser/ │ │ │ │ │ └── WebBrowser.ts │ │ │ │ ├── WebScraperTool/ │ │ │ │ │ └── WebScraperTool.ts │ │ │ │ └── WolframAlpha/ │ │ │ │ └── WolframAlpha.ts │ │ │ ├── utilities/ │ │ │ │ ├── CustomFunction/ │ │ │ │ │ └── CustomFunction.ts │ │ │ │ ├── GetVariable/ │ │ │ │ │ └── GetVariable.ts │ │ │ │ ├── IfElseFunction/ │ │ │ │ │ └── IfElseFunction.ts │ │ │ │ ├── SetVariable/ │ │ │ │ │ └── SetVariable.ts │ │ │ │ └── StickyNote/ │ │ │ │ └── StickyNote.ts │ │ │ └── vectorstores/ │ │ │ ├── Astra/ │ │ │ │ └── Astra.ts │ │ │ ├── Chroma/ │ │ │ │ ├── Chroma.ts │ │ │ │ └── core.ts │ │ │ ├── Couchbase/ │ │ │ │ └── Couchbase.ts │ │ │ ├── DocumentStoreVS/ │ │ │ │ └── DocStoreVector.ts │ │ │ ├── Elasticsearch/ │ │ │ │ └── Elasticsearch.ts │ │ │ ├── Faiss/ │ │ │ │ └── Faiss.ts │ │ │ ├── InMemory/ │ │ │ │ └── InMemoryVectorStore.ts │ │ │ ├── Kendra/ │ │ │ │ └── Kendra.ts │ │ │ ├── Meilisearch/ │ │ │ │ ├── Meilisearch.ts │ │ │ │ └── core.ts │ │ │ ├── Milvus/ │ │ │ │ └── Milvus.ts │ │ │ ├── MongoDBAtlas/ │ │ │ │ ├── MongoDBAtlas.ts │ │ │ │ └── core.ts │ │ │ ├── OpenSearch/ │ │ │ │ └── OpenSearch.ts │ │ │ ├── Pinecone/ │ │ │ │ ├── Pinecone.ts │ │ │ │ └── Pinecone_LlamaIndex.ts │ │ │ ├── Postgres/ │ │ │ │ ├── Postgres.ts │ │ │ │ ├── README.md │ │ │ │ ├── driver/ │ │ │ │ │ ├── Base.ts │ │ │ │ │ ├── PGVector.ts │ │ │ │ │ └── TypeORM.ts │ │ │ │ └── utils.ts │ │ │ ├── Qdrant/ │ │ │ │ └── Qdrant.ts │ │ │ ├── Redis/ │ │ │ │ ├── Redis.ts │ │ │ │ └── utils.ts │ │ │ ├── SimpleStore/ │ │ │ │ └── SimpleStore.ts │ │ │ ├── Singlestore/ │ │ │ │ └── Singlestore.ts │ │ │ ├── Supabase/ │ │ │ │ ├── Supabase.ts │ │ │ │ └── filterParser.ts │ │ │ ├── Upstash/ │ │ │ │ └── Upstash.ts │ │ │ ├── Vectara/ │ │ │ │ ├── Vectara.ts │ │ │ │ └── Vectara_Upload.ts │ │ │ ├── VectorStoreUtils.ts │ │ │ ├── Weaviate/ │ │ │ │ └── Weaviate.ts │ │ │ ├── Zep/ │ │ │ │ └── Zep.ts │ │ │ └── ZepCloud/ │ │ │ └── ZepCloud.ts │ │ ├── package.json │ │ ├── src/ │ │ │ ├── Interface.Evaluation.ts │ │ │ ├── Interface.ts │ │ │ ├── MetricsLogger.ts │ │ │ ├── agentflowv2Generator.ts │ │ │ ├── agents.ts │ │ │ ├── awsToolsUtils.ts │ │ │ ├── error.ts │ │ │ ├── followUpPrompts.ts │ │ │ ├── google-utils.ts │ │ │ ├── handler.test.ts │ │ │ ├── handler.ts │ │ │ ├── httpSecurity.ts │ │ │ ├── index.ts │ │ │ ├── indexing.ts │ │ │ ├── modelLoader.ts │ │ │ ├── multiModalUtils.ts │ │ │ ├── pythonCodeValidator.test.ts │ │ │ ├── pythonCodeValidator.ts │ │ │ ├── secureZodParser.ts │ │ │ ├── speechToText.ts │ │ │ ├── storage/ │ │ │ │ ├── AzureBlobStorageProvider.ts │ │ │ │ ├── BaseStorageProvider.ts │ │ │ │ ├── GCSStorageProvider.ts │ │ │ │ ├── IStorageProvider.ts │ │ │ │ ├── LocalStorageProvider.ts │ │ │ │ ├── S3StorageProvider.ts │ │ │ │ ├── StorageProviderFactory.ts │ │ │ │ └── index.ts │ │ │ ├── storageUtils.ts │ │ │ ├── textToSpeech.ts │ │ │ ├── utils.test.ts │ │ │ ├── utils.ts │ │ │ ├── validator.test.ts │ │ │ └── validator.ts │ │ └── tsconfig.json │ ├── server/ │ │ ├── README-ZH.md │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── bin/ │ │ │ ├── .gitattributes │ │ │ ├── dev │ │ │ ├── dev.cmd │ │ │ ├── run │ │ │ └── run.cmd │ │ ├── cypress/ │ │ │ ├── e2e/ │ │ │ │ ├── 1-apikey/ │ │ │ │ │ └── apikey.cy.js │ │ │ │ └── 2-variables/ │ │ │ │ └── variables.cy.js │ │ │ ├── fixtures/ │ │ │ │ └── .keep │ │ │ └── support/ │ │ │ ├── commands.ts │ │ │ └── e2e.ts │ │ ├── cypress.config.ts │ │ ├── gulpfile.ts │ │ ├── jest.config.js │ │ ├── marketplaces/ │ │ │ ├── agentflows/ │ │ │ │ ├── Agentic RAG.json │ │ │ │ ├── Branch Out Merge In.json │ │ │ │ ├── Customer Support Team Agents.json │ │ │ │ ├── Essay Writing & Grading.json │ │ │ │ ├── Human In Loop RAG.json │ │ │ │ ├── Lead Outreach.json │ │ │ │ ├── Multi Agents.json │ │ │ │ ├── Patient Concierge.json │ │ │ │ ├── Plan and Execute.json │ │ │ │ ├── Portfolio Management Team.json │ │ │ │ ├── Prompt Engineering Team.json │ │ │ │ ├── Software Team.json │ │ │ │ ├── Support Routing System.json │ │ │ │ └── Text to SQL.json │ │ │ ├── agentflowsv2/ │ │ │ │ ├── Agentic RAG.json │ │ │ │ ├── Agents Handoff.json │ │ │ │ ├── Deep Research With Multi-turn Conversations.json │ │ │ │ ├── Deep Research With Subagents.json │ │ │ │ ├── Human In The Loop.json │ │ │ │ ├── Interacting With API.json │ │ │ │ ├── Iterations.json │ │ │ │ ├── SQL Agent.json │ │ │ │ ├── Simple RAG.json │ │ │ │ ├── Structured Output.json │ │ │ │ ├── Supervisor Worker.json │ │ │ │ ├── Translator.json │ │ │ │ └── Workplace Chat.json │ │ │ ├── chatflows/ │ │ │ │ ├── Advanced Structured Output Parser.json │ │ │ │ ├── CSV Agent.json │ │ │ │ ├── Context Chat Engine.json │ │ │ │ ├── Conversation Chain.json │ │ │ │ ├── Conversational Agent.json │ │ │ │ ├── Conversational Retrieval QA Chain.json │ │ │ │ ├── Github Docs QnA.json │ │ │ │ ├── HuggingFace LLM Chain.json │ │ │ │ ├── Image Generation.json │ │ │ │ ├── Input Moderation.json │ │ │ │ ├── LLM Chain.json │ │ │ │ ├── List Output Parser.json │ │ │ │ ├── Local QnA.json │ │ │ │ ├── Multiple Documents QnA.json │ │ │ │ ├── OpenAI Assistant.json │ │ │ │ ├── OpenAPI YAML Agent.json │ │ │ │ ├── Prompt Chaining.json │ │ │ │ ├── Query Engine.json │ │ │ │ ├── ReAct Agent.json │ │ │ │ ├── Replicate LLM.json │ │ │ │ ├── SQL DB Chain.json │ │ │ │ ├── Simple Chat Engine.json │ │ │ │ ├── SubQuestion Query Engine.json │ │ │ │ └── Tool Agent.json │ │ │ └── tools/ │ │ │ ├── Add Hubspot Contact.json │ │ │ ├── Create Airtable Record.json │ │ │ ├── Get Current DateTime.json │ │ │ ├── Get Stock Mover.json │ │ │ ├── Make Webhook.json │ │ │ ├── Perplexity AI Search.json │ │ │ ├── Print or Export Text Document.json │ │ │ ├── Send Discord Message.json │ │ │ ├── Send Slack Message.json │ │ │ ├── Send Teams Message.json │ │ │ ├── SendGrid Email.json │ │ │ ├── Spider Web Scraper.json │ │ │ └── Spider Web Search & Scrape.json │ │ ├── nodemon.json │ │ ├── package.json │ │ ├── src/ │ │ │ ├── AbortControllerPool.ts │ │ │ ├── AppConfig.ts │ │ │ ├── CachePool.ts │ │ │ ├── DataSource.ts │ │ │ ├── IdentityManager.ts │ │ │ ├── Interface.DocumentStore.ts │ │ │ ├── Interface.Evaluation.ts │ │ │ ├── Interface.Metrics.ts │ │ │ ├── Interface.ts │ │ │ ├── NodesPool.ts │ │ │ ├── StripeManager.ts │ │ │ ├── UsageCacheManager.ts │ │ │ ├── commands/ │ │ │ │ ├── base.ts │ │ │ │ ├── start.ts │ │ │ │ ├── user.ts │ │ │ │ └── worker.ts │ │ │ ├── controllers/ │ │ │ │ ├── agentflowv2-generator/ │ │ │ │ │ └── index.ts │ │ │ │ ├── apikey/ │ │ │ │ │ └── index.ts │ │ │ │ ├── assistants/ │ │ │ │ │ └── index.ts │ │ │ │ ├── attachments/ │ │ │ │ │ └── index.ts │ │ │ │ ├── chat-messages/ │ │ │ │ │ └── index.ts │ │ │ │ ├── chatflows/ │ │ │ │ │ └── index.ts │ │ │ │ ├── components-credentials/ │ │ │ │ │ └── index.ts │ │ │ │ ├── credentials/ │ │ │ │ │ └── index.ts │ │ │ │ ├── dataset/ │ │ │ │ │ └── index.ts │ │ │ │ ├── documentstore/ │ │ │ │ │ └── index.ts │ │ │ │ ├── evaluations/ │ │ │ │ │ └── index.ts │ │ │ │ ├── evaluators/ │ │ │ │ │ └── index.ts │ │ │ │ ├── executions/ │ │ │ │ │ └── index.ts │ │ │ │ ├── export-import/ │ │ │ │ │ └── index.ts │ │ │ │ ├── feedback/ │ │ │ │ │ └── index.ts │ │ │ │ ├── fetch-links/ │ │ │ │ │ └── index.ts │ │ │ │ ├── files/ │ │ │ │ │ └── index.ts │ │ │ │ ├── flow-configs/ │ │ │ │ │ └── index.ts │ │ │ │ ├── get-upload-file/ │ │ │ │ │ └── index.ts │ │ │ │ ├── internal-predictions/ │ │ │ │ │ └── index.ts │ │ │ │ ├── leads/ │ │ │ │ │ └── index.ts │ │ │ │ ├── load-prompts/ │ │ │ │ │ └── index.ts │ │ │ │ ├── log/ │ │ │ │ │ └── index.ts │ │ │ │ ├── marketplaces/ │ │ │ │ │ └── index.ts │ │ │ │ ├── node-configs/ │ │ │ │ │ └── index.ts │ │ │ │ ├── node-icons/ │ │ │ │ │ └── index.ts │ │ │ │ ├── nodes/ │ │ │ │ │ └── index.ts │ │ │ │ ├── nvidia-nim/ │ │ │ │ │ └── index.ts │ │ │ │ ├── openai-assistants/ │ │ │ │ │ └── index.ts │ │ │ │ ├── openai-assistants-vector-store/ │ │ │ │ │ └── index.ts │ │ │ │ ├── openai-realtime/ │ │ │ │ │ └── index.ts │ │ │ │ ├── ping/ │ │ │ │ │ └── index.ts │ │ │ │ ├── predictions/ │ │ │ │ │ └── index.ts │ │ │ │ ├── pricing/ │ │ │ │ │ └── index.ts │ │ │ │ ├── prompts-lists/ │ │ │ │ │ └── index.ts │ │ │ │ ├── settings/ │ │ │ │ │ └── index.ts │ │ │ │ ├── stats/ │ │ │ │ │ └── index.ts │ │ │ │ ├── text-to-speech/ │ │ │ │ │ └── index.ts │ │ │ │ ├── tools/ │ │ │ │ │ └── index.ts │ │ │ │ ├── upsert-history/ │ │ │ │ │ └── index.ts │ │ │ │ ├── validation/ │ │ │ │ │ └── index.ts │ │ │ │ ├── variables/ │ │ │ │ │ └── index.ts │ │ │ │ ├── vectors/ │ │ │ │ │ └── index.ts │ │ │ │ └── versions/ │ │ │ │ └── index.ts │ │ │ ├── database/ │ │ │ │ ├── entities/ │ │ │ │ │ ├── ApiKey.ts │ │ │ │ │ ├── Assistant.ts │ │ │ │ │ ├── ChatFlow.ts │ │ │ │ │ ├── ChatMessage.ts │ │ │ │ │ ├── ChatMessageFeedback.ts │ │ │ │ │ ├── Credential.ts │ │ │ │ │ ├── CustomTemplate.ts │ │ │ │ │ ├── Dataset.ts │ │ │ │ │ ├── DatasetRow.ts │ │ │ │ │ ├── DocumentStore.ts │ │ │ │ │ ├── DocumentStoreFileChunk.ts │ │ │ │ │ ├── Evaluation.ts │ │ │ │ │ ├── EvaluationRun.ts │ │ │ │ │ ├── Evaluator.ts │ │ │ │ │ ├── Execution.ts │ │ │ │ │ ├── Lead.ts │ │ │ │ │ ├── Tool.ts │ │ │ │ │ ├── UpsertHistory.ts │ │ │ │ │ ├── Variable.ts │ │ │ │ │ └── index.ts │ │ │ │ └── migrations/ │ │ │ │ ├── mariadb/ │ │ │ │ │ ├── 1693840429259-Init.ts │ │ │ │ │ ├── 1693997791471-ModifyChatFlow.ts │ │ │ │ │ ├── 1693999022236-ModifyChatMessage.ts │ │ │ │ │ ├── 1693999261583-ModifyCredential.ts │ │ │ │ │ ├── 1694001465232-ModifyTool.ts │ │ │ │ │ ├── 1694099200729-AddApiConfig.ts │ │ │ │ │ ├── 1694432361423-AddAnalytic.ts │ │ │ │ │ ├── 1694658767766-AddChatHistory.ts │ │ │ │ │ ├── 1699325775451-AddAssistantEntity.ts │ │ │ │ │ ├── 1699481607341-AddUsedToolsToChatMessage.ts │ │ │ │ │ ├── 1699900910291-AddCategoryToChatFlow.ts │ │ │ │ │ ├── 1700271021237-AddFileAnnotationsToChatMessage.ts │ │ │ │ │ ├── 1701788586491-AddFileUploadsToChatMessage.ts │ │ │ │ │ ├── 1702200925471-AddVariableEntity.ts │ │ │ │ │ ├── 1706364937060-AddSpeechToText.ts │ │ │ │ │ ├── 1707213626553-AddFeedback.ts │ │ │ │ │ ├── 1709814301358-AddUpsertHistoryEntity.ts │ │ │ │ │ ├── 1710832127079-AddLead.ts │ │ │ │ │ ├── 1711538023578-AddLeadToChatMessage.ts │ │ │ │ │ ├── 1711637331047-AddDocumentStore.ts │ │ │ │ │ ├── 1714548873039-AddEvaluation.ts │ │ │ │ │ ├── 1714548903384-AddDataset.ts │ │ │ │ │ ├── 1714679514451-AddAgentReasoningToChatMessage.ts │ │ │ │ │ ├── 1714808591644-AddEvaluator.ts │ │ │ │ │ ├── 1715861032479-AddVectorStoreConfigToDocStore.ts │ │ │ │ │ ├── 1716300000000-AddTypeToChatFlow.ts │ │ │ │ │ ├── 1720230151480-AddApiKey.ts │ │ │ │ │ ├── 1721078251523-AddActionToChatMessage.ts │ │ │ │ │ ├── 1722301395521-LongTextColumn.ts │ │ │ │ │ ├── 1725629836652-AddCustomTemplate.ts │ │ │ │ │ ├── 1726156258465-AddArtifactsToChatMessage.ts │ │ │ │ │ ├── 1726666318346-AddFollowUpPrompts.ts │ │ │ │ │ ├── 1733011290987-AddTypeToAssistant.ts │ │ │ │ │ ├── 1733752119696-AddSeqNoToDatasetRow.ts │ │ │ │ │ ├── 1738090872625-AddExecutionEntity.ts │ │ │ │ │ ├── 1743758056188-FixOpenSourceAssistantTable.ts │ │ │ │ │ ├── 1744964560174-AddErrorToEvaluationRun.ts │ │ │ │ │ ├── 1747902489801-ModifyExecutionDataColumnType.ts │ │ │ │ │ ├── 1754986457485-AddTextToSpeechToChatFlow.ts │ │ │ │ │ ├── 1755066758601-ModifyChatflowType.ts │ │ │ │ │ ├── 1759419231100-AddTextToSpeechToChatFlow.ts │ │ │ │ │ ├── 1759424809984-AddChatFlowNameIndex.ts │ │ │ │ │ ├── 1764759496768-AddReasonContentToChatMessage.ts │ │ │ │ │ ├── 1765000000000-FixDocumentStoreFileChunkLongText.ts │ │ │ │ │ ├── 1765360298674-AddApiKeyPermission.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── mysql/ │ │ │ │ │ ├── 1693840429259-Init.ts │ │ │ │ │ ├── 1693997791471-ModifyChatFlow.ts │ │ │ │ │ ├── 1693999022236-ModifyChatMessage.ts │ │ │ │ │ ├── 1693999261583-ModifyCredential.ts │ │ │ │ │ ├── 1694001465232-ModifyTool.ts │ │ │ │ │ ├── 1694099200729-AddApiConfig.ts │ │ │ │ │ ├── 1694432361423-AddAnalytic.ts │ │ │ │ │ ├── 1694658767766-AddChatHistory.ts │ │ │ │ │ ├── 1699325775451-AddAssistantEntity.ts │ │ │ │ │ ├── 1699481607341-AddUsedToolsToChatMessage.ts │ │ │ │ │ ├── 1699900910291-AddCategoryToChatFlow.ts │ │ │ │ │ ├── 1700271021237-AddFileAnnotationsToChatMessage.ts │ │ │ │ │ ├── 1701788586491-AddFileUploadsToChatMessage.ts │ │ │ │ │ ├── 1702200925471-AddVariableEntity.ts │ │ │ │ │ ├── 1706364937060-AddSpeechToText.ts │ │ │ │ │ ├── 1707213626553-AddFeedback.ts │ │ │ │ │ ├── 1709814301358-AddUpsertHistoryEntity.ts │ │ │ │ │ ├── 1710832127079-AddLead.ts │ │ │ │ │ ├── 1711538023578-AddLeadToChatMessage.ts │ │ │ │ │ ├── 1711637331047-AddDocumentStore.ts │ │ │ │ │ ├── 1714548873039-AddEvaluation.ts │ │ │ │ │ ├── 1714548903384-AddDataset.ts │ │ │ │ │ ├── 1714679514451-AddAgentReasoningToChatMessage.ts │ │ │ │ │ ├── 1714808591644-AddEvaluator.ts │ │ │ │ │ ├── 1715861032479-AddVectorStoreConfigToDocStore.ts │ │ │ │ │ ├── 1716300000000-AddTypeToChatFlow.ts │ │ │ │ │ ├── 1720230151480-AddApiKey.ts │ │ │ │ │ ├── 1721078251523-AddActionToChatMessage.ts │ │ │ │ │ ├── 1722301395521-LongTextColumn.ts │ │ │ │ │ ├── 1725629836652-AddCustomTemplate.ts │ │ │ │ │ ├── 1726156258465-AddArtifactsToChatMessage.ts │ │ │ │ │ ├── 1726666302024-AddFollowUpPrompts.ts │ │ │ │ │ ├── 1733011290987-AddTypeToAssistant.ts │ │ │ │ │ ├── 1733752119696-AddSeqNoToDatasetRow.ts │ │ │ │ │ ├── 1738090872625-AddExecutionEntity.ts │ │ │ │ │ ├── 1743758056188-FixOpenSourceAssistantTable.ts │ │ │ │ │ ├── 1744964560174-AddErrorToEvaluationRun.ts │ │ │ │ │ ├── 1746437114935-FixErrorsColumnInEvaluationRun.ts │ │ │ │ │ ├── 1747902489801-ModifyExecutionDataColumnType.ts │ │ │ │ │ ├── 1754986468397-AddTextToSpeechToChatFlow.ts │ │ │ │ │ ├── 1755066758601-ModifyChatflowType.ts │ │ │ │ │ ├── 1759419216034-AddTextToSpeechToChatFlow.ts │ │ │ │ │ ├── 1759424828558-AddChatFlowNameIndex.ts │ │ │ │ │ ├── 1764759496768-AddReasonContentToChatMessage.ts │ │ │ │ │ ├── 1765000000000-FixDocumentStoreFileChunkLongText.ts │ │ │ │ │ ├── 1765360298674-AddApiKeyPermission.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── postgres/ │ │ │ │ │ ├── 1693891895163-Init.ts │ │ │ │ │ ├── 1693995626941-ModifyChatFlow.ts │ │ │ │ │ ├── 1693996694528-ModifyChatMessage.ts │ │ │ │ │ ├── 1693997070000-ModifyCredential.ts │ │ │ │ │ ├── 1693997339912-ModifyTool.ts │ │ │ │ │ ├── 1694099183389-AddApiConfig.ts │ │ │ │ │ ├── 1694432361423-AddAnalytic.ts │ │ │ │ │ ├── 1694658756136-AddChatHistory.ts │ │ │ │ │ ├── 1699325775451-AddAssistantEntity.ts │ │ │ │ │ ├── 1699481607341-AddUsedToolsToChatMessage.ts │ │ │ │ │ ├── 1699900910291-AddCategoryToChatFlow.ts │ │ │ │ │ ├── 1700271021237-AddFileAnnotationsToChatMessage.ts │ │ │ │ │ ├── 1701788586491-AddFileUploadsToChatMessage.ts │ │ │ │ │ ├── 1702200925471-AddVariableEntity.ts │ │ │ │ │ ├── 1706364937060-AddSpeechToText.ts │ │ │ │ │ ├── 1707213601923-AddFeedback.ts │ │ │ │ │ ├── 1709814301358-AddUpsertHistoryEntity.ts │ │ │ │ │ ├── 1710497452584-FieldTypes.ts │ │ │ │ │ ├── 1710832137905-AddLead.ts │ │ │ │ │ ├── 1711538016098-AddLeadToChatMessage.ts │ │ │ │ │ ├── 1711637331047-AddDocumentStore.ts │ │ │ │ │ ├── 1714548873039-AddEvaluation.ts │ │ │ │ │ ├── 1714548903384-AddDataset.ts │ │ │ │ │ ├── 1714679514451-AddAgentReasoningToChatMessage.ts │ │ │ │ │ ├── 1714808591644-AddEvaluator.ts │ │ │ │ │ ├── 1715861032479-AddVectorStoreConfigToDocStore.ts │ │ │ │ │ ├── 1716300000000-AddTypeToChatFlow.ts │ │ │ │ │ ├── 1720230151480-AddApiKey.ts │ │ │ │ │ ├── 1721078251523-AddActionToChatMessage.ts │ │ │ │ │ ├── 1725629836652-AddCustomTemplate.ts │ │ │ │ │ ├── 1726156258465-AddArtifactsToChatMessage.ts │ │ │ │ │ ├── 1726666309552-AddFollowUpPrompts.ts │ │ │ │ │ ├── 1733011290987-AddTypeToAssistant.ts │ │ │ │ │ ├── 1733752119696-AddSeqNoToDatasetRow.ts │ │ │ │ │ ├── 1738090872625-AddExecutionEntity.ts │ │ │ │ │ ├── 1743758056188-FixOpenSourceAssistantTable.ts │ │ │ │ │ ├── 1744964560174-AddErrorToEvaluationRun.ts │ │ │ │ │ ├── 1748450230238-ModifyExecutionSessionIdFieldType.ts │ │ │ │ │ ├── 1754986480347-AddTextToSpeechToChatFlow.ts │ │ │ │ │ ├── 1755066758601-ModifyChatflowType.ts │ │ │ │ │ ├── 1759419194331-AddTextToSpeechToChatFlow.ts │ │ │ │ │ ├── 1759424903973-AddChatFlowNameIndex.ts │ │ │ │ │ ├── 1764759496768-AddReasonContentToChatMessage.ts │ │ │ │ │ ├── 1765360298674-AddApiKeyPermission.ts │ │ │ │ │ └── index.ts │ │ │ │ └── sqlite/ │ │ │ │ ├── 1693835579790-Init.ts │ │ │ │ ├── 1693920824108-ModifyChatFlow.ts │ │ │ │ ├── 1693921865247-ModifyChatMessage.ts │ │ │ │ ├── 1693923551694-ModifyCredential.ts │ │ │ │ ├── 1693924207475-ModifyTool.ts │ │ │ │ ├── 1694090982460-AddApiConfig.ts │ │ │ │ ├── 1694432361423-AddAnalytic.ts │ │ │ │ ├── 1694657778173-AddChatHistory.ts │ │ │ │ ├── 1699325775451-AddAssistantEntity.ts │ │ │ │ ├── 1699481607341-AddUsedToolsToChatMessage.ts │ │ │ │ ├── 1699900910291-AddCategoryToChatFlow.ts │ │ │ │ ├── 1700271021237-AddFileAnnotationsToChatMessage.ts │ │ │ │ ├── 1701788586491-AddFileUploadsToChatMessage.ts │ │ │ │ ├── 1702200925471-AddVariableEntity.ts │ │ │ │ ├── 1706364937060-AddSpeechToText.ts │ │ │ │ ├── 1707213619308-AddFeedback.ts │ │ │ │ ├── 1709814301358-AddUpsertHistoryEntity.ts │ │ │ │ ├── 1710832117612-AddLead.ts │ │ │ │ ├── 1711537986113-AddLeadToChatMessage.ts │ │ │ │ ├── 1711637331047-AddDocumentStore.ts │ │ │ │ ├── 1714548873039-AddEvaluation.ts │ │ │ │ ├── 1714548903384-AddDataset.ts │ │ │ │ ├── 1714679514451-AddAgentReasoningToChatMessage.ts │ │ │ │ ├── 1714808591644-AddEvaluator.ts │ │ │ │ ├── 1715861032479-AddVectorStoreConfigToDocStore.ts │ │ │ │ ├── 1716300000000-AddTypeToChatFlow.ts │ │ │ │ ├── 1720230151480-AddApiKey.ts │ │ │ │ ├── 1721078251523-AddActionToChatMessage.ts │ │ │ │ ├── 1725629836652-AddCustomTemplate.ts │ │ │ │ ├── 1726156258465-AddArtifactsToChatMessage.ts │ │ │ │ ├── 1726666294213-AddFollowUpPrompts.ts │ │ │ │ ├── 1733011290987-AddTypeToAssistant.ts │ │ │ │ ├── 1733752119696-AddSeqNoToDatasetRow.ts │ │ │ │ ├── 1738090872625-AddExecutionEntity.ts │ │ │ │ ├── 1743758056188-FixOpenSourceAssistantTable.ts │ │ │ │ ├── 1744964560174-AddErrorToEvaluationRun.ts │ │ │ │ ├── 1754986486669-AddTextToSpeechToChatFlow.ts │ │ │ │ ├── 1755066758601-ModifyChatflowType.ts │ │ │ │ ├── 1759419136055-AddTextToSpeechToChatFlow.ts │ │ │ │ ├── 1759424923093-AddChatFlowNameIndex.ts │ │ │ │ ├── 1764759496768-AddReasonContentToChatMessage.ts │ │ │ │ ├── 1765360298674-AddApiKeyPermission.ts │ │ │ │ └── index.ts │ │ │ ├── enterprise/ │ │ │ │ ├── Interface.Enterprise.ts │ │ │ │ ├── LICENSE.md │ │ │ │ ├── controllers/ │ │ │ │ │ ├── account.controller.ts │ │ │ │ │ ├── audit/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── auth/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── login-method.controller.ts │ │ │ │ │ ├── organization-user.controller.ts │ │ │ │ │ ├── organization.controller.ts │ │ │ │ │ ├── role.controller.ts │ │ │ │ │ ├── user.controller.ts │ │ │ │ │ ├── workspace-user.controller.ts │ │ │ │ │ └── workspace.controller.ts │ │ │ │ ├── database/ │ │ │ │ │ ├── entities/ │ │ │ │ │ │ ├── EnterpriseEntities.ts │ │ │ │ │ │ ├── login-method.entity.ts │ │ │ │ │ │ ├── login-session.entity.ts │ │ │ │ │ │ ├── organization-user.entity.ts │ │ │ │ │ │ ├── organization.entity.ts │ │ │ │ │ │ ├── role.entity.ts │ │ │ │ │ │ ├── user.entity.ts │ │ │ │ │ │ ├── workspace-user.entity.ts │ │ │ │ │ │ └── workspace.entity.ts │ │ │ │ │ └── migrations/ │ │ │ │ │ ├── mariadb/ │ │ │ │ │ │ ├── 1720230151482-AddAuthTables.ts │ │ │ │ │ │ ├── 1725437498242-AddWorkspace.ts │ │ │ │ │ │ ├── 1726654922034-AddWorkspaceShared.ts │ │ │ │ │ │ ├── 1726655750383-AddWorkspaceIdToCustomTemplate.ts │ │ │ │ │ │ ├── 1727798417345-AddOrganization.ts │ │ │ │ │ │ ├── 1729130948686-LinkWorkspaceId.ts │ │ │ │ │ │ ├── 1729133111652-LinkOrganizationId.ts │ │ │ │ │ │ ├── 1730519457880-AddSSOColumns.ts │ │ │ │ │ │ ├── 1734074497540-AddPersonalWorkspace.ts │ │ │ │ │ │ ├── 1737076223692-RefactorEnterpriseDatabase.ts │ │ │ │ │ │ ├── 1746862866554-ExecutionLinkWorkspaceId.ts │ │ │ │ │ │ └── mariaDbCustomFunctions.ts │ │ │ │ │ ├── mysql/ │ │ │ │ │ │ ├── 1720230151482-AddAuthTables.ts │ │ │ │ │ │ ├── 1720230151484-AddWorkspace.ts │ │ │ │ │ │ ├── 1726654922034-AddWorkspaceShared.ts │ │ │ │ │ │ ├── 1726655750383-AddWorkspaceIdToCustomTemplate.ts │ │ │ │ │ │ ├── 1727798417345-AddOrganization.ts │ │ │ │ │ │ ├── 1729130948686-LinkWorkspaceId.ts │ │ │ │ │ │ ├── 1729133111652-LinkOrganizationId.ts │ │ │ │ │ │ ├── 1730519457880-AddSSOColumns.ts │ │ │ │ │ │ ├── 1734074497540-AddPersonalWorkspace.ts │ │ │ │ │ │ ├── 1737076223692-RefactorEnterpriseDatabase.ts │ │ │ │ │ │ ├── 1746862866554-ExecutionLinkWorkspaceId.ts │ │ │ │ │ │ └── mysqlCustomFunctions.ts │ │ │ │ │ ├── postgres/ │ │ │ │ │ │ ├── 1720230151482-AddAuthTables.ts │ │ │ │ │ │ ├── 1720230151484-AddWorkspace.ts │ │ │ │ │ │ ├── 1726654922034-AddWorkspaceShared.ts │ │ │ │ │ │ ├── 1726655750383-AddWorkspaceIdToCustomTemplate.ts │ │ │ │ │ │ ├── 1727798417345-AddOrganization.ts │ │ │ │ │ │ ├── 1729130948686-LinkWorkspaceId.ts │ │ │ │ │ │ ├── 1729133111652-LinkOrganizationId.ts │ │ │ │ │ │ ├── 1730519457880-AddSSOColumns.ts │ │ │ │ │ │ ├── 1734074497540-AddPersonalWorkspace.ts │ │ │ │ │ │ ├── 1737076223692-RefactorEnterpriseDatabase.ts │ │ │ │ │ │ └── 1746862866554-ExecutionLinkWorkspaceId.ts │ │ │ │ │ └── sqlite/ │ │ │ │ │ ├── 1720230151482-AddAuthTables.ts │ │ │ │ │ ├── 1720230151484-AddWorkspace.ts │ │ │ │ │ ├── 1726654922034-AddWorkspaceShared.ts │ │ │ │ │ ├── 1726655750383-AddWorkspaceIdToCustomTemplate.ts │ │ │ │ │ ├── 1727798417345-AddOrganization.ts │ │ │ │ │ ├── 1729130948686-LinkWorkspaceId.ts │ │ │ │ │ ├── 1729133111652-LinkOrganizationId.ts │ │ │ │ │ ├── 1730519457880-AddSSOColumns.ts │ │ │ │ │ ├── 1734074497540-AddPersonalWorkspace.ts │ │ │ │ │ ├── 1737076223692-RefactorEnterpriseDatabase.ts │ │ │ │ │ ├── 1746862866554-ExecutionLinkWorkspaceId.ts │ │ │ │ │ └── sqlliteCustomFunctions.ts │ │ │ │ ├── emails/ │ │ │ │ │ ├── verify_email_cloud.hbs │ │ │ │ │ ├── verify_email_cloud.html │ │ │ │ │ ├── workspace_add_cloud.hbs │ │ │ │ │ ├── workspace_add_cloud.html │ │ │ │ │ ├── workspace_new_invite_cloud.hbs │ │ │ │ │ ├── workspace_new_invite_cloud.html │ │ │ │ │ ├── workspace_new_invite_enterprise.hbs │ │ │ │ │ ├── workspace_new_invite_enterprise.html │ │ │ │ │ ├── workspace_update_invite_cloud.hbs │ │ │ │ │ ├── workspace_update_invite_cloud.html │ │ │ │ │ ├── workspace_update_invite_enterprise.hbs │ │ │ │ │ ├── workspace_update_invite_enterprise.html │ │ │ │ │ ├── workspace_user_reset_password.hbs │ │ │ │ │ └── workspace_user_reset_password.html │ │ │ │ ├── middleware/ │ │ │ │ │ ├── passport/ │ │ │ │ │ │ ├── AuthStrategy.ts │ │ │ │ │ │ ├── SessionPersistance.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── prometheus/ │ │ │ │ │ └── index.ts │ │ │ │ ├── rbac/ │ │ │ │ │ ├── PermissionCheck.ts │ │ │ │ │ └── Permissions.ts │ │ │ │ ├── routes/ │ │ │ │ │ ├── account.route.ts │ │ │ │ │ ├── audit/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── auth/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── login-method.route.ts │ │ │ │ │ ├── organization-user.route.ts │ │ │ │ │ ├── organization.route.ts │ │ │ │ │ ├── role.route.ts │ │ │ │ │ ├── user.route.ts │ │ │ │ │ ├── workspace-user.route.ts │ │ │ │ │ └── workspace.route.ts │ │ │ │ ├── services/ │ │ │ │ │ ├── account.service.ts │ │ │ │ │ ├── audit/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── login-method.service.ts │ │ │ │ │ ├── organization-user.service.ts │ │ │ │ │ ├── organization.service.ts │ │ │ │ │ ├── role.service.ts │ │ │ │ │ ├── user.service.ts │ │ │ │ │ ├── workspace-user.service.ts │ │ │ │ │ └── workspace.service.ts │ │ │ │ ├── sso/ │ │ │ │ │ ├── Auth0SSO.ts │ │ │ │ │ ├── AzureSSO.ts │ │ │ │ │ ├── GithubSSO.ts │ │ │ │ │ ├── GoogleSSO.ts │ │ │ │ │ └── SSOBase.ts │ │ │ │ └── utils/ │ │ │ │ ├── ControllerServiceUtils.ts │ │ │ │ ├── authSecrets.ts │ │ │ │ ├── encryption.util.ts │ │ │ │ ├── sendEmail.ts │ │ │ │ ├── tempTokenUtils.ts │ │ │ │ ├── url.util.test.ts │ │ │ │ ├── url.util.ts │ │ │ │ └── validation.util.ts │ │ │ ├── errors/ │ │ │ │ ├── internalFlowiseError/ │ │ │ │ │ └── index.ts │ │ │ │ └── utils.ts │ │ │ ├── index.ts │ │ │ ├── metrics/ │ │ │ │ ├── OpenTelemetry.ts │ │ │ │ └── Prometheus.ts │ │ │ ├── middlewares/ │ │ │ │ └── errors/ │ │ │ │ └── index.ts │ │ │ ├── queue/ │ │ │ │ ├── BaseQueue.ts │ │ │ │ ├── PredictionQueue.ts │ │ │ │ ├── QueueManager.ts │ │ │ │ ├── RedisEventPublisher.ts │ │ │ │ ├── RedisEventSubscriber.ts │ │ │ │ └── UpsertQueue.ts │ │ │ ├── routes/ │ │ │ │ ├── agentflowv2-generator/ │ │ │ │ │ └── index.ts │ │ │ │ ├── apikey/ │ │ │ │ │ └── index.ts │ │ │ │ ├── assistants/ │ │ │ │ │ └── index.ts │ │ │ │ ├── attachments/ │ │ │ │ │ └── index.ts │ │ │ │ ├── chat-messages/ │ │ │ │ │ └── index.ts │ │ │ │ ├── chatflows/ │ │ │ │ │ └── index.ts │ │ │ │ ├── chatflows-streaming/ │ │ │ │ │ └── index.ts │ │ │ │ ├── chatflows-uploads/ │ │ │ │ │ └── index.ts │ │ │ │ ├── components-credentials/ │ │ │ │ │ └── index.ts │ │ │ │ ├── components-credentials-icon/ │ │ │ │ │ └── index.ts │ │ │ │ ├── credentials/ │ │ │ │ │ └── index.ts │ │ │ │ ├── dataset/ │ │ │ │ │ └── index.ts │ │ │ │ ├── documentstore/ │ │ │ │ │ └── index.ts │ │ │ │ ├── evaluations/ │ │ │ │ │ └── index.ts │ │ │ │ ├── evaluator/ │ │ │ │ │ └── index.ts │ │ │ │ ├── executions/ │ │ │ │ │ └── index.ts │ │ │ │ ├── export-import/ │ │ │ │ │ └── index.ts │ │ │ │ ├── feedback/ │ │ │ │ │ └── index.ts │ │ │ │ ├── fetch-links/ │ │ │ │ │ └── index.ts │ │ │ │ ├── files/ │ │ │ │ │ └── index.ts │ │ │ │ ├── flow-config/ │ │ │ │ │ └── index.ts │ │ │ │ ├── get-upload-file/ │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── internal-chat-messages/ │ │ │ │ │ └── index.ts │ │ │ │ ├── internal-predictions/ │ │ │ │ │ └── index.ts │ │ │ │ ├── leads/ │ │ │ │ │ └── index.ts │ │ │ │ ├── load-prompts/ │ │ │ │ │ └── index.ts │ │ │ │ ├── log/ │ │ │ │ │ └── index.ts │ │ │ │ ├── marketplaces/ │ │ │ │ │ └── index.ts │ │ │ │ ├── node-configs/ │ │ │ │ │ └── index.ts │ │ │ │ ├── node-custom-functions/ │ │ │ │ │ └── index.ts │ │ │ │ ├── node-icons/ │ │ │ │ │ └── index.ts │ │ │ │ ├── node-load-methods/ │ │ │ │ │ └── index.ts │ │ │ │ ├── nodes/ │ │ │ │ │ └── index.ts │ │ │ │ ├── nvidia-nim/ │ │ │ │ │ └── index.ts │ │ │ │ ├── oauth2/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── templates.ts │ │ │ │ ├── openai-assistants/ │ │ │ │ │ └── index.ts │ │ │ │ ├── openai-assistants-files/ │ │ │ │ │ └── index.ts │ │ │ │ ├── openai-assistants-vector-store/ │ │ │ │ │ └── index.ts │ │ │ │ ├── openai-realtime/ │ │ │ │ │ └── index.ts │ │ │ │ ├── ping/ │ │ │ │ │ └── index.ts │ │ │ │ ├── predictions/ │ │ │ │ │ └── index.ts │ │ │ │ ├── pricing/ │ │ │ │ │ └── index.ts │ │ │ │ ├── prompts-lists/ │ │ │ │ │ └── index.ts │ │ │ │ ├── public-chatbots/ │ │ │ │ │ └── index.ts │ │ │ │ ├── public-chatflows/ │ │ │ │ │ └── index.ts │ │ │ │ ├── public-executions/ │ │ │ │ │ └── index.ts │ │ │ │ ├── settings/ │ │ │ │ │ └── index.ts │ │ │ │ ├── stats/ │ │ │ │ │ └── index.ts │ │ │ │ ├── text-to-speech/ │ │ │ │ │ └── index.ts │ │ │ │ ├── tools/ │ │ │ │ │ └── index.ts │ │ │ │ ├── upsert-history/ │ │ │ │ │ └── index.ts │ │ │ │ ├── validation/ │ │ │ │ │ └── index.ts │ │ │ │ ├── variables/ │ │ │ │ │ └── index.ts │ │ │ │ ├── vectors/ │ │ │ │ │ └── index.ts │ │ │ │ ├── verify/ │ │ │ │ │ └── index.ts │ │ │ │ └── versions/ │ │ │ │ └── index.ts │ │ │ ├── services/ │ │ │ │ ├── agentflowv2-generator/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── prompt.ts │ │ │ │ ├── apikey/ │ │ │ │ │ └── index.ts │ │ │ │ ├── assistants/ │ │ │ │ │ └── index.ts │ │ │ │ ├── attachments/ │ │ │ │ │ └── index.ts │ │ │ │ ├── chat-messages/ │ │ │ │ │ └── index.ts │ │ │ │ ├── chatflows/ │ │ │ │ │ └── index.ts │ │ │ │ ├── components-credentials/ │ │ │ │ │ └── index.ts │ │ │ │ ├── credentials/ │ │ │ │ │ └── index.ts │ │ │ │ ├── dataset/ │ │ │ │ │ └── index.ts │ │ │ │ ├── documentstore/ │ │ │ │ │ └── index.ts │ │ │ │ ├── evaluations/ │ │ │ │ │ ├── CostCalculator.ts │ │ │ │ │ ├── EvaluatorRunner.ts │ │ │ │ │ ├── LLMEvaluationRunner.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── evaluator/ │ │ │ │ │ └── index.ts │ │ │ │ ├── executions/ │ │ │ │ │ └── index.ts │ │ │ │ ├── export-import/ │ │ │ │ │ └── index.ts │ │ │ │ ├── feedback/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── validation.ts │ │ │ │ ├── fetch-links/ │ │ │ │ │ └── index.ts │ │ │ │ ├── flow-configs/ │ │ │ │ │ └── index.ts │ │ │ │ ├── leads/ │ │ │ │ │ └── index.ts │ │ │ │ ├── load-prompts/ │ │ │ │ │ └── index.ts │ │ │ │ ├── log/ │ │ │ │ │ └── index.ts │ │ │ │ ├── marketplaces/ │ │ │ │ │ └── index.ts │ │ │ │ ├── node-configs/ │ │ │ │ │ └── index.ts │ │ │ │ ├── nodes/ │ │ │ │ │ └── index.ts │ │ │ │ ├── openai-assistants/ │ │ │ │ │ └── index.ts │ │ │ │ ├── openai-assistants-vector-store/ │ │ │ │ │ └── index.ts │ │ │ │ ├── openai-realtime/ │ │ │ │ │ └── index.ts │ │ │ │ ├── predictions/ │ │ │ │ │ └── index.ts │ │ │ │ ├── prompts-lists/ │ │ │ │ │ └── index.ts │ │ │ │ ├── settings/ │ │ │ │ │ └── index.ts │ │ │ │ ├── stats/ │ │ │ │ │ └── index.ts │ │ │ │ ├── text-to-speech/ │ │ │ │ │ └── index.ts │ │ │ │ ├── tools/ │ │ │ │ │ └── index.ts │ │ │ │ ├── upsert-history/ │ │ │ │ │ └── index.ts │ │ │ │ ├── validation/ │ │ │ │ │ └── index.ts │ │ │ │ ├── variables/ │ │ │ │ │ └── index.ts │ │ │ │ ├── vectors/ │ │ │ │ │ └── index.ts │ │ │ │ └── versions/ │ │ │ │ └── index.ts │ │ │ └── utils/ │ │ │ ├── SSEStreamer.ts │ │ │ ├── XSS.ts │ │ │ ├── addChatMesage.ts │ │ │ ├── addChatMessageFeedback.ts │ │ │ ├── addChatflowsCount.ts │ │ │ ├── apiKey.test.ts │ │ │ ├── apiKey.ts │ │ │ ├── buildAgentGraph.ts │ │ │ ├── buildAgentflow.ts │ │ │ ├── buildChatflow.ts │ │ │ ├── config.ts │ │ │ ├── constants.ts │ │ │ ├── createAttachment.ts │ │ │ ├── database.util.ts │ │ │ ├── domainValidation.ts │ │ │ ├── executeCustomNodeFunction.ts │ │ │ ├── fileRepository.ts │ │ │ ├── fileValidation.ts │ │ │ ├── getChatMessage.ts │ │ │ ├── getChatMessageFeedback.ts │ │ │ ├── getRunningExpressApp.ts │ │ │ ├── getUploadsConfig.ts │ │ │ ├── hub.ts │ │ │ ├── index.ts │ │ │ ├── logger.ts │ │ │ ├── pagination.ts │ │ │ ├── prompt.ts │ │ │ ├── quotaUsage.ts │ │ │ ├── rateLimit.ts │ │ │ ├── sanitize.util.ts │ │ │ ├── sanitizeFlowData.test.ts │ │ │ ├── sanitizeFlowData.ts │ │ │ ├── telemetry.ts │ │ │ ├── typeormDataSource.ts │ │ │ ├── updateChatMessageFeedback.ts │ │ │ ├── upsertVector.ts │ │ │ └── validateKey.ts │ │ └── tsconfig.json │ └── ui/ │ ├── .npmignore │ ├── README-ZH.md │ ├── README.md │ ├── craco.config.js │ ├── index.html │ ├── jsconfig.json │ ├── package.json │ ├── public/ │ │ ├── index.html │ │ └── manifest.json │ ├── src/ │ │ ├── App.jsx │ │ ├── ErrorBoundary.jsx │ │ ├── api/ │ │ │ ├── account.api.js │ │ │ ├── apikey.js │ │ │ ├── assistants.js │ │ │ ├── attachments.js │ │ │ ├── audit.js │ │ │ ├── auth.js │ │ │ ├── chatflows.js │ │ │ ├── chatmessage.js │ │ │ ├── chatmessagefeedback.js │ │ │ ├── client.js │ │ │ ├── config.js │ │ │ ├── credentials.js │ │ │ ├── dataset.js │ │ │ ├── documentstore.js │ │ │ ├── evaluations.js │ │ │ ├── evaluators.js │ │ │ ├── executions.js │ │ │ ├── exportimport.js │ │ │ ├── feedback.js │ │ │ ├── files.js │ │ │ ├── lead.js │ │ │ ├── log.js │ │ │ ├── loginmethod.js │ │ │ ├── marketplaces.js │ │ │ ├── nodes.js │ │ │ ├── oauth2.js │ │ │ ├── platformsettings.js │ │ │ ├── prediction.js │ │ │ ├── pricing.js │ │ │ ├── prompt.js │ │ │ ├── role.js │ │ │ ├── scraper.js │ │ │ ├── sso.js │ │ │ ├── tools.js │ │ │ ├── tts.js │ │ │ ├── user.js │ │ │ ├── validation.js │ │ │ ├── variables.js │ │ │ ├── vectorstore.js │ │ │ └── workspace.js │ │ ├── assets/ │ │ │ └── scss/ │ │ │ ├── _themes-vars.module.scss │ │ │ └── style.scss │ │ ├── config.js │ │ ├── hooks/ │ │ │ ├── useApi.jsx │ │ │ ├── useAuth.jsx │ │ │ ├── useConfirm.jsx │ │ │ ├── useScriptRef.jsx │ │ │ └── useSearchShortcut.jsx │ │ ├── index.jsx │ │ ├── layout/ │ │ │ ├── AuthLayout/ │ │ │ │ └── index.jsx │ │ │ ├── MainLayout/ │ │ │ │ ├── Header/ │ │ │ │ │ ├── OrgWorkspaceBreadcrumbs/ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ ├── ProfileSection/ │ │ │ │ │ │ ├── index.css │ │ │ │ │ │ └── index.jsx │ │ │ │ │ ├── WorkspaceSwitcher/ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ └── index.jsx │ │ │ │ ├── LogoSection/ │ │ │ │ │ └── index.jsx │ │ │ │ ├── Sidebar/ │ │ │ │ │ ├── CloudMenuList.jsx │ │ │ │ │ ├── MenuList/ │ │ │ │ │ │ ├── NavCollapse/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── NavGroup/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── NavItem/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ └── index.jsx │ │ │ │ │ ├── TrialInfo.jsx │ │ │ │ │ └── index.jsx │ │ │ │ ├── ViewHeader.jsx │ │ │ │ └── index.jsx │ │ │ ├── MinimalLayout/ │ │ │ │ └── index.jsx │ │ │ ├── NavMotion.jsx │ │ │ └── NavigationScroll.jsx │ │ ├── menu-items/ │ │ │ ├── agentsettings.js │ │ │ ├── customassistant.js │ │ │ ├── dashboard.js │ │ │ ├── index.js │ │ │ └── settings.js │ │ ├── routes/ │ │ │ ├── AuthRoutes.jsx │ │ │ ├── CanvasRoutes.jsx │ │ │ ├── ChatbotRoutes.jsx │ │ │ ├── DefaultRedirect.jsx │ │ │ ├── ExecutionRoutes.jsx │ │ │ ├── MainRoutes.jsx │ │ │ ├── RequireAuth.jsx │ │ │ └── index.jsx │ │ ├── serviceWorker.js │ │ ├── store/ │ │ │ ├── actions.js │ │ │ ├── constant.js │ │ │ ├── context/ │ │ │ │ ├── ConfigContext.jsx │ │ │ │ ├── ConfirmContext.jsx │ │ │ │ ├── ConfirmContextProvider.jsx │ │ │ │ ├── ErrorContext.jsx │ │ │ │ └── ReactFlowContext.jsx │ │ │ ├── index.jsx │ │ │ ├── reducer.jsx │ │ │ └── reducers/ │ │ │ ├── authSlice.js │ │ │ ├── canvasReducer.js │ │ │ ├── customizationReducer.js │ │ │ ├── dialogReducer.js │ │ │ └── notifierReducer.js │ │ ├── themes/ │ │ │ ├── compStyleOverride.js │ │ │ ├── index.js │ │ │ ├── palette.js │ │ │ └── typography.js │ │ ├── ui-component/ │ │ │ ├── array/ │ │ │ │ └── ArrayRenderer.jsx │ │ │ ├── button/ │ │ │ │ ├── AnimateButton.jsx │ │ │ │ ├── CopyToClipboardButton.jsx │ │ │ │ ├── FlowListMenu.jsx │ │ │ │ ├── ImageButton.js │ │ │ │ ├── RBACButtons.jsx │ │ │ │ ├── StyledButton.jsx │ │ │ │ ├── StyledFab.jsx │ │ │ │ ├── ThumbsDownButton.jsx │ │ │ │ └── ThumbsUpButton.jsx │ │ │ ├── cards/ │ │ │ │ ├── DocumentStoreCard.jsx │ │ │ │ ├── FollowUpPromptsCard.jsx │ │ │ │ ├── ItemCard.jsx │ │ │ │ ├── MainCard.jsx │ │ │ │ ├── NodeCardWrapper.jsx │ │ │ │ ├── Skeleton/ │ │ │ │ │ └── ChatflowCard.jsx │ │ │ │ ├── StarterPromptsCard.css │ │ │ │ ├── StarterPromptsCard.jsx │ │ │ │ └── StatsCard.jsx │ │ │ ├── checkbox/ │ │ │ │ └── Checkbox.jsx │ │ │ ├── dialog/ │ │ │ │ ├── AboutDialog.jsx │ │ │ │ ├── AdditionalParamsDialog.jsx │ │ │ │ ├── AgentflowGeneratorDialog.jsx │ │ │ │ ├── AllowedDomainsDialog.jsx │ │ │ │ ├── ChatFeedbackContentDialog.jsx │ │ │ │ ├── ChatFeedbackDialog.jsx │ │ │ │ ├── ChatflowConfigurationDialog.jsx │ │ │ │ ├── ConditionDialog.jsx │ │ │ │ ├── ConfirmDialog.jsx │ │ │ │ ├── ExpandRichInputDialog.jsx │ │ │ │ ├── ExpandTextDialog.css │ │ │ │ ├── ExpandTextDialog.jsx │ │ │ │ ├── ExportAsTemplateDialog.jsx │ │ │ │ ├── FormatPromptValuesDialog.jsx │ │ │ │ ├── InputHintDialog.jsx │ │ │ │ ├── InviteUsersDialog.jsx │ │ │ │ ├── ManageScrapedLinksDialog.jsx │ │ │ │ ├── NodeInfoDialog.jsx │ │ │ │ ├── NvidiaNIMDialog.jsx │ │ │ │ ├── PromptGeneratorDialog.jsx │ │ │ │ ├── PromptLangsmithHubDialog.jsx │ │ │ │ ├── SaveChatflowDialog.jsx │ │ │ │ ├── ShareWithWorkspaceDialog.jsx │ │ │ │ ├── SourceDocDialog.jsx │ │ │ │ ├── SpeechToTextDialog.jsx │ │ │ │ ├── StarterPromptsDialog.jsx │ │ │ │ ├── TagDialog.jsx │ │ │ │ ├── ViewLeadsDialog.jsx │ │ │ │ └── ViewMessagesDialog.jsx │ │ │ ├── dropdown/ │ │ │ │ ├── AsyncDropdown.jsx │ │ │ │ ├── Dropdown.jsx │ │ │ │ └── MultiDropdown.jsx │ │ │ ├── editor/ │ │ │ │ └── CodeEditor.jsx │ │ │ ├── extended/ │ │ │ │ ├── AllowedDomains.jsx │ │ │ │ ├── AnalyseFlow.jsx │ │ │ │ ├── AudioWaveform.jsx │ │ │ │ ├── Avatar.jsx │ │ │ │ ├── Breadcrumbs.jsx │ │ │ │ ├── ChatFeedback.jsx │ │ │ │ ├── Feedback.jsx │ │ │ │ ├── FileUpload.jsx │ │ │ │ ├── FollowUpPrompts.jsx │ │ │ │ ├── Leads.jsx │ │ │ │ ├── Logo.jsx │ │ │ │ ├── OverrideConfig.jsx │ │ │ │ ├── PostProcessing.jsx │ │ │ │ ├── RateLimit.jsx │ │ │ │ ├── Security.jsx │ │ │ │ ├── SpeechToText.jsx │ │ │ │ ├── StarterPrompts.jsx │ │ │ │ ├── TextToSpeech.jsx │ │ │ │ └── Transitions.jsx │ │ │ ├── file/ │ │ │ │ └── File.jsx │ │ │ ├── form/ │ │ │ │ └── settings.jsx │ │ │ ├── grid/ │ │ │ │ ├── DataGrid.jsx │ │ │ │ └── Grid.jsx │ │ │ ├── input/ │ │ │ │ ├── Input.jsx │ │ │ │ ├── RichInput.jsx │ │ │ │ ├── SuggestionList.jsx │ │ │ │ └── suggestionOption.js │ │ │ ├── json/ │ │ │ │ ├── JsonEditor.jsx │ │ │ │ ├── JsonViewer.jsx │ │ │ │ └── SelectVariable.jsx │ │ │ ├── loading/ │ │ │ │ ├── BackdropLoader.jsx │ │ │ │ ├── Loadable.jsx │ │ │ │ └── Loader.jsx │ │ │ ├── markdown/ │ │ │ │ ├── CodeBlock.jsx │ │ │ │ ├── Markdown.css │ │ │ │ └── MemoizedReactMarkdown.jsx │ │ │ ├── pagination/ │ │ │ │ └── TablePagination.jsx │ │ │ ├── rbac/ │ │ │ │ └── available.jsx │ │ │ ├── safe/ │ │ │ │ └── SafeHTML.jsx │ │ │ ├── slider/ │ │ │ │ └── InputSlider.jsx │ │ │ ├── subscription/ │ │ │ │ └── PricingDialog.jsx │ │ │ ├── switch/ │ │ │ │ └── Switch.jsx │ │ │ ├── table/ │ │ │ │ ├── DocumentStoreTable.jsx │ │ │ │ ├── ExecutionsListTable.jsx │ │ │ │ ├── FilesTable.jsx │ │ │ │ ├── FlowListTable.jsx │ │ │ │ ├── MarketplaceTable.jsx │ │ │ │ ├── Table.jsx │ │ │ │ ├── TableStyles.jsx │ │ │ │ └── ToolsListTable.jsx │ │ │ ├── tabs/ │ │ │ │ ├── Tab.jsx │ │ │ │ ├── TabPanel.jsx │ │ │ │ ├── TabsList.jsx │ │ │ │ └── tabColors.js │ │ │ ├── toolbar/ │ │ │ │ └── Toolbar.js │ │ │ └── tooltip/ │ │ │ ├── MoreItemsTooltip.jsx │ │ │ ├── NodeTooltip.jsx │ │ │ └── TooltipWithParser.jsx │ │ ├── utils/ │ │ │ ├── authUtils.js │ │ │ ├── customMention.js │ │ │ ├── errorHandler.js │ │ │ ├── exportImport.js │ │ │ ├── genericHelper.js │ │ │ ├── useNotifier.js │ │ │ ├── usePrompt.js │ │ │ └── validation.js │ │ └── views/ │ │ ├── account/ │ │ │ └── index.jsx │ │ ├── agentexecutions/ │ │ │ ├── ExecutionDetails.jsx │ │ │ ├── NodeExecutionDetails.jsx │ │ │ ├── PublicExecutionDetails.jsx │ │ │ ├── ShareExecutionDialog.jsx │ │ │ └── index.jsx │ │ ├── agentflows/ │ │ │ └── index.jsx │ │ ├── agentflowsv2/ │ │ │ ├── AgentFlowEdge.jsx │ │ │ ├── AgentFlowNode.jsx │ │ │ ├── Canvas.jsx │ │ │ ├── ConfigInput.jsx │ │ │ ├── ConnectionLine.jsx │ │ │ ├── EditNodeDialog.jsx │ │ │ ├── IterationNode.jsx │ │ │ ├── MarketplaceCanvas.jsx │ │ │ ├── StickyNote.jsx │ │ │ └── index.css │ │ ├── apikey/ │ │ │ ├── APIKeyDialog.css │ │ │ ├── APIKeyDialog.jsx │ │ │ └── index.jsx │ │ ├── assistants/ │ │ │ ├── custom/ │ │ │ │ ├── AddCustomAssistantDialog.jsx │ │ │ │ ├── CustomAssistantConfigurePreview.jsx │ │ │ │ ├── CustomAssistantLayout.jsx │ │ │ │ └── toolAgentFlow.js │ │ │ ├── index.jsx │ │ │ └── openai/ │ │ │ ├── AssistantDialog.jsx │ │ │ ├── AssistantVectorStoreDialog.jsx │ │ │ ├── DeleteConfirmDialog.jsx │ │ │ ├── LoadAssistantDialog.jsx │ │ │ └── OpenAIAssistantLayout.jsx │ │ ├── auth/ │ │ │ ├── expired.jsx │ │ │ ├── forgotPassword.jsx │ │ │ ├── login.jsx │ │ │ ├── loginActivity.jsx │ │ │ ├── rateLimited.jsx │ │ │ ├── register.jsx │ │ │ ├── resetPassword.jsx │ │ │ ├── signIn.jsx │ │ │ ├── ssoConfig.jsx │ │ │ ├── ssoSuccess.jsx │ │ │ ├── unauthorized.jsx │ │ │ └── verify-email.jsx │ │ ├── canvas/ │ │ │ ├── AddNodes.jsx │ │ │ ├── ButtonEdge.jsx │ │ │ ├── CanvasHeader.jsx │ │ │ ├── CanvasNode.jsx │ │ │ ├── CredentialInputHandler.jsx │ │ │ ├── NodeInputHandler.jsx │ │ │ ├── NodeOutputHandler.jsx │ │ │ ├── StickyNote.jsx │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── chatbot/ │ │ │ └── index.jsx │ │ ├── chatflows/ │ │ │ ├── APICodeDialog.jsx │ │ │ ├── EmbedChat.jsx │ │ │ ├── ShareChatbot.jsx │ │ │ └── index.jsx │ │ ├── chatmessage/ │ │ │ ├── AgentExecutedDataCard.jsx │ │ │ ├── AgentReasoningCard.jsx │ │ │ ├── ChatExpandDialog.jsx │ │ │ ├── ChatInputHistory.js │ │ │ ├── ChatMessage.css │ │ │ ├── ChatMessage.jsx │ │ │ ├── ChatPopUp.jsx │ │ │ ├── ThinkingCard.jsx │ │ │ ├── ValidationPopUp.jsx │ │ │ ├── audio-recording.css │ │ │ └── audio-recording.js │ │ ├── credentials/ │ │ │ ├── AddEditCredentialDialog.jsx │ │ │ ├── CredentialInputHandler.jsx │ │ │ ├── CredentialListDialog.jsx │ │ │ └── index.jsx │ │ ├── datasets/ │ │ │ ├── AddEditDatasetDialog.jsx │ │ │ ├── AddEditDatasetRowDialog.jsx │ │ │ ├── DatasetItems.jsx │ │ │ ├── UploadCSVFileDialog.jsx │ │ │ └── index.jsx │ │ ├── docstore/ │ │ │ ├── AddDocStoreDialog.jsx │ │ │ ├── ComponentsListDialog.jsx │ │ │ ├── DeleteDocStoreDialog.jsx │ │ │ ├── DocStoreAPIDialog.jsx │ │ │ ├── DocStoreInputHandler.jsx │ │ │ ├── DocumentLoaderListDialog.jsx │ │ │ ├── DocumentStoreDetail.jsx │ │ │ ├── DocumentStoreStatus.jsx │ │ │ ├── ExpandedChunkDialog.jsx │ │ │ ├── LoaderConfigPreviewChunks.jsx │ │ │ ├── ShowStoredChunks.jsx │ │ │ ├── UpsertHistoryDetailsDialog.jsx │ │ │ ├── UpsertHistorySideDrawer.jsx │ │ │ ├── VectorStoreConfigure.jsx │ │ │ ├── VectorStoreQuery.jsx │ │ │ └── index.jsx │ │ ├── evaluations/ │ │ │ ├── ChartLatency.jsx │ │ │ ├── ChartPassPrnt.jsx │ │ │ ├── ChartTokens.jsx │ │ │ ├── CreateEvaluationDialog.jsx │ │ │ ├── EvalsResultDialog.jsx │ │ │ ├── EvaluationResult.jsx │ │ │ ├── EvaluationResultSideDrawer.jsx │ │ │ ├── EvaluationResultVersionsSideDrawer.jsx │ │ │ ├── MetricsItemCard.jsx │ │ │ └── index.jsx │ │ ├── evaluators/ │ │ │ ├── AddEditEvaluatorDialog.jsx │ │ │ ├── SamplePromptDialog.jsx │ │ │ ├── evaluationPrompts.js │ │ │ ├── evaluatorConstant.js │ │ │ └── index.jsx │ │ ├── files/ │ │ │ └── index.jsx │ │ ├── marketplaces/ │ │ │ ├── MarketplaceCanvas.jsx │ │ │ ├── MarketplaceCanvasHeader.jsx │ │ │ ├── MarketplaceCanvasNode.jsx │ │ │ └── index.jsx │ │ ├── organization/ │ │ │ └── index.jsx │ │ ├── roles/ │ │ │ ├── CreateEditRoleDialog.css │ │ │ ├── CreateEditRoleDialog.jsx │ │ │ └── index.jsx │ │ ├── serverlogs/ │ │ │ └── index.jsx │ │ ├── settings/ │ │ │ └── index.jsx │ │ ├── tools/ │ │ │ ├── HowToUseFunctionDialog.jsx │ │ │ ├── PasteJSONDialog.jsx │ │ │ ├── ToolDialog.jsx │ │ │ └── index.jsx │ │ ├── users/ │ │ │ ├── EditUserDialog.jsx │ │ │ └── index.jsx │ │ ├── variables/ │ │ │ ├── AddEditVariableDialog.jsx │ │ │ ├── HowToUseVariablesDialog.jsx │ │ │ └── index.jsx │ │ ├── vectorstore/ │ │ │ ├── UpsertHistoryDialog.jsx │ │ │ ├── UpsertResultDialog.jsx │ │ │ ├── VectorStoreDialog.jsx │ │ │ └── VectorStorePopUp.jsx │ │ └── workspace/ │ │ ├── AddEditWorkspaceDialog.jsx │ │ ├── EditWorkspaceUserRoleDialog.jsx │ │ ├── WorkspaceUsers.jsx │ │ └── index.jsx │ └── vite.config.js ├── pnpm-workspace.yaml └── turbo.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ node_modules dist build **/node_modules **/build **/dist packages/server/.env packages/ui/.env ================================================ FILE: .eslintrc.js ================================================ module.exports = { extends: [ 'eslint:recommended', 'plugin:markdown/recommended', 'plugin:react/recommended', 'plugin:react/jsx-runtime', 'plugin:react-hooks/recommended', 'plugin:jsx-a11y/recommended', 'plugin:prettier/recommended' ], settings: { react: { version: 'detect' } }, parser: '@typescript-eslint/parser', ignorePatterns: ['**/node_modules', '**/dist', '**/build', '**/coverage', '**/package-lock.json'], plugins: ['unused-imports'], rules: { '@typescript-eslint/explicit-module-boundary-types': 'off', 'no-unused-vars': 'off', 'unused-imports/no-unused-imports': 'warn', 'unused-imports/no-unused-vars': ['warn', { vars: 'all', varsIgnorePattern: '^_', args: 'after-used', argsIgnorePattern: '^_' }], 'no-undef': 'off', 'no-console': [process.env.CI ? 'error' : 'warn', { allow: ['warn', 'error', 'info'] }], 'prettier/prettier': 'error', 'no-control-regex': 0 // Used to match control regex's in user input } } ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: [FlowiseAI] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.yml ================================================ name: Bug Report description: File a bug report to help us improve labels: ['bug'] assignees: [] body: - type: markdown attributes: value: | Make sure to have a proper title and description. - type: textarea id: bug-description attributes: label: Describe the bug description: A clear and concise description of what the bug is. placeholder: Tell us what you see! validations: required: true - type: textarea id: reproduce attributes: label: To Reproduce description: Steps to reproduce the behavior placeholder: | 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error validations: required: true - type: textarea id: expected attributes: label: Expected behavior description: A clear and concise description of what you expected to happen. validations: required: true - type: textarea id: screenshots attributes: label: Screenshots description: If applicable, add screenshots to help explain your problem. placeholder: Drag and drop or paste screenshots here - type: textarea id: flow attributes: label: Flow description: If applicable, add exported flow in order to help replicating the problem. placeholder: Paste your exported flow here - type: dropdown id: method attributes: label: Use Method description: How did you use Flowise? options: - Flowise Cloud - Docker - npx flowise start - pnpm start - type: input id: version attributes: label: Flowise Version description: What version of Flowise are you running? placeholder: e.g., 1.2.11 - type: dropdown id: os attributes: label: Operating System description: What operating system are you using? options: - Windows - macOS - Linux - Other - type: dropdown id: browser attributes: label: Browser description: What browser are you using? options: - Chrome - Firefox - Safari - Edge - Other - type: textarea id: context attributes: label: Additional context description: Add any other context about the problem here. placeholder: Any additional information that might be helpful ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.yml ================================================ name: Feature Request description: Suggest a new feature or enhancement for Flowise labels: ['enhancement'] assignees: [] body: - type: markdown attributes: value: | Thanks for suggesting a new feature! Please provide as much detail as possible to help us understand your request. - type: textarea id: feature-description attributes: label: Feature Description description: A clear and concise description of the feature you'd like to see in Flowise. placeholder: Describe what you want to be added or improved... validations: required: true - type: dropdown id: feature-category attributes: label: Feature Category description: What category does this feature belong to? options: - UI/UX Improvement - New Node/Component - Integration - Performance - Security - Documentation - API Enhancement - Workflow/Flow Management - Authentication/Authorization - Database/Storage - Deployment/DevOps - Other validations: required: true - type: textarea id: problem-statement attributes: label: Problem Statement description: What problem does this feature solve? What's the current pain point? placeholder: Describe the problem or limitation you're facing... - type: textarea id: proposed-solution attributes: label: Proposed Solution description: How would you like this feature to work? Be as specific as possible. placeholder: Describe your ideal solution in detail... - type: textarea id: mockups-references attributes: label: Mockups or References description: Any mockups, screenshots, or references to similar features in other tools? placeholder: Upload images or provide links to examples... - type: textarea id: additional-context attributes: label: Additional Context description: Any other information, context, or examples that would help us understand this request. placeholder: Add any other relevant information... ================================================ FILE: .github/workflows/docker-image-dockerhub.yml ================================================ name: Docker Image CI - Docker Hub on: workflow_dispatch: inputs: node_version: description: 'Node.js version to build this image with.' type: choice required: true default: '20' options: - '20' tag_version: description: 'Tag version of the image to be pushed.' type: string required: true default: 'latest' jobs: docker: runs-on: ubuntu-latest steps: - name: Set default values id: defaults run: | echo "node_version=${{ github.event.inputs.node_version || '20' }}" >> $GITHUB_OUTPUT echo "tag_version=${{ github.event.inputs.tag_version || 'latest' }}" >> $GITHUB_OUTPUT - name: Checkout uses: actions/checkout@v6.0.2 - name: Set up QEMU uses: docker/setup-qemu-action@v4.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4.0.0 - name: Login to Docker Hub uses: docker/login-action@v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} # ------------------------- # Build and push main image # ------------------------- - name: Build and push main image uses: docker/build-push-action@v6.19.2 with: context: . file: ./docker/Dockerfile build-args: | NODE_VERSION=${{ steps.defaults.outputs.node_version }} platforms: linux/amd64,linux/arm64 push: true tags: | flowiseai/flowise:${{ steps.defaults.outputs.tag_version }} # ------------------------- # Build and push worker image # ------------------------- - name: Build and push worker image uses: docker/build-push-action@v6.19.2 with: context: . file: docker/worker/Dockerfile build-args: | NODE_VERSION=${{ steps.defaults.outputs.node_version }} platforms: linux/amd64,linux/arm64 push: true tags: | flowiseai/flowise-worker:${{ steps.defaults.outputs.tag_version }} ================================================ FILE: .github/workflows/docker-image-ecr.yml ================================================ name: Docker Image CI - AWS ECR on: workflow_dispatch: inputs: environment: description: 'Environment to push the image to.' required: true default: 'dev' type: choice options: - dev - prod node_version: description: 'Node.js version to build this image with.' type: choice required: true default: '20' options: - '20' tag_version: description: 'Tag version of the image to be pushed.' type: string required: true default: 'latest' permissions: contents: read # Required for checkout id-token: write # Required for AWS OIDC jobs: docker: runs-on: ubuntu-latest environment: ${{ github.event.inputs.environment }} steps: - name: Set default values id: defaults run: | echo "node_version=${{ github.event.inputs.node_version || '20' }}" >> $GITHUB_OUTPUT echo "tag_version=${{ github.event.inputs.tag_version || 'latest' }}" >> $GITHUB_OUTPUT - name: Checkout uses: actions/checkout@v6.0.2 - name: Set up QEMU uses: docker/setup-qemu-action@v4.0.0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4.0.0 - name: Configure AWS Credentials if: ${{ inputs.environment != 'prod' }} uses: aws-actions/configure-aws-credentials@v6 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: ${{ secrets.AWS_REGION }} - name: Configure AWS OIDC Credentials if: ${{ inputs.environment == 'prod' }} uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 with: aws-region: ${{ secrets.AWS_REGION }} role-to-assume: ${{ secrets.AWS_OIDC_IAM_ROLE }} mask-aws-account-id: true unset-current-credentials: true - name: Login to Amazon ECR uses: aws-actions/amazon-ecr-login@v2 # ------------------------- # Build and push main image # ------------------------- - name: Build and push main image uses: docker/build-push-action@v6.19.2 with: context: . file: Dockerfile build-args: | NODE_VERSION=${{ steps.defaults.outputs.node_version }} platforms: linux/amd64,linux/arm64 push: true tags: | ${{ format('{0}.dkr.ecr.{1}.amazonaws.com/flowise:{2}', secrets.AWS_ACCOUNT_ID, secrets.AWS_REGION, steps.defaults.outputs.tag_version) }} ================================================ FILE: .github/workflows/main.yml ================================================ name: Node CI on: push: branches: - main pull_request: branches: - '*' workflow_dispatch: permissions: contents: read jobs: build: strategy: matrix: platform: [ubuntu-latest] node-version: [18.15.0] runs-on: ${{ matrix.platform }} env: PUPPETEER_SKIP_DOWNLOAD: true steps: - uses: actions/checkout@v6 - uses: pnpm/action-setup@v4 with: version: 10.26.0 - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' cache-dependency-path: 'pnpm-lock.yaml' - run: pnpm install - run: pnpm lint - run: pnpm build env: NODE_OPTIONS: '--max_old_space_size=4096' - run: pnpm test:coverage - name: Cypress install run: pnpm cypress install - name: Install dependencies (Cypress Action) uses: cypress-io/github-action@v7.1.5 with: working-directory: ./ runTests: false - name: Cypress test uses: cypress-io/github-action@v7.1.5 with: install: false working-directory: packages/server start: pnpm start wait-on: 'http://localhost:3000' wait-on-timeout: 120 browser: chrome ================================================ FILE: .github/workflows/proprietary-path-guard.yml ================================================ name: Proprietary Path Guard # ============================================================================= # This workflow checks that PRs don't add files to proprietary paths. # # Proprietary paths: # - extensions/ Reserved for enterprise extensions # - apps/* Only apps/oss-app/ is allowed # # These paths are reserved for downstream forks and enterprise distributions. # ============================================================================= on: pull_request: branches: [main, develop, master] push: branches: ['**'] # Manual trigger for testing workflow_dispatch: inputs: reason: description: 'Reason for manual run' required: false default: 'Testing' permissions: contents: read jobs: check-proprietary-paths: name: Check for Proprietary Paths runs-on: ubuntu-latest if: github.repository == 'FlowiseAI/Flowise' steps: - name: Checkout repository uses: actions/checkout@v6 with: fetch-depth: 0 - name: Check for proprietary paths id: check-paths run: | echo "🔍 Checking for proprietary paths..." echo "Trigger: ${{ github.event_name }}" echo "" # Get changed files based on event type if [ "${{ github.event_name }}" = "pull_request" ]; then CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD) elif [ "${{ github.event.before }}" != "0000000000000000000000000000000000000000" ]; then # Push to existing branch - compare with previous commit # Fall back to default branch comparison if before SHA is unreachable (e.g. force-push, shallow clone) CHANGED_FILES=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} 2>/dev/null || git diff --name-only origin/${{ github.event.repository.default_branch }}...${{ github.sha }} 2>/dev/null || echo "") else # New branch - compare against default branch CHANGED_FILES=$(git diff --name-only origin/${{ github.event.repository.default_branch }}...${{ github.sha }} 2>/dev/null || echo "") fi echo "Files to check:" echo "$CHANGED_FILES" | head -50 | sed 's/^/ /' echo "" # Check for proprietary paths VIOLATIONS="" while IFS= read -r file; do [ -z "$file" ] && continue # Block all extensions/ if echo "$file" | grep -qE "^extensions/"; then VIOLATIONS="$VIOLATIONS$file\n" continue fi # Block all apps/ except apps/oss-app/ if echo "$file" | grep -qE "^apps/"; then if ! echo "$file" | grep -qE "^apps/oss-app/"; then VIOLATIONS="$VIOLATIONS$file\n" fi fi done <<< "$CHANGED_FILES" if [ -n "$VIOLATIONS" ]; then echo "has_violations=true" >> $GITHUB_OUTPUT echo "violations<> $GITHUB_OUTPUT printf "%s" "$VIOLATIONS" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT echo "❌ Files in proprietary paths detected!" echo "" printf "%s" "$VIOLATIONS" | sed 's/^/ ❌ /' echo "" echo "Proprietary paths:" echo " - extensions/ (reserved for enterprise extensions)" echo " - apps/* (only apps/oss-app/ is allowed)" else echo "has_violations=false" >> $GITHUB_OUTPUT echo "✅ No proprietary paths detected" fi - name: Fail if violations found if: steps.check-paths.outputs.has_violations == 'true' run: | echo "::error::Files detected in proprietary paths. These paths are reserved for enterprise extensions." exit 1 ================================================ FILE: .github/workflows/publish-agentflow.yml ================================================ name: Publish @flowiseai/agentflow on: workflow_dispatch: inputs: bump: description: 'Version bump type' required: true type: choice default: 'prerelease' options: - prerelease - patch - minor - major - custom custom_version: description: 'Custom version (only used when bump is "custom", e.g. 1.0.0-beta.1)' required: false type: string tag: description: 'npm dist-tag' required: false type: choice default: 'dev' options: - dev - latest jobs: dry-run: runs-on: ubuntu-latest permissions: contents: read outputs: version: ${{ steps.resolve-version.outputs.version }} steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v2 with: version: 10.26.0 - uses: actions/setup-node@v4 with: node-version: '18.15.0' registry-url: 'https://registry.npmjs.org' - name: Validate custom version if: inputs.bump == 'custom' run: | if [ -z "$CUSTOM_VERSION" ]; then echo "::error::custom_version is required when bump is 'custom'" exit 1 fi npx semver "$CUSTOM_VERSION" || (echo "::error::Invalid semver: $CUSTOM_VERSION" && exit 1) env: CUSTOM_VERSION: ${{ inputs.custom_version }} - name: Install dependencies run: pnpm install --frozen-lockfile env: PUPPETEER_SKIP_DOWNLOAD: 'true' - name: Set version run: | CURRENT=$(npm pkg get version --prefix packages/agentflow | tr -d '"') if [ "$BUMP" = "custom" ]; then NEW_VERSION="$CUSTOM_VERSION" else NEW_VERSION=$(npx semver "$CURRENT" -i "$BUMP" --preid dev) fi npm pkg set version="$NEW_VERSION" --prefix packages/agentflow echo "Version set to $NEW_VERSION" env: BUMP: ${{ inputs.bump }} CUSTOM_VERSION: ${{ inputs.custom_version }} - name: Resolve version id: resolve-version run: | VERSION=$(npm pkg get version --prefix packages/agentflow | tr -d '"') echo "version=$VERSION" >> "$GITHUB_OUTPUT" echo "## Version to publish: \`$VERSION\`" >> "$GITHUB_STEP_SUMMARY" echo "## Tag: \`${{ inputs.tag }}\`" >> "$GITHUB_STEP_SUMMARY" - name: Package contents run: pnpm --filter @flowiseai/agentflow pack --dry-run - name: Dry run publish run: pnpm --filter @flowiseai/agentflow publish --no-git-checks --dry-run --tag ${{ inputs.tag }} env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} publish: needs: dry-run runs-on: ubuntu-latest environment: npm-publish permissions: contents: write pull-requests: write steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v2 with: version: 10.26.0 - uses: actions/setup-node@v4 with: node-version: '18.15.0' registry-url: 'https://registry.npmjs.org' - name: Install dependencies run: pnpm install --frozen-lockfile env: PUPPETEER_SKIP_DOWNLOAD: 'true' - name: Set version run: | CURRENT=$(npm pkg get version --prefix packages/agentflow | tr -d '"') if [ "$BUMP" = "custom" ]; then NEW_VERSION="$CUSTOM_VERSION" else NEW_VERSION=$(npx semver "$CURRENT" -i "$BUMP" --preid dev) fi npm pkg set version="$NEW_VERSION" --prefix packages/agentflow echo "Version set to $NEW_VERSION" env: BUMP: ${{ inputs.bump }} CUSTOM_VERSION: ${{ inputs.custom_version }} - name: Log version run: | echo "Publishing version: ${{ needs.dry-run.outputs.version }}" echo "Tag: ${{ inputs.tag }}" - name: Publish run: pnpm --filter @flowiseai/agentflow publish --no-git-checks --tag ${{ inputs.tag }} env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - name: Create version bump PR run: | VERSION="${{ needs.dry-run.outputs.version }}" BRANCH="chore/bump-agentflow-${VERSION}" git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git checkout -b "$BRANCH" git add packages/agentflow/package.json git commit -m "chore: bump @flowiseai/agentflow to ${VERSION}" git push -u origin "$BRANCH" gh pr create \ --title "chore: bump @flowiseai/agentflow to ${VERSION}" \ --body "Automated version bump after publishing \`@flowiseai/agentflow@${VERSION}\` to npm with tag \`${{ inputs.tag }}\`." \ --base main \ --head "$BRANCH" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/test_docker_build.yml ================================================ name: Test Docker Build on: push: branches: - main pull_request: branches: - '*' workflow_dispatch: jobs: build: runs-on: ubuntu-latest env: PUPPETEER_SKIP_DOWNLOAD: true steps: - uses: actions/checkout@v6 - run: docker build --no-cache -t flowise . ================================================ FILE: .gitignore ================================================ # editor .idea .vscode # dependencies **/node_modules **/package-lock.json !**/examples/package-lock.json **/yarn.lock ## logs **/logs **/*.log ## pnpm .pnpm-store/ ## build **/dist **/build ## temp **/tmp **/temp ## test **/coverage # misc .DS_Store ## env .env.local .env.development.local .env.test.local .env.production.local .env ## turbo .turbo ## secrets **/*.key **/api.json ## uploads **/uploads ## compressed **/*.tgz ## vscode .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json !.vscode/*.code-snippets # Local History for Visual Studio Code .history/ ## other keys *.key *.keys *.priv *.rsa *.key.json ## ssh keys *.ssh *.ssh-key .key-mrc ## Certificate Authority *.ca ## Certificate *.crt ## Certificate Sign Request *.csr ## Certificate *.der ## Key database file *.kdb ## OSCP request data *.org ## PKCS #12 *.p12 ## PEM-encoded certificate data *.pem ## Random number seed *.rnd ## SSLeay data *.ssleay ## S/MIME message *.smime *.vsix # ============================================================================= # Proprietary paths (should never exist in OSS) # ============================================================================= extensions/ # Only allow apps/oss-app, ignore all other apps apps/*/ !apps/oss-app/ # Claude - session/user specific files .claude/plans/ .claude/settings.local.json ================================================ FILE: .husky/pre-commit ================================================ #!/bin/sh . "$(dirname "$0")/_/husky.sh" pnpm quick # prettify pnpm lint-staged # eslint lint(also include prettify but prettify support more file extensions than eslint, so run prettify first) ================================================ FILE: .husky/pre-push ================================================ #!/bin/bash [ -f "$(dirname "$0")/_/husky.sh" ] && . "$(dirname "$0")/_/husky.sh" # ============================================================================= # OSS Guardrail: Prevent pushing proprietary code to OSS repository # ============================================================================= # Paths that should NEVER go to OSS (explicitly blocked) BLOCKED_PATHS="^extensions/" # Allowed apps (whitelist) - everything else in apps/ is blocked ALLOWED_APPS="^apps/oss-app/" # Get the remote being pushed to remote="$1" url="$2" # Check if pushing to OSS remote (FlowiseAI/Flowise) if echo "$url" | grep -qE "FlowiseAI/Flowise(\.git)?$"; then echo "🔒 Pushing to OSS repo - checking for proprietary code..." # Read stdin for refs being pushed while read local_ref local_sha remote_ref remote_sha; do # Skip delete operations if [ "$local_sha" = "0000000000000000000000000000000000000000" ]; then continue fi # Get list of files to check based on whether this is a new or existing branch if [ "$remote_sha" = "0000000000000000000000000000000000000000" ]; then # New branch - check ALL files across ALL commits being pushed # Find merge base with remote's main/master to determine the branch point base=$(git merge-base "$local_sha" "$remote/main" 2>/dev/null || \ git merge-base "$local_sha" "$remote/master" 2>/dev/null || \ echo "") if [ -n "$base" ]; then # Found common ancestor - diff from there to get all new files files_to_check=$(git diff --name-only "$base..$local_sha") else # No common ancestor - check all files in all commits on this branch files_to_check=$(git log --name-only --pretty=format: "$local_sha" | sort -u) fi else # Existing branch - check only files changed in new commits files_to_check=$(git diff --name-only "$remote_sha..$local_sha") fi # Check for proprietary paths # Note: || true prevents grep's exit code 1 (no match) from aborting the subshell violations=$( { echo "$files_to_check" | grep -E "$BLOCKED_PATHS" || true echo "$files_to_check" | grep -E "^apps/" | grep -vE "$ALLOWED_APPS" || true } 2>/dev/null | sort -u ) if [ -n "$violations" ]; then echo "" echo "❌ BLOCKED: Push contains changes to proprietary paths!" echo "" echo "The following files cannot be pushed to OSS:" echo "$violations" | sed 's/^/ - /' echo "" echo "Proprietary paths that are blocked:" echo " - extensions/ (all extensions)" echo " - apps/* (except apps/oss-app/)" echo "" echo "Only apps/oss-app/ is allowed in the OSS repository." echo "" echo "These paths are reserved for proprietary extensions." echo "" exit 1 fi done echo "✅ No proprietary code detected - push allowed" fi exit 0 ================================================ FILE: .npmrc ================================================ auto-install-peers = true strict-peer-dependencies = false prefer-workspace-packages = true link-workspace-packages = deep hoist = true shamefully-hoist = true engine-strict = false ================================================ FILE: .nvmrc ================================================ v20.19.2 ================================================ FILE: .prettierignore ================================================ pnpm-lock.yaml ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct English | [中文](./i18n/CODE_OF_CONDUCT-ZH.md) ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: - Using welcoming and inclusive language - Being respectful of differing viewpoints and experiences - Gracefully accepting constructive criticism - Focusing on what is best for the community - Showing empathy towards other community members Examples of unacceptable behavior by participants include: - The use of sexualized language or imagery and unwelcome sexual attention or advances - Trolling, insulting/derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or electronic address, without explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at hello@flowiseai.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Flowise English | [中文](./i18n/CONTRIBUTING-ZH.md) We appreciate any form of contributions. ## ⭐ Star Star and share the [Github Repo](https://github.com/FlowiseAI/Flowise). ## 🙋 Q&A Search up for any questions in [Q&A section](https://github.com/FlowiseAI/Flowise/discussions/categories/q-a), if you can't find one, don't hesitate to create one. It might helps others that have similar question. ## 🙌 Share Chatflow Yes! Sharing how you use Flowise is a way of contribution. Export your chatflow as JSON, attach a screenshot and share it in [Show and Tell section](https://github.com/FlowiseAI/Flowise/discussions/categories/show-and-tell). ## 💡 Ideas Ideas are welcome such as new feature, apps integration, and blockchain networks. Submit in [Ideas section](https://github.com/FlowiseAI/Flowise/discussions/categories/ideas). ## 🐞 Report Bugs Found an issue? [Report it](https://github.com/FlowiseAI/Flowise/issues/new/choose). ## 👨‍💻 Contribute to Code Not sure what to contribute? Some ideas: - Create new components from `packages/components` - Update existing components such as extending functionality, fixing bugs - Add new chatflow ideas ### Developers Flowise has 3 different modules in a single mono repository. - `server`: Node backend to serve API logics - `ui`: React frontend - `components`: Third-party nodes integrations #### Prerequisite - Install [PNPM](https://pnpm.io/installation). The project is configured to use pnpm v10. ```bash npm i -g pnpm ``` #### Step by step 1. Fork the official [Flowise Github Repository](https://github.com/FlowiseAI/Flowise). 2. Clone your forked repository. 3. Create a new branch, see [guide](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-and-deleting-branches-within-your-repository). Naming conventions: - For feature branch: `feature/` - For bug fix branch: `bugfix/`. 4. Switch to the newly created branch. 5. Go into repository folder ```bash cd Flowise ``` 6. Install all dependencies of all modules: ```bash pnpm install ``` 7. Build all the code: ```bash pnpm build ``` 8. Start the app on [http://localhost:3000](http://localhost:3000) ```bash pnpm start ``` 9. For development: - Create `.env` file and specify the `VITE_PORT` (refer to `.env.example`) in `packages/ui` - Create `.env` file and specify the `PORT` (refer to `.env.example`) in `packages/server` - Run ```bash pnpm dev ``` Any changes made in `packages/ui` or `packages/server` will be reflected on [http://localhost:8080](http://localhost:8080) For changes made in `packages/components`, run `pnpm build` again to pickup the changes. 10. After making all the changes, run ```bash pnpm build ``` and ```bash pnpm start ``` to make sure everything works fine in production. 11. Commit code and submit Pull Request from forked branch pointing to [Flowise main](https://github.com/FlowiseAI/Flowise/tree/main). ### Testing - Unit tests are **co-located** with their source files — a test for `Foo.ts` lives in `Foo.test.ts` in the same directory. This is the standard used across all packages in this repo. - Run tests per package: ```bash cd packages/server && pnpm test cd packages/components && pnpm test cd packages/agentflow && pnpm test ``` Or from the repo root using `--filter`: ```bash pnpm --filter flowise-components test pnpm --filter @flowiseai/agentflow test pnpm --filter "./packages/server" test # root and server share the same package name. ``` - Or run all tests from the repo root: ```bash pnpm test ``` - When adding new functionality, place your test file next to the source file it tests: ``` packages/components/nodes/tools/MyTool/ ├── MyTool.ts └── MyTool.test.ts ← co-located test ``` ## 🌱 Env Variables Flowise support different environment variables to configure your instance. You can specify the following variables in the `.env` file inside `packages/server` folder. Read [more](https://docs.flowiseai.com/environment-variables) | Variable | Description | Type | Default | | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ----------------------------------- | | PORT | The HTTP port Flowise runs on | Number | 3000 | | CORS_ORIGINS | The allowed origins for all cross-origin HTTP calls | String | | | IFRAME_ORIGINS | The allowed origins for iframe src embedding | String | | | FLOWISE_FILE_SIZE_LIMIT | Upload File Size Limit | String | 50mb | | DEBUG | Print logs from components | Boolean | | | LOG_PATH | Location where log files are stored | String | `your-path/Flowise/logs` | | LOG_LEVEL | Different levels of logs | Enum String: `error`, `info`, `verbose`, `debug` | `info` | | LOG_JSON_SPACES | Spaces to beautify JSON logs | | 2 | | TOOL_FUNCTION_BUILTIN_DEP | NodeJS built-in modules to be used for Custom Tool or Function | String | | | TOOL_FUNCTION_EXTERNAL_DEP | External modules to be used for Custom Tool or Function | String | | | ALLOW_BUILTIN_DEP | Allow project dependencies to be used for Custom Tool or Function | Boolean | false | | DATABASE_TYPE | Type of database to store the flowise data | Enum String: `sqlite`, `mysql`, `postgres` | `sqlite` | | DATABASE_PATH | Location where database is saved (When DATABASE_TYPE is sqlite) | String | `your-home-dir/.flowise` | | DATABASE_HOST | Host URL or IP address (When DATABASE_TYPE is not sqlite) | String | | | DATABASE_PORT | Database port (When DATABASE_TYPE is not sqlite) | String | | | DATABASE_USER | Database username (When DATABASE_TYPE is not sqlite) | String | | | DATABASE_PASSWORD | Database password (When DATABASE_TYPE is not sqlite) | String | | | DATABASE_NAME | Database name (When DATABASE_TYPE is not sqlite) | String | | | DATABASE_SSL_KEY_BASE64 | Database SSL client cert in base64 (takes priority over DATABASE_SSL) | Boolean | false | | DATABASE_SSL | Database connection overssl (When DATABASE_TYPE is postgre) | Boolean | false | | SECRETKEY_PATH | Location where encryption key (used to encrypt/decrypt credentials) is saved | String | `your-path/Flowise/packages/server` | | FLOWISE_SECRETKEY_OVERWRITE | Encryption key to be used instead of the key stored in SECRETKEY_PATH | String | | | MODEL_LIST_CONFIG_JSON | File path to load list of models from your local config file | String | `/your_model_list_config_file_path` | | STORAGE_TYPE | Type of storage for uploaded files. default is `local` | Enum String: `s3`, `local`, `gcs` ,`azure` | `local` | | BLOB_STORAGE_PATH | Local folder path where uploaded files are stored when `STORAGE_TYPE` is `local` | String | `your-home-dir/.flowise/storage` | | S3_STORAGE_BUCKET_NAME | Bucket name to hold the uploaded files when `STORAGE_TYPE` is `s3` | String | | | S3_STORAGE_ACCESS_KEY_ID | AWS Access Key | String | | | S3_STORAGE_SECRET_ACCESS_KEY | AWS Secret Key | String | | | S3_STORAGE_REGION | Region for S3 bucket | String | | | S3_ENDPOINT_URL | Custom Endpoint for S3 | String | | | S3_FORCE_PATH_STYLE | Set this to true to force the request to use path-style addressing | Boolean | false | | GOOGLE_CLOUD_STORAGE_PROJ_ID | The GCP project id for cloud storage & logging when `STORAGE_TYPE` is `gcs` | String | | | GOOGLE_CLOUD_STORAGE_CREDENTIAL | The credential key file path when `STORAGE_TYPE` is `gcs` | String | | | GOOGLE_CLOUD_STORAGE_BUCKET_NAME | Bucket name to hold the uploaded files when `STORAGE_TYPE` is `gcs` | String | | | GOOGLE_CLOUD_UNIFORM_BUCKET_ACCESS | Enable uniform bucket level access when `STORAGE_TYPE` is `gcs` | Boolean | true | | AZURE_BLOB_STORAGE_CONNECTION_STRING | Azure Blob Storage connection string when `STORAGE_TYPE` is `azure`. Either this or account name + key is required | String | | | AZURE_BLOB_STORAGE_ACCOUNT_NAME | Azure storage account name when `STORAGE_TYPE` is `azure`. Required if connection string is not provided | String | | | AZURE_BLOB_STORAGE_ACCOUNT_KEY | Azure storage account key when `STORAGE_TYPE` is `azure`. Required if connection string is not provided | String | | | AZURE_BLOB_STORAGE_CONTAINER_NAME | Container name to hold the uploaded files when `STORAGE_TYPE` is `azure` | String | | | SHOW_COMMUNITY_NODES | Show nodes created by community | Boolean | | | DISABLED_NODES | Hide nodes from UI (comma separated list of node names) | String | | | TRUST_PROXY | Configure proxy trust settings for proper IP detection. Values: 'true' (trust all), 'false' (disable), number (hop count), or Express proxy values (e.g., 'loopback', 'linklocal', 'uniquelocal', IP addresses). [Learn More](https://expressjs.com/en/guide/behind-proxies.html) | Boolean/String/Number | true | You can also specify the env variables when using `npx`. For example: ``` npx flowise start --PORT=3000 --DEBUG=true ``` ## 📖 Contribute to Docs [Flowise Docs](https://github.com/FlowiseAI/FlowiseDocs) ## 🏷️ Pull Request process A member of the FlowiseAI team will automatically be notified/assigned when you open a pull request. You can also reach out to us on [Discord](https://discord.gg/jbaHfsRVBW). ## 📜 Code of Conduct This project and everyone participating in it are governed by the Code of Conduct which can be found in the [file](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to hello@flowiseai.com. ================================================ FILE: Dockerfile ================================================ # Build local monorepo image # docker build --no-cache -t flowise . # Run image # docker run -d -p 3000:3000 flowise FROM node:20-alpine # Install system dependencies and build tools RUN apk update && \ apk add --no-cache \ libc6-compat \ python3 \ make \ g++ \ build-base \ cairo-dev \ pango-dev \ chromium \ curl && \ npm install -g pnpm ENV PUPPETEER_SKIP_DOWNLOAD=true ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser ENV NODE_OPTIONS=--max-old-space-size=8192 WORKDIR /usr/src/flowise # Copy app source COPY . . # Install dependencies and build RUN pnpm install && \ pnpm build # Give the node user ownership of the application files RUN chown -R node:node . # Switch to non-root user (node user already exists in node:20-alpine) USER node EXPOSE 3000 CMD [ "pnpm", "start" ] ================================================ FILE: LICENSE.md ================================================ Copyright (c) 2023-present FlowiseAI, Inc. Portions of this software are licensed as follows: - All content that resides under https://github.com/FlowiseAI/Flowise/tree/main/packages/server/src/enterprise directory and files with explicit copyright notice such as [IdentityManager.ts](https://github.com/FlowiseAI/Flowise/tree/main/packages/server/src/IdentityManager.ts) are licensed under [Commercial License](https://github.com/FlowiseAI/Flowise/tree/main/packages/server/src/enterprise/LICENSE.md). - All third party components incorporated into the FlowiseAI Software are licensed under the original license provided by the owner of the applicable component. - Content outside of the above mentioned directories or restrictions above is available under the "Apache 2.0" license as defined below. Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS ================================================ FILE: README.md ================================================

[![Release Notes](https://img.shields.io/github/release/FlowiseAI/Flowise)](https://github.com/FlowiseAI/Flowise/releases) [![Discord](https://img.shields.io/discord/1087698854775881778?label=Discord&logo=discord)](https://discord.gg/jbaHfsRVBW) [![Twitter Follow](https://img.shields.io/twitter/follow/FlowiseAI?style=social)](https://twitter.com/FlowiseAI) [![GitHub star chart](https://img.shields.io/github/stars/FlowiseAI/Flowise?style=social)](https://star-history.com/#FlowiseAI/Flowise) [![GitHub fork](https://img.shields.io/github/forks/FlowiseAI/Flowise?style=social)](https://github.com/FlowiseAI/Flowise/fork) English | [繁體中文](./i18n/README-TW.md) | [简体中文](./i18n/README-ZH.md) | [日本語](./i18n/README-JA.md) | [한국어](./i18n/README-KR.md)

Build AI Agents, Visually

## 📚 Table of Contents - [⚡ Quick Start](#-quick-start) - [🐳 Docker](#-docker) - [👨‍💻 Developers](#-developers) - [🌱 Env Variables](#-env-variables) - [📖 Documentation](#-documentation) - [🌐 Self Host](#-self-host) - [☁️ Flowise Cloud](#️-flowise-cloud) - [🙋 Support](#-support) - [🙌 Contributing](#-contributing) - [📄 License](#-license) ## ⚡Quick Start Download and Install [NodeJS](https://nodejs.org/en/download) >= 18.15.0 1. Install Flowise ```bash npm install -g flowise ``` 2. Start Flowise ```bash npx flowise start ``` 3. Open [http://localhost:3000](http://localhost:3000) ## 🐳 Docker ### Docker Compose 1. Clone the Flowise project 2. Go to `docker` folder at the root of the project 3. Copy `.env.example` file, paste it into the same location, and rename to `.env` file 4. `docker compose up -d` 5. Open [http://localhost:3000](http://localhost:3000) 6. You can bring the containers down by `docker compose stop` ### Docker Image 1. Build the image locally: ```bash docker build --no-cache -t flowise . ``` 2. Run image: ```bash docker run -d --name flowise -p 3000:3000 flowise ``` 3. Stop image: ```bash docker stop flowise ``` ## 👨‍💻 Developers Flowise has 3 different modules in a single mono repository. - `server`: Node backend to serve API logics - `ui`: React frontend - `components`: Third-party nodes integrations - `api-documentation`: Auto-generated swagger-ui API docs from express ### Prerequisite - Install [PNPM](https://pnpm.io/installation) ```bash npm i -g pnpm ``` ### Setup 1. Clone the repository: ```bash git clone https://github.com/FlowiseAI/Flowise.git ``` 2. Go into repository folder: ```bash cd Flowise ``` 3. Install all dependencies of all modules: ```bash pnpm install ``` 4. Build all the code: ```bash pnpm build ```
Exit code 134 (JavaScript heap out of memory) If you get this error when running the above `build` script, try increasing the Node.js heap size and run the script again: ```bash # macOS / Linux / Git Bash export NODE_OPTIONS="--max-old-space-size=4096" # Windows PowerShell $env:NODE_OPTIONS="--max-old-space-size=4096" # Windows CMD set NODE_OPTIONS=--max-old-space-size=4096 ``` Then run: ```bash pnpm build ```
5. Start the app: ```bash pnpm start ``` You can now access the app on [http://localhost:3000](http://localhost:3000) 6. For development build: - Create `.env` file and specify the `VITE_PORT` (refer to `.env.example`) in `packages/ui` - Create `.env` file and specify the `PORT` (refer to `.env.example`) in `packages/server` - Run: ```bash pnpm dev ``` Any code changes will reload the app automatically on [http://localhost:8080](http://localhost:8080) ## 🌱 Env Variables Flowise supports different environment variables to configure your instance. You can specify the following variables in the `.env` file inside `packages/server` folder. Read [more](https://github.com/FlowiseAI/Flowise/blob/main/CONTRIBUTING.md#-env-variables) ## 📖 Documentation You can view the Flowise Docs [here](https://docs.flowiseai.com/) ## 🌐 Self Host Deploy Flowise self-hosted in your existing infrastructure, we support various [deployments](https://docs.flowiseai.com/configuration/deployment) - [AWS](https://docs.flowiseai.com/configuration/deployment/aws) - [Azure](https://docs.flowiseai.com/configuration/deployment/azure) - [Digital Ocean](https://docs.flowiseai.com/configuration/deployment/digital-ocean) - [GCP](https://docs.flowiseai.com/configuration/deployment/gcp) - [Alibaba Cloud](https://computenest.console.aliyun.com/service/instance/create/default?type=user&ServiceName=Flowise社区版) -
Others - [Railway](https://docs.flowiseai.com/configuration/deployment/railway) [![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/pn4G8S?referralCode=WVNPD9) - [Northflank](https://northflank.com/stacks/deploy-flowiseai) [![Deploy to Northflank](https://assets.northflank.com/deploy_to_northflank_smm_36700fb050.svg)](https://northflank.com/stacks/deploy-flowiseai) - [Render](https://docs.flowiseai.com/configuration/deployment/render) [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://docs.flowiseai.com/configuration/deployment/render) - [HuggingFace Spaces](https://docs.flowiseai.com/deployment/hugging-face) HuggingFace Spaces - [Elestio](https://elest.io/open-source/flowiseai) [![Deploy on Elestio](https://elest.io/images/logos/deploy-to-elestio-btn.png)](https://elest.io/open-source/flowiseai) - [Sealos](https://template.sealos.io/deploy?templateName=flowise) [![Deploy on Sealos](https://sealos.io/Deploy-on-Sealos.svg)](https://template.sealos.io/deploy?templateName=flowise) - [RepoCloud](https://repocloud.io/details/?app_id=29) [![Deploy on RepoCloud](https://d16t0pc4846x52.cloudfront.net/deploy.png)](https://repocloud.io/details/?app_id=29)
## ☁️ Flowise Cloud Get Started with [Flowise Cloud](https://flowiseai.com/). ## 🙋 Support Feel free to ask any questions, raise problems, and request new features in [Discussion](https://github.com/FlowiseAI/Flowise/discussions). ## 🙌 Contributing Thanks go to these awesome contributors

See [Contributing Guide](CONTRIBUTING.md). Reach out to us at [Discord](https://discord.gg/jbaHfsRVBW) if you have any questions or issues. [![Star History Chart](https://api.star-history.com/svg?repos=FlowiseAI/Flowise&type=Timeline)](https://star-history.com/#FlowiseAI/Flowise&Date) ## 📄 License Source code in this repository is made available under the [Apache License Version 2.0](LICENSE.md). ================================================ FILE: SECURITY.md ================================================ ### Responsible Disclosure Policy At Flowise, we prioritize security and continuously work to safeguard our systems. However, vulnerabilities can still exist. If you identify a security issue, please report it to us so we can address it promptly. Your cooperation helps us better protect our platform and users. ### Scope - Flowise Cloud: cloud.flowiseai.com - Public Flowise Repositories ### Out of scope vulnerabilities - Hypothetical issues that do not have a demonstrable, practical impact - Vulnerabilities that affect out-of-date browsers - ClickjackingCSRF on unauthenticated/logout/login pages - Banner disclosure on common/public services - Disclosure of known public files or directories (e.g. robots.txt) - Attacks requiring MITM (Man-in-the-Middle) or physical device access - Social engineering attacks - Denial service via bruteforce attack - Content spoofing and text injection without a valid attack vector - Username enumeration via Login Page error message - Username enumeration via Forgot password error message - Bruteforce attacks - Email spoofing - Absence of DNSSEC, CAA, CSP headers - Missing Secure or HTTP-only flag on non-sensitive cookies - Deadlinks - User enumeration - Social Engineering - Version Disclosure - Vulnerabilities that can only affect the attacker (e.g. self-XSS) - Known vulnerabilities in used libraries (unless exploitability can be proven) - Static application security testing findings ### Reporting Guidelines - Submit your findings to https://github.com/FlowiseAI/Flowise/security - Provide clear details to help us reproduce and fix the issue quickly. ### Reporting Guidelines - Submit your findings to https://github.com/FlowiseAI/Flowise/security - Ensure that the vulnerability is exploitable. Theoretical or static application security testing reports are subject to dismissal. - Submit the report with CVSS vector and calculated severity. - Provide a clear detailed report with proof of concept to help us reproduce and remediate the vulnerability. ### Disclosure Terms The Flowise team believes that transparency is important and public bug bounty reports are a valuable source of knowledge for bug bounty researchers. However, the Flowise team may have legitimate reasons not to disclose vulnerabilities. Do not discuss or disclose vulnerability information without prior written consent. If you plan on presenting your research, please share a draft with us at least 45 days in advance for review. Avoid including: - Data from any Flowise customer projects - Flowise user/customer information - Details about Flowise employees, contractors, or partners ### Report Validation Times We will validate submissions within the below timelines. | Vulnerability Severity | Time to Validate | | ---------------------- | ---------------- | | Critical | 5 business days | | High | 5 business days | | Medium | 15 business days | | Low | 15 business days | Your report will be kept _confidential_, and your details will not be shared without your consent. The Flowise team will triage and adjust severity or CVSS score if necessary. We appreciate your efforts in helping us maintain a secure platform and look forward to working together to resolve any issues responsibly. ### Remediation Once the report has been verified, the Flowise team will plan the remediation steps. Below is the estimated time to remediate the triaged security reports. | Triaged Severity | Estimated Time to Remediate | | ---------------- | --------------------------- | | Critical | 30 business days | | High | 60 business days | | Medium | 90 business days | ### Public Disclosure Timeline Public Disclosure occurs exactly 30 days after the next official release that includes the security patch. This period gives Flowise users a time to adopt the patched version before technical vulnerability details are made public, mitigating the risk of immediate post-disclosure exploitation. #### Reaching out to the Security team To report a new vulnerability, please submit a Github security Security Advisory report. If you have any questions or concerns about the existing Security Advisory, please contact security-team@flowiseai.com. ================================================ FILE: artillery-load-test.yml ================================================ # npm install -g artillery@latest # artillery run artillery-load-test.yml # Refer https://www.artillery.io/docs config: target: http://128.128.128.128:3000 # replace with your url phases: - duration: 1 arrivalRate: 1 rampTo: 2 name: Warm up phase - duration: 1 arrivalRate: 2 rampTo: 3 name: Ramp up load - duration: 1 arrivalRate: 3 name: Sustained peak load scenarios: - flow: - loop: - post: url: '/api/v1/prediction/chatflow-id' # replace with your chatflowid json: question: 'hello' # replace with your question count: 1 # how many request each user make # User __ # 3 / # 2 / # 1 _/ # 1 2 3 # Seconds # Total Users = 2 + 3 + 3 = 8 # Each making 1 HTTP call # Over a durations of 3 seconds ================================================ FILE: docker/Dockerfile ================================================ # Stage 1: Build stage FROM node:20-alpine AS build USER root # Skip downloading Chrome for Puppeteer (saves build time) ENV PUPPETEER_SKIP_DOWNLOAD=true # Install latest Flowise globally (specific version can be set: flowise@1.0.0) RUN npm install -g flowise # Stage 2: Runtime stage FROM node:20-alpine # Install runtime dependencies RUN apk add --no-cache chromium git python3 py3-pip make g++ build-base cairo-dev pango-dev curl # Set the environment variable for Puppeteer to find Chromium ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser # Copy Flowise from the build stage COPY --from=build /usr/local/lib/node_modules /usr/local/lib/node_modules COPY --from=build /usr/local/bin /usr/local/bin ENTRYPOINT ["flowise", "start"] ================================================ FILE: docker/README.md ================================================ # Flowise Docker Hub Image Starts Flowise from [DockerHub Image](https://hub.docker.com/r/flowiseai/flowise) ## Usage 1. Create `.env` file and specify the `PORT` (refer to `.env.example`) 2. `docker compose up -d` 3. Open [http://localhost:3000](http://localhost:3000) 4. You can bring the containers down by `docker compose stop` ## 🌱 Env Variables If you like to persist your data (flows, logs, credentials, storage), set these variables in the `.env` file inside `docker` folder: - DATABASE_PATH=/root/.flowise - LOG_PATH=/root/.flowise/logs - SECRETKEY_PATH=/root/.flowise - BLOB_STORAGE_PATH=/root/.flowise/storage Flowise also support different environment variables to configure your instance. Read [more](https://docs.flowiseai.com/configuration/environment-variables) ## Queue Mode: ### Building from source: You can build the images for worker and main from scratch with: ``` docker compose -f docker-compose-queue-source.yml up -d ``` Monitor Health: ``` docker compose -f docker-compose-queue-source.yml ps ``` ### From pre-built images: You can also use the pre-built images: ``` docker compose -f docker-compose-queue-prebuilt.yml up -d ``` Monitor Health: ``` docker compose -f docker-compose-queue-prebuilt.yml ps ``` ================================================ FILE: docker/docker-compose-queue-prebuilt.yml ================================================ version: '3.1' services: redis: image: redis:alpine container_name: flowise-redis ports: - '6379:6379' volumes: - redis_data:/data networks: - flowise-net restart: always flowise: image: flowiseai/flowise:latest container_name: flowise-main restart: always ports: - '${PORT:-3000}:${PORT:-3000}' volumes: - ~/.flowise:/root/.flowise environment: # --- Essential Flowise Vars --- - PORT=${PORT:-3000} - DATABASE_PATH=${DATABASE_PATH:-/root/.flowise} - DATABASE_TYPE=${DATABASE_TYPE} - DATABASE_PORT=${DATABASE_PORT} - DATABASE_HOST=${DATABASE_HOST} - DATABASE_NAME=${DATABASE_NAME} - DATABASE_USER=${DATABASE_USER} - DATABASE_PASSWORD=${DATABASE_PASSWORD} - DATABASE_SSL=${DATABASE_SSL} - DATABASE_SSL_KEY_BASE64=${DATABASE_SSL_KEY_BASE64} # SECRET KEYS - SECRETKEY_STORAGE_TYPE=${SECRETKEY_STORAGE_TYPE} - SECRETKEY_PATH=${SECRETKEY_PATH} - FLOWISE_SECRETKEY_OVERWRITE=${FLOWISE_SECRETKEY_OVERWRITE} - SECRETKEY_AWS_ACCESS_KEY=${SECRETKEY_AWS_ACCESS_KEY} - SECRETKEY_AWS_SECRET_KEY=${SECRETKEY_AWS_SECRET_KEY} - SECRETKEY_AWS_REGION=${SECRETKEY_AWS_REGION} - SECRETKEY_AWS_NAME=${SECRETKEY_AWS_NAME} # LOGGING - DEBUG=${DEBUG} - LOG_PATH=${LOG_PATH} - LOG_LEVEL=${LOG_LEVEL} - LOG_SANITIZE_BODY_FIELDS=${LOG_SANITIZE_BODY_FIELDS} - LOG_SANITIZE_HEADER_FIELDS=${LOG_SANITIZE_HEADER_FIELDS} # CUSTOM TOOL/FUNCTION DEPENDENCIES - TOOL_FUNCTION_BUILTIN_DEP=${TOOL_FUNCTION_BUILTIN_DEP} - TOOL_FUNCTION_EXTERNAL_DEP=${TOOL_FUNCTION_EXTERNAL_DEP} - ALLOW_BUILTIN_DEP=${ALLOW_BUILTIN_DEP} # STORAGE - STORAGE_TYPE=${STORAGE_TYPE} - BLOB_STORAGE_PATH=${BLOB_STORAGE_PATH} - S3_STORAGE_BUCKET_NAME=${S3_STORAGE_BUCKET_NAME} - S3_STORAGE_ACCESS_KEY_ID=${S3_STORAGE_ACCESS_KEY_ID} - S3_STORAGE_SECRET_ACCESS_KEY=${S3_STORAGE_SECRET_ACCESS_KEY} - S3_STORAGE_REGION=${S3_STORAGE_REGION} - S3_ENDPOINT_URL=${S3_ENDPOINT_URL} - S3_FORCE_PATH_STYLE=${S3_FORCE_PATH_STYLE} - GOOGLE_CLOUD_STORAGE_CREDENTIAL=${GOOGLE_CLOUD_STORAGE_CREDENTIAL} - GOOGLE_CLOUD_STORAGE_PROJ_ID=${GOOGLE_CLOUD_STORAGE_PROJ_ID} - GOOGLE_CLOUD_STORAGE_BUCKET_NAME=${GOOGLE_CLOUD_STORAGE_BUCKET_NAME} - GOOGLE_CLOUD_UNIFORM_BUCKET_ACCESS=${GOOGLE_CLOUD_UNIFORM_BUCKET_ACCESS} # Azure Blob Storage (provide EITHER connection string OR account name + key) - AZURE_BLOB_STORAGE_CONNECTION_STRING=${AZURE_BLOB_STORAGE_CONNECTION_STRING} - AZURE_BLOB_STORAGE_ACCOUNT_NAME=${AZURE_BLOB_STORAGE_ACCOUNT_NAME} - AZURE_BLOB_STORAGE_ACCOUNT_KEY=${AZURE_BLOB_STORAGE_ACCOUNT_KEY} - AZURE_BLOB_STORAGE_CONTAINER_NAME=${AZURE_BLOB_STORAGE_CONTAINER_NAME} # SETTINGS - NUMBER_OF_PROXIES=${NUMBER_OF_PROXIES} - CORS_ORIGINS=${CORS_ORIGINS} - IFRAME_ORIGINS=${IFRAME_ORIGINS} - FLOWISE_FILE_SIZE_LIMIT=${FLOWISE_FILE_SIZE_LIMIT} - SHOW_COMMUNITY_NODES=${SHOW_COMMUNITY_NODES} - DISABLE_FLOWISE_TELEMETRY=${DISABLE_FLOWISE_TELEMETRY} - DISABLED_NODES=${DISABLED_NODES} - MODEL_LIST_CONFIG_JSON=${MODEL_LIST_CONFIG_JSON} # AUTH PARAMETERS - APP_URL=${APP_URL} - JWT_AUTH_TOKEN_SECRET=${JWT_AUTH_TOKEN_SECRET} - JWT_REFRESH_TOKEN_SECRET=${JWT_REFRESH_TOKEN_SECRET} - JWT_ISSUER=${JWT_ISSUER} - JWT_AUDIENCE=${JWT_AUDIENCE} - JWT_TOKEN_EXPIRY_IN_MINUTES=${JWT_TOKEN_EXPIRY_IN_MINUTES} - JWT_REFRESH_TOKEN_EXPIRY_IN_MINUTES=${JWT_REFRESH_TOKEN_EXPIRY_IN_MINUTES} - EXPIRE_AUTH_TOKENS_ON_RESTART=${EXPIRE_AUTH_TOKENS_ON_RESTART} - EXPRESS_SESSION_SECRET=${EXPRESS_SESSION_SECRET} - PASSWORD_RESET_TOKEN_EXPIRY_IN_MINS=${PASSWORD_RESET_TOKEN_EXPIRY_IN_MINS} - PASSWORD_SALT_HASH_ROUNDS=${PASSWORD_SALT_HASH_ROUNDS} - TOKEN_HASH_SECRET=${TOKEN_HASH_SECRET} - SECURE_COOKIES=${SECURE_COOKIES} # EMAIL - SMTP_HOST=${SMTP_HOST} - SMTP_PORT=${SMTP_PORT} - SMTP_USER=${SMTP_USER} - SMTP_PASSWORD=${SMTP_PASSWORD} - SMTP_SECURE=${SMTP_SECURE} - ALLOW_UNAUTHORIZED_CERTS=${ALLOW_UNAUTHORIZED_CERTS} - SENDER_EMAIL=${SENDER_EMAIL} # ENTERPRISE - LICENSE_URL=${LICENSE_URL} - FLOWISE_EE_LICENSE_KEY=${FLOWISE_EE_LICENSE_KEY} - OFFLINE=${OFFLINE} - INVITE_TOKEN_EXPIRY_IN_HOURS=${INVITE_TOKEN_EXPIRY_IN_HOURS} - WORKSPACE_INVITE_TEMPLATE_PATH=${WORKSPACE_INVITE_TEMPLATE_PATH} # METRICS COLLECTION - POSTHOG_PUBLIC_API_KEY=${POSTHOG_PUBLIC_API_KEY} - ENABLE_METRICS=${ENABLE_METRICS} - METRICS_PROVIDER=${METRICS_PROVIDER} - METRICS_INCLUDE_NODE_METRICS=${METRICS_INCLUDE_NODE_METRICS} - METRICS_SERVICE_NAME=${METRICS_SERVICE_NAME} - METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT=${METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT} - METRICS_OPEN_TELEMETRY_PROTOCOL=${METRICS_OPEN_TELEMETRY_PROTOCOL} - METRICS_OPEN_TELEMETRY_DEBUG=${METRICS_OPEN_TELEMETRY_DEBUG} # PROXY - GLOBAL_AGENT_HTTP_PROXY=${GLOBAL_AGENT_HTTP_PROXY} - GLOBAL_AGENT_HTTPS_PROXY=${GLOBAL_AGENT_HTTPS_PROXY} - GLOBAL_AGENT_NO_PROXY=${GLOBAL_AGENT_NO_PROXY} # --- Queue Configuration (Main Instance) --- - MODE=${MODE:-queue} - QUEUE_NAME=${QUEUE_NAME:-flowise-queue} - QUEUE_REDIS_EVENT_STREAM_MAX_LEN=${QUEUE_REDIS_EVENT_STREAM_MAX_LEN} - WORKER_CONCURRENCY=${WORKER_CONCURRENCY} - REMOVE_ON_AGE=${REMOVE_ON_AGE} - REMOVE_ON_COUNT=${REMOVE_ON_COUNT} - REDIS_URL=${REDIS_URL:-redis://redis:6379} - REDIS_HOST=${REDIS_HOST} - REDIS_PORT=${REDIS_PORT} - REDIS_USERNAME=${REDIS_USERNAME} - REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_TLS=${REDIS_TLS} - REDIS_CERT=${REDIS_CERT} - REDIS_KEY=${REDIS_KEY} - REDIS_CA=${REDIS_CA} - REDIS_KEEP_ALIVE=${REDIS_KEEP_ALIVE} - ENABLE_BULLMQ_DASHBOARD=${ENABLE_BULLMQ_DASHBOARD} # SECURITY - CUSTOM_MCP_SECURITY_CHECK=${CUSTOM_MCP_SECURITY_CHECK} - CUSTOM_MCP_PROTOCOL=${CUSTOM_MCP_PROTOCOL} - HTTP_DENY_LIST=${HTTP_DENY_LIST} - HTTP_SECURITY_CHECK=${HTTP_SECURITY_CHECK} - PATH_TRAVERSAL_SAFETY=${PATH_TRAVERSAL_SAFETY} - TRUST_PROXY=${TRUST_PROXY} healthcheck: test: ['CMD', 'curl', '-f', 'http://localhost:${PORT:-3000}/api/v1/ping'] interval: 10s timeout: 5s retries: 5 start_period: 30s entrypoint: /bin/sh -c "sleep 3; flowise start" depends_on: - redis networks: - flowise-net flowise-worker: image: flowiseai/flowise-worker:latest container_name: flowise-worker restart: always volumes: - ~/.flowise:/root/.flowise environment: # --- Essential Flowise Vars --- - WORKER_PORT=${WORKER_PORT:-5566} - DATABASE_PATH=${DATABASE_PATH:-/root/.flowise} - DATABASE_TYPE=${DATABASE_TYPE} - DATABASE_PORT=${DATABASE_PORT} - DATABASE_HOST=${DATABASE_HOST} - DATABASE_NAME=${DATABASE_NAME} - DATABASE_USER=${DATABASE_USER} - DATABASE_PASSWORD=${DATABASE_PASSWORD} - DATABASE_SSL=${DATABASE_SSL} - DATABASE_SSL_KEY_BASE64=${DATABASE_SSL_KEY_BASE64} # SECRET KEYS - SECRETKEY_STORAGE_TYPE=${SECRETKEY_STORAGE_TYPE} - SECRETKEY_PATH=${SECRETKEY_PATH} - FLOWISE_SECRETKEY_OVERWRITE=${FLOWISE_SECRETKEY_OVERWRITE} - SECRETKEY_AWS_ACCESS_KEY=${SECRETKEY_AWS_ACCESS_KEY} - SECRETKEY_AWS_SECRET_KEY=${SECRETKEY_AWS_SECRET_KEY} - SECRETKEY_AWS_REGION=${SECRETKEY_AWS_REGION} - SECRETKEY_AWS_NAME=${SECRETKEY_AWS_NAME} # LOGGING - DEBUG=${DEBUG} - LOG_PATH=${LOG_PATH} - LOG_LEVEL=${LOG_LEVEL} - LOG_SANITIZE_BODY_FIELDS=${LOG_SANITIZE_BODY_FIELDS} - LOG_SANITIZE_HEADER_FIELDS=${LOG_SANITIZE_HEADER_FIELDS} # CUSTOM TOOL/FUNCTION DEPENDENCIES - TOOL_FUNCTION_BUILTIN_DEP=${TOOL_FUNCTION_BUILTIN_DEP} - TOOL_FUNCTION_EXTERNAL_DEP=${TOOL_FUNCTION_EXTERNAL_DEP} - ALLOW_BUILTIN_DEP=${ALLOW_BUILTIN_DEP} # STORAGE - STORAGE_TYPE=${STORAGE_TYPE} - BLOB_STORAGE_PATH=${BLOB_STORAGE_PATH} - S3_STORAGE_BUCKET_NAME=${S3_STORAGE_BUCKET_NAME} - S3_STORAGE_ACCESS_KEY_ID=${S3_STORAGE_ACCESS_KEY_ID} - S3_STORAGE_SECRET_ACCESS_KEY=${S3_STORAGE_SECRET_ACCESS_KEY} - S3_STORAGE_REGION=${S3_STORAGE_REGION} - S3_ENDPOINT_URL=${S3_ENDPOINT_URL} - S3_FORCE_PATH_STYLE=${S3_FORCE_PATH_STYLE} - GOOGLE_CLOUD_STORAGE_CREDENTIAL=${GOOGLE_CLOUD_STORAGE_CREDENTIAL} - GOOGLE_CLOUD_STORAGE_PROJ_ID=${GOOGLE_CLOUD_STORAGE_PROJ_ID} - GOOGLE_CLOUD_STORAGE_BUCKET_NAME=${GOOGLE_CLOUD_STORAGE_BUCKET_NAME} - GOOGLE_CLOUD_UNIFORM_BUCKET_ACCESS=${GOOGLE_CLOUD_UNIFORM_BUCKET_ACCESS} # SETTINGS - NUMBER_OF_PROXIES=${NUMBER_OF_PROXIES} - CORS_ORIGINS=${CORS_ORIGINS} - IFRAME_ORIGINS=${IFRAME_ORIGINS} - FLOWISE_FILE_SIZE_LIMIT=${FLOWISE_FILE_SIZE_LIMIT} - SHOW_COMMUNITY_NODES=${SHOW_COMMUNITY_NODES} - DISABLE_FLOWISE_TELEMETRY=${DISABLE_FLOWISE_TELEMETRY} - DISABLED_NODES=${DISABLED_NODES} - MODEL_LIST_CONFIG_JSON=${MODEL_LIST_CONFIG_JSON} # AUTH PARAMETERS - APP_URL=${APP_URL} - JWT_AUTH_TOKEN_SECRET=${JWT_AUTH_TOKEN_SECRET} - JWT_REFRESH_TOKEN_SECRET=${JWT_REFRESH_TOKEN_SECRET} - JWT_ISSUER=${JWT_ISSUER} - JWT_AUDIENCE=${JWT_AUDIENCE} - JWT_TOKEN_EXPIRY_IN_MINUTES=${JWT_TOKEN_EXPIRY_IN_MINUTES} - JWT_REFRESH_TOKEN_EXPIRY_IN_MINUTES=${JWT_REFRESH_TOKEN_EXPIRY_IN_MINUTES} - EXPIRE_AUTH_TOKENS_ON_RESTART=${EXPIRE_AUTH_TOKENS_ON_RESTART} - EXPRESS_SESSION_SECRET=${EXPRESS_SESSION_SECRET} - PASSWORD_RESET_TOKEN_EXPIRY_IN_MINS=${PASSWORD_RESET_TOKEN_EXPIRY_IN_MINS} - PASSWORD_SALT_HASH_ROUNDS=${PASSWORD_SALT_HASH_ROUNDS} - TOKEN_HASH_SECRET=${TOKEN_HASH_SECRET} - SECURE_COOKIES=${SECURE_COOKIES} # EMAIL - SMTP_HOST=${SMTP_HOST} - SMTP_PORT=${SMTP_PORT} - SMTP_USER=${SMTP_USER} - SMTP_PASSWORD=${SMTP_PASSWORD} - SMTP_SECURE=${SMTP_SECURE} - ALLOW_UNAUTHORIZED_CERTS=${ALLOW_UNAUTHORIZED_CERTS} - SENDER_EMAIL=${SENDER_EMAIL} # ENTERPRISE - LICENSE_URL=${LICENSE_URL} - FLOWISE_EE_LICENSE_KEY=${FLOWISE_EE_LICENSE_KEY} - OFFLINE=${OFFLINE} - INVITE_TOKEN_EXPIRY_IN_HOURS=${INVITE_TOKEN_EXPIRY_IN_HOURS} - WORKSPACE_INVITE_TEMPLATE_PATH=${WORKSPACE_INVITE_TEMPLATE_PATH} # METRICS COLLECTION - POSTHOG_PUBLIC_API_KEY=${POSTHOG_PUBLIC_API_KEY} - ENABLE_METRICS=${ENABLE_METRICS} - METRICS_PROVIDER=${METRICS_PROVIDER} - METRICS_INCLUDE_NODE_METRICS=${METRICS_INCLUDE_NODE_METRICS} - METRICS_SERVICE_NAME=${METRICS_SERVICE_NAME} - METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT=${METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT} - METRICS_OPEN_TELEMETRY_PROTOCOL=${METRICS_OPEN_TELEMETRY_PROTOCOL} - METRICS_OPEN_TELEMETRY_DEBUG=${METRICS_OPEN_TELEMETRY_DEBUG} # PROXY - GLOBAL_AGENT_HTTP_PROXY=${GLOBAL_AGENT_HTTP_PROXY} - GLOBAL_AGENT_HTTPS_PROXY=${GLOBAL_AGENT_HTTPS_PROXY} - GLOBAL_AGENT_NO_PROXY=${GLOBAL_AGENT_NO_PROXY} # --- Queue Configuration (Worker Instance) --- - MODE=${MODE:-queue} - QUEUE_NAME=${QUEUE_NAME:-flowise-queue} - QUEUE_REDIS_EVENT_STREAM_MAX_LEN=${QUEUE_REDIS_EVENT_STREAM_MAX_LEN} - WORKER_CONCURRENCY=${WORKER_CONCURRENCY} - REMOVE_ON_AGE=${REMOVE_ON_AGE} - REMOVE_ON_COUNT=${REMOVE_ON_COUNT} - REDIS_URL=${REDIS_URL:-redis://redis:6379} - REDIS_HOST=${REDIS_HOST} - REDIS_PORT=${REDIS_PORT} - REDIS_USERNAME=${REDIS_USERNAME} - REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_TLS=${REDIS_TLS} - REDIS_CERT=${REDIS_CERT} - REDIS_KEY=${REDIS_KEY} - REDIS_CA=${REDIS_CA} - REDIS_KEEP_ALIVE=${REDIS_KEEP_ALIVE} - ENABLE_BULLMQ_DASHBOARD=${ENABLE_BULLMQ_DASHBOARD} # SECURITY - CUSTOM_MCP_SECURITY_CHECK=${CUSTOM_MCP_SECURITY_CHECK} - CUSTOM_MCP_PROTOCOL=${CUSTOM_MCP_PROTOCOL} - HTTP_DENY_LIST=${HTTP_DENY_LIST} - HTTP_SECURITY_CHECK=${HTTP_SECURITY_CHECK} - PATH_TRAVERSAL_SAFETY=${PATH_TRAVERSAL_SAFETY} - TRUST_PROXY=${TRUST_PROXY} healthcheck: test: ['CMD', 'curl', '-f', 'http://localhost:${WORKER_PORT:-5566}/healthz'] interval: 10s timeout: 5s retries: 5 start_period: 30s entrypoint: /bin/sh -c "node /app/healthcheck/healthcheck.js & sleep 5 && pnpm run start-worker" depends_on: - redis - flowise networks: - flowise-net volumes: redis_data: driver: local networks: flowise-net: driver: bridge ================================================ FILE: docker/docker-compose-queue-source.yml ================================================ version: '3.1' services: redis: image: redis:alpine container_name: flowise-redis ports: - '6379:6379' volumes: - redis_data:/data networks: - flowise-net flowise: container_name: flowise-main build: context: .. # Build using the Dockerfile in the root directory dockerfile: docker/Dockerfile ports: - '${PORT}:${PORT}' volumes: # Mount local .flowise to container's default location - ../.flowise:/root/.flowise environment: # --- Essential Flowise Vars --- - PORT=${PORT:-3000} - DATABASE_PATH=/root/.flowise - SECRETKEY_PATH=/root/.flowise - LOG_PATH=/root/.flowise/logs - BLOB_STORAGE_PATH=/root/.flowise/storage # --- Queue Vars (Main Instance) --- - MODE=queue - QUEUE_NAME=flowise-queue # Ensure this matches worker - REDIS_URL=redis://redis:6379 # Use service name 'redis' depends_on: - redis networks: - flowise-net flowise-worker: container_name: flowise-worker build: context: .. # Build context is still the root dockerfile: docker/worker/Dockerfile # Ensure this path is correct volumes: # Mount same local .flowise to worker - ../.flowise:/root/.flowise environment: # --- Essential Flowise Vars --- - WORKER_PORT=${WORKER_PORT:-5566} # Port for worker healthcheck - DATABASE_PATH=/root/.flowise - SECRETKEY_PATH=/root/.flowise - LOG_PATH=/root/.flowise/logs - BLOB_STORAGE_PATH=/root/.flowise/storage # --- Queue Vars (Main Instance) --- - MODE=queue - QUEUE_NAME=flowise-queue # Ensure this matches worker - REDIS_URL=redis://redis:6379 # Use service name 'redis' depends_on: - redis - flowise networks: - flowise-net volumes: redis_data: driver: local networks: flowise-net: driver: bridge ================================================ FILE: docker/docker-compose.yml ================================================ version: '3.1' services: flowise: image: flowiseai/flowise:latest restart: always environment: - PORT=${PORT} # DATABASE - DATABASE_PATH=${DATABASE_PATH} - DATABASE_TYPE=${DATABASE_TYPE} - DATABASE_PORT=${DATABASE_PORT} - DATABASE_HOST=${DATABASE_HOST} - DATABASE_NAME=${DATABASE_NAME} - DATABASE_USER=${DATABASE_USER} - DATABASE_PASSWORD=${DATABASE_PASSWORD} - DATABASE_SSL=${DATABASE_SSL} - DATABASE_SSL_KEY_BASE64=${DATABASE_SSL_KEY_BASE64} # SECRET KEYS - SECRETKEY_STORAGE_TYPE=${SECRETKEY_STORAGE_TYPE} - SECRETKEY_PATH=${SECRETKEY_PATH} - FLOWISE_SECRETKEY_OVERWRITE=${FLOWISE_SECRETKEY_OVERWRITE} - SECRETKEY_AWS_ACCESS_KEY=${SECRETKEY_AWS_ACCESS_KEY} - SECRETKEY_AWS_SECRET_KEY=${SECRETKEY_AWS_SECRET_KEY} - SECRETKEY_AWS_REGION=${SECRETKEY_AWS_REGION} - SECRETKEY_AWS_NAME=${SECRETKEY_AWS_NAME} # LOGGING - DEBUG=${DEBUG} - LOG_PATH=${LOG_PATH} - LOG_LEVEL=${LOG_LEVEL} - LOG_SANITIZE_BODY_FIELDS=${LOG_SANITIZE_BODY_FIELDS} - LOG_SANITIZE_HEADER_FIELDS=${LOG_SANITIZE_HEADER_FIELDS} # CUSTOM TOOL/FUNCTION DEPENDENCIES - TOOL_FUNCTION_BUILTIN_DEP=${TOOL_FUNCTION_BUILTIN_DEP} - TOOL_FUNCTION_EXTERNAL_DEP=${TOOL_FUNCTION_EXTERNAL_DEP} - ALLOW_BUILTIN_DEP=${ALLOW_BUILTIN_DEP} # STORAGE - STORAGE_TYPE=${STORAGE_TYPE} - BLOB_STORAGE_PATH=${BLOB_STORAGE_PATH} - S3_STORAGE_BUCKET_NAME=${S3_STORAGE_BUCKET_NAME} - S3_STORAGE_ACCESS_KEY_ID=${S3_STORAGE_ACCESS_KEY_ID} - S3_STORAGE_SECRET_ACCESS_KEY=${S3_STORAGE_SECRET_ACCESS_KEY} - S3_STORAGE_REGION=${S3_STORAGE_REGION} - S3_ENDPOINT_URL=${S3_ENDPOINT_URL} - S3_FORCE_PATH_STYLE=${S3_FORCE_PATH_STYLE} - GOOGLE_CLOUD_STORAGE_CREDENTIAL=${GOOGLE_CLOUD_STORAGE_CREDENTIAL} - GOOGLE_CLOUD_STORAGE_PROJ_ID=${GOOGLE_CLOUD_STORAGE_PROJ_ID} - GOOGLE_CLOUD_STORAGE_BUCKET_NAME=${GOOGLE_CLOUD_STORAGE_BUCKET_NAME} - GOOGLE_CLOUD_UNIFORM_BUCKET_ACCESS=${GOOGLE_CLOUD_UNIFORM_BUCKET_ACCESS} # Azure Blob Storage (provide EITHER connection string OR account name + key) - AZURE_BLOB_STORAGE_CONNECTION_STRING=${AZURE_BLOB_STORAGE_CONNECTION_STRING} - AZURE_BLOB_STORAGE_ACCOUNT_NAME=${AZURE_BLOB_STORAGE_ACCOUNT_NAME} - AZURE_BLOB_STORAGE_ACCOUNT_KEY=${AZURE_BLOB_STORAGE_ACCOUNT_KEY} - AZURE_BLOB_STORAGE_CONTAINER_NAME=${AZURE_BLOB_STORAGE_CONTAINER_NAME} # SETTINGS - NUMBER_OF_PROXIES=${NUMBER_OF_PROXIES} - CORS_ORIGINS=${CORS_ORIGINS} - IFRAME_ORIGINS=${IFRAME_ORIGINS} - FLOWISE_FILE_SIZE_LIMIT=${FLOWISE_FILE_SIZE_LIMIT} - SHOW_COMMUNITY_NODES=${SHOW_COMMUNITY_NODES} - DISABLE_FLOWISE_TELEMETRY=${DISABLE_FLOWISE_TELEMETRY} - DISABLED_NODES=${DISABLED_NODES} - MODEL_LIST_CONFIG_JSON=${MODEL_LIST_CONFIG_JSON} # AUTH PARAMETERS - APP_URL=${APP_URL} - JWT_AUTH_TOKEN_SECRET=${JWT_AUTH_TOKEN_SECRET} - JWT_REFRESH_TOKEN_SECRET=${JWT_REFRESH_TOKEN_SECRET} - JWT_ISSUER=${JWT_ISSUER} - JWT_AUDIENCE=${JWT_AUDIENCE} - JWT_TOKEN_EXPIRY_IN_MINUTES=${JWT_TOKEN_EXPIRY_IN_MINUTES} - JWT_REFRESH_TOKEN_EXPIRY_IN_MINUTES=${JWT_REFRESH_TOKEN_EXPIRY_IN_MINUTES} - EXPIRE_AUTH_TOKENS_ON_RESTART=${EXPIRE_AUTH_TOKENS_ON_RESTART} - EXPRESS_SESSION_SECRET=${EXPRESS_SESSION_SECRET} - PASSWORD_RESET_TOKEN_EXPIRY_IN_MINS=${PASSWORD_RESET_TOKEN_EXPIRY_IN_MINS} - PASSWORD_SALT_HASH_ROUNDS=${PASSWORD_SALT_HASH_ROUNDS} - TOKEN_HASH_SECRET=${TOKEN_HASH_SECRET} - SECURE_COOKIES=${SECURE_COOKIES} # EMAIL - SMTP_HOST=${SMTP_HOST} - SMTP_PORT=${SMTP_PORT} - SMTP_USER=${SMTP_USER} - SMTP_PASSWORD=${SMTP_PASSWORD} - SMTP_SECURE=${SMTP_SECURE} - ALLOW_UNAUTHORIZED_CERTS=${ALLOW_UNAUTHORIZED_CERTS} - SENDER_EMAIL=${SENDER_EMAIL} # ENTERPRISE - LICENSE_URL=${LICENSE_URL} - FLOWISE_EE_LICENSE_KEY=${FLOWISE_EE_LICENSE_KEY} - OFFLINE=${OFFLINE} - INVITE_TOKEN_EXPIRY_IN_HOURS=${INVITE_TOKEN_EXPIRY_IN_HOURS} - WORKSPACE_INVITE_TEMPLATE_PATH=${WORKSPACE_INVITE_TEMPLATE_PATH} # METRICS COLLECTION - POSTHOG_PUBLIC_API_KEY=${POSTHOG_PUBLIC_API_KEY} - ENABLE_METRICS=${ENABLE_METRICS} - METRICS_PROVIDER=${METRICS_PROVIDER} - METRICS_INCLUDE_NODE_METRICS=${METRICS_INCLUDE_NODE_METRICS} - METRICS_SERVICE_NAME=${METRICS_SERVICE_NAME} - METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT=${METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT} - METRICS_OPEN_TELEMETRY_PROTOCOL=${METRICS_OPEN_TELEMETRY_PROTOCOL} - METRICS_OPEN_TELEMETRY_DEBUG=${METRICS_OPEN_TELEMETRY_DEBUG} # PROXY - GLOBAL_AGENT_HTTP_PROXY=${GLOBAL_AGENT_HTTP_PROXY} - GLOBAL_AGENT_HTTPS_PROXY=${GLOBAL_AGENT_HTTPS_PROXY} - GLOBAL_AGENT_NO_PROXY=${GLOBAL_AGENT_NO_PROXY} # QUEUE CONFIGURATION - MODE=${MODE} - QUEUE_NAME=${QUEUE_NAME} - QUEUE_REDIS_EVENT_STREAM_MAX_LEN=${QUEUE_REDIS_EVENT_STREAM_MAX_LEN} - WORKER_CONCURRENCY=${WORKER_CONCURRENCY} - REMOVE_ON_AGE=${REMOVE_ON_AGE} - REMOVE_ON_COUNT=${REMOVE_ON_COUNT} - REDIS_URL=${REDIS_URL} - REDIS_HOST=${REDIS_HOST} - REDIS_PORT=${REDIS_PORT} - REDIS_USERNAME=${REDIS_USERNAME} - REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_TLS=${REDIS_TLS} - REDIS_CERT=${REDIS_CERT} - REDIS_KEY=${REDIS_KEY} - REDIS_CA=${REDIS_CA} - REDIS_KEEP_ALIVE=${REDIS_KEEP_ALIVE} - ENABLE_BULLMQ_DASHBOARD=${ENABLE_BULLMQ_DASHBOARD} # SECURITY - CUSTOM_MCP_SECURITY_CHECK=${CUSTOM_MCP_SECURITY_CHECK} - CUSTOM_MCP_PROTOCOL=${CUSTOM_MCP_PROTOCOL} - HTTP_DENY_LIST=${HTTP_DENY_LIST} - HTTP_SECURITY_CHECK=${HTTP_SECURITY_CHECK} - PATH_TRAVERSAL_SAFETY=${PATH_TRAVERSAL_SAFETY} - TRUST_PROXY=${TRUST_PROXY} ports: - '${PORT}:${PORT}' healthcheck: test: ['CMD', 'curl', '-f', 'http://localhost:${PORT}/api/v1/ping'] interval: 10s timeout: 5s retries: 5 start_period: 30s volumes: - ~/.flowise:/root/.flowise entrypoint: /bin/sh -c "sleep 3; flowise start" ================================================ FILE: docker/worker/Dockerfile ================================================ FROM node:20-alpine RUN apk add --update libc6-compat python3 make g++ # needed for pdfjs-dist RUN apk add --no-cache build-base cairo-dev pango-dev # Install Chromium and curl for container-level health checks RUN apk add --no-cache chromium curl #install PNPM globally RUN npm install -g pnpm ENV PUPPETEER_SKIP_DOWNLOAD=true ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser ENV NODE_OPTIONS=--max-old-space-size=8192 WORKDIR /usr/src # Copy app source COPY . . RUN pnpm install RUN pnpm build # --- Healthcheck Setup --- WORKDIR /app/healthcheck COPY docker/worker/healthcheck/package.json . RUN npm install --omit=dev COPY docker/worker/healthcheck/healthcheck.js . # --- End Healthcheck Setup --- # Set the main working directory back WORKDIR /usr/src # Environment variables for port configuration ENV WORKER_PORT=5566 # Expose port (can be overridden by env var) EXPOSE ${WORKER_PORT} # Start healthcheck in background and flowise worker in foreground CMD ["/bin/sh", "-c", "node /app/healthcheck/healthcheck.js & sleep 5 && pnpm run start-worker"] ================================================ FILE: docker/worker/README.md ================================================ # Flowise Worker By utilizing worker instances when operating in queue mode, Flowise can be scaled horizontally by adding more workers to handle increased workloads or scaled down by removing workers when demand decreases. Here’s an overview of the process: 1. The primary Flowise instance sends an execution ID to a message broker, Redis, which maintains a queue of pending executions, allowing the next available worker to process them. 2. A worker from the pool retrieves a message from Redis. The worker starts execute the actual job. 3. Once the execution is completed, the worker alerts the main instance that the execution is finished. # How to use ## Setting up Main Server: 1. Follow [setup guide](https://github.com/FlowiseAI/Flowise/blob/main/docker/README.md) 2. In the `.env.example`, setup all the necessary env variables for `QUEUE CONFIGURATION` ## Setting up Worker: 1. Navigate to `docker/worker` folder 2. In the `.env.example`, setup all the necessary env variables for `QUEUE CONFIGURATION`. Env variables for worker must match the one for main server. Change the `WORKER_PORT` to other available port numbers to listen for healthcheck. Ex: 5566 3. `docker compose up -d` 4. You can bring the worker container down by `docker compose stop` ## Entrypoint: Different from main server image which is using `flowise start`, entrypoint for worker is `pnpm run start-worker`. This is because the worker's [Dockerfile](./Dockerfile) build the image from source files via `pnpm build` instead of npm registry via `RUN npm install -g flowise`. ================================================ FILE: docker/worker/docker-compose.yml ================================================ version: '3.1' services: flowise: image: flowiseai/flowise-worker:latest restart: always environment: - WORKER_PORT=${WORKER_PORT:-5566} # DATABASE - DATABASE_PATH=${DATABASE_PATH} - DATABASE_TYPE=${DATABASE_TYPE} - DATABASE_PORT=${DATABASE_PORT} - DATABASE_HOST=${DATABASE_HOST} - DATABASE_NAME=${DATABASE_NAME} - DATABASE_USER=${DATABASE_USER} - DATABASE_PASSWORD=${DATABASE_PASSWORD} - DATABASE_SSL=${DATABASE_SSL} - DATABASE_SSL_KEY_BASE64=${DATABASE_SSL_KEY_BASE64} # SECRET KEYS - SECRETKEY_STORAGE_TYPE=${SECRETKEY_STORAGE_TYPE} - SECRETKEY_PATH=${SECRETKEY_PATH} - FLOWISE_SECRETKEY_OVERWRITE=${FLOWISE_SECRETKEY_OVERWRITE} - SECRETKEY_AWS_ACCESS_KEY=${SECRETKEY_AWS_ACCESS_KEY} - SECRETKEY_AWS_SECRET_KEY=${SECRETKEY_AWS_SECRET_KEY} - SECRETKEY_AWS_REGION=${SECRETKEY_AWS_REGION} - SECRETKEY_AWS_NAME=${SECRETKEY_AWS_NAME} # LOGGING - DEBUG=${DEBUG} - LOG_PATH=${LOG_PATH} - LOG_LEVEL=${LOG_LEVEL} - LOG_SANITIZE_BODY_FIELDS=${LOG_SANITIZE_BODY_FIELDS} - LOG_SANITIZE_HEADER_FIELDS=${LOG_SANITIZE_HEADER_FIELDS} # CUSTOM TOOL/FUNCTION DEPENDENCIES - TOOL_FUNCTION_BUILTIN_DEP=${TOOL_FUNCTION_BUILTIN_DEP} - TOOL_FUNCTION_EXTERNAL_DEP=${TOOL_FUNCTION_EXTERNAL_DEP} - ALLOW_BUILTIN_DEP=${ALLOW_BUILTIN_DEP} # STORAGE - STORAGE_TYPE=${STORAGE_TYPE} - BLOB_STORAGE_PATH=${BLOB_STORAGE_PATH} - S3_STORAGE_BUCKET_NAME=${S3_STORAGE_BUCKET_NAME} - S3_STORAGE_ACCESS_KEY_ID=${S3_STORAGE_ACCESS_KEY_ID} - S3_STORAGE_SECRET_ACCESS_KEY=${S3_STORAGE_SECRET_ACCESS_KEY} - S3_STORAGE_REGION=${S3_STORAGE_REGION} - S3_ENDPOINT_URL=${S3_ENDPOINT_URL} - S3_FORCE_PATH_STYLE=${S3_FORCE_PATH_STYLE} - GOOGLE_CLOUD_STORAGE_CREDENTIAL=${GOOGLE_CLOUD_STORAGE_CREDENTIAL} - GOOGLE_CLOUD_STORAGE_PROJ_ID=${GOOGLE_CLOUD_STORAGE_PROJ_ID} - GOOGLE_CLOUD_STORAGE_BUCKET_NAME=${GOOGLE_CLOUD_STORAGE_BUCKET_NAME} - GOOGLE_CLOUD_UNIFORM_BUCKET_ACCESS=${GOOGLE_CLOUD_UNIFORM_BUCKET_ACCESS} # Azure Blob Storage (provide EITHER connection string OR account name + key) - AZURE_BLOB_STORAGE_CONNECTION_STRING=${AZURE_BLOB_STORAGE_CONNECTION_STRING} - AZURE_BLOB_STORAGE_ACCOUNT_NAME=${AZURE_BLOB_STORAGE_ACCOUNT_NAME} - AZURE_BLOB_STORAGE_ACCOUNT_KEY=${AZURE_BLOB_STORAGE_ACCOUNT_KEY} - AZURE_BLOB_STORAGE_CONTAINER_NAME=${AZURE_BLOB_STORAGE_CONTAINER_NAME} # SETTINGS - NUMBER_OF_PROXIES=${NUMBER_OF_PROXIES} - CORS_ORIGINS=${CORS_ORIGINS} - IFRAME_ORIGINS=${IFRAME_ORIGINS} - FLOWISE_FILE_SIZE_LIMIT=${FLOWISE_FILE_SIZE_LIMIT} - SHOW_COMMUNITY_NODES=${SHOW_COMMUNITY_NODES} - DISABLE_FLOWISE_TELEMETRY=${DISABLE_FLOWISE_TELEMETRY} - DISABLED_NODES=${DISABLED_NODES} - MODEL_LIST_CONFIG_JSON=${MODEL_LIST_CONFIG_JSON} # AUTH PARAMETERS - APP_URL=${APP_URL} - JWT_AUTH_TOKEN_SECRET=${JWT_AUTH_TOKEN_SECRET} - JWT_REFRESH_TOKEN_SECRET=${JWT_REFRESH_TOKEN_SECRET} - JWT_ISSUER=${JWT_ISSUER} - JWT_AUDIENCE=${JWT_AUDIENCE} - JWT_TOKEN_EXPIRY_IN_MINUTES=${JWT_TOKEN_EXPIRY_IN_MINUTES} - JWT_REFRESH_TOKEN_EXPIRY_IN_MINUTES=${JWT_REFRESH_TOKEN_EXPIRY_IN_MINUTES} - EXPIRE_AUTH_TOKENS_ON_RESTART=${EXPIRE_AUTH_TOKENS_ON_RESTART} - EXPRESS_SESSION_SECRET=${EXPRESS_SESSION_SECRET} - PASSWORD_RESET_TOKEN_EXPIRY_IN_MINS=${PASSWORD_RESET_TOKEN_EXPIRY_IN_MINS} - PASSWORD_SALT_HASH_ROUNDS=${PASSWORD_SALT_HASH_ROUNDS} - TOKEN_HASH_SECRET=${TOKEN_HASH_SECRET} - SECURE_COOKIES=${SECURE_COOKIES} # EMAIL - SMTP_HOST=${SMTP_HOST} - SMTP_PORT=${SMTP_PORT} - SMTP_USER=${SMTP_USER} - SMTP_PASSWORD=${SMTP_PASSWORD} - SMTP_SECURE=${SMTP_SECURE} - ALLOW_UNAUTHORIZED_CERTS=${ALLOW_UNAUTHORIZED_CERTS} - SENDER_EMAIL=${SENDER_EMAIL} # ENTERPRISE - LICENSE_URL=${LICENSE_URL} - FLOWISE_EE_LICENSE_KEY=${FLOWISE_EE_LICENSE_KEY} - OFFLINE=${OFFLINE} - INVITE_TOKEN_EXPIRY_IN_HOURS=${INVITE_TOKEN_EXPIRY_IN_HOURS} - WORKSPACE_INVITE_TEMPLATE_PATH=${WORKSPACE_INVITE_TEMPLATE_PATH} # METRICS COLLECTION - POSTHOG_PUBLIC_API_KEY=${POSTHOG_PUBLIC_API_KEY} - ENABLE_METRICS=${ENABLE_METRICS} - METRICS_PROVIDER=${METRICS_PROVIDER} - METRICS_INCLUDE_NODE_METRICS=${METRICS_INCLUDE_NODE_METRICS} - METRICS_SERVICE_NAME=${METRICS_SERVICE_NAME} - METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT=${METRICS_OPEN_TELEMETRY_METRIC_ENDPOINT} - METRICS_OPEN_TELEMETRY_PROTOCOL=${METRICS_OPEN_TELEMETRY_PROTOCOL} - METRICS_OPEN_TELEMETRY_DEBUG=${METRICS_OPEN_TELEMETRY_DEBUG} # PROXY - GLOBAL_AGENT_HTTP_PROXY=${GLOBAL_AGENT_HTTP_PROXY} - GLOBAL_AGENT_HTTPS_PROXY=${GLOBAL_AGENT_HTTPS_PROXY} - GLOBAL_AGENT_NO_PROXY=${GLOBAL_AGENT_NO_PROXY} # QUEUE CONFIGURATION - MODE=${MODE} - QUEUE_NAME=${QUEUE_NAME} - QUEUE_REDIS_EVENT_STREAM_MAX_LEN=${QUEUE_REDIS_EVENT_STREAM_MAX_LEN} - WORKER_CONCURRENCY=${WORKER_CONCURRENCY} - REMOVE_ON_AGE=${REMOVE_ON_AGE} - REMOVE_ON_COUNT=${REMOVE_ON_COUNT} - REDIS_URL=${REDIS_URL} - REDIS_HOST=${REDIS_HOST} - REDIS_PORT=${REDIS_PORT} - REDIS_USERNAME=${REDIS_USERNAME} - REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_TLS=${REDIS_TLS} - REDIS_CERT=${REDIS_CERT} - REDIS_KEY=${REDIS_KEY} - REDIS_CA=${REDIS_CA} - REDIS_KEEP_ALIVE=${REDIS_KEEP_ALIVE} - ENABLE_BULLMQ_DASHBOARD=${ENABLE_BULLMQ_DASHBOARD} # SECURITY - CUSTOM_MCP_SECURITY_CHECK=${CUSTOM_MCP_SECURITY_CHECK} - CUSTOM_MCP_PROTOCOL=${CUSTOM_MCP_PROTOCOL} - HTTP_DENY_LIST=${HTTP_DENY_LIST} - HTTP_SECURITY_CHECK=${HTTP_SECURITY_CHECK} - PATH_TRAVERSAL_SAFETY=${PATH_TRAVERSAL_SAFETY} - TRUST_PROXY=${TRUST_PROXY} ports: - '${WORKER_PORT}:${WORKER_PORT}' healthcheck: test: ['CMD', 'curl', '-f', 'http://localhost:${WORKER_PORT}/healthz'] interval: 10s timeout: 5s retries: 5 start_period: 30s volumes: - ~/.flowise:/root/.flowise entrypoint: /bin/sh -c "node /app/healthcheck/healthcheck.js & sleep 5 && pnpm run start-worker" ================================================ FILE: docker/worker/healthcheck/healthcheck.js ================================================ const express = require('express') const app = express() const port = process.env.WORKER_PORT || 5566 app.get('/healthz', (req, res) => { res.status(200).send('OK') }) app.listen(port, () => { // eslint-disable-next-line no-console console.log(`Healthcheck server listening on port ${port}`) }) ================================================ FILE: docker/worker/healthcheck/package.json ================================================ { "name": "flowise-worker-healthcheck", "version": "1.0.0", "description": "Simple healthcheck server for Flowise worker", "main": "healthcheck.js", "private": true, "scripts": { "start": "node healthcheck.js" }, "dependencies": { "express": "^4.19.2" } } ================================================ FILE: i18n/CODE_OF_CONDUCT-ZH.md ================================================ # 贡献者公约行为准则 [English](../CODE_OF_CONDUCT.md) | 中文 ## 我们的承诺 为了促进一个开放和友好的环境,我们作为贡献者和维护者承诺,使参与我们的项目和社区的体验对每个人来说都是无骚扰的,无论年龄、体型、残疾、种族、性别认同和表达、经验水平、国籍、个人形象、种族、宗教或性取向如何。 ## 我们的标准 有助于创建积极环境的行为示例包括: - 使用友好和包容性的语言 - 尊重不同的观点和经验 - 优雅地接受建设性的批评 - 关注社区最有利的事情 - 向其他社区成员表达同理心 参与者不可接受的行为示例包括: - 使用性暗示的语言或图像和不受欢迎的性关注或进展 - 恶作剧、侮辱/贬低的评论和个人或政治攻击 - 公开或私下骚扰 - 未经明确许可发布他人的私人信息,如实际或电子地址 - 在专业环境中可能被合理认为不适当的其他行为 ## 我们的责任 项目维护者有责任明确可接受行为的标准,并预期对任何不可接受行为的情况采取适当和公正的纠正措施。 项目维护者有权和责任删除、编辑或拒绝不符合本行为准则的评论、提交、代码、维基编辑、问题和其他贡献,或者临时或永久禁止任何贡献者,如果他们认为其行为不适当、威胁、冒犯或有害。 ## 适用范围 本行为准则适用于项目空间和公共空间,当个人代表项目或其社区时。代表项目或社区的示例包括使用官方项目电子邮件地址、通过官方社交媒体账号发布或在线或离线活动中担任指定代表。项目的代表可以由项目维护者进一步定义和澄清。 ## 执法 可以通过联系项目团队 hello@flowiseai.com 来报告滥用、骚扰或其他不可接受的行为。所有投诉将经过审核和调查,并将得出视情况认为必要和适当的回应。项目团队有义务对事件举报人保持机密。具体执行政策的更多细节可能会单独发布。 如果项目维护者不诚信地遵守或执行行为准则,可能会面临其他项目领导成员决定的临时或永久的后果。 ## 归属 该行为准则的内容来自于[贡献者公约](http://contributor-covenant.org/)1.4 版,可在[http://contributor-covenant.org/version/1/4](http://contributor-covenant.org/version/1/4)上获取。 [主页]: http://contributor-covenant.org ================================================ FILE: i18n/CONTRIBUTING-ZH.md ================================================ # 贡献给 Flowise [English](../CONTRIBUTING.md) | 中文 我们欢迎任何形式的贡献。 ## ⭐ 点赞 点赞并分享[Github 仓库](https://github.com/FlowiseAI/Flowise)。 ## 🙋 问题和回答 在[问题和回答](https://github.com/FlowiseAI/Flowise/discussions/categories/q-a)部分搜索任何问题,如果找不到,可以毫不犹豫地创建一个。这可能会帮助到其他有类似问题的人。 ## 🙌 分享 Chatflow 是的!分享你如何使用 Flowise 是一种贡献方式。将你的 Chatflow 导出为 JSON,附上截图并在[展示和分享](https://github.com/FlowiseAI/Flowise/discussions/categories/show-and-tell)部分分享。 ## 💡 想法 欢迎各种想法,如新功能、应用集成和区块链网络。在[想法](https://github.com/FlowiseAI/Flowise/discussions/categories/ideas)部分提交。 ## 🐞 报告错误 发现问题了吗?[报告它](https://github.com/FlowiseAI/Flowise/issues/new/choose)。 ## 👨‍💻 贡献代码 不确定要贡献什么?一些想法: - 从 `packages/components` 创建新组件 - 更新现有组件,如扩展功能、修复错误 - 添加新的 Chatflow 想法 ### 开发人员 Flowise 在一个单一的单体存储库中有 3 个不同的模块。 - `server`:用于提供 API 逻辑的 Node 后端 - `ui`:React 前端 - `components`:Langchain/LlamaIndex 组件 #### 先决条件 - 安装 [PNPM](https://pnpm.io/installation) ```bash npm i -g pnpm ``` #### 逐步指南 1. Fork 官方的[Flowise Github 仓库](https://github.com/FlowiseAI/Flowise)。 2. 克隆你 fork 的存储库。 3. 创建一个新的分支,参考[指南](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-and-deleting-branches-within-your-repository)。命名约定: - 对于功能分支:`feature/<你的新功能>` - 对于 bug 修复分支:`bugfix/<你的新bug修复>`。 4. 切换到新创建的分支。 5. 进入存储库文件夹 ```bash cd Flowise ``` 6. 安装所有模块的依赖项: ```bash pnpm install ``` 7. 构建所有代码: ```bash pnpm build ``` 8. 在[http://localhost:3000](http://localhost:3000)上启动应用程序 ```bash pnpm start ``` 9. 开发时: - 在`packages/ui`中创建`.env`文件并指定`VITE_PORT`(参考`.env.example`) - 在`packages/server`中创建`.env`文件并指定`PORT`(参考`.env.example`) - 运行 ```bash pnpm dev ``` 对`packages/ui`或`packages/server`进行的任何更改都将反映在[http://localhost:8080](http://localhost:8080)上 对于`packages/components`中进行的更改,再次运行`pnpm build`以应用更改。 10. 做完所有的更改后,运行以下命令来确保在生产环境中一切正常: ```bash pnpm build ``` 和 ```bash pnpm start ``` 11. 提交代码并从指向 [Flowise 主分支](https://github.com/FlowiseAI/Flowise/tree/main) 的分叉分支上提交 Pull Request。 ## 🌱 环境变量 Flowise 支持不同的环境变量来配置您的实例。您可以在 `packages/server` 文件夹中的 `.env` 文件中指定以下变量。阅读[更多信息](https://docs.flowiseai.com/environment-variables) | 变量名 | 描述 | 类型 | 默认值 | |-----------------------------|---------------------------------------------------------|-------------------------------------------------|-------------------------------------| | `PORT` | Flowise 运行的 HTTP 端口 | 数字 | 3000 | | `FLOWISE_FILE_SIZE_LIMIT` | 上传文件大小限制 | 字符串 | 50mb | | `DEBUG` | 打印组件的日志 | 布尔值 | | | `LOG_PATH` | 存储日志文件的位置 | 字符串 | `your-path/Flowise/logs` | | `LOG_LEVEL` | 日志的不同级别 | 枚举字符串: `error`, `info`, `verbose`, `debug` | `info` | | `TOOL_FUNCTION_BUILTIN_DEP` | 用于工具函数的 NodeJS 内置模块 | 字符串 | | | `TOOL_FUNCTION_EXTERNAL_DEP`| 用于工具函数的外部模块 | 字符串 | | | `DATABASE_TYPE` | 存储 Flowise 数据的数据库类型 | 枚举字符串: `sqlite`, `mysql`, `postgres` | `sqlite` | | `DATABASE_PATH` | 数据库保存的位置(当 `DATABASE_TYPE` 是 sqlite 时) | 字符串 | `your-home-dir/.flowise` | | `DATABASE_HOST` | 主机 URL 或 IP 地址(当 `DATABASE_TYPE` 不是 sqlite 时)| 字符串 | | | `DATABASE_PORT` | 数据库端口(当 `DATABASE_TYPE` 不是 sqlite 时) | 字符串 | | | `DATABASE_USERNAME` | 数据库用户名(当 `DATABASE_TYPE` 不是 sqlite 时) | 字符串 | | | `DATABASE_PASSWORD` | 数据库密码(当 `DATABASE_TYPE` 不是 sqlite 时) | 字符串 | | | `DATABASE_NAME` | 数据库名称(当 `DATABASE_TYPE` 不是 sqlite 时) | 字符串 | | | `SECRETKEY_PATH` | 保存加密密钥(用于加密/解密凭据)的位置 | 字符串 | `your-path/Flowise/packages/server` | | `FLOWISE_SECRETKEY_OVERWRITE`| 加密密钥用于替代存储在 `SECRETKEY_PATH` 中的密钥 | 字符串 | | | `MODEL_LIST_CONFIG_JSON` | 加载模型的位置 | 字符串 | `/your_model_list_config_file_path` | | `STORAGE_TYPE` | 上传文件的存储类型 | 枚举字符串: `local`, `s3` | `local` | | `BLOB_STORAGE_PATH` | 本地上传文件存储路径(当 `STORAGE_TYPE` 为 `local`) | 字符串 | `your-home-dir/.flowise/storage` | | `S3_STORAGE_BUCKET_NAME` | S3 存储文件夹路径(当 `STORAGE_TYPE` 为 `s3`) | 字符串 | | | `S3_STORAGE_ACCESS_KEY_ID` | AWS 访问密钥 (Access Key) | 字符串 | | | `S3_STORAGE_SECRET_ACCESS_KEY` | AWS 密钥 (Secret Key) | 字符串 | | | `S3_STORAGE_REGION` | S3 存储地区 | 字符串 | | | `S3_ENDPOINT_URL` | S3 端点 URL | 字符串 | | | `S3_FORCE_PATH_STYLE` | 设置为 true 以强制请求使用路径样式寻址 | 布尔值 | false | | `SHOW_COMMUNITY_NODES` | 显示由社区创建的节点 | 布尔值 | | | `DISABLED_NODES` | 从界面中隐藏节点(以逗号分隔的节点名称列表) | 字符串 | | 您也可以在使用 `npx` 时指定环境变量。例如: ``` npx flowise start --PORT=3000 --DEBUG=true ``` ## 📖 贡献文档 [Flowise 文档](https://github.com/FlowiseAI/FlowiseDocs) ## 🏷️ Pull Request 流程 当您打开一个 Pull Request 时,FlowiseAI 团队的成员将自动收到通知/指派。您也可以在 [Discord](https://discord.gg/jbaHfsRVBW) 上联系我们。 ================================================ FILE: i18n/README-JA.md ================================================

[![Release Notes](https://img.shields.io/github/release/FlowiseAI/Flowise)](https://github.com/FlowiseAI/Flowise/releases) [![Discord](https://img.shields.io/discord/1087698854775881778?label=Discord&logo=discord)](https://discord.gg/jbaHfsRVBW) [![Twitter Follow](https://img.shields.io/twitter/follow/FlowiseAI?style=social)](https://twitter.com/FlowiseAI) [![GitHub star chart](https://img.shields.io/github/stars/FlowiseAI/Flowise?style=social)](https://star-history.com/#FlowiseAI/Flowise) [![GitHub fork](https://img.shields.io/github/forks/FlowiseAI/Flowise?style=social)](https://github.com/FlowiseAI/Flowise/fork) [English](../README.md) | [繁體中文](./README-TW.md) | [简体中文](./README-ZH.md) | 日本語 | [한국어](./README-KR.md)

AIエージェントをビジュアルに構築

## ⚡ クイックスタート [NodeJS](https://nodejs.org/en/download) >= 18.15.0 をダウンロードしてインストール 1. Flowise のインストール ```bash npm install -g flowise ``` 2. Flowise の実行 ```bash npx flowise start ``` 3. [http://localhost:3000](http://localhost:3000) を開く ## 🐳 Docker ### Docker Compose 1. プロジェクトのルートにある `docker` フォルダに移動する 2. `.env.example` ファイルをコピーして同じ場所に貼り付け、名前を `.env` に変更する 3. `docker compose up -d` 4. [http://localhost:3000](http://localhost:3000) を開く 5. コンテナを停止するには、`docker compose stop` を使用します ### Docker Image 1. ローカルにイメージを構築する: ```bash docker build --no-cache -t flowise . ``` 2. image を実行: ```bash docker run -d --name flowise -p 3000:3000 flowise ``` 3. image を停止: ```bash docker stop flowise ``` ## 👨‍💻 開発者向け Flowise には、3 つの異なるモジュールが 1 つの mono リポジトリにあります。 - `server`: API ロジックを提供する Node バックエンド - `ui`: React フロントエンド - `components`: サードパーティノードとの統合 ### 必須条件 - [PNPM](https://pnpm.io/installation) をインストール ```bash npm i -g pnpm ``` ### セットアップ 1. リポジトリをクローン ```bash git clone https://github.com/FlowiseAI/Flowise.git ``` 2. リポジトリフォルダに移動 ```bash cd Flowise ``` 3. すべてのモジュールの依存関係をインストール: ```bash pnpm install ``` 4. すべてのコードをビルド: ```bash pnpm build ``` 5. アプリを起動: ```bash pnpm start ``` [http://localhost:3000](http://localhost:3000) でアプリにアクセスできるようになりました 6. 開発用ビルド: - `.env` ファイルを作成し、`packages/ui` に `VITE_PORT` を指定する(`.env.example` を参照) - `.env` ファイルを作成し、`packages/server` に `PORT` を指定する(`.env.example` を参照) - 実行 ```bash pnpm dev ``` コードの変更は [http://localhost:8080](http://localhost:8080) に自動的にアプリをリロードします ## 🌱 環境変数 Flowise は、インスタンスを設定するためのさまざまな環境変数をサポートしています。`packages/server` フォルダ内の `.env` ファイルで以下の変数を指定することができる。[続き](https://github.com/FlowiseAI/Flowise/blob/main/CONTRIBUTING.md#-env-variables)を読む ## 📖 ドキュメント [Flowise ドキュメント](https://docs.flowiseai.com/) ## 🌐 セルフホスト お客様の既存インフラに Flowise をセルフホストでデプロイ、様々な[デプロイ](https://docs.flowiseai.com/configuration/deployment)をサポートします - [AWS](https://docs.flowiseai.com/deployment/aws) - [Azure](https://docs.flowiseai.com/deployment/azure) - [Digital Ocean](https://docs.flowiseai.com/deployment/digital-ocean) - [GCP](https://docs.flowiseai.com/deployment/gcp) -
その他 - [Railway](https://docs.flowiseai.com/deployment/railway) [![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/pn4G8S?referralCode=WVNPD9) - [Render](https://docs.flowiseai.com/deployment/render) [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://docs.flowiseai.com/deployment/render) - [Hugging Face Spaces](https://docs.flowiseai.com/deployment/hugging-face) Hugging Face Spaces - [Elestio](https://elest.io/open-source/flowiseai) [![Deploy](https://pub-da36157c854648669813f3f76c526c2b.r2.dev/deploy-on-elestio-black.png)](https://elest.io/open-source/flowiseai) - [Sealos](https://cloud.sealos.io/?openapp=system-template%3FtemplateName%3Dflowise) [![](https://raw.githubusercontent.com/labring-actions/templates/main/Deploy-on-Sealos.svg)](https://cloud.sealos.io/?openapp=system-template%3FtemplateName%3Dflowise) - [RepoCloud](https://repocloud.io/details/?app_id=29) [![Deploy on RepoCloud](https://d16t0pc4846x52.cloudfront.net/deploy.png)](https://repocloud.io/details/?app_id=29)
## ☁️ クラウドホスト [Flowise Cloud の使い方を始める](https://flowiseai.com/) ## 🙋 サポート ご質問、問題提起、新機能のご要望は、[discussion](https://github.com/FlowiseAI/Flowise/discussions)までお気軽にどうぞ ## 🙌 コントリビュート これらの素晴らしい貢献者に感謝します [コントリビューティングガイド](../CONTRIBUTING.md)を参照してください。質問や問題があれば、[Discord](https://discord.gg/jbaHfsRVBW) までご連絡ください。 [![Star History Chart](https://api.star-history.com/svg?repos=FlowiseAI/Flowise&type=Timeline)](https://star-history.com/#FlowiseAI/Flowise&Date) ## 📄 ライセンス このリポジトリのソースコードは、[Apache License Version 2.0](../LICENSE.md)の下で利用可能です。 ================================================ FILE: i18n/README-KR.md ================================================

[![Release Notes](https://img.shields.io/github/release/FlowiseAI/Flowise)](https://github.com/FlowiseAI/Flowise/releases) [![Discord](https://img.shields.io/discord/1087698854775881778?label=Discord&logo=discord)](https://discord.gg/jbaHfsRVBW) [![Twitter Follow](https://img.shields.io/twitter/follow/FlowiseAI?style=social)](https://twitter.com/FlowiseAI) [![GitHub star chart](https://img.shields.io/github/stars/FlowiseAI/Flowise?style=social)](https://star-history.com/#FlowiseAI/Flowise) [![GitHub fork](https://img.shields.io/github/forks/FlowiseAI/Flowise?style=social)](https://github.com/FlowiseAI/Flowise/fork) [English](../README.md) | [繁體中文](./README-TW.md) | [简体中文](./README-ZH.md) | [日本語](./README-JA.md) | 한국어

AI 에이전트를 시각적으로 구축하세요

## ⚡빠른 시작 가이드 18.15.0 버전 이상의 [NodeJS](https://nodejs.org/en/download) 다운로드 및 설치 1. Flowise 설치 ```bash npm install -g flowise ``` 2. Flowise 시작하기 ```bash npx flowise start ``` 3. [http://localhost:3000](http://localhost:3000) URL 열기 ## 🐳 도커(Docker)를 활용하여 시작하기 ### 도커 컴포즈 활용 1. 프로젝트의 최상위(root) 디렉토리에 있는 `docker` 폴더로 이동하세요. 2. `.env.example` 파일을 복사한 후, 같은 경로에 붙여넣기 한 다음, `.env`로 이름을 변경합니다. 3. `docker compose up -d` 실행 4. [http://localhost:3000](http://localhost:3000) URL 열기 5. `docker compose stop` 명령어를 통해 컨테이너를 종료시킬 수 있습니다. ### 도커 이미지 활용 1. 로컬에서 이미지 빌드하기: ```bash docker build --no-cache -t flowise . ``` 2. 이미지 실행하기: ```bash docker run -d --name flowise -p 3000:3000 flowise ``` 3. 이미지 종료하기: ```bash docker stop flowise ``` ## 👨‍💻 개발자들을 위한 가이드 Flowise는 단일 리포지토리에 3개의 서로 다른 모듈이 있습니다. - `server`: API 로직을 제공하는 노드 백엔드 - `ui`: 리액트 프론트엔드 - `components`: 서드파티 노드 통합을 위한 컴포넌트 ### 사전 설치 요건 - [PNPM](https://pnpm.io/installation) 설치하기 ```bash npm i -g pnpm ``` ### 설치 및 설정 1. 리포지토리 복제 ```bash git clone https://github.com/FlowiseAI/Flowise.git ``` 2. 리포지토리 폴더로 이동 ```bash cd Flowise ``` 3. 모든 모듈의 종속성 설치: ```bash pnpm install ``` 4. 모든 코드 빌드하기: ```bash pnpm build ``` 5. 애플리케이션 시작: ```bash pnpm start ``` 이제 [http://localhost:3000](http://localhost:3000)에서 애플리케이션에 접속할 수 있습니다. 6. 개발 환경에서 빌드할 경우: - `packages/ui`경로에 `.env` 파일을 생성하고 `VITE_PORT`(`.env.example` 참조)를 지정합니다. - `packages/server`경로에 `.env` 파일을 생성하고 `PORT`(`.env.example` 참조)를 지정합니다. - 실행하기 ```bash pnpm dev ``` 코드가 변경되면 [http://localhost:8080](http://localhost:8080)에서 자동으로 애플리케이션을 새로고침 합니다. ## 🌱 환경 변수 Flowise는 인스턴스 구성을 위한 다양한 환경 변수를 지원합니다. `packages/server` 폴더 내 `.env` 파일에 다양한 환경 변수를 지정할 수 있습니다. [자세히 보기](https://github.com/FlowiseAI/Flowise/blob/main/CONTRIBUTING.md#-env-variables) ## 📖 공식 문서 [Flowise 문서](https://docs.flowiseai.com/) ## 🌐 자체 호스팅 하기 기존 인프라 환경에서 Flowise를 자체 호스팅으로 배포하세요. 다양한 배포 [deployments](https://docs.flowiseai.com/configuration/deployment) 방법을 지원합니다. - [AWS](https://docs.flowiseai.com/deployment/aws) - [Azure](https://docs.flowiseai.com/deployment/azure) - [Digital Ocean](https://docs.flowiseai.com/deployment/digital-ocean) - [GCP](https://docs.flowiseai.com/deployment/gcp) -
그 외 - [Railway](https://docs.flowiseai.com/deployment/railway) [![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/pn4G8S?referralCode=WVNPD9) - [Render](https://docs.flowiseai.com/deployment/render) [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://docs.flowiseai.com/deployment/render) - [HuggingFace Spaces](https://docs.flowiseai.com/deployment/hugging-face) HuggingFace Spaces - [Elestio](https://elest.io/open-source/flowiseai) [![Deploy](https://pub-da36157c854648669813f3f76c526c2b.r2.dev/deploy-on-elestio-black.png)](https://elest.io/open-source/flowiseai) - [Sealos](https://cloud.sealos.io/?openapp=system-template%3FtemplateName%3Dflowise) [![](https://raw.githubusercontent.com/labring-actions/templates/main/Deploy-on-Sealos.svg)](https://cloud.sealos.io/?openapp=system-template%3FtemplateName%3Dflowise) - [RepoCloud](https://repocloud.io/details/?app_id=29) [![Deploy on RepoCloud](https://d16t0pc4846x52.cloudfront.net/deploy.png)](https://repocloud.io/details/?app_id=29)
## ☁️ 클라우드 호스팅 서비스 [Flowise Cloud 시작하기](https://flowiseai.com/) ## 🙋 기술 지원 질문, 버그 리포팅, 새로운 기능 요청 등은 [discussion](https://github.com/FlowiseAI/Flowise/discussions) 섹션에서 자유롭게 이야기 해주세요. ## 🙌 오픈소스 활동에 기여하기 다음과 같은 멋진 기여자들(contributors)에게 감사드립니다. [contributing guide](../CONTRIBUTING.md)를 살펴보세요. 디스코드 [Discord](https://discord.gg/jbaHfsRVBW) 채널에서도 이슈나 질의응답을 진행하실 수 있습니다. [![Star History Chart](https://api.star-history.com/svg?repos=FlowiseAI/Flowise&type=Timeline)](https://star-history.com/#FlowiseAI/Flowise&Date) ## 📄 라이센스 본 리포지토리의 소스코드는 [Apache License Version 2.0](../LICENSE.md) 라이센스가 적용됩니다. ================================================ FILE: i18n/README-TW.md ================================================

[![Release Notes](https://img.shields.io/github/release/FlowiseAI/Flowise)](https://github.com/FlowiseAI/Flowise/releases) [![Discord](https://img.shields.io/discord/1087698854775881778?label=Discord&logo=discord)](https://discord.gg/jbaHfsRVBW) [![Twitter Follow](https://img.shields.io/twitter/follow/FlowiseAI?style=social)](https://twitter.com/FlowiseAI) [![GitHub star chart](https://img.shields.io/github/stars/FlowiseAI/Flowise?style=social)](https://star-history.com/#FlowiseAI/Flowise) [![GitHub fork](https://img.shields.io/github/forks/FlowiseAI/Flowise?style=social)](https://github.com/FlowiseAI/Flowise/fork) [English](../README.md) | 繁體中文 | [简体中文](./README-ZH.md) | [日本語](./README-JA.md) | [한국어](./README-KR.md)

可視化建置 AI/LLM 流程

## ⚡ 快速開始 下載並安裝 [NodeJS](https://nodejs.org/en/download) >= 18.15.0 1. 安裝 Flowise ```bash npm install -g flowise ``` 2. 啟動 Flowise ```bash npx flowise start ``` 3. 打開 [http://localhost:3000](http://localhost:3000) ## 🐳 Docker ### Docker Compose 1. 複製 Flowise 專案 2. 進入專案根目錄的 `docker` 資料夾 3. 複製 `.env.example` 文件,貼到相同位置,並重新命名為 `.env` 文件 4. `docker compose up -d` 5. 打開 [http://localhost:3000](http://localhost:3000) 6. 您可以透過 `docker compose stop` 停止容器 ### Docker 映像 1. 本地建置映像: ```bash docker build --no-cache -t flowise . ``` 2. 運行映像: ```bash docker run -d --name flowise -p 3000:3000 flowise ``` 3. 停止映像: ```bash docker stop flowise ``` ## 👨‍💻 開發者 Flowise 在單個 mono 儲存庫中有 3 個不同的模組。 - `server`: 提供 API 邏輯的 Node 後端 - `ui`: React 前端 - `components`: 第三方節點集成 - `api-documentation`: 從 express 自動生成的 swagger-ui API 文檔 ### 先決條件 - 安裝 [PNPM](https://pnpm.io/installation) ```bash npm i -g pnpm ``` ### 設置 1. 複製儲存庫 ```bash git clone https://github.com/FlowiseAI/Flowise.git ``` 2. 進入儲存庫文件夾 ```bash cd Flowise ``` 3. 安裝所有模組的所有依賴項: ```bash pnpm install ``` 4. 建置所有程式碼: ```bash pnpm build ```
Exit code 134(JavaScript heap out of memory) 如果在運行上述 `build` 腳本時遇到此錯誤,請嘗試增加 Node.js 中的 Heap 記憶體大小並重新運行腳本: export NODE_OPTIONS="--max-old-space-size=4096" pnpm build
5. 啟動應用: ```bash pnpm start ``` 您現在可以開啟 [http://localhost:3000](http://localhost:3000) 6. 對於開發建置: - 在 `packages/ui` 中創建 `.env` 文件並指定 `VITE_PORT`(參考 `.env.example`) - 在 `packages/server` 中創建 `.env` 文件並指定 `PORT`(參考 `.env.example`) - 運行 ```bash pnpm dev ``` 任何程式碼更改都會自動重新加載應用程式 [http://localhost:8080](http://localhost:8080) ## 🌱 環境變數 Flowise 支持不同的環境變數來配置您的實例。您可以在 `packages/server` 文件夾中的 `.env` 文件中指定以下變數。閱讀 [更多](https://github.com/FlowiseAI/Flowise/blob/main/CONTRIBUTING.md#-env-variables) ## 📖 文檔 [Flowise 文檔](https://docs.flowiseai.com/) ## 🌐 自行架設 在您現有的基礎設施中部署 Flowise,我們支持各種自行架設選項 [部署](https://docs.flowiseai.com/configuration/deployment) - [AWS](https://docs.flowiseai.com/configuration/deployment/aws) - [Azure](https://docs.flowiseai.com/configuration/deployment/azure) - [Digital Ocean](https://docs.flowiseai.com/configuration/deployment/digital-ocean) - [GCP](https://docs.flowiseai.com/configuration/deployment/gcp) - [阿里雲](https://computenest.console.aliyun.com/service/instance/create/default?type=user&ServiceName=Flowise社区版) -
其他 - [Railway](https://docs.flowiseai.com/configuration/deployment/railway) [![Deploy on Railway](https://railway.app/button.svg)](https://railway.app/template/pn4G8S?referralCode=WVNPD9) - [Render](https://docs.flowiseai.com/configuration/deployment/render) [![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://docs.flowiseai.com/configuration/deployment/render) - [HuggingFace Spaces](https://docs.flowiseai.com/deployment/hugging-face) HuggingFace Spaces - [Elestio](https://elest.io/open-source/flowiseai) [![Deploy on Elestio](https://elest.io/images/logos/deploy-to-elestio-btn.png)](https://elest.io/open-source/flowiseai) - [Sealos](https://cloud.sealos.io/?openapp=system-template%3FtemplateName%3Dflowise) [![](https://raw.githubusercontent.com/labring-actions/templates/main/Deploy-on-Sealos.svg)](https://cloud.sealos.io/?openapp=system-template%3FtemplateName%3Dflowise) - [RepoCloud](https://repocloud.io/details/?app_id=29) [![Deploy on RepoCloud](https://d16t0pc4846x52.cloudfront.net/deploy.png)](https://repocloud.io/details/?app_id=29)
## ☁️ Flowise 雲端平台 [開始使用 Flowise 雲端平台](https://flowiseai.com/) ## 🙋 支持 隨時在 [討論](https://github.com/FlowiseAI/Flowise/discussions) 中提出任何問題、提出問題和請求新功能 ## 🙌 貢獻 感謝這些出色的貢獻者 請參閱 [貢獻指南](../CONTRIBUTING.md)。如果您有任何問題或問題,請透過 [Discord](https://discord.gg/jbaHfsRVBW) 與我們聯繫。 [![Star History Chart](https://api.star-history.com/svg?repos=FlowiseAI/Flowise&type=Timeline)](https://star-history.com/#FlowiseAI/Flowise&Date) ## 📄 許可證 此儲存庫中的原始碼根據 [Apache 2.0 授權條款](../LICENSE.md) 授權使用。 ================================================ FILE: i18n/README-ZH.md ================================================

[![发布说明](https://img.shields.io/github/release/FlowiseAI/Flowise)](https://github.com/FlowiseAI/Flowise/releases) [![Discord](https://img.shields.io/discord/1087698854775881778?label=Discord&logo=discord)](https://discord.gg/jbaHfsRVBW) [![Twitter关注](https://img.shields.io/twitter/follow/FlowiseAI?style=social)](https://twitter.com/FlowiseAI) [![GitHub星图](https://img.shields.io/github/stars/FlowiseAI/Flowise?style=social)](https://star-history.com/#FlowiseAI/Flowise) [![GitHub分支](https://img.shields.io/github/forks/FlowiseAI/Flowise?style=social)](https://github.com/FlowiseAI/Flowise/fork) [English](../README.md) | [繁體中文](./README-TW.md) | 简体中文 | [日本語](./README-JA.md) | [한국어](./README-KR.md)

可视化构建 AI/LLM 流程

## ⚡ 快速入门 下载并安装 [NodeJS](https://nodejs.org/en/download) >= 18.15.0 1. 安装 Flowise ```bash npm install -g flowise ``` 2. 启动 Flowise ```bash npx flowise start ``` 3. 打开 [http://localhost:3000](http://localhost:3000) ## 🐳 Docker ### Docker Compose 1. 进入项目根目录下的 `docker` 文件夹 2. 创建 `.env` 文件并指定 `PORT`(参考 `.env.example`) 3. 运行 `docker compose up -d` 4. 打开 [http://localhost:3000](http://localhost:3000) 5. 可以通过 `docker compose stop` 停止容器 ### Docker 镜像 1. 本地构建镜像: ```bash docker build --no-cache -t flowise . ``` 2. 运行镜像: ```bash docker run -d --name flowise -p 3000:3000 flowise ``` 3. 停止镜像: ```bash docker stop flowise ``` ## 👨‍💻 开发者 Flowise 在一个单一的代码库中有 3 个不同的模块。 - `server`:用于提供 API 逻辑的 Node 后端 - `ui`:React 前端 - `components`:第三方节点集成 ### 先决条件 - 安装 [PNPM](https://pnpm.io/installation) ```bash npm i -g pnpm ``` ### 设置 1. 克隆仓库 ```bash git clone https://github.com/FlowiseAI/Flowise.git ``` 2. 进入仓库文件夹 ```bash cd Flowise ``` 3. 安装所有模块的依赖: ```bash pnpm install ``` 4. 构建所有代码: ```bash pnpm build ``` 5. 启动应用: ```bash pnpm start ``` 现在可以在 [http://localhost:3000](http://localhost:3000) 访问应用 6. 用于开发构建: - 在 `packages/ui` 中创建 `.env` 文件并指定 `VITE_PORT`(参考 `.env.example`) - 在 `packages/server` 中创建 `.env` 文件并指定 `PORT`(参考 `.env.example`) - 运行 ```bash pnpm dev ``` 任何代码更改都会自动重新加载应用程序,访问 [http://localhost:8080](http://localhost:8080) ## 🌱 环境变量 Flowise 支持不同的环境变量来配置您的实例。您可以在 `packages/server` 文件夹中的 `.env` 文件中指定以下变量。了解更多信息,请阅读[文档](https://github.com/FlowiseAI/Flowise/blob/main/CONTRIBUTING.md#-env-variables) ## 📖 文档 [Flowise 文档](https://docs.flowiseai.com/) ## 🌐 自托管 在您现有的基础设施中部署自托管的 Flowise,我们支持各种[部署](https://docs.flowiseai.com/configuration/deployment) - [AWS](https://docs.flowiseai.com/deployment/aws) - [Azure](https://docs.flowiseai.com/deployment/azure) - [Digital Ocean](https://docs.flowiseai.com/deployment/digital-ocean) - [GCP](https://docs.flowiseai.com/deployment/gcp) -
其他 - [Railway](https://docs.flowiseai.com/deployment/railway) [![在 Railway 上部署](https://railway.app/button.svg)](https://railway.app/template/pn4G8S?referralCode=WVNPD9) - [Render](https://docs.flowiseai.com/deployment/render) [![部署到 Render](https://render.com/images/deploy-to-render-button.svg)](https://docs.flowiseai.com/deployment/render) - [HuggingFace Spaces](https://docs.flowiseai.com/deployment/hugging-face) HuggingFace Spaces - [Elestio](https://elest.io/open-source/flowiseai) [![Deploy](https://pub-da36157c854648669813f3f76c526c2b.r2.dev/deploy-on-elestio-black.png)](https://elest.io/open-source/flowiseai) - [Sealos](https://template.sealos.io/deploy?templateName=flowise) [![部署到 Sealos](https://sealos.io/Deploy-on-Sealos.svg)](https://template.sealos.io/deploy?templateName=flowise) - [RepoCloud](https://repocloud.io/details/?app_id=29) [![部署到 RepoCloud](https://d16t0pc4846x52.cloudfront.net/deploy.png)](https://repocloud.io/details/?app_id=29)
## ☁️ 云托管 [开始使用云托管](https://flowiseai.com/) ## 🙋 支持 在[讨论区](https://github.com/FlowiseAI/Flowise/discussions)中随时提问、提出问题和请求新功能 ## 🙌 贡献 感谢这些了不起的贡献者 参见[贡献指南](CONTRIBUTING-ZH.md)。如果您有任何问题或问题,请在[Discord](https://discord.gg/jbaHfsRVBW)上与我们联系。 ## 📄 许可证 此代码库中的源代码在[Apache License Version 2.0 许可证](../LICENSE.md)下提供。 ================================================ FILE: metrics/grafana/grafana.dashboard.app.json.txt ================================================ { "annotations": { "list": [ { "builtIn": 1, "datasource": { "type": "grafana", "uid": "-- Grafana --" }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", "type": "dashboard" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "enable": true, "expr": "ALERTS", "hide": false, "iconColor": "rgba(255, 96, 96, 1)", "limit": 100, "name": "Alerts", "showIn": 0, "step": "10s", "type": "alert" } ] }, "description": "Application metrics", "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, "id": 3, "links": [], "panels": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 0, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "auto", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] } }, "overrides": [] }, "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 }, "id": 11, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "single", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "disableTextWrap": false, "editorMode": "code", "expr": "sum(rate(internal_predictions[1m])) by (status) * 60", "fullMetaSearch": false, "hide": false, "includeNullMetadata": false, "instant": false, "legendFormat": "__auto", "range": true, "refId": "B", "useBackend": false } ], "title": "Internal Predictions", "type": "timeseries" }, { "collapsed": false, "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 8 }, "id": 7, "panels": [], "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "refId": "A" } ], "title": "Throughput", "type": "row" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "mappings": [ { "options": { "match": "null", "result": { "text": "N/A" } }, "type": "special" } ], "max": 1, "min": 0, "thresholds": { "mode": "absolute", "steps": [ { "color": "rgba(50, 172, 45, 0.97)", "value": null }, { "color": "rgba(237, 129, 40, 0.89)", "value": 0.1 }, { "color": "rgba(245, 54, 54, 0.9)" } ] }, "unit": "none" }, "overrides": [] }, "gridPos": { "h": 7, "w": 6, "x": 0, "y": 9 }, "hideTimeOverride": false, "id": 6, "maxDataPoints": 100, "options": { "colorMode": "value", "graphMode": "none", "justifyMode": "auto", "orientation": "horizontal", "percentChangeColorMode": "standard", "reduceOptions": { "calcs": [ "mean" ], "fields": "/^Value$/", "values": false }, "showPercentChange": false, "textMode": "auto", "wideLayout": true }, "pluginVersion": "11.1.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "sum(increase(http_request_duration_ms_count{code=~\"^5..$\"}[1m])) / sum(increase(http_request_duration_ms_count[1m]))", "format": "time_series", "interval": "", "intervalFactor": 2, "legendFormat": "", "refId": "A", "step": 20 } ], "title": "Error rate", "type": "stat" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "rpm" }, "overrides": [] }, "gridPos": { "h": 7, "w": 18, "x": 6, "y": 9 }, "id": 1, "links": [ { "url": "/" } ], "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "sum(rate(http_request_duration_ms_count[1m])) by (service, route, method, code) * 60", "format": "time_series", "hide": false, "intervalFactor": 2, "legendFormat": "{{service}} - {{method}} {{route}} {{code}}", "metric": "", "refId": "A", "step": 2 } ], "title": "Throughput", "type": "timeseries" }, { "collapsed": true, "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 16 }, "id": 8, "panels": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green" }, { "color": "red", "value": 80 } ] }, "unit": "ms" }, "overrides": [] }, "gridPos": { "h": 7, "w": 24, "x": 0, "y": 17 }, "id": 4, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "histogram_quantile(0.5, sum(rate(http_request_duration_ms_bucket[1m])) by (le, service, route, method))", "format": "time_series", "intervalFactor": 2, "legendFormat": "{{service}} - {{method}} {{route}}", "refId": "A", "step": 2 } ], "title": "Median Response Time", "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green" }, { "color": "red", "value": 80 } ] }, "unit": "ms" }, "overrides": [] }, "gridPos": { "h": 7, "w": 24, "x": 0, "y": 24 }, "id": 2, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "histogram_quantile(0.95, sum(rate(http_request_duration_ms_bucket[1m])) by (le, service, route, method))", "format": "time_series", "interval": "", "intervalFactor": 2, "legendFormat": "{{service}} - {{method}} {{route}}", "refId": "A", "step": 2 } ], "title": "95th Response Time", "type": "timeseries" } ], "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "refId": "A" } ], "title": "Response time", "type": "row" }, { "collapsed": false, "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 17 }, "id": 10, "panels": [], "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "refId": "A" } ], "title": "Business", "type": "row" } ], "refresh": "10s", "schemaVersion": 39, "tags": [], "templating": { "list": [] }, "time": { "from": "now-15m", "to": "now" }, "timepicker": { "refresh_intervals": [ "5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d" ], "time_options": [ "5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d" ] }, "timezone": "browser", "title": "FlowiseAI - Custom Metrics", "uid": "dds4pojnfec5cc", "version": 8, "weekStart": "" } ================================================ FILE: metrics/grafana/grafana.dashboard.server.json.txt ================================================ { "annotations": { "list": [ { "builtIn": 1, "datasource": { "type": "datasource", "uid": "grafana" }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", "type": "dashboard" } ] }, "description": "node.js prometheus client basic metrics", "editable": true, "fiscalYearStartMonth": 0, "gnetId": 11159, "graphTooltip": 0, "id": 1, "links": [], "panels": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "percent" }, "overrides": [] }, "gridPos": { "h": 7, "w": 10, "x": 0, "y": 0 }, "id": 6, "options": { "legend": { "calcs": [ "mean", "lastNotNull", "max", "min" ], "displayMode": "table", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "irate(process_cpu_user_seconds_total{instance=~\"$instance\"}[2m]) * 100", "format": "time_series", "intervalFactor": 1, "legendFormat": "User CPU - {{instance}}", "refId": "A" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "irate(process_cpu_system_seconds_total{instance=~\"$instance\"}[2m]) * 100", "format": "time_series", "intervalFactor": 1, "legendFormat": "Sys CPU - {{instance}}", "refId": "B" } ], "title": "Process CPU Usage", "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "s" }, "overrides": [] }, "gridPos": { "h": 7, "w": 9, "x": 10, "y": 0 }, "id": 8, "options": { "legend": { "calcs": [ "mean", "lastNotNull", "max", "min" ], "displayMode": "table", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "nodejs_eventloop_lag_seconds{instance=~\"$instance\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "{{instance}}", "refId": "A" } ], "title": "Event Loop Lag", "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "description": "", "fieldConfig": { "defaults": { "mappings": [ { "options": { "match": "null", "result": { "text": "N/A" } }, "type": "special" } ], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "none" }, "overrides": [] }, "gridPos": { "h": 3, "w": 5, "x": 19, "y": 0 }, "id": 2, "interval": "", "maxDataPoints": 100, "options": { "colorMode": "none", "graphMode": "none", "justifyMode": "auto", "orientation": "horizontal", "percentChangeColorMode": "standard", "reduceOptions": { "calcs": [ "mean" ], "fields": "/^v22\\.3\\.0$/", "values": false }, "showPercentChange": false, "textMode": "name", "wideLayout": true }, "pluginVersion": "11.1.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "disableTextWrap": false, "editorMode": "code", "expr": "sum(nodejs_version_info{instance=~\"$instance\"}) by (version)", "fullMetaSearch": false, "hide": false, "includeNullMetadata": true, "instant": false, "legendFormat": "__auto", "range": true, "refId": "A", "useBackend": false } ], "title": "Node.js Version", "type": "stat" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "color": { "fixedColor": "#F2495C", "mode": "fixed" }, "mappings": [ { "options": { "match": "null", "result": { "text": "N/A" } }, "type": "special" } ], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "none" }, "overrides": [] }, "gridPos": { "h": 4, "w": 5, "x": 19, "y": 3 }, "id": 4, "maxDataPoints": 100, "options": { "colorMode": "none", "graphMode": "area", "justifyMode": "auto", "orientation": "horizontal", "percentChangeColorMode": "standard", "reduceOptions": { "calcs": [ "lastNotNull" ], "fields": "", "values": false }, "showPercentChange": false, "textMode": "auto", "wideLayout": true }, "pluginVersion": "11.1.0", "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "sum(changes(process_start_time_seconds{instance=~\"$instance\"}[1m]))", "format": "time_series", "intervalFactor": 1, "legendFormat": "{{instance}}", "refId": "A" } ], "title": "Process Restart Times", "type": "stat" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "bytes" }, "overrides": [] }, "gridPos": { "h": 7, "w": 16, "x": 0, "y": 7 }, "id": 7, "options": { "legend": { "calcs": [ "mean", "lastNotNull", "max", "min" ], "displayMode": "table", "placement": "right", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "process_resident_memory_bytes{instance=~\"$instance\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "Process Memory - {{instance}}", "refId": "A" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "nodejs_heap_size_total_bytes{instance=~\"$instance\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "Heap Total - {{instance}}", "refId": "B" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "nodejs_heap_size_used_bytes{instance=~\"$instance\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "Heap Used - {{instance}}", "refId": "C" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "nodejs_external_memory_bytes{instance=~\"$instance\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "External Memory - {{instance}}", "refId": "D" } ], "title": "Process Memory Usage", "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "short" }, "overrides": [] }, "gridPos": { "h": 7, "w": 8, "x": 16, "y": 7 }, "id": 9, "options": { "legend": { "calcs": [ "mean", "lastNotNull", "max", "min" ], "displayMode": "table", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "nodejs_active_handles_total{instance=~\"$instance\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "Active Handler - {{instance}}", "refId": "A" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "nodejs_active_requests_total{instance=~\"$instance\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "Active Request - {{instance}}", "refId": "B" } ], "title": "Active Handlers/Requests Total", "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "bytes" }, "overrides": [] }, "gridPos": { "h": 8, "w": 8, "x": 0, "y": 14 }, "id": 10, "options": { "legend": { "calcs": [ "mean", "lastNotNull", "max", "min" ], "displayMode": "table", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "nodejs_heap_space_size_total_bytes{instance=~\"$instance\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "Heap Total - {{instance}} - {{space}}", "refId": "A" } ], "title": "Heap Total Detail", "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "bytes" }, "overrides": [] }, "gridPos": { "h": 8, "w": 8, "x": 8, "y": 14 }, "id": 11, "options": { "legend": { "calcs": [ "mean", "lastNotNull", "max", "min" ], "displayMode": "table", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "nodejs_heap_space_size_used_bytes{instance=~\"$instance\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "Heap Used - {{instance}} - {{space}}", "refId": "A" } ], "title": "Heap Used Detail", "type": "timeseries" }, { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { "axisBorderShow": false, "axisCenteredZero": false, "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, "drawStyle": "line", "fillOpacity": 10, "gradientMode": "none", "hideFrom": { "legend": false, "tooltip": false, "viz": false }, "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, "scaleDistribution": { "type": "linear" }, "showPoints": "never", "spanNulls": false, "stacking": { "group": "A", "mode": "none" }, "thresholdsStyle": { "mode": "off" } }, "mappings": [], "thresholds": { "mode": "absolute", "steps": [ { "color": "green", "value": null }, { "color": "red", "value": 80 } ] }, "unit": "bytes" }, "overrides": [] }, "gridPos": { "h": 8, "w": 8, "x": 16, "y": 14 }, "id": 12, "options": { "legend": { "calcs": [ "mean", "lastNotNull", "max", "min" ], "displayMode": "table", "placement": "bottom", "showLegend": true }, "tooltip": { "mode": "multi", "sort": "none" } }, "targets": [ { "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "expr": "nodejs_heap_space_size_available_bytes{instance=~\"$instance\"}", "format": "time_series", "intervalFactor": 1, "legendFormat": "Heap Used - {{instance}} - {{space}}", "refId": "A" } ], "title": "Heap Available Detail", "type": "timeseries" } ], "schemaVersion": 39, "tags": [ "nodejs" ], "templating": { "list": [ { "current": { "selected": false, "text": "All", "value": "$__all" }, "datasource": { "type": "prometheus", "uid": "cds4j1ybfuhogb" }, "definition": "label_values(nodejs_version_info, instance)", "hide": 0, "includeAll": true, "label": "instance", "multi": true, "name": "instance", "options": [], "query": "label_values(nodejs_version_info, instance)", "refresh": 1, "regex": "", "skipUrlSync": false, "sort": 1, "tagValuesQuery": "", "tagsQuery": "", "type": "query", "useTags": false } ] }, "time": { "from": "now-1h", "to": "now" }, "timepicker": { "refresh_intervals": [ "5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d" ], "time_options": [ "5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d" ] }, "timezone": "", "title": "FlowiseAI Server", "uid": "PTSqcpJWk", "version": 5, "weekStart": "" } ================================================ FILE: metrics/otel/compose.yaml ================================================ version: "2" services: otel-collector: read_only: true image: otel/opentelemetry-collector-contrib command: ["--config=/etc/otelcol-contrib/config.yaml", "--feature-gates=-exporter.datadogexporter.DisableAPMStats", "${OTELCOL_ARGS}"] volumes: - ./otel.config.yml:/etc/otelcol-contrib/config.yaml ports: - 1888:1888 # pprof extension - 8888:8888 # Prometheus metrics exposed by the Collector - 8889:8889 # Prometheus exporter metrics - 13133:13133 # health_check extension - 4317:4317 # OTLP gRPC receiver - 4318:4318 # OTLP http receiver - 55679:55679 # zpages extension ================================================ FILE: metrics/otel/otel.config.yml ================================================ receivers: otlp: protocols: http: endpoint: 0.0.0.0:4318 grpc: endpoint: 0.0.0.0:4317 # The hostmetrics receiver is required to get correct infrastructure metrics in Datadog. hostmetrics: collection_interval: 10s scrapers: paging: metrics: system.paging.utilization: enabled: true cpu: metrics: system.cpu.utilization: enabled: true disk: filesystem: metrics: system.filesystem.utilization: enabled: true load: memory: network: # The prometheus receiver scrapes metrics needed for the OpenTelemetry Collector Dashboard. prometheus: config: scrape_configs: - job_name: 'otelcol' scrape_interval: 10s static_configs: - targets: ['0.0.0.0:8888'] filelog: include_file_path: true poll_interval: 10s include: - /var/log/**/*example*/*.log processors: batch: send_batch_max_size: 100 send_batch_size: 10 timeout: 10s connectors: datadog/connector: exporters: datadog/exporter: api: site: us5.datadoghq.com key: "replace_api_key" service: pipelines: metrics: receivers: [datadog/connector, hostmetrics, prometheus, otlp] processors: [batch] exporters: [datadog/exporter] traces: receivers: [otlp] processors: [batch] exporters: [datadog/connector, datadog/exporter] logs: receivers: [otlp, filelog] processors: [batch] exporters: [datadog/exporter] ================================================ FILE: metrics/prometheus/prometheus.config.yml ================================================ global: scrape_interval: 5s scrape_configs: - job_name: 'FlowiseAI' static_configs: - targets: ['localhost:8080', 'localhost:3000'] metrics_path: /api/v1/metrics/ scheme: http authorization: type: Bearer credentials_file: '/etc/prometheus/api_key.txt' ================================================ FILE: package.json ================================================ { "name": "flowise", "version": "3.1.0", "private": true, "homepage": "https://flowiseai.com", "workspaces": [ "packages/*", "flowise", "ui", "components", "api-documentation" ], "scripts": { "build": "turbo run build", "build-force": "pnpm clean && turbo run build --force", "dev": "turbo run dev --parallel --no-cache", "start": "run-script-os", "start:windows": "cd packages/server/bin && run start", "start:default": "cd packages/server/bin && ./run start", "start-worker": "run-script-os", "start-worker:windows": "cd packages/server/bin && run worker", "start-worker:default": "cd packages/server/bin && ./run worker", "user": "run-script-os", "user:windows": "cd packages/server/bin && run user", "user:default": "cd packages/server/bin && ./run user", "test": "turbo run test", "test:coverage": "turbo run test:coverage", "clean": "pnpm --filter \"./packages/**\" clean", "nuke": "pnpm --filter \"./packages/**\" nuke && rimraf node_modules .turbo", "format": "prettier --write \"**/*.{ts,tsx,md}\"", "lint": "eslint \"**/*.{js,jsx,ts,tsx,json,md}\"", "lint-fix": "pnpm lint --fix", "quick": "pretty-quick --staged", "postinstall": "husky install", "migration:create": "pnpm typeorm migration:create" }, "lint-staged": { "*.{js,jsx,ts,tsx,json,md}": "eslint --fix" }, "devDependencies": { "@babel/preset-env": "^7.19.4", "@babel/preset-typescript": "7.18.6", "@types/express": "^4.17.13", "@typescript-eslint/typescript-estree": "^7.13.1", "eslint": "^8.24.0", "eslint-config-prettier": "^8.3.0", "eslint-config-react-app": "^7.0.1", "eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-markdown": "^3.0.0", "eslint-plugin-prettier": "^3.4.0", "eslint-plugin-react": "^7.26.1", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-unused-imports": "^2.0.0", "husky": "^8.0.1", "kill-port": "2.0.1", "lint-staged": "^13.0.3", "prettier": "^2.7.1", "pretty-quick": "^3.1.3", "rimraf": "^3.0.2", "run-script-os": "^1.1.6", "turbo": "1.10.16", "typescript": "^5.4.5" }, "pnpm": { "onlyBuiltDependencies": [ "faiss-node", "sqlite3" ], "overrides": { "axios": "1.12.0", "body-parser": "2.0.2", "braces": "3.0.3", "cross-spawn": "7.0.6", "form-data": "4.0.4", "glob-parent": "6.0.2", "http-proxy-middleware": "3.0.3", "json5": "2.2.3", "nth-check": "2.1.1", "path-to-regexp": "0.1.12", "prismjs": "1.29.0", "rollup": "4.45.0", "semver": "7.7.1", "set-value": "4.1.0", "solid-js": "1.9.7", "tar-fs": "3.1.0", "unset-value": "2.0.1", "webpack-dev-middleware": "7.4.2", "ws": "8.18.3", "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", "uuid": "^10.0.0", "request>uuid": "^3.4.0" } }, "engines": { "node": ">=18.15.0 <19.0.0 || ^20", "pnpm": "^10.26.0" }, "resolutions": { "@anthropic-ai/sdk": "^0.73.0", "@google/generative-ai": "^0.24.0", "@grpc/grpc-js": "^1.10.10", "@langchain/core": "1.1.20", "@qdrant/openapi-typescript-fetch": "1.2.6", "openai": "6.19.0", "protobufjs": "7.4.0", "uuid": "^10.0.0" }, "eslintIgnore": [ "**/dist", "**/node_modules", "**/build", "**/package-lock.json" ], "prettier": { "printWidth": 140, "singleQuote": true, "jsxSingleQuote": true, "trailingComma": "none", "tabWidth": 4, "semi": false, "endOfLine": "auto" }, "babel": { "presets": [ "@babel/preset-typescript", [ "@babel/preset-env", { "targets": { "node": "current" } } ] ] } } ================================================ FILE: packages/agentflow/.eslintignore ================================================ dist node_modules build coverage *.config.ts *.config.js vite.config.ts examples/dist examples/vite.config.ts ================================================ FILE: packages/agentflow/.eslintrc.js ================================================ const features = ['canvas', 'generator', 'node-editor', 'node-palette'] const crossFeatureRules = features.map((feature) => ({ target: `./src/features/${feature}`, from: './src/features', except: [`./${feature}`], message: 'Features cannot import from other features. Move shared logic to core.' })) module.exports = { root: true, extends: [ 'eslint:recommended', 'plugin:markdown/recommended', 'plugin:react/recommended', 'plugin:react/jsx-runtime', 'plugin:react-hooks/recommended', 'plugin:jsx-a11y/recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended' ], parser: '@typescript-eslint/parser', parserOptions: { ecmaVersion: 'latest', sourceType: 'module', ecmaFeatures: { jsx: true } }, settings: { react: { version: 'detect' }, 'import/resolver': { typescript: { project: './tsconfig.json' } } }, plugins: ['react', 'react-hooks', '@typescript-eslint', 'unused-imports', 'jsx-a11y', 'simple-import-sort', 'import'], ignorePatterns: ['dist', 'node_modules', 'build', 'vite.config.ts', 'examples/dist', '**/*.json'], rules: { '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-explicit-any': 'warn', '@typescript-eslint/no-unused-vars': 'off', 'no-unused-vars': 'off', 'unused-imports/no-unused-imports': 'warn', 'unused-imports/no-unused-vars': [ 'warn', { vars: 'all', varsIgnorePattern: '^_', args: 'after-used', argsIgnorePattern: '^_' } ], 'no-console': ['warn', { allow: ['warn', 'error', 'info'] }], 'react/prop-types': 'off', 'react/react-in-jsx-scope': 'off', 'simple-import-sort/imports': [ 'error', { groups: [ // Side effect imports ['^\\u0000'], // React and React-related packages first ['^react', '^react-dom'], // Other external packages (starting with @ or letter) ['^@?\\w'], // Internal packages (using @ alias) ['^@/'], // Parent imports (../) ['^\\.\\.(?!/?$)', '^\\.\\./?$'], // Same directory imports (./) ['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'], // Type imports ['^.+\\.?(css|scss)$'] ] } ], 'simple-import-sort/exports': 'error', 'import/first': 'error', 'import/newline-after-import': 'error', 'import/no-duplicates': 'error', // Allow autoFocus on custom components (e.g. RichTextEditor in dialogs) — they manage // focus programmatically per WAI-ARIA dialog patterns. Native elements are still flagged. 'jsx-a11y/no-autofocus': ['error', { ignoreNonDOM: true }], 'prettier/prettier': 'error', // Ban @/features alias — features use relative imports internally, and no other // layer should import from features (enforced by import/no-restricted-paths below). // This catches any remaining edge case where the alias would bypass zone checks. 'no-restricted-imports': [ 'error', { patterns: [ { group: ['@/features', '@/features/*'], message: '@/features alias is not allowed. Features use relative imports internally; other layers cannot import from features.' } ] } ], // Architectural boundary enforcement 'import/no-restricted-paths': [ 'error', { zones: [ // atoms/ can only import from core/types (not from features, infrastructure, or core utils) { target: './src/atoms', from: './src/features', message: 'Atoms cannot import from features. Keep atoms dumb and reusable.' }, { target: './src/atoms', from: './src/infrastructure', message: 'Atoms cannot import from infrastructure. Use props instead of contexts.' }, { target: './src/atoms', from: './src/core', except: ['./types', './theme'], message: 'Atoms can only import from core/types and core/theme, not utilities or business logic.' }, // core/ cannot import from anything (leaf node) { target: './src/core', from: './src/atoms', message: 'Core is a leaf node and cannot import from atoms.' }, { target: './src/core', from: './src/features', message: 'Core is a leaf node and cannot import from features.' }, { target: './src/core', from: './src/infrastructure', message: 'Core is a leaf node and cannot import from infrastructure.' }, // infrastructure/ can only import from core/ { target: './src/infrastructure', from: './src/atoms', message: 'Infrastructure cannot import from atoms. Move shared code to core.' }, { target: './src/infrastructure', from: './src/features', message: 'Infrastructure cannot import from features. Move shared code to core.' }, // features/ cannot import from other features (prevent cross-feature dependencies) ...crossFeatureRules ] } ] }, env: { browser: true, es2021: true, node: true }, overrides: [ { files: ['examples/**/*.{js,jsx,ts,tsx}', '**/*.md/**'], rules: { 'no-console': 'off', '@typescript-eslint/no-non-null-assertion': 'off' } }, { files: ['src/__mocks__/**/*.{ts,tsx}'], rules: { '@typescript-eslint/no-explicit-any': 'off' } }, { files: ['src/__test_utils__/**/*.js'], rules: { '@typescript-eslint/no-require-imports': 'off' } } ] } ================================================ FILE: packages/agentflow/.npmignore ================================================ # Source & config /src /examples *.ts !*.d.ts tsconfig.json vite.config.ts jest.config.js .eslintrc.js # Dev artifacts .turbo node_modules .DS_Store # Keep dist !dist ================================================ FILE: packages/agentflow/.prettierignore ================================================ dist node_modules build coverage *.config.ts *.config.js vite.config.ts examples/dist examples/vite.config.ts pnpm-lock.yaml package-lock.json ================================================ FILE: packages/agentflow/.prettierrc ================================================ { "printWidth": 140, "singleQuote": true, "jsxSingleQuote": true, "trailingComma": "none", "tabWidth": 4, "semi": false, "endOfLine": "auto" } ================================================ FILE: packages/agentflow/ARCHITECTURE.md ================================================ # @flowiseai/agentflow - Architecture This document describes the internal architecture of the `@flowiseai/agentflow` package. ## Overview The package follows a **Domain-Driven Modular Architecture** with clear separation of concerns. The goal is to separate low-level UI primitives from high-level business logic to ensure high reusability and easy testing. ``` src/ ├── index.ts # Public Package API ("Public Face") ├── Agentflow.tsx # Main component ├── AgentflowProvider.tsx # Root provider (composition) ├── useAgentflow.ts # Primary public hook │ ├── atoms/ # ⚛️ UI Primitives ("What it looks like" (Dumb)) ├── features/ # 🧩 Domain Features ("What it does" (Smart)) ├── core/ # 🧠 Business Logic ("Business Rules" (Types/Logic)) └── infrastructure/ # 🌐 External Services ("Outside World" (API/Storage)) ``` --- ## Directory Structure ### `atoms/` - UI Primitives **"What it looks like."** Tiny, irreducible UI components with no business logic. These are the building blocks used by features. ``` atoms/ ├── MainCard.tsx # Styled card wrapper ├── NodeInputHandler.tsx # Form input for node properties ├── ... # Other UI primitives └── index.ts # Central export ``` **Rules:** - Must be "dumb" and stateless - No business logic - No API calls - Stateless or minimal local state - Imported by features, never the reverse - **Forbidden**: Importing from `features/` or `infrastructure/` (except types from `core/types` for prop definitions and design tokens from `core/theme`) **Goal:** 100% visual consistency. --- ### `features/` - Domain Features **"What it does."** Complex, self-contained domain modules (silos) that house the application's core functionality. Each feature owns its components, hooks, and utilities. ``` features/ ├── canvas/ # Core ReactFlow canvas │ ├── containers/ # Smart components with state/logic │ │ ├── AgentFlowNode.tsx │ │ ├── AgentFlowEdge.tsx │ │ ├── ... # Other node containers │ │ └── index.ts │ ├── components/ # Presentational components │ │ ├── ConnectionLine.tsx │ │ ├── NodeOutputHandles.tsx │ │ ├── ... # Other presentational components │ │ └── index.ts │ ├── hooks/ # Canvas-related hooks │ │ ├── useFlowHandlers.ts │ │ ├── useDragAndDrop.ts │ │ ├── ... # Other canvas hooks │ │ └── index.ts │ ├── styled.ts # Styled components │ └── index.ts # Public API │ ├── node-palette/ # Add nodes drawer │ ├── AddNodesDrawer.tsx │ ├── search.ts # Feature-specific utility (private) │ ├── ... │ └── index.ts │ ├── generator/ # AI flow generation │ ├── GenerateFlowDialog.tsx │ ├── ... │ └── index.ts │ └── node-editor/ # Node property editing ├── EditNodeDialog.tsx └── index.ts ``` **Rules:** - Each feature has an `index.ts` gatekeeper - **Features never import from other features directly** - If `canvas` needs logic from `generator`, move that logic to `core/` - Feature-specific utils stay in the feature folder - Styles are co-located with their feature - Use `containers/` for smart components (with state, hooks, side effects) - Use `components/` for presentational components (props in, JSX out) **Goal:** High cohesion. Should be able to delete a feature folder without breaking others. --- ### `core/` - Business Logic **"The Brain."** Framework-agnostic logic, types, and utilities. No React, no UI - pure TypeScript. Contains validation schemas, node registries, domain constants, and shared types. ``` core/ ├── types/ # Global interfaces (Node, Edge, Flow) │ └── index.ts ├── node-config/ # Node configuration (icons, colors, default types) │ ├── nodeIcons.ts # AGENTFLOW_ICONS, DEFAULT_AGENTFLOW_NODES │ └── ... ├── node-catalog/ # Node catalog and filtering logic │ ├── nodeFilters.ts # filterNodesByComponents, isAgentflowNode │ └── ... ├── theme/ # Design tokens and MUI theming │ ├── tokens.ts # Color palettes, spacing, shadows │ ├── createAgentflowTheme.ts │ └── ... ├── validation/ # Flow validation logic │ ├── flowValidation.ts # validateFlow, validateNode │ ├── connectionValidation.ts # isValidConnectionAgentflowV2 │ └── ... ├── utils/ # Generic utilities │ ├── nodeFactory.ts # initNode, getUniqueNodeId │ └── ... └── index.ts # Barrel export (use sparingly) ``` **Rules:** - **No React components allowed** - Pure TypeScript only - No browser-specific APIs if possible - No side effects - Pure functions where possible - Can be tested in isolation **Goal:** To be the framework-agnostic source of truth. --- ### `infrastructure/` - External Services **"The Outside World."** Handles communication with external systems: data persistence, network requests, and global state management. ``` infrastructure/ ├── api/ # API client layer (network requests) │ ├── client.ts # Axios factory │ ├── ... # Endpoint modules (nodes, chatflows, etc.) │ └── index.ts │ └── store/ # State management ├── AgentflowContext.tsx # Flow state context ├── agentflowReducer.ts # Reducer for flow state actions ├── ... # Other contexts (ApiContext, ConfigContext) └── index.ts ``` **Rules:** - All external communication goes here - Contexts are internal (composed in AgentflowProvider) - API hooks live with their API modules **Goal:** To wrap external dependencies so they can be easily swapped or mocked in tests. --- ## Dependency Flow **Dependencies must only flow downwards.** ``` ┌─────────────────────────────────────────────────────────┐ │ Root Files (Public API) │ │ (index.ts, Agentflow.tsx, AgentflowProvider.tsx) │ │ "The Public Face" │ └─────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────┐ │ features/ │ │ (canvas, node-palette, generator, node-editor) │ │ "What it does" │ └─────────────────────────────────────────────────────────┘ │ │ ▼ ▼ ┌──────────────────┐ ┌────────────────────────┐ │ atoms/ │ │ infrastructure/ │ │ (UI primitives) │ │ (api, store) │ │ "What it looks │ │ "The Outside World" │ │ like" │ │ │ └──────────────────┘ └────────────────────────┘ │ │ └──────────────┬─────────────────────┘ ▼ ┌─────────────────────┐ │ core/ │ │ (types, constants, │ │ validation, etc.) │ │ "The Brain" │ └─────────────────────┘ ``` **Import Rules:** - `features` → `atoms`, `infrastructure`, `core` ✅ - `infrastructure` → `core` ✅ - `atoms` → `core/types` and `core/theme` only (for type definitions and design tokens) ✅ - `core` → nothing (leaf node) ✅ - **Atoms and Core are "leaf" nodes** - they cannot import from `features/` or `infrastructure/` --- ## Gatekeeper Pattern Each module exposes only what's needed via its `index.ts`: ```typescript // features/canvas/index.ts // ✅ Public API export const nodeTypes = { ... } export const edgeTypes = { ... } export { ConnectionLine, AgentflowHeader, createHeaderProps } export { useFlowNodes, useFlowHandlers, useDragAndDrop } // Container components are re-exported for advanced usage export { AgentFlowNode, AgentFlowEdge, StickyNote, IterationNode } // ❌ Internal sub-components stay private within containers/components ``` This enables: - **Encapsulation**: Internal refactoring doesn't break consumers - **Tree-shaking**: Bundlers can eliminate unused code - **Clarity**: Clear contract of what each module provides --- ## Adding a New Feature 1. Create folder under `features/`: ``` features/my-feature/ ├── containers/ # Smart components (optional) │ └── MyContainer.tsx ├── components/ # Presentational components (optional) │ └── MyComponent.tsx ├── hooks/ # Feature-specific hooks (optional) │ └── useMyHook.ts ├── helper.ts # Feature-specific util └── index.ts # Public exports only ``` 2. Export only what's needed: ```typescript // index.ts export { MyContainer } from './containers' export { MyComponent } from './components' export { useMyHook } from './hooks' export type { MyComponentProps } from './components' ``` 3. Import from infrastructure/core, never from other features: ```typescript // ✅ Good import { useApiContext } from '../../infrastructure/store' import type { NodeData } from '../../core/types' // ❌ Bad - cross-feature import import { AgentFlowNode } from '../canvas/containers/AgentFlowNode' ``` --- ## Root Files (`src/*.ts`) **"The Public Face."** The entry point of the package. - **`AgentflowProvider.tsx`**: Injects infrastructure (stores/api) into the app - **`Agentflow.tsx`**: The primary component users will drop into their apps - **`useAgentflow.ts`**: Primary public hook for accessing flow state and actions - **`index.ts`**: The "Barrel" that exports the public API for npm --- ## Public API The package exposes a minimal public API via `src/index.ts`: ```typescript // Components export { Agentflow } from './Agentflow' export { AgentflowProvider } from './AgentflowProvider' // Hooks export { useAgentflow } from './useAgentflow' export { useApiContext, useConfigContext, useAgentflowContext } from './infrastructure/store' // Types export type { AgentflowProps, FlowData, NodeData, ... } from './core/types' // Utilities (for advanced usage) export { AGENTFLOW_ICONS, validateFlow, ... } from './core/...' ``` Everything else is internal implementation detail. --- ## Development Principles ### Barrel Exports Every directory must have an `index.ts` that acts as a gatekeeper. **✅ Good:** ```typescript import { Button } from '@atoms' import { useFlowHandlers } from '@features/canvas' ``` **❌ Bad:** ```typescript // Never deep-link into files import { Button } from '@atoms/Button/Button' import { useFlowHandlers } from '@features/canvas/hooks/useFlowHandlers' ``` ### Prop Drilling vs. Context - **Atoms**: Use props for all configuration - **Features**: Use context/state for shared data ### Naming Convention | Type | Convention | Example | | ----------- | ------------------------- | ------------------------------------- | | Component | PascalCase.tsx | `AgentFlowNode.tsx` | | Hook | camelCase.ts (use prefix) | `useFlowHandlers.ts` | | Logic/Types | camelCase.ts | `flowValidation.ts`, `nodeFilters.ts` | | Styles | kebab-case (co-located) | `canvas.css` | ================================================ FILE: packages/agentflow/README.md ================================================ # @flowiseai/agentflow [![Version](https://img.shields.io/npm/v/@flowiseai/agentflow)](https://www.npmjs.com/package/@flowiseai/agentflow) [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/FlowiseAI/Flowise/blob/main/LICENSE.md) > Embeddable React component for building and visualizing AI agent workflows ## ⚠️ Status **This package is currently under active development.** - 🚧 Components are not yet fully functional - ❌ End-to-end functionality is not complete - 🔄 Features are still being implemented and tested - ⚡ APIs may change before stable release - 📝 Documentation is being updated as development progresses **Cannot be used in production. For development and testing purposes only.** ## Overview `@flowiseai/agentflow` is a React-based flow editor for creating AI agent workflows. It provides a visual canvas built on ReactFlow for connecting AI agents, LLMs, tools, and logic nodes. ## Features - **Visual Canvas** — Drag-and-drop flow editor built on ReactFlow with zoom, pan, minimap, and fit-to-view controls - **15 Built-in Node Types** — Start, Agent, LLM, Condition, Condition Agent, Human Input, Loop, Direct Reply, Custom Function, Tool, Retriever, Sticky Note, HTTP, Iteration, and Execute Flow - **Node Editor Dialog** — Modal for editing node parameters with dynamic input types (text, number, boolean, dropdown, arrays, async options) - **Rich Text Editor** — TipTap-based editor with syntax highlighting for JavaScript, TypeScript, Python, and JSON (lazy-loaded) - **Specialized Input Components** — Condition builder, messages input (role + content), and structured output schema builder - **AI Flow Generator** — Generate flows from natural language descriptions with model selection - **Flow Validation** — Detects empty flows, missing start nodes, disconnected nodes, cycles, hanging edges, and per-node input errors with visual feedback - **Dark Mode** — Full light/dark theme support via design tokens and CSS variables - **Read-Only Mode** — Disable editing for view-only embedding - **Custom Rendering** — Replace the default header and node palette with your own components via render props - **Imperative API** — Programmatic control via ref (`getFlow`, `validate`, `fitView`, `clear`, `addNode`, `toJSON`) - **Request Interceptor** — Customize outgoing API requests (headers, credentials) via an Axios interceptor callback - **Keyboard Shortcuts** — Cmd/Ctrl+S to save ## Installation ```bash pnpm add @flowiseai/agentflow ``` **Peer Dependencies:** ```bash pnpm add react react-dom @mui/material @mui/icons-material @emotion/react @emotion/styled reactflow ``` ## Basic Usage ```tsx import { Agentflow } from '@flowiseai/agentflow' import '@flowiseai/agentflow/flowise.css' export default function App() { return (
) } ``` ### With Initial Flow Data and Callbacks ```tsx import { useRef } from 'react' import { Agentflow, type AgentFlowInstance, type FlowData } from '@flowiseai/agentflow' import '@flowiseai/agentflow/flowise.css' export default function App() { const ref = useRef(null) const initialFlow: FlowData = { nodes: [ { id: 'startAgentflow_0', type: 'agentflowNode', position: { x: 100, y: 100 }, data: { id: 'startAgentflow_0', name: 'startAgentflow', label: 'Start', color: '#7EE787', hideInput: true, outputAnchors: [{ id: 'startAgentflow_0-output-0', name: 'start', label: 'Start', type: 'start' }] } } ], edges: [], viewport: { x: 0, y: 0, zoom: 1 } } return (
console.log('Flow changed:', flow)} onSave={(flow) => console.log('Flow saved:', flow)} />
) } ``` ## Props | Prop | Type | Default | Description | | -------------------- | ------------------------------------------ | -------------- | --------------------------------------------------------------- | | `apiBaseUrl` | `string` | **(required)** | Flowise API server endpoint | | `token` | `string` | — | Authentication token for API calls | | `requestInterceptor` | `(config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig` | — | Customize outgoing API requests (e.g., set `withCredentials`, add headers). The callback receives the full Axios request config — only modify what you need. See [Security: requestInterceptor](#security-requestinterceptor) below. | | `initialFlow` | `FlowData` | — | Initial flow data to render (uncontrolled — only used on mount) | | `components` | `string[]` | — | Restrict which node types appear in the palette | | `onFlowChange` | `(flow: FlowData) => void` | — | Called when the flow changes (node/edge add, remove, move) | | `onSave` | `(flow: FlowData) => void` | — | Called when the user triggers a save | | `onFlowGenerated` | `(flow: FlowData) => void` | — | Called when a flow is generated via AI | | `isDarkMode` | `boolean` | `false` | Use dark mode theme | | `readOnly` | `boolean` | `false` | Disable editing (nodes not draggable/connectable) | | `showDefaultHeader` | `boolean` | `true` | Show built-in header (ignored if `renderHeader` provided) | | `showDefaultPalette` | `boolean` | `true` | Show built-in node palette | | `enableGenerator` | `boolean` | `true` | Show the AI flow generator button | | `renderHeader` | `(props: HeaderRenderProps) => ReactNode` | — | Custom header renderer | | `renderNodePalette` | `(props: PaletteRenderProps) => ReactNode` | — | Custom node palette renderer | ### Imperative Methods (via `ref`) | Method | Return Type | Description | | ------------------------ | ------------------------- | ------------------------------------- | | `getFlow()` | `FlowData` | Get current flow data | | `toJSON()` | `string` | Export flow as JSON string | | `validate()` | `ValidationResult` | Validate the current flow | | `fitView()` | `void` | Fit all nodes into view | | `clear()` | `void` | Remove all nodes and edges | | `addNode(nodeData)` | `void` | Add a node (`Partial`) | | `getReactFlowInstance()` | `ReactFlowInstance\|null` | Get the underlying ReactFlow instance | ### Security: `requestInterceptor` The `requestInterceptor` callback runs inside the Axios request pipeline and has access to the full request configuration, including authentication headers. This is the same trust model as any other callback prop (e.g., `onSave`, `renderHeader`) — the host application developer supplies the function and is responsible for its behavior. **Guidelines for consumers:** - Only pass **trusted, developer-authored** functions. Never use dynamically evaluated code (`eval`, `new Function`, etc.) or user-generated input as the interceptor. - Follow the **principle of least privilege** — only read or modify the specific config properties you need (e.g., `withCredentials`, custom headers). - If the interceptor throws, the error is caught, logged, and the **original unmodified config** is used so the request still proceeds safely. ### Node Types The following node types are available in the palette by default. Use the `components` prop to restrict which types are shown. | Node Type | Description | | -------------------------- | ------------------------------------ | | `startAgentflow` | Entry point (required, always shown) | | `agentAgentflow` | AI agent execution | | `llmAgentflow` | LLM / language model call | | `conditionAgentflow` | Conditional branching | | `conditionAgentAgentflow` | Agent-level conditional branching | | `humanInputAgentflow` | Wait for user input | | `loopAgentflow` | Loop / iteration | | `directReplyAgentflow` | Direct response to user | | `customFunctionAgentflow` | Custom JavaScript function | | `toolAgentflow` | Tool integration | | `retrieverAgentflow` | Data retrieval | | `stickyNoteAgentflow` | Canvas annotation (not connectable) | | `httpAgentflow` | HTTP request | | `iterationAgentflow` | Iteration / map-reduce container | | `executeFlowAgentflow` | Execute a sub-flow | ### Design Note `` is an **uncontrolled component**. The `initialFlow` prop seeds the canvas state on mount, but the component owns its own state afterward. Use the `ref` for imperative access and `onFlowChange` to observe changes. ## Exports Beyond the main `` component, the package exports utilities for advanced usage: ```ts // Main component and provider // Types // Hooks // Validation // Node utilities // Field visibility helpers ``` ## Development ```bash # Install dependencies pnpm install # Build the package pnpm build # Run tests pnpm test # Run examples cd examples && pnpm install && pnpm dev ``` Visit the [examples](./examples) directory for more usage patterns. See [TESTS.md](./TESTS.md) for the full test plan and coverage status. ## Publishing ### Version Update Bump the version in `package.json` before publishing. Use `npm version` to update the version and create a git tag: ```bash # Prerelease (for testing) npm version prerelease --preid=dev # 0.0.0-dev.1 → 0.0.0-dev.2 # Patch / Minor / Major (for stable releases) npm version patch # 0.0.1 npm version minor # 0.1.0 npm version major # 1.0.0 ``` ### Verify Before Publishing ```bash # Build and check the tarball contents pnpm build npm pack --dry-run # Full publish dry-run (runs prepublishOnly + simulates upload) npm publish --dry-run ``` ### Publish ```bash # Prerelease — tagged so `npm install @flowiseai/agentflow` won't pick it up npm publish --tag dev # Stable release — gets the `latest` tag npm publish ``` > The `prepublishOnly` script automatically runs `clean` and `build` before every publish, so stale dist files are never uploaded. ## Documentation - [ARCHITECTURE.md](./ARCHITECTURE.md) - Internal architecture and design patterns - [TESTS.md](./TESTS.md) - Test plan, coverage tiers, and configuration - [Examples](./examples/README.md) - Usage examples and demos ## Contributing This package follows a feature-based architecture with clear separation of concerns. See [ARCHITECTURE.md](./ARCHITECTURE.md) for details on the project structure and development guidelines. ## License Apache-2.0 — see the repository root [LICENSE.md](https://github.com/FlowiseAI/Flowise/blob/main/LICENSE.md) for details. --- Part of the [Flowise](https://github.com/FlowiseAI/Flowise) ecosystem ================================================ FILE: packages/agentflow/TESTS.md ================================================ # @flowiseai/agentflow — Testing Guide ## Running Tests ```bash pnpm test # Fast run (no coverage) pnpm test:coverage # With coverage enforcement pnpm test:watch # Watch mode during development ``` ## Test Strategy Tests are prioritized by impact. When modifying a file, add or update tests in the same PR. ### Tier 1 — Core Logic (must test) Pure business logic in `core/`, `infrastructure/`, and critical hooks. These carry the highest risk — a bug here affects every user. Always test in the same PR when modifying. **What belongs here:** validation rules, node utilities, API clients, state management (reducers, context actions), flow data hooks (`useFlowHandlers`). ### Tier 2 — Feature Hooks & Dialogs (test when changing) Feature-level hooks and dialog components that orchestrate UI behavior. Test when adding features or fixing bugs. **What belongs here:** search logic, drag-and-drop, node color calculations, dialog state machines, theme detection. ### Tier 3 — UI Components (test if logic exists) Presentational components that are mostly JSX. Only add tests if the component contains meaningful business logic (e.g., an exported helper function). Pure styling components (`styled.ts`, `MainCard.tsx`, etc.) do not need tests. ## Writing Tests ### File Extension Convention The Jest config uses file extensions to select the test environment: | Extension | Environment | When to use | | ----------- | ----------------------- | -------------------------------------------------------------------------- | | `.test.ts` | **node** (no DOM) | Pure logic — utilities, reducers, data transformations | | `.test.tsx` | **jsdom** (browser DOM) | Anything that renders React — `renderHook` with providers, component tests | Source files use `.tsx` only when they contain JSX syntax. A hook like `useAgentflow.ts` has no JSX, so it stays `.ts` even though its test is `.test.tsx` (because the test uses `renderHook` with a JSX wrapper). ### Factory Functions Use factory functions from `@test-utils/factories` to create test fixtures with sensible defaults: ```typescript import { makeFlowNode, makeFlowEdge, makeNodeData } from '@test-utils/factories' const node = makeFlowNode('node-1', { type: 'agentflowNode', data: { name: 'llmAgentflow', label: 'LLM' } }) const edge = makeFlowEdge('node-1', 'node-2') const nodeData = makeNodeData({ name: 'llmAgentflow', label: 'LLM' }) ``` ### Mocking Patterns **Mocking a module with `jest.mock`:** ```typescript import { isValidConnectionAgentflowV2 } from '@/core' jest.mock('@/core', () => ({ isValidConnectionAgentflowV2: jest.fn(() => true), getUniqueNodeId: jest.fn(() => 'new-node-1') })) // Override per-test: it('should reject invalid connection', () => { ;(isValidConnectionAgentflowV2 as jest.Mock).mockReturnValueOnce(false) // ... }) ``` **Mocking context hooks:** ```typescript const mockSetDirty = jest.fn() jest.mock('@/infrastructure/store', () => ({ useAgentflowContext: () => ({ state: { reactFlowInstance: null }, setDirty: mockSetDirty }) })) ``` ### Module Mocks **ReactFlow** (`src/__mocks__/reactflow.tsx`): Mock implementations of ReactFlow components and hooks. Uses `forwardRef` for MUI `styled()` compatibility and `useState` internally for stable references. **Axios** (`src/__mocks__/axios.ts`): Prevents network errors by mocking all HTTP methods. Returns empty arrays/objects by default. **CSS/SVG** (`src/__mocks__/styleMock.js`): Empty object export for CSS and SVG imports. ### Custom Jest Environment `src/__test_utils__/jest-environment-jsdom.js` intercepts `require('canvas')` and returns a mock before jsdom tries to load the native binary. This prevents build failures in environments without native canvas compilation. ## Configuration - **Jest config**: `jest.config.js` — two projects: `unit` (node env, `.test.ts`) and `components` (custom jsdom env, `.test.tsx`) - **Import aliases**: `@test-utils` maps to `src/__test_utils__`, `@/` maps to `src/` - **Coverage thresholds**: 80% floor for `branches`, `functions`, `lines`, `statements` — see `coverageThreshold` in `jest.config.js` for per-path entries - **Coverage exclusions**: `src/__test_utils__/**`, `src/__mocks__/**` - **CI**: `pnpm test:coverage` runs in GitHub Actions between lint and build - **Reports**: `coverage/lcov-report/index.html` for detailed HTML report ================================================ FILE: packages/agentflow/examples/README.md ================================================ # @flowiseai/agentflow Examples This folder demonstrates various usage patterns of the `@flowiseai/agentflow` package. ## Setup 1. First, build the agentflow package from the root: ```bash cd packages/agentflow pnpm build ``` 2. Install dependencies for this example: ```bash cd examples pnpm install ``` 3. Start the development server: ```bash pnpm dev ``` 4. Open http://localhost:5174 in your browser ## Configuration The examples app uses environment variables for configuration. To set up: 1. Copy the `.env.example` file to `.env`: ```bash cp .env.example .env ``` 2. Edit `.env` to configure your Flowise API server: ```bash # Flowise API Base URL VITE_INSTANCE_URL=http://localhost:3000 # API Key (required for authenticated endpoints) VITE_API_TOKEN=your-api-key-here ``` 3. **Get your API Key from Flowise:** - Open your Flowise instance (http://localhost:3000) - Go to **Settings** → **API Keys** - Click **Create New Key** - Copy the generated key and paste it in `.env` ⚠️ **Important:** Use an **API Key**, not a user authentication token (JWT). 4. Restart the dev server to apply changes: ```bash pnpm dev ``` **Environment Variables:** - `VITE_INSTANCE_URL`: Flowise API server endpoint (maps to `apiBaseUrl` prop, default: `http://localhost:3000`) - `VITE_API_TOKEN`: Flowise API Key for programmatic access (required for authenticated endpoints) **Note**: The `.env` file is gitignored and will not be committed to version control. Add your actual API key to `.env`, not `.env.example`. ### Troubleshooting Authentication **Getting 401 Unauthorized errors?** Common causes: 1. **Using wrong token type** ❌ - Don't use: User authentication JWT tokens (long tokens starting with `eyJhbGc...`) - Use: API Keys (shorter tokens like `9CnKuLRHbEY...`) 2. **Token not loaded** - Restart dev server after editing `.env`: `pnpm dev` - Check browser console for: `[BasicExample] Environment check` 3. **Invalid API Key** - Regenerate key in Flowise: Settings → API Keys → Create New Key - Copy the new key to `.env` 4. **CORS issues** - Ensure Flowise allows requests from `http://localhost:5174` - Check Flowise CORS configuration ## Examples ### Basic Usage (`BasicExample.tsx`) Demonstrates core usage: - Basic canvas rendering with `` component - Passing `apiBaseUrl` and `initialFlow` props - Using the `ref` to access imperative methods (`validate`, `fitView`, `getFlow`, `clear`) - Handling `onFlowChange` and `onSave` callbacks ### Additional Examples | Example | File | Description | | ----------------------- | ------------------------------- | ------------------------------------------------------------------------------------ | | **Multi-Node Flow** | `MultiNodeFlow.tsx` | Complete translation agent flow with multiple connected nodes showing gradient edges | | **Dark Mode** | `DarkModeExample.tsx` | Theme toggle demonstrating light/dark mode support | | **Status Indicators** | `StatusIndicatorsExample.tsx` | Node execution states (running, finished, error, stopped) with animated loader | | **Custom UI** | `CustomUIExample.tsx` | Custom header and node palette using render props | | **All Node Types** | `AllNodeTypesExample.tsx` | Visual catalog of all 15 available node types with colors and icons | | **Filtered Components** | `FilteredComponentsExample.tsx` | Restricting available nodes with preset configurations | ## Switching Examples Use the dropdown selector at the top of the page to switch between examples. All examples are lazy-loaded for better performance. ## Node Types Reference | Node Type | Color | Description | | ------------------------- | ------- | -------------------------- | | `startAgentflow` | #7EE787 | Entry point for the flow | | `llmAgentflow` | #64B5F6 | Large Language Model node | | `agentAgentflow` | #4DD0E1 | AI Agent with tools | | `conditionAgentflow` | #FFB938 | Conditional branching | | `conditionAgentAgentflow` | #ff8fab | Agent-based condition | | `humanInputAgentflow` | #6E6EFD | Human approval required | | `loopAgentflow` | #FFA07A | Loop iteration | | `iterationAgentflow` | #9C89B8 | Iteration container | | `directReplyAgentflow` | #4DDBBB | Send response to user | | `customFunctionAgentflow` | #E4B7FF | Custom JavaScript function | | `toolAgentflow` | #d4a373 | External tool integration | | `retrieverAgentflow` | #b8bedd | Vector store retrieval | | `httpAgentflow` | #FF7F7F | HTTP API request | | `executeFlowAgentflow` | #a3b18a | Execute another flow | | `stickyNoteAgentflow` | #fee440 | Documentation note | ## Requirements The examples work best with a running Flowise instance at `http://localhost:3000` for the node API. Without it: - The canvas will render - Initial flow data will display - Node palette may be empty (nodes load from API) For standalone testing, examples include mock flow data. ================================================ FILE: packages/agentflow/examples/index.html ================================================ @flowiseai/agentflow - Basic Example
================================================ FILE: packages/agentflow/examples/package-lock.json ================================================ { "name": "agentflow-basic-example", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "agentflow-basic-example", "version": "0.0.0", "dependencies": { "@emotion/react": "^11.10.0", "@emotion/styled": "^11.10.0", "@mui/icons-material": "^5.15.0", "@mui/material": "^5.15.0", "react": "^18.2.0", "react-dom": "^18.2.0", "reactflow": "^11.5.0" }, "devDependencies": { "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "@vitejs/plugin-react": "^4.0.0", "typescript": "^5.0.0", "vite": "^5.0.0" } }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/code-frame/-/code-frame-7.29.0.tgz", "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { "version": "7.29.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/compat-data/-/compat-data-7.29.0.tgz", "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { "version": "7.29.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/core/-/core-7.29.0.tgz", "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/babel" } }, "node_modules/@babel/core/node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, "node_modules/@babel/generator": { "version": "7.29.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/generator/-/generator-7.29.1.tgz", "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { "version": "7.28.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-globals": { "version": "7.28.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { "version": "7.28.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "license": "MIT", "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { "version": "7.28.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-plugin-utils": { "version": "7.28.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { "version": "7.28.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { "version": "7.27.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { "version": "7.28.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/helpers/-/helpers-7.28.6.tgz", "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.28.6", "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { "version": "7.29.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/parser/-/parser-7.29.0.tgz", "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.27.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/plugin-transform-react-jsx-source": { "version": "7.27.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/@babel/runtime": { "version": "7.28.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/runtime/-/runtime-7.28.6.tgz", "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { "version": "7.28.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/template/-/template-7.28.6.tgz", "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.28.6", "@babel/parser": "^7.28.6", "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { "version": "7.29.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/traverse/-/traverse-7.29.0.tgz", "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/types": "^7.29.0", "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { "version": "7.29.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@babel/types/-/types-7.29.0.tgz", "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@emotion/babel-plugin": { "version": "11.13.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/serialize": "^1.3.3", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", "find-root": "^1.1.0", "source-map": "^0.5.7", "stylis": "4.2.0" } }, "node_modules/@emotion/cache": { "version": "11.14.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/cache/-/cache-11.14.0.tgz", "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", "license": "MIT", "dependencies": { "@emotion/memoize": "^0.9.0", "@emotion/sheet": "^1.4.0", "@emotion/utils": "^1.4.2", "@emotion/weak-memoize": "^0.4.0", "stylis": "4.2.0" } }, "node_modules/@emotion/hash": { "version": "0.9.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/hash/-/hash-0.9.2.tgz", "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", "license": "MIT" }, "node_modules/@emotion/is-prop-valid": { "version": "1.4.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", "license": "MIT", "dependencies": { "@emotion/memoize": "^0.9.0" } }, "node_modules/@emotion/memoize": { "version": "0.9.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/memoize/-/memoize-0.9.0.tgz", "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", "license": "MIT" }, "node_modules/@emotion/react": { "version": "11.14.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", "@emotion/cache": "^11.14.0", "@emotion/serialize": "^1.3.3", "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", "@emotion/utils": "^1.4.2", "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" }, "peerDependencies": { "react": ">=16.8.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true } } }, "node_modules/@emotion/serialize": { "version": "1.3.3", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/serialize/-/serialize-1.3.3.tgz", "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", "license": "MIT", "dependencies": { "@emotion/hash": "^0.9.2", "@emotion/memoize": "^0.9.0", "@emotion/unitless": "^0.10.0", "@emotion/utils": "^1.4.2", "csstype": "^3.0.2" } }, "node_modules/@emotion/sheet": { "version": "1.4.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/sheet/-/sheet-1.4.0.tgz", "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", "license": "MIT" }, "node_modules/@emotion/styled": { "version": "11.14.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/styled/-/styled-11.14.1.tgz", "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", "@emotion/is-prop-valid": "^1.3.0", "@emotion/serialize": "^1.3.3", "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", "@emotion/utils": "^1.4.2" }, "peerDependencies": { "@emotion/react": "^11.0.0-rc.0", "react": ">=16.8.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true } } }, "node_modules/@emotion/unitless": { "version": "0.10.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/unitless/-/unitless-0.10.0.tgz", "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", "license": "MIT" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { "version": "1.2.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", "license": "MIT", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { "version": "1.4.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/utils/-/utils-1.4.2.tgz", "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", "license": "MIT" }, "node_modules/@emotion/weak-memoize": { "version": "0.4.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "aix" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/android-arm": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/android-arm/-/android-arm-0.21.5.tgz", "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/android-arm64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/android-x64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/android-x64/-/android-x64-0.21.5.tgz", "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "android" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/darwin-arm64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/darwin-x64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/freebsd-arm64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/freebsd-x64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-arm": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-arm64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-ia32": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-loong64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-mips64el": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-ppc64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-riscv64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-s390x": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-x64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/netbsd-x64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "netbsd" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/openbsd-x64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "openbsd" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/sunos-x64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "sunos" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/win32-arm64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/win32-ia32": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/win32-x64": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { "node": ">=12" } }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "node_modules/@jridgewell/remapping": { "version": "2.3.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@mui/core-downloads-tracker": { "version": "5.18.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@mui/core-downloads-tracker/-/core-downloads-tracker-5.18.0.tgz", "integrity": "sha512-jbhwoQ1AY200PSSOrNXmrFCaSDSJWP7qk6urkTmIirvRXDROkqe+QwcLlUiw/PrREwsIF/vm3/dAXvjlMHF0RA==", "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/icons-material": { "version": "5.18.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@mui/icons-material/-/icons-material-5.18.0.tgz", "integrity": "sha512-1s0vEZj5XFXDMmz3Arl/R7IncFqJ+WQ95LDp1roHWGDE2oCO3IS4/hmiOv1/8SD9r6B7tv9GLiqVZYHo+6PkTg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@mui/material": "^5.0.0", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true } } }, "node_modules/@mui/material": { "version": "5.18.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@mui/material/-/material-5.18.0.tgz", "integrity": "sha512-bbH/HaJZpFtXGvWg3TsBWG4eyt3gah3E7nCNU8GLyRjVoWcA91Vm/T+sjHfUcwgJSw9iLtucfHBoq+qW/T30aA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", "@mui/core-downloads-tracker": "^5.18.0", "@mui/system": "^5.18.0", "@mui/types": "~7.2.15", "@mui/utils": "^5.17.1", "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1", "react-is": "^19.0.0", "react-transition-group": "^4.4.5" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/react": { "optional": true }, "@emotion/styled": { "optional": true }, "@types/react": { "optional": true } } }, "node_modules/@mui/private-theming": { "version": "5.17.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@mui/private-theming/-/private-theming-5.17.1.tgz", "integrity": "sha512-XMxU0NTYcKqdsG8LRmSoxERPXwMbp16sIXPcLVgLGII/bVNagX0xaheWAwFv8+zDK7tI3ajllkuD3GZZE++ICQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", "@mui/utils": "^5.17.1", "prop-types": "^15.8.1" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true } } }, "node_modules/@mui/styled-engine": { "version": "5.18.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@mui/styled-engine/-/styled-engine-5.18.0.tgz", "integrity": "sha512-BN/vKV/O6uaQh2z5rXV+MBlVrEkwoS/TK75rFQ2mjxA7+NBo8qtTAOA4UaM0XeJfn7kh2wZ+xQw2HAx0u+TiBg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.13.5", "@emotion/serialize": "^1.3.3", "csstype": "^3.1.3", "prop-types": "^15.8.1" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.4.1", "@emotion/styled": "^11.3.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/react": { "optional": true }, "@emotion/styled": { "optional": true } } }, "node_modules/@mui/system": { "version": "5.18.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@mui/system/-/system-5.18.0.tgz", "integrity": "sha512-ojZGVcRWqWhu557cdO3pWHloIGJdzVtxs3rk0F9L+x55LsUjcMUVkEhiF7E4TMxZoF9MmIHGGs0ZX3FDLAf0Xw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", "@mui/private-theming": "^5.17.1", "@mui/styled-engine": "^5.18.0", "@mui/types": "~7.2.15", "@mui/utils": "^5.17.1", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/react": { "optional": true }, "@emotion/styled": { "optional": true }, "@types/react": { "optional": true } } }, "node_modules/@mui/types": { "version": "7.2.24", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@mui/types/-/types-7.2.24.tgz", "integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==", "license": "MIT", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true } } }, "node_modules/@mui/utils": { "version": "5.17.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@mui/utils/-/utils-5.17.1.tgz", "integrity": "sha512-jEZ8FTqInt2WzxDV8bhImWBqeQRD99c/id/fq83H0ER9tFl+sfZlaAoCdznGvbSQQ9ividMxqSV2c7cC1vBcQg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.23.9", "@mui/types": "~7.2.15", "@types/prop-types": "^15.7.12", "clsx": "^2.1.1", "prop-types": "^15.8.1", "react-is": "^19.0.0" }, "engines": { "node": ">=12.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true } } }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" } }, "node_modules/@reactflow/background": { "version": "11.3.14", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@reactflow/background/-/background-11.3.14.tgz", "integrity": "sha512-Gewd7blEVT5Lh6jqrvOgd4G6Qk17eGKQfsDXgyRSqM+CTwDqRldG2LsWN4sNeno6sbqVIC2fZ+rAUBFA9ZEUDA==", "license": "MIT", "dependencies": { "@reactflow/core": "11.11.4", "classcat": "^5.0.3", "zustand": "^4.4.1" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "node_modules/@reactflow/controls": { "version": "11.2.14", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@reactflow/controls/-/controls-11.2.14.tgz", "integrity": "sha512-MiJp5VldFD7FrqaBNIrQ85dxChrG6ivuZ+dcFhPQUwOK3HfYgX2RHdBua+gx+40p5Vw5It3dVNp/my4Z3jF0dw==", "license": "MIT", "dependencies": { "@reactflow/core": "11.11.4", "classcat": "^5.0.3", "zustand": "^4.4.1" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "node_modules/@reactflow/core": { "version": "11.11.4", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@reactflow/core/-/core-11.11.4.tgz", "integrity": "sha512-H4vODklsjAq3AMq6Np4LE12i1I4Ta9PrDHuBR9GmL8uzTt2l2jh4CiQbEMpvMDcp7xi4be0hgXj+Ysodde/i7Q==", "license": "MIT", "dependencies": { "@types/d3": "^7.4.0", "@types/d3-drag": "^3.0.1", "@types/d3-selection": "^3.0.3", "@types/d3-zoom": "^3.0.1", "classcat": "^5.0.3", "d3-drag": "^3.0.0", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0", "zustand": "^4.4.1" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "node_modules/@reactflow/minimap": { "version": "11.7.14", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@reactflow/minimap/-/minimap-11.7.14.tgz", "integrity": "sha512-mpwLKKrEAofgFJdkhwR5UQ1JYWlcAAL/ZU/bctBkuNTT1yqV+y0buoNVImsRehVYhJwffSWeSHaBR5/GJjlCSQ==", "license": "MIT", "dependencies": { "@reactflow/core": "11.11.4", "@types/d3-selection": "^3.0.3", "@types/d3-zoom": "^3.0.1", "classcat": "^5.0.3", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0", "zustand": "^4.4.1" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "node_modules/@reactflow/node-resizer": { "version": "2.2.14", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@reactflow/node-resizer/-/node-resizer-2.2.14.tgz", "integrity": "sha512-fwqnks83jUlYr6OHcdFEedumWKChTHRGw/kbCxj0oqBd+ekfs+SIp4ddyNU0pdx96JIm5iNFS0oNrmEiJbbSaA==", "license": "MIT", "dependencies": { "@reactflow/core": "11.11.4", "classcat": "^5.0.4", "d3-drag": "^3.0.0", "d3-selection": "^3.0.0", "zustand": "^4.4.1" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "node_modules/@reactflow/node-toolbar": { "version": "1.3.14", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@reactflow/node-toolbar/-/node-toolbar-1.3.14.tgz", "integrity": "sha512-rbynXQnH/xFNu4P9H+hVqlEUafDCkEoCy0Dg9mG22Sg+rY/0ck6KkrAQrYrTgXusd+cEJOMK0uOOFCK2/5rSGQ==", "license": "MIT", "dependencies": { "@reactflow/core": "11.11.4", "classcat": "^5.0.3", "zustand": "^4.4.1" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", "dev": true, "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", "cpu": [ "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", "cpu": [ "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", "cpu": [ "arm" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", "cpu": [ "loong64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", "cpu": [ "loong64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", "cpu": [ "ppc64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", "cpu": [ "ppc64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", "cpu": [ "riscv64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", "cpu": [ "riscv64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", "cpu": [ "s390x" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-openbsd-x64": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "openbsd" ] }, "node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "openharmony" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", "cpu": [ "ia32" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", "cpu": [ "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" } }, "node_modules/@types/babel__generator": { "version": "7.27.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { "version": "7.4.4", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__traverse": { "version": "7.28.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.2" } }, "node_modules/@types/d3": { "version": "7.4.3", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3/-/d3-7.4.3.tgz", "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", "license": "MIT", "dependencies": { "@types/d3-array": "*", "@types/d3-axis": "*", "@types/d3-brush": "*", "@types/d3-chord": "*", "@types/d3-color": "*", "@types/d3-contour": "*", "@types/d3-delaunay": "*", "@types/d3-dispatch": "*", "@types/d3-drag": "*", "@types/d3-dsv": "*", "@types/d3-ease": "*", "@types/d3-fetch": "*", "@types/d3-force": "*", "@types/d3-format": "*", "@types/d3-geo": "*", "@types/d3-hierarchy": "*", "@types/d3-interpolate": "*", "@types/d3-path": "*", "@types/d3-polygon": "*", "@types/d3-quadtree": "*", "@types/d3-random": "*", "@types/d3-scale": "*", "@types/d3-scale-chromatic": "*", "@types/d3-selection": "*", "@types/d3-shape": "*", "@types/d3-time": "*", "@types/d3-time-format": "*", "@types/d3-timer": "*", "@types/d3-transition": "*", "@types/d3-zoom": "*" } }, "node_modules/@types/d3-array": { "version": "3.2.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-array/-/d3-array-3.2.2.tgz", "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", "license": "MIT" }, "node_modules/@types/d3-axis": { "version": "3.0.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-axis/-/d3-axis-3.0.6.tgz", "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", "license": "MIT", "dependencies": { "@types/d3-selection": "*" } }, "node_modules/@types/d3-brush": { "version": "3.0.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-brush/-/d3-brush-3.0.6.tgz", "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", "license": "MIT", "dependencies": { "@types/d3-selection": "*" } }, "node_modules/@types/d3-chord": { "version": "3.0.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-chord/-/d3-chord-3.0.6.tgz", "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", "license": "MIT" }, "node_modules/@types/d3-color": { "version": "3.1.3", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-color/-/d3-color-3.1.3.tgz", "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", "license": "MIT" }, "node_modules/@types/d3-contour": { "version": "3.0.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-contour/-/d3-contour-3.0.6.tgz", "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", "license": "MIT", "dependencies": { "@types/d3-array": "*", "@types/geojson": "*" } }, "node_modules/@types/d3-delaunay": { "version": "6.0.4", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", "license": "MIT" }, "node_modules/@types/d3-dispatch": { "version": "3.0.7", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", "license": "MIT" }, "node_modules/@types/d3-drag": { "version": "3.0.7", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-drag/-/d3-drag-3.0.7.tgz", "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", "license": "MIT", "dependencies": { "@types/d3-selection": "*" } }, "node_modules/@types/d3-dsv": { "version": "3.0.7", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", "license": "MIT" }, "node_modules/@types/d3-ease": { "version": "3.0.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-ease/-/d3-ease-3.0.2.tgz", "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", "license": "MIT" }, "node_modules/@types/d3-fetch": { "version": "3.0.7", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", "license": "MIT", "dependencies": { "@types/d3-dsv": "*" } }, "node_modules/@types/d3-force": { "version": "3.0.10", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-force/-/d3-force-3.0.10.tgz", "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", "license": "MIT" }, "node_modules/@types/d3-format": { "version": "3.0.4", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-format/-/d3-format-3.0.4.tgz", "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", "license": "MIT" }, "node_modules/@types/d3-geo": { "version": "3.1.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-geo/-/d3-geo-3.1.0.tgz", "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", "license": "MIT", "dependencies": { "@types/geojson": "*" } }, "node_modules/@types/d3-hierarchy": { "version": "3.1.7", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", "license": "MIT" }, "node_modules/@types/d3-interpolate": { "version": "3.0.4", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", "license": "MIT", "dependencies": { "@types/d3-color": "*" } }, "node_modules/@types/d3-path": { "version": "3.1.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-path/-/d3-path-3.1.1.tgz", "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", "license": "MIT" }, "node_modules/@types/d3-polygon": { "version": "3.0.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", "license": "MIT" }, "node_modules/@types/d3-quadtree": { "version": "3.0.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", "license": "MIT" }, "node_modules/@types/d3-random": { "version": "3.0.3", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-random/-/d3-random-3.0.3.tgz", "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", "license": "MIT" }, "node_modules/@types/d3-scale": { "version": "4.0.9", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-scale/-/d3-scale-4.0.9.tgz", "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", "license": "MIT", "dependencies": { "@types/d3-time": "*" } }, "node_modules/@types/d3-scale-chromatic": { "version": "3.1.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", "license": "MIT" }, "node_modules/@types/d3-selection": { "version": "3.0.11", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-selection/-/d3-selection-3.0.11.tgz", "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", "license": "MIT" }, "node_modules/@types/d3-shape": { "version": "3.1.8", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-shape/-/d3-shape-3.1.8.tgz", "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", "license": "MIT", "dependencies": { "@types/d3-path": "*" } }, "node_modules/@types/d3-time": { "version": "3.0.4", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-time/-/d3-time-3.0.4.tgz", "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", "license": "MIT" }, "node_modules/@types/d3-time-format": { "version": "4.0.3", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", "license": "MIT" }, "node_modules/@types/d3-timer": { "version": "3.0.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-timer/-/d3-timer-3.0.2.tgz", "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "license": "MIT" }, "node_modules/@types/d3-transition": { "version": "3.0.9", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-transition/-/d3-transition-3.0.9.tgz", "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", "license": "MIT", "dependencies": { "@types/d3-selection": "*" } }, "node_modules/@types/d3-zoom": { "version": "3.0.8", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", "license": "MIT", "dependencies": { "@types/d3-interpolate": "*", "@types/d3-selection": "*" } }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/estree/-/estree-1.0.8.tgz", "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "dev": true, "license": "MIT" }, "node_modules/@types/geojson": { "version": "7946.0.16", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/geojson/-/geojson-7946.0.16.tgz", "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", "license": "MIT" }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/parse-json/-/parse-json-4.0.2.tgz", "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "license": "MIT" }, "node_modules/@types/prop-types": { "version": "15.7.15", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/prop-types/-/prop-types-15.7.15.tgz", "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.28", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/react/-/react-18.3.28.tgz", "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", "license": "MIT", "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { "version": "18.3.7", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/react-dom/-/react-dom-18.3.7.tgz", "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "^18.0.0" } }, "node_modules/@types/react-transition-group": { "version": "4.4.12", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", "license": "MIT", "peerDependencies": { "@types/react": "*" } }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "engines": { "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/babel-plugin-macros": { "version": "3.1.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", "resolve": "^1.19.0" }, "engines": { "node": ">=10", "npm": ">=6" } }, "node_modules/baseline-browser-mapping": { "version": "2.9.19", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/baseline-browser-mapping/-/baseline-browser-mapping-2.9.19.tgz", "integrity": "sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==", "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "node_modules/browserslist": { "version": "4.28.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/browserslist/-/browserslist-4.28.1.tgz", "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/browserslist" }, { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" }, { "type": "github", "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { "version": "1.0.30001769", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/browserslist" }, { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" }, { "type": "github", "url": "https://github.com/sponsors/ai" } ], "license": "CC-BY-4.0" }, "node_modules/classcat": { "version": "5.0.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/classcat/-/classcat-5.0.5.tgz", "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==", "license": "MIT" }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/clsx/-/clsx-2.1.1.tgz", "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "license": "MIT" }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "license": "MIT", "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", "parse-json": "^5.0.0", "path-type": "^4.0.0", "yaml": "^1.10.0" }, "engines": { "node": ">=10" } }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, "node_modules/d3-color": { "version": "3.1.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-dispatch": { "version": "3.0.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/d3-dispatch/-/d3-dispatch-3.0.1.tgz", "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-drag": { "version": "3.0.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/d3-drag/-/d3-drag-3.0.0.tgz", "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" }, "engines": { "node": ">=12" } }, "node_modules/d3-ease": { "version": "3.0.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/d3-ease/-/d3-ease-3.0.1.tgz", "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", "license": "BSD-3-Clause", "engines": { "node": ">=12" } }, "node_modules/d3-interpolate": { "version": "3.0.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/d3-interpolate/-/d3-interpolate-3.0.1.tgz", "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", "license": "ISC", "dependencies": { "d3-color": "1 - 3" }, "engines": { "node": ">=12" } }, "node_modules/d3-selection": { "version": "3.0.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-timer": { "version": "3.0.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/d3-timer/-/d3-timer-3.0.1.tgz", "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/d3-transition": { "version": "3.0.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/d3-transition/-/d3-transition-3.0.1.tgz", "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", "license": "ISC", "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", "d3-ease": "1 - 3", "d3-interpolate": "1 - 3", "d3-timer": "1 - 3" }, "engines": { "node": ">=12" }, "peerDependencies": { "d3-selection": "2 - 3" } }, "node_modules/d3-zoom": { "version": "3.0.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/d3-zoom/-/d3-zoom-3.0.0.tgz", "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", "license": "ISC", "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", "d3-interpolate": "1 - 3", "d3-selection": "2 - 3", "d3-transition": "2 - 3" }, "engines": { "node": ">=12" } }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" }, "engines": { "node": ">=6.0" }, "peerDependenciesMeta": { "supports-color": { "optional": true } } }, "node_modules/dom-helpers": { "version": "5.2.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/dom-helpers/-/dom-helpers-5.2.1.tgz", "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "node_modules/electron-to-chromium": { "version": "1.5.286", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/electron-to-chromium/-/electron-to-chromium-1.5.286.tgz", "integrity": "sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==", "dev": true, "license": "ISC" }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/error-ex/-/error-ex-1.3.4.tgz", "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/esbuild/-/esbuild-0.21.5.tgz", "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { "node": ">=12" }, "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "license": "MIT", "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/find-root": { "version": "1.1.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/find-root/-/find-root-1.1.0.tgz", "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", "license": "MIT" }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", "license": "BSD-3-Clause", "dependencies": { "react-is": "^16.7.0" } }, "node_modules/hoist-non-react-statics/node_modules/react-is": { "version": "16.13.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" }, "engines": { "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "license": "MIT" }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { "node": ">=6" } }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "license": "MIT" }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" }, "engines": { "node": ">=6" } }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "license": "MIT" }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" } }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, "engines": { "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, "node_modules/node-releases": { "version": "2.0.27", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/node-releases/-/node-releases-2.0.27.tgz", "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", "dev": true, "license": "MIT" }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, "engines": { "node": ">=6" } }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", "json-parse-even-better-errors": "^2.3.0", "lines-and-columns": "^1.1.6" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/postcss/-/postcss-8.5.6.tgz", "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/postcss/" }, { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" }, { "type": "github", "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", "object-assign": "^4.1.1", "react-is": "^16.13.1" } }, "node_modules/prop-types/node_modules/react-is": { "version": "16.13.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, "node_modules/react": { "version": "18.3.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" }, "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "node_modules/react-is": { "version": "19.2.4", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/react-is/-/react-is-19.2.4.tgz", "integrity": "sha512-W+EWGn2v0ApPKgKKCy/7s7WHXkboGcsrXE+2joLyVxkbyVQfO3MUEaUQDHoSmb8TFFrSKYa9mw64WZHNHSDzYA==", "license": "MIT" }, "node_modules/react-refresh": { "version": "0.17.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/react-refresh/-/react-refresh-0.17.0.tgz", "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/react-transition-group/-/react-transition-group-4.4.5.tgz", "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", "license": "BSD-3-Clause", "dependencies": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" }, "peerDependencies": { "react": ">=16.6.0", "react-dom": ">=16.6.0" } }, "node_modules/reactflow": { "version": "11.11.4", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/reactflow/-/reactflow-11.11.4.tgz", "integrity": "sha512-70FOtJkUWH3BAOsN+LU9lCrKoKbtOPnz2uq0CV2PLdNSwxTXOhCbsZr50GmZ+Rtw3jx8Uv7/vBFtCGixLfd4Og==", "license": "MIT", "dependencies": { "@reactflow/background": "11.3.14", "@reactflow/controls": "11.2.14", "@reactflow/core": "11.11.4", "@reactflow/minimap": "11.7.14", "@reactflow/node-resizer": "2.2.14", "@reactflow/node-toolbar": "1.3.14" }, "peerDependencies": { "react": ">=17", "react-dom": ">=17" } }, "node_modules/resolve": { "version": "1.22.11", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/resolve/-/resolve-1.22.11.tgz", "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "license": "MIT", "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/rollup": { "version": "4.57.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/rollup/-/rollup-4.57.1.tgz", "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", "dev": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" }, "engines": { "node": ">=18.0.0", "npm": ">=8.0.0" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "~2.3.2" } }, "node_modules/scheduler": { "version": "0.23.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/scheduler/-/scheduler-0.23.2.tgz", "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/source-map": { "version": "0.5.7", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/source-map/-/source-map-0.5.7.tgz", "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/stylis": { "version": "4.2.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/stylis/-/stylis-4.2.0.tgz", "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", "license": "MIT" }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "license": "MIT", "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { "node": ">=14.17" } }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/browserslist" }, { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" }, { "type": "github", "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" } }, "node_modules/use-sync-external-store": { "version": "1.6.0", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "node_modules/vite": { "version": "5.4.21", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/vite/-/vite-5.4.21.tgz", "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.21.3", "postcss": "^8.4.43", "rollup": "^4.20.0" }, "bin": { "vite": "bin/vite.js" }, "engines": { "node": "^18.0.0 || >=20.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || >=20.0.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.4.0" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, "less": { "optional": true }, "lightningcss": { "optional": true }, "sass": { "optional": true }, "sass-embedded": { "optional": true }, "stylus": { "optional": true }, "sugarss": { "optional": true }, "terser": { "optional": true } } }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "license": "ISC", "engines": { "node": ">= 6" } }, "node_modules/zustand": { "version": "4.5.7", "resolved": "https://artifactory.workday.com/artifactory/api/npm/npm-virtual/zustand/-/zustand-4.5.7.tgz", "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", "license": "MIT", "dependencies": { "use-sync-external-store": "^1.2.2" }, "engines": { "node": ">=12.7.0" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "peerDependenciesMeta": { "@types/react": { "optional": true }, "immer": { "optional": true }, "react": { "optional": true } } } } } ================================================ FILE: packages/agentflow/examples/package.json ================================================ { "name": "agentflow-basic-example", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" }, "dependencies": { "@emotion/react": "^11.10.0", "@emotion/styled": "^11.10.0", "@mui/material": "^5.15.0", "@mui/icons-material": "^5.15.0", "react": "^18.2.0", "react-dom": "^18.2.0", "reactflow": "^11.5.0" }, "devDependencies": { "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "@vitejs/plugin-react": "^4.0.0", "typescript": "^5.0.0", "vite": "^5.0.0" } } ================================================ FILE: packages/agentflow/examples/src/App.tsx ================================================ /** * Example App with Dropdown Selector * * Select different examples from the dropdown to see various SDK usage patterns. */ import { type ComponentType, lazy, Suspense, useState } from 'react' import { apiBaseUrl, token } from './config' import { AllNodeTypesExampleProps, BasicExampleProps, CustomNodeExampleProps, CustomUIExampleProps, DarkModeExampleProps, FilteredComponentsExampleProps, MultiNodeFlowProps, StatusIndicatorsExampleProps } from './demos' import { PropsDisplay } from './PropsDisplay' const examples: Array<{ id: string name: string description: string props: object component: ComponentType }> = [ { id: 'basic', name: 'Basic Usage', description: 'Simple canvas with imperative methods', props: BasicExampleProps, component: lazy(() => import('./demos/BasicExample').then((m) => ({ default: m.BasicExample }))) }, { id: 'multi-node', name: 'Multi-Node Flow', description: 'Complete flow with gradient edges', props: MultiNodeFlowProps, component: lazy(() => import('./demos/MultiNodeFlow').then((m) => ({ default: m.MultiNodeFlow }))) }, { id: 'dark-mode', name: 'Dark Mode', description: 'Light/dark theme toggle', props: DarkModeExampleProps, component: lazy(() => import('./demos/DarkModeExample').then((m) => ({ default: m.DarkModeExample }))) }, { id: 'status', name: 'Status Indicators', description: 'Node execution states with animations', props: StatusIndicatorsExampleProps, component: lazy(() => import('./demos/StatusIndicatorsExample').then((m) => ({ default: m.StatusIndicatorsExample }))) }, { id: 'custom-node', name: 'Custom Node', description: 'Node with self-contained InputParam definitions and show/hide conditions', props: CustomNodeExampleProps, component: lazy(() => import('./demos/CustomNodeExample').then((m) => ({ default: m.CustomNodeExample }))) }, { id: 'custom-ui', name: 'Custom UI', description: 'Custom header and palette via render props', props: CustomUIExampleProps, component: lazy(() => import('./demos/CustomUIExample').then((m) => ({ default: m.CustomUIExample }))) }, { id: 'all-nodes', name: 'All Node Types', description: 'Visual catalog of all 15 node types', props: AllNodeTypesExampleProps, component: lazy(() => import('./demos/AllNodeTypesExample').then((m) => ({ default: m.AllNodeTypesExample }))) }, { id: 'filtered', name: 'Filtered Components', description: 'Restrict available nodes with presets', props: FilteredComponentsExampleProps, component: lazy(() => import('./demos/FilteredComponentsExample').then((m) => ({ default: m.FilteredComponentsExample }))) } ] type ExampleId = (typeof examples)[number]['id'] function isExampleId(id: string): id is ExampleId { return examples.some((e) => e.id === id) } function LoadingFallback() { return (
Loading example...
) } export default function App() { const [selectedExample, setSelectedExample] = useState('basic') const [showProps, setShowProps] = useState(false) // Config loaded from environment variables const currentExample = examples.find((e) => e.id === selectedExample) // Replace placeholder values with actual runtime values const actualProps = currentExample?.props ? Object.fromEntries( Object.entries(currentExample.props).map(([key, value]) => { if (key === 'apiBaseUrl' && typeof value === 'string' && value.includes('environment variables')) { return [key, apiBaseUrl] } if (key === 'token' && typeof value === 'string' && value.includes('environment variables')) { return [key, token ? `${token.substring(0, 20)}...` : 'undefined'] } return [key, value] }) ) : {} const Component = currentExample?.component return (
{/* Example Selector Header */}
{currentExample && {currentExample.description}} {/* API Base URL Display */}
{apiBaseUrl}
{/* Props Display Section */} {currentExample && actualProps && ( } exampleId={selectedExample} showProps={showProps} onToggleProps={setShowProps} /> )} {/* Example Content */}
}>{Component ? : null}
) } ================================================ FILE: packages/agentflow/examples/src/FlowStatePanel.tsx ================================================ /** * FlowStatePanel Component * * Displays live onFlowChange data and saved flow snapshots * in a dark-themed, resizable side panel with copy support. */ import { useCallback, useEffect, useRef, useState } from 'react' import type { FlowData } from '@flowiseai/agentflow' type FlowStatePanelTab = 'live' | 'saved' interface FlowStatePanelProps { currentFlow: FlowData | null savedFlow: FlowData | null changeCount: number } export function FlowStatePanel({ currentFlow, savedFlow, changeCount }: FlowStatePanelProps) { const [tab, setTab] = useState('live') const [copied, setCopied] = useState(false) const [width, setWidth] = useState(300) const dragging = useRef(false) const flow = tab === 'live' ? currentFlow : savedFlow const startX = useRef(0) const startWidth = useRef(0) const resizeBy = useCallback((delta: number) => { setWidth((w) => Math.max(200, Math.min(800, w + delta))) }, []) const onMouseMove = useCallback((moveEvent: MouseEvent) => { if (!dragging.current) return const newWidth = Math.max(200, Math.min(800, startWidth.current + (startX.current - moveEvent.clientX))) setWidth(newWidth) }, []) const onMouseUp = useCallback(() => { dragging.current = false document.removeEventListener('mousemove', onMouseMove) document.removeEventListener('mouseup', onMouseUp) document.body.style.cursor = '' document.body.style.userSelect = '' }, [onMouseMove]) // Clean up global listeners on unmount to prevent memory leaks useEffect(() => { return () => { document.removeEventListener('mousemove', onMouseMove) document.removeEventListener('mouseup', onMouseUp) document.body.style.cursor = '' document.body.style.userSelect = '' } }, [onMouseMove, onMouseUp]) const handleMouseDown = useCallback( (e: React.MouseEvent) => { e.preventDefault() dragging.current = true startX.current = e.clientX startWidth.current = width document.addEventListener('mousemove', onMouseMove) document.addEventListener('mouseup', onMouseUp) document.body.style.cursor = 'col-resize' document.body.style.userSelect = 'none' }, [width, onMouseMove, onMouseUp] ) const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { if (e.key === 'ArrowLeft') { e.preventDefault() resizeBy(-20) } else if (e.key === 'ArrowRight') { e.preventDefault() resizeBy(20) } }, [resizeBy] ) return (
{/* Drag handle */}
{/* Summary stats + copy button */} {flow && (
nodes: {flow.nodes.length} edges: {flow.edges.length}
)} {/* JSON payload */}
{flow ? (
                        {JSON.stringify(flow, null, 2)}
                    
) : (
{tab === 'live' ? 'Interact with the canvas to see live flow data.' : 'Click Save or press Cmd+S to capture a snapshot.'}
)}
) } ================================================ FILE: packages/agentflow/examples/src/PropsDisplay.tsx ================================================ /** * PropsDisplay Component * * Displays Agentflow component props in an expandable accordion format */ interface PropsDisplayProps { exampleName: string props: Record exampleId: string showProps: boolean onToggleProps: (show: boolean) => void } export function PropsDisplay({ exampleName, props, exampleId, showProps, onToggleProps }: PropsDisplayProps) { return (
{/* Accordion Header */} {/* Accordion Content */} {showProps && (
                            {` {
                                    const isLast = index === arr.length - 1
                                    let displayValue: string

                                    if (typeof value === 'boolean') {
                                        displayValue = `{${value}}`
                                    } else if (typeof value === 'string') {
                                        // Check if it's an expression (starts with { or contains =>)
                                        if (value.startsWith('{') || value.includes('=>')) {
                                            displayValue = value
                                        } else {
                                            displayValue = `"${value}"`
                                        }
                                    } else {
                                        displayValue = `"${String(value)}"`
                                    }

                                    return `  ${key}=${displayValue}${isLast ? '' : '\n'}`
                                })
                                .join('')}\n/>`}
                        
ℹ️ These are the main props used in the {exampleName} example. See the source code for complete implementation details.
)}
) } ================================================ FILE: packages/agentflow/examples/src/config.ts ================================================ /** * Application configuration from environment variables */ export const apiBaseUrl = import.meta.env.VITE_INSTANCE_URL || 'http://localhost:3000' export const token = import.meta.env.VITE_API_TOKEN || undefined ================================================ FILE: packages/agentflow/examples/src/demos/AllNodeTypesExample.tsx ================================================ /** * All Node Types Example * * Showcases all available node types with their distinct colors and icons. * Useful for understanding the visual vocabulary of Agentflow. */ import { useRef } from 'react' import type { AgentFlowInstance, FlowData } from '@flowiseai/agentflow' import { Agentflow } from '@flowiseai/agentflow' import { apiBaseUrl, token } from '../config' // Showcase all node types in a grid layout const allNodesFlow: FlowData = { nodes: [ // Row 1: Core Flow Nodes { id: 'startAgentflow_0', type: 'agentflowNode', position: { x: 50, y: 50 }, data: { id: 'startAgentflow_0', name: 'startAgentflow', label: 'Start', color: '#7EE787', hideInput: true, outputAnchors: [{ id: 'startAgentflow_0-output-0', name: 'start', label: 'Start', type: 'start' }] } }, { id: 'llmAgentflow_0', type: 'agentflowNode', position: { x: 250, y: 50 }, data: { id: 'llmAgentflow_0', name: 'llmAgentflow', label: 'LLM', color: '#64B5F6', outputAnchors: [{ id: 'llmAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, { id: 'agentAgentflow_0', type: 'agentflowNode', position: { x: 450, y: 50 }, data: { id: 'agentAgentflow_0', name: 'agentAgentflow', label: 'Agent', color: '#4DD0E1', outputAnchors: [{ id: 'agentAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, { id: 'directReplyAgentflow_0', type: 'agentflowNode', position: { x: 650, y: 50 }, data: { id: 'directReplyAgentflow_0', name: 'directReplyAgentflow', label: 'Direct Reply', color: '#4DDBBB', outputAnchors: [{ id: 'directReplyAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, // Row 2: Control Flow Nodes { id: 'conditionAgentflow_0', type: 'agentflowNode', position: { x: 50, y: 180 }, data: { id: 'conditionAgentflow_0', name: 'conditionAgentflow', label: 'Condition', color: '#FFB938', outputAnchors: [ { id: 'conditionAgentflow_0-output-0', name: 'true', label: 'True', type: 'boolean' }, { id: 'conditionAgentflow_0-output-1', name: 'false', label: 'False', type: 'boolean' } ] } }, { id: 'conditionAgentAgentflow_0', type: 'agentflowNode', position: { x: 250, y: 180 }, data: { id: 'conditionAgentAgentflow_0', name: 'conditionAgentAgentflow', label: 'Condition Agent', color: '#ff8fab', outputAnchors: [{ id: 'conditionAgentAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, { id: 'loopAgentflow_0', type: 'agentflowNode', position: { x: 450, y: 180 }, data: { id: 'loopAgentflow_0', name: 'loopAgentflow', label: 'Loop', color: '#FFA07A', outputAnchors: [{ id: 'loopAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, { id: 'iterationAgentflow_0', type: 'agentflowNode', position: { x: 650, y: 180 }, data: { id: 'iterationAgentflow_0', name: 'iterationAgentflow', label: 'Iteration', color: '#9C89B8', outputAnchors: [{ id: 'iterationAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, // Row 3: Interactive & Tool Nodes { id: 'humanInputAgentflow_0', type: 'agentflowNode', position: { x: 50, y: 310 }, data: { id: 'humanInputAgentflow_0', name: 'humanInputAgentflow', label: 'Human Input', color: '#6E6EFD', outputAnchors: [ { id: 'humanInputAgentflow_0-output-0', name: 'proceed', label: 'Proceed', type: 'string' }, { id: 'humanInputAgentflow_0-output-1', name: 'reject', label: 'Reject', type: 'string' } ] } }, { id: 'toolAgentflow_0', type: 'agentflowNode', position: { x: 250, y: 310 }, data: { id: 'toolAgentflow_0', name: 'toolAgentflow', label: 'Tool', color: '#d4a373', outputAnchors: [{ id: 'toolAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, { id: 'retrieverAgentflow_0', type: 'agentflowNode', position: { x: 450, y: 310 }, data: { id: 'retrieverAgentflow_0', name: 'retrieverAgentflow', label: 'Retriever', color: '#b8bedd', outputAnchors: [{ id: 'retrieverAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, { id: 'customFunctionAgentflow_0', type: 'agentflowNode', position: { x: 650, y: 310 }, data: { id: 'customFunctionAgentflow_0', name: 'customFunctionAgentflow', label: 'Custom Function', color: '#E4B7FF', outputAnchors: [{ id: 'customFunctionAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, // Row 4: Integration Nodes { id: 'httpAgentflow_0', type: 'agentflowNode', position: { x: 50, y: 440 }, data: { id: 'httpAgentflow_0', name: 'httpAgentflow', label: 'HTTP Request', color: '#FF7F7F', outputAnchors: [{ id: 'httpAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, { id: 'executeFlowAgentflow_0', type: 'agentflowNode', position: { x: 250, y: 440 }, data: { id: 'executeFlowAgentflow_0', name: 'executeFlowAgentflow', label: 'Execute Flow', color: '#a3b18a', outputAnchors: [{ id: 'executeFlowAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, { id: 'stickyNoteAgentflow_0', type: 'agentflowNode', position: { x: 450, y: 440 }, data: { id: 'stickyNoteAgentflow_0', name: 'stickyNoteAgentflow', label: 'Sticky Note', color: '#fee440', outputAnchors: [] } } ], edges: [], viewport: { x: 0, y: 0, zoom: 0.85 } } export function AllNodeTypesExample() { // Config loaded from environment variables const agentflowRef = useRef(null) return (
{/* Info Header */}

All Node Types

Showcasing all available node types with their colors and icons. Hover over nodes to see the output handles.

{/* Canvas */}
) } export const AllNodeTypesExampleProps = { apiBaseUrl: apiBaseUrl, token: token, initialFlow: 'FlowData (15 node types)', readOnly: true, showDefaultHeader: false, enableGenerator: false } ================================================ FILE: packages/agentflow/examples/src/demos/BasicExample.tsx ================================================ /** * Basic Example * * Demonstrates basic @flowiseai/agentflow usage with imperative methods, * onFlowChange tracking, and save flow functionality. */ import { useCallback, useRef, useState } from 'react' import type { AgentFlowInstance, FlowData, ValidationResult } from '@flowiseai/agentflow' import { Agentflow } from '@flowiseai/agentflow' import { InternalAxiosRequestConfig } from 'axios' import { apiBaseUrl, token } from '../config' import { FlowStatePanel } from '../FlowStatePanel' // Example flow data const initialFlow: FlowData = { nodes: [ { id: 'startAgentflow_0', type: 'agentflowNode', position: { x: 100, y: 100 }, data: { id: 'startAgentflow_0', name: 'startAgentflow', label: 'Start', color: '#7EE787', hideInput: true, outputAnchors: [{ id: 'startAgentflow_0-output-0', name: 'start', label: 'Start', type: 'start' }] } }, { id: 'agentAgentflow_0', type: 'agentflowNode', position: { x: 250, y: 100 }, data: { id: 'agentAgentflow_0', name: 'agentAgentflow', label: 'Agent', color: '#4DD0E1', outputAnchors: [{ id: 'agentAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } } ], edges: [ { id: 'edge-1', source: 'startAgentflow_0', sourceHandle: 'startAgentflow_0-output-0', target: 'agentAgentflow_0', targetHandle: 'agentAgentflow_0', type: 'agentflowEdge', data: { sourceColor: '#7EE787', targetColor: '#4DD0E1' } } ], viewport: { x: 0, y: 0, zoom: 1 } } export function BasicExample() { const agentflowRef = useRef(null) const [validationResult, setValidationResult] = useState(null) const [currentFlow, setCurrentFlow] = useState(null) const [savedFlow, setSavedFlow] = useState(null) const [changeCount, setChangeCount] = useState(0) const handleFlowChange = useCallback((flow: FlowData) => { setCurrentFlow(flow) setChangeCount((c) => c + 1) console.log('onFlowChange:', flow) }, []) const handleSave = useCallback((flow: FlowData) => { setSavedFlow(flow) console.log('onSave:', flow) }, []) const handleValidate = () => { if (agentflowRef.current) { const result = agentflowRef.current.validate() setValidationResult(result) console.log('Validation result:', result) } } const handleFitView = () => { if (agentflowRef.current) { agentflowRef.current.fitView() } } const handleGetFlow = () => { if (agentflowRef.current) { const flow = agentflowRef.current.getFlow() console.log('Current flow:', flow) alert('Flow data logged to console!') } } const handleClear = () => { if (agentflowRef.current) { agentflowRef.current.clear() } } return (
{/* Toolbar */}
{validationResult && ( {validationResult.valid ? '✓ Valid' : `✗ ${validationResult.errors.length} error(s)`} )}
{/* Canvas + Flow State Panel */}
{ // pass cookies if no token is provided if (!token) { config.withCredentials = true } return config }} />
) } export const BasicExampleProps = { apiBaseUrl: '{from environment variables}', token: '{from environment variables}', initialFlow: 'FlowData', onFlowChange: '(flow: FlowData) => void', onSave: '(flow: FlowData) => void', showDefaultHeader: true, requestInterceptor: '(config: InternalAxiosRequestConfig) => InternalAxiosRequestConfig' } ================================================ FILE: packages/agentflow/examples/src/demos/CustomNodeExample.tsx ================================================ /** * Custom Node Example * * Demonstrates how a node can carry its own InputParam[] definitions * in data.inputs, bypassing the API schema. The node includes show/hide * conditions so double-clicking it opens the real EditNodeDialog with * conditional field visibility. * * A side panel shows the live visibility state (input values, stripped * values, and per-field visibility map) as the node is edited. */ import { useCallback, useMemo, useState } from 'react' import type { FlowData, HeaderRenderProps, InputParam } from '@flowiseai/agentflow' import { Agentflow, evaluateFieldVisibility, stripHiddenFieldValues } from '@flowiseai/agentflow' import { apiBaseUrl, token } from '../config' // ── Custom node InputParam definitions with show/hide conditions ────────── const customNodeInputParams: InputParam[] = [ { id: 'provider', name: 'provider', label: 'Model Provider', type: 'options', options: [ { label: 'OpenAI', name: 'openAI' }, { label: 'Google', name: 'google' }, { label: 'Anthropic', name: 'anthropic' } ] }, { id: 'openAIModel', name: 'openAIModel', label: 'OpenAI Model', type: 'options', options: [ { label: 'GPT-4o', name: 'gpt-4o' }, { label: 'GPT-4o Mini', name: 'gpt-4o-mini' }, { label: 'o1', name: 'o1' } ], show: { provider: 'openAI' } }, { id: 'googleModel', name: 'googleModel', label: 'Google Model', type: 'options', options: [ { label: 'Gemini 2.0 Flash', name: 'gemini-2.0-flash' }, { label: 'Gemini 2.5 Pro', name: 'gemini-2.5-pro' } ], show: { provider: 'google' } }, { id: 'anthropicModel', name: 'anthropicModel', label: 'Anthropic Model', type: 'options', options: [ { label: 'Claude Sonnet 4', name: 'claude-sonnet-4' }, { label: 'Claude Opus 4', name: 'claude-opus-4' } ], show: { provider: 'anthropic' } }, { id: 'enableMemory', name: 'enableMemory', label: 'Enable Memory', type: 'boolean' }, { id: 'memoryType', name: 'memoryType', label: 'Memory Type', type: 'options', options: [ { label: 'Buffer Window', name: 'bufferWindow' }, { label: 'Token Buffer', name: 'tokenBuffer' }, { label: 'Summary', name: 'summary' } ], show: { enableMemory: true } }, { id: 'windowSize', name: 'windowSize', label: 'Window Size', type: 'number', default: 5, show: { enableMemory: true, memoryType: 'bufferWindow' } }, { id: 'maxTokens', name: 'maxTokens', label: 'Max Tokens', type: 'number', default: 2000, show: { enableMemory: true, memoryType: 'tokenBuffer' } }, { id: 'conditions', name: 'conditions', label: 'Condition', type: 'array', array: [ { id: 'variable', name: 'variable', label: 'Variable', type: 'string' }, { id: 'operation', name: 'operation', label: 'Operation', type: 'options', options: [ { label: 'Equals', name: 'equals' }, { label: 'Contains', name: 'contains' }, { label: 'Is Empty', name: 'isEmpty' } ] }, { id: 'value', name: 'value', label: 'Value', type: 'string', hide: { 'conditions[$index].operation': 'isEmpty' } } ] }, { id: 'outputFormat', name: 'outputFormat', label: 'Output Format', type: 'options', options: [ { label: 'Text', name: 'text' }, { label: 'JSON', name: 'json' }, { label: 'Markdown', name: 'markdown' } ] }, { id: 'schema', name: 'schema', label: 'Output Schema', type: 'string', placeholder: 'Define the output structure...', hide: { outputFormat: 'text' } }, { id: 'apiKey', name: 'apiKey', label: 'API Key', type: 'string', description: 'Shown for any provider (regex match)', show: { provider: '(openAI|google|anthropic)' } }, { id: 'streamingSupport', name: 'streamingSupport', label: 'Enable Streaming', type: 'boolean', description: 'Available for OpenAI and Anthropic', show: { provider: ['openAI', 'anthropic'] } } ] // ── Canvas flow data with a custom node carrying its own input definitions ─ const initialInputValues: Record = { provider: '', enableMemory: false, outputFormat: 'text' } const canvasFlow: FlowData = { nodes: [ { id: 'customNode_0', type: 'agentflowNode', position: { x: 300, y: 150 }, data: { id: 'customNode_0', name: 'customNodeDemo', label: 'Custom Node', color: '#64B5F6', inputs: customNodeInputParams, inputValues: initialInputValues, outputAnchors: [{ id: 'customNode_0-output-0', name: 'output', label: 'Output', type: 'string' }] } } ], edges: [], viewport: { x: 0, y: 0, zoom: 1 } } // ── Side panel for live visibility state ─────────────────────────────────── type VisibilityTab = 'values' | 'stripped' | 'visibility' function VisibilityStatePanel({ inputValues }: { inputValues: Record }) { const [tab, setTab] = useState('values') const evaluated = useMemo(() => evaluateFieldVisibility(customNodeInputParams, inputValues), [inputValues]) const stripped = useMemo(() => stripHiddenFieldValues(customNodeInputParams, inputValues), [inputValues]) const visibilityMap = useMemo(() => Object.fromEntries(evaluated.map((p) => [p.name, p.display])), [evaluated]) const visibleCount = evaluated.filter((p) => p.display).length const hiddenCount = evaluated.filter((p) => !p.display).length const tabData: Record = { values: inputValues, stripped, visibility: visibilityMap } const tabButton = (id: VisibilityTab, label: string) => ( ) return (
{/* Tabs */}
{tabButton('values', 'Input Values')} {tabButton('stripped', 'Stripped')} {tabButton('visibility', 'Visibility')}
{/* Stats */}
visible: {visibleCount} hidden: {hiddenCount}
{/* JSON payload */}
                    {JSON.stringify(tabData[tab], null, 2)}
                
) } // ── Component ────────────────────────────────────────────────────────────── export function CustomNodeExample() { const [inputValues, setInputValues] = useState>(initialInputValues) const handleFlowChange = useCallback((flow: FlowData) => { const node = flow.nodes.find((n) => n.id === 'customNode_0') if (node?.data?.inputValues) { setInputValues(node.data.inputValues) } }, []) const renderHeader = useCallback( (_props: HeaderRenderProps) => (
Custom Node Demo — Double-click the node to open EditNodeDialog with show/hide conditions.
), [] ) return (
) } export const CustomNodeExampleProps = { apiBaseUrl: '{from environment variables}', token: '{from environment variables}', initialFlow: 'FlowData (custom node with data.inputs)', onFlowChange: '(flow: FlowData) => void', renderHeader: '(props: HeaderRenderProps) => ReactNode' } ================================================ FILE: packages/agentflow/examples/src/demos/CustomUIExample.tsx ================================================ /** * Custom UI Example * * Demonstrates how to customize the header and node palette * using render props for full control over the UI. */ import { useRef, useState } from 'react' import type { AgentFlowInstance, FlowData, HeaderRenderProps, PaletteRenderProps } from '@flowiseai/agentflow' import { Agentflow } from '@flowiseai/agentflow' import { apiBaseUrl, token } from '../config' const initialFlow: FlowData = { nodes: [ { id: 'startAgentflow_0', type: 'agentflowNode', position: { x: 300, y: 200 }, data: { id: 'startAgentflow_0', name: 'startAgentflow', label: 'Start', color: '#7EE787', hideInput: true, outputAnchors: [{ id: 'startAgentflow_0-output-0', name: 'start', label: 'Start', type: 'start' }] } } ], edges: [], viewport: { x: 0, y: 0, zoom: 1 } } // Custom header component function CustomHeader({ flowName, isDirty, onSave, onExport, onValidate }: HeaderRenderProps) { const [validationStatus, setValidationStatus] = useState<'valid' | 'invalid' | null>(null) const handleValidate = () => { const result = onValidate() setValidationStatus(result.valid ? 'valid' : 'invalid') setTimeout(() => setValidationStatus(null), 3000) } return (
🤖 {flowName} {isDirty && ( Unsaved )}
) } // Custom palette component function CustomPalette({ availableNodes, onAddNode }: PaletteRenderProps) { const [search, setSearch] = useState('') const [hoveredNode, setHoveredNode] = useState(null) const filteredNodes = availableNodes.filter( (node) => node.label.toLowerCase().includes(search.toLowerCase()) || node.name.toLowerCase().includes(search.toLowerCase()) ) // Group nodes by category const categories = filteredNodes.reduce((acc, node) => { const category = node.category || 'Other' if (!acc[category]) acc[category] = [] acc[category].push(node) return acc }, {} as Record) return (
{/* Search */}
setSearch(e.target.value)} style={{ width: '100%', padding: '10px 12px', border: '1px solid #e0e0e0', borderRadius: '8px', fontSize: '14px', outline: 'none' }} />
{/* Node List */}
{Object.entries(categories).map(([category, nodes]) => (
{category}
{nodes.map((node) => (
onAddNode(node.name)} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault() onAddNode(node.name) } }} onMouseEnter={() => setHoveredNode(node.name)} onMouseLeave={() => setHoveredNode(null)} style={{ display: 'flex', alignItems: 'center', gap: '10px', padding: '10px 12px', marginBottom: '4px', background: hoveredNode === node.name ? '#fff' : 'transparent', border: `1px solid ${hoveredNode === node.name ? '#e0e0e0' : 'transparent'}`, borderRadius: '8px', cursor: 'pointer', transition: 'all 0.15s' }} >
{node.label.charAt(0)}
{node.label}
{node.description && (
{node.description}
)}
))}
))}
) } export function CustomUIExample() { // Config loaded from environment variables const agentflowRef = useRef(null) return (
} renderNodePalette={(props: PaletteRenderProps) => } showDefaultHeader={false} showDefaultPalette={false} onSave={(flow: FlowData) => { console.log('Saving flow:', flow) alert('Flow saved! Check console.') }} />
) } export const CustomUIExampleProps = { apiBaseUrl: '{from environment variables}', token: '{from environment variables}', initialFlow: 'FlowData', renderHeader: '(props: HeaderRenderProps) => ReactNode', renderNodePalette: '(props: PaletteRenderProps) => ReactNode', showDefaultHeader: false, showDefaultPalette: false, onSave: '(flow: FlowData) => void' } ================================================ FILE: packages/agentflow/examples/src/demos/DarkModeExample.tsx ================================================ /** * Dark Mode Example * * Demonstrates the agentflow canvas with dark theme styling. * The nodes and edges automatically adapt to the dark theme. */ import { useRef, useState } from 'react' import type { AgentFlowInstance, FlowData } from '@flowiseai/agentflow' import { Agentflow } from '@flowiseai/agentflow' import CssBaseline from '@mui/material/CssBaseline' import { createTheme, ThemeProvider } from '@mui/material/styles' import { apiBaseUrl, token } from '../config' const sampleFlow: FlowData = { nodes: [ { id: 'startAgentflow_0', type: 'agentflowNode', position: { x: 100, y: 150 }, data: { id: 'startAgentflow_0', name: 'startAgentflow', label: 'Start', color: '#7EE787', hideInput: true, outputAnchors: [{ id: 'startAgentflow_0-output-0', name: 'start', label: 'Start', type: 'start' }] } }, { id: 'agentAgentflow_0', type: 'agentflowNode', position: { x: 400, y: 150 }, data: { id: 'agentAgentflow_0', name: 'agentAgentflow', label: 'AI Assistant', color: '#4DD0E1', outputAnchors: [{ id: 'agentAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }], inputValues: { agentModel: 'chatAnthropic', agentModelConfig: { modelName: 'claude-3-5-sonnet' } } } }, { id: 'directReplyAgentflow_0', type: 'agentflowNode', position: { x: 700, y: 150 }, data: { id: 'directReplyAgentflow_0', name: 'directReplyAgentflow', label: 'Reply', color: '#4DDBBB', outputAnchors: [{ id: 'directReplyAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } } ], edges: [ { id: 'edge-1', source: 'startAgentflow_0', sourceHandle: 'startAgentflow_0-output-0', target: 'agentAgentflow_0', targetHandle: 'agentAgentflow_0', type: 'agentflowEdge', data: { sourceColor: '#7EE787', targetColor: '#4DD0E1' } }, { id: 'edge-2', source: 'agentAgentflow_0', sourceHandle: 'agentAgentflow_0-output-0', target: 'directReplyAgentflow_0', targetHandle: 'directReplyAgentflow_0', type: 'agentflowEdge', data: { sourceColor: '#4DD0E1', targetColor: '#4DDBBB' } } ], viewport: { x: 0, y: 0, zoom: 1 } } export function DarkModeExample() { // Config loaded from environment variables const agentflowRef = useRef(null) const [isDark, setIsDark] = useState(true) const darkTheme = createTheme({ palette: { mode: isDark ? 'dark' : 'light', background: { default: isDark ? '#1a1a2e' : '#f5f5f5', paper: isDark ? '#16213e' : '#ffffff' }, primary: { main: '#4DD0E1' } } }) return (
{/* Theme Toggle */}
Theme:
{/* Canvas */}
) } export const DarkModeExampleProps = { apiBaseUrl: '{from environment variables}', token: '{from environment variables}', initialFlow: 'FlowData (sample flow)', isDarkMode: '{isDark}', showDefaultHeader: false } ================================================ FILE: packages/agentflow/examples/src/demos/FilteredComponentsExample.tsx ================================================ /** * Filtered Components Example * * Demonstrates how to restrict which node types are available in the palette. * Useful for creating simplified or specialized workflows. */ import { useRef, useState } from 'react' import type { AgentFlowInstance, FlowData } from '@flowiseai/agentflow' import { Agentflow } from '@flowiseai/agentflow' import { apiBaseUrl, token } from '../config' const initialFlow: FlowData = { nodes: [ { id: 'startAgentflow_0', type: 'agentflowNode', position: { x: 200, y: 200 }, data: { id: 'startAgentflow_0', name: 'startAgentflow', label: 'Start', color: '#7EE787', hideInput: true, outputAnchors: [{ id: 'startAgentflow_0-output-0', name: 'start', label: 'Start', type: 'start' }] } } ], edges: [], viewport: { x: 0, y: 0, zoom: 1 } } // Different preset configurations const presets = { full: { name: 'Full Access', description: 'All nodes available', components: undefined // undefined = all nodes }, simple: { name: 'Simple Chat', description: 'Basic LLM flow nodes only', components: ['llmAgentflow', 'directReplyAgentflow'] }, agent: { name: 'Agent Builder', description: 'Agent and tool nodes', components: ['agentAgentflow', 'toolAgentflow', 'retrieverAgentflow', 'directReplyAgentflow'] }, conditional: { name: 'Conditional Flow', description: 'Branching and control flow', components: ['conditionAgentflow', 'conditionAgentAgentflow', 'loopAgentflow', 'humanInputAgentflow', 'llmAgentflow'] }, integration: { name: 'Integration', description: 'External services and functions', components: ['httpAgentflow', 'customFunctionAgentflow', 'executeFlowAgentflow', 'directReplyAgentflow'] } } type PresetKey = keyof typeof presets export function FilteredComponentsExample() { // Config loaded from environment variables const agentflowRef = useRef(null) const [selectedPreset, setSelectedPreset] = useState('full') const [key, setKey] = useState(0) // Used to force re-render when preset changes const handlePresetChange = (preset: PresetKey) => { setSelectedPreset(preset) setKey((k) => k + 1) // Force re-mount to apply new components filter } const currentPreset = presets[selectedPreset] return (
{/* Preset Selector */}

Select Component Preset

The components prop restricts which node types appear in the palette.

{(Object.keys(presets) as PresetKey[]).map((key) => { const preset = presets[key] const isSelected = selectedPreset === key return ( ) })}
{/* Show current filter */}
components= {currentPreset.components ? ( {JSON.stringify(currentPreset.components)} ) : ( undefined (all nodes) )}
{/* Canvas - re-mounts when key changes */}
) } export const FilteredComponentsExampleProps = { apiBaseUrl: '{from environment variables}', token: '{from environment variables}', initialFlow: 'FlowData', components: 'string[] (preset-based)', showDefaultHeader: false } ================================================ FILE: packages/agentflow/examples/src/demos/MultiNodeFlow.tsx ================================================ /** * Multi-Node Flow Example * * Demonstrates a complete flow with multiple connected nodes, * showing the styled edges with gradient colors. */ import { useRef } from 'react' import type { AgentFlowInstance, FlowData } from '@flowiseai/agentflow' import { Agentflow } from '@flowiseai/agentflow' import { apiBaseUrl, token } from '../config' // A complete translation agent flow const translationFlow: FlowData = { nodes: [ { id: 'startAgentflow_0', type: 'agentflowNode', position: { x: 100, y: 200 }, data: { id: 'startAgentflow_0', name: 'startAgentflow', label: 'Start', color: '#7EE787', hideInput: true, outputAnchors: [{ id: 'startAgentflow_0-output-0', name: 'start', label: 'Start', type: 'start' }] } }, { id: 'llmAgentflow_0', type: 'agentflowNode', position: { x: 400, y: 100 }, data: { id: 'llmAgentflow_0', name: 'llmAgentflow', label: 'Translator', color: '#64B5F6', outputAnchors: [{ id: 'llmAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }], inputValues: { llmModel: 'chatGoogleGenerativeAI', llmModelConfig: { modelName: 'gemini-2.0-flash' } } } }, { id: 'conditionAgentflow_0', type: 'agentflowNode', position: { x: 700, y: 100 }, data: { id: 'conditionAgentflow_0', name: 'conditionAgentflow', label: 'Check Quality', color: '#FFB938', outputAnchors: [ { id: 'conditionAgentflow_0-output-0', name: 'true', label: 'Pass', type: 'boolean' }, { id: 'conditionAgentflow_0-output-1', name: 'false', label: 'Fail', type: 'boolean' } ] } }, { id: 'directReplyAgentflow_0', type: 'agentflowNode', position: { x: 1000, y: 50 }, data: { id: 'directReplyAgentflow_0', name: 'directReplyAgentflow', label: 'Send Response', color: '#4DDBBB', outputAnchors: [{ id: 'directReplyAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, { id: 'humanInputAgentflow_0', type: 'agentflowNode', position: { x: 1000, y: 200 }, data: { id: 'humanInputAgentflow_0', name: 'humanInputAgentflow', label: 'Review Required', color: '#6E6EFD', outputAnchors: [ { id: 'humanInputAgentflow_0-output-0', name: 'proceed', label: 'Proceed', type: 'string' }, { id: 'humanInputAgentflow_0-output-1', name: 'reject', label: 'Reject', type: 'string' } ] } } ], edges: [ { id: 'edge-start-translator', source: 'startAgentflow_0', sourceHandle: 'startAgentflow_0-output-0', target: 'llmAgentflow_0', targetHandle: 'llmAgentflow_0', type: 'agentflowEdge', data: { sourceColor: '#7EE787', targetColor: '#64B5F6' } }, { id: 'edge-translator-condition', source: 'llmAgentflow_0', sourceHandle: 'llmAgentflow_0-output-0', target: 'conditionAgentflow_0', targetHandle: 'conditionAgentflow_0', type: 'agentflowEdge', data: { sourceColor: '#64B5F6', targetColor: '#FFB938' } }, { id: 'edge-condition-reply', source: 'conditionAgentflow_0', sourceHandle: 'conditionAgentflow_0-output-0', target: 'directReplyAgentflow_0', targetHandle: 'directReplyAgentflow_0', type: 'agentflowEdge', data: { sourceColor: '#FFB938', targetColor: '#4DDBBB', edgeLabel: '0' } }, { id: 'edge-condition-human', source: 'conditionAgentflow_0', sourceHandle: 'conditionAgentflow_0-output-1', target: 'humanInputAgentflow_0', targetHandle: 'humanInputAgentflow_0', type: 'agentflowEdge', data: { sourceColor: '#FFB938', targetColor: '#6E6EFD', edgeLabel: '1' } } ], viewport: { x: 0, y: 0, zoom: 0.8 } } export function MultiNodeFlow() { // Config loaded from environment variables const agentflowRef = useRef(null) return (
console.log('Flow changed:', flow.nodes.length, 'nodes')} />
) } export const MultiNodeFlowProps = { apiBaseUrl: '{from environment variables}', token: '{from environment variables}', initialFlow: 'FlowData (multiple nodes)', showDefaultHeader: true, onFlowChange: '(flow: FlowData) => void' } ================================================ FILE: packages/agentflow/examples/src/demos/StatusIndicatorsExample.tsx ================================================ /** * Status Indicators Example * * Demonstrates node status indicators showing execution state: * - INPROGRESS: Spinning loader * - FINISHED: Green checkmark * - ERROR: Red exclamation * - STOPPED/TERMINATED: Stop icons */ import { useRef, useState } from 'react' import type { AgentFlowInstance, FlowData, FlowNode } from '@flowiseai/agentflow' import { Agentflow } from '@flowiseai/agentflow' import { apiBaseUrl, token } from '../config' const createFlowWithStatuses = (): FlowData => ({ nodes: [ { id: 'startAgentflow_0', type: 'agentflowNode', position: { x: 100, y: 200 }, data: { id: 'startAgentflow_0', name: 'startAgentflow', label: 'Start', color: '#7EE787', hideInput: true, status: 'FINISHED', outputAnchors: [{ id: 'startAgentflow_0-output-0', name: 'start', label: 'Start', type: 'start' }] } }, { id: 'llmAgentflow_0', type: 'agentflowNode', position: { x: 350, y: 100 }, data: { id: 'llmAgentflow_0', name: 'llmAgentflow', label: 'Processing...', color: '#64B5F6', status: 'INPROGRESS', outputAnchors: [{ id: 'llmAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, { id: 'llmAgentflow_1', type: 'agentflowNode', position: { x: 350, y: 300 }, data: { id: 'llmAgentflow_1', name: 'llmAgentflow', label: 'Failed Task', color: '#64B5F6', status: 'ERROR', error: 'API rate limit exceeded. Please try again later.', outputAnchors: [{ id: 'llmAgentflow_1-output-0', name: 'output', label: 'Output', type: 'string' }] } }, { id: 'agentAgentflow_0', type: 'agentflowNode', position: { x: 600, y: 100 }, data: { id: 'agentAgentflow_0', name: 'agentAgentflow', label: 'Completed', color: '#4DD0E1', status: 'FINISHED', outputAnchors: [{ id: 'agentAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } }, { id: 'humanInputAgentflow_0', type: 'agentflowNode', position: { x: 600, y: 300 }, data: { id: 'humanInputAgentflow_0', name: 'humanInputAgentflow', label: 'Stopped', color: '#6E6EFD', status: 'STOPPED', outputAnchors: [{ id: 'humanInputAgentflow_0-output-0', name: 'proceed', label: 'Proceed', type: 'string' }] } }, { id: 'directReplyAgentflow_0', type: 'agentflowNode', position: { x: 850, y: 200 }, data: { id: 'directReplyAgentflow_0', name: 'directReplyAgentflow', label: 'Pending', color: '#4DDBBB', // No status = pending/not yet executed outputAnchors: [{ id: 'directReplyAgentflow_0-output-0', name: 'output', label: 'Output', type: 'string' }] } } ], edges: [ { id: 'e1', source: 'startAgentflow_0', sourceHandle: 'startAgentflow_0-output-0', target: 'llmAgentflow_0', targetHandle: 'llmAgentflow_0', type: 'agentflowEdge', data: { sourceColor: '#7EE787', targetColor: '#64B5F6' } }, { id: 'e2', source: 'startAgentflow_0', sourceHandle: 'startAgentflow_0-output-0', target: 'llmAgentflow_1', targetHandle: 'llmAgentflow_1', type: 'agentflowEdge', data: { sourceColor: '#7EE787', targetColor: '#64B5F6' } }, { id: 'e3', source: 'llmAgentflow_0', sourceHandle: 'llmAgentflow_0-output-0', target: 'agentAgentflow_0', targetHandle: 'agentAgentflow_0', type: 'agentflowEdge', data: { sourceColor: '#64B5F6', targetColor: '#4DD0E1' } }, { id: 'e4', source: 'llmAgentflow_1', sourceHandle: 'llmAgentflow_1-output-0', target: 'humanInputAgentflow_0', targetHandle: 'humanInputAgentflow_0', type: 'agentflowEdge', data: { sourceColor: '#64B5F6', targetColor: '#6E6EFD' } } ], viewport: { x: 0, y: 0, zoom: 0.9 } }) export function StatusIndicatorsExample() { // Config loaded from environment variables const agentflowRef = useRef(null) const [flow, setFlow] = useState(createFlowWithStatuses) const simulateExecution = () => { // Reset all statuses const newNodes: FlowNode[] = flow.nodes.map((node) => ({ ...node, data: { ...node.data, status: undefined, error: undefined } })) setFlow({ ...flow, nodes: newNodes }) // Simulate step-by-step execution const statuses: Array<{ nodeId: string; status: 'INPROGRESS' | 'FINISHED' | 'ERROR' }> = [ { nodeId: 'startAgentflow_0', status: 'INPROGRESS' }, { nodeId: 'startAgentflow_0', status: 'FINISHED' }, { nodeId: 'llmAgentflow_0', status: 'INPROGRESS' }, { nodeId: 'llmAgentflow_1', status: 'INPROGRESS' }, { nodeId: 'llmAgentflow_0', status: 'FINISHED' }, { nodeId: 'llmAgentflow_1', status: 'ERROR' }, { nodeId: 'agentAgentflow_0', status: 'INPROGRESS' }, { nodeId: 'agentAgentflow_0', status: 'FINISHED' } ] statuses.forEach(({ nodeId, status }, index) => { setTimeout(() => { setFlow((prev) => ({ ...prev, nodes: prev.nodes.map((node) => node.id === nodeId ? { ...node, data: { ...node.data, status, error: status === 'ERROR' ? 'Simulated error for demo' : undefined } } : node ) })) }, (index + 1) * 800) }) } return (
{/* Controls */}
Status Indicators Demo Hover over error nodes to see error messages
{/* Canvas */}
) } export const StatusIndicatorsExampleProps = { apiBaseUrl: '{from environment variables}', token: '{from environment variables}', initialFlow: 'FlowData (status indicators)', showDefaultHeader: false, readOnly: true } ================================================ FILE: packages/agentflow/examples/src/demos/index.ts ================================================ export * from './AllNodeTypesExample' export * from './BasicExample' export * from './CustomNodeExample' export * from './CustomUIExample' export * from './DarkModeExample' export * from './FilteredComponentsExample' export * from './MultiNodeFlow' export * from './StatusIndicatorsExample' ================================================ FILE: packages/agentflow/examples/src/main.tsx ================================================ import React from 'react' import ReactDOM from 'react-dom/client' import CssBaseline from '@mui/material/CssBaseline' import { createTheme, ThemeProvider } from '@mui/material/styles' import App from './App' // Import the agentflow CSS (from source for development) import '../../src/features/canvas/canvas.css' const theme = createTheme({ palette: { mode: 'light' } }) ReactDOM.createRoot(document.getElementById('root')!).render( ) ================================================ FILE: packages/agentflow/examples/src/vite-env.d.ts ================================================ /// interface ImportMetaEnv { readonly VITE_INSTANCE_URL: string readonly VITE_API_TOKEN: string } interface ImportMeta { readonly env: ImportMetaEnv } ================================================ FILE: packages/agentflow/examples/tsconfig.json ================================================ { "compilerOptions": { "target": "ES2020", "useDefineForClassFields": true, "lib": ["ES2020", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true, "moduleResolution": "bundler", "allowImportingTsExtensions": true, "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true }, "include": ["src", "*.tsx", "*.ts", "../src/**/*.ts", "../src/**/*.tsx"] } ================================================ FILE: packages/agentflow/examples/vite.config.ts ================================================ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import path from 'path' export default defineConfig({ plugins: [react()], root: __dirname, resolve: { alias: { // Use the source files directly for development '@flowiseai/agentflow': path.resolve(__dirname, '../src'), '@': path.resolve(__dirname, '../src') } }, server: { port: 5174, // Watch the parent src directory for changes watch: { // Include the agentflow source directory ignored: ['!**/packages/agentflow/src/**'] } }, optimizeDeps: { include: ['react', 'react-dom', '@mui/material', 'reactflow'] } }) ================================================ FILE: packages/agentflow/jest.config.js ================================================ // Shared config inherited by both project types const baseConfig = { preset: 'ts-jest', roots: ['/src'], transform: { '^.+\\.tsx?$': [ 'ts-jest', { tsconfig: 'tsconfig.json' } ] }, testPathIgnorePatterns: ['/node_modules/', '/dist/'], moduleNameMapper: { '\\.(css|less|scss|sass)$': '/src/__mocks__/styleMock.js', '\\.svg$': '/src/__mocks__/styleMock.js', '^@/(.*)$': '/src/$1', '^@test-utils/(.*)$': '/src/__test_utils__/$1', // TipTap + lowlight ship ESM-only — Jest (CJS) cannot import them, // so we redirect to lightweight CJS stubs under src/__mocks__/. '^@tiptap/(.+)$': '/src/__mocks__/@tiptap/$1.ts', '^lowlight$': '/src/__mocks__/lowlight.ts', // Bypass React.lazy wrappers — resolve Foo.lazy → Foo so tests render synchronously '(.*)\\.lazy$': '$1' } } module.exports = { verbose: true, collectCoverageFrom: [ 'src/**/*.{ts,tsx}', '!src/**/*.test.{ts,tsx}', '!src/**/*.d.ts', '!src/**/index.ts', '!src/__mocks__/**', '!src/__test_utils__/**', '!src/infrastructure/api/hooks/**' ], // text: per-folder table, text-summary: totals, lcov: HTML report at coverage/lcov-report/ coverageReporters: ['text', 'text-summary', 'lcov'], coverageDirectory: 'coverage', // 80% floor to catch regressions without blocking active development. // Add new paths here as more modules gain test coverage. coverageThreshold: { './src/*.ts': { branches: 80, functions: 80, lines: 80, statements: 80 }, './src/Agentflow.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 }, './src/atoms/ArrayInput.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 }, './src/atoms/ExpandTextDialog.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 }, './src/atoms/MessagesInput.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 }, './src/atoms/ScenariosInput.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 }, // Tier 3 UI atom — only the onChange/disabled/sync logic is tested, not styled internals './src/atoms/RichTextEditor.tsx': { branches: 30, functions: 50, lines: 50, statements: 50 }, './src/core/': { branches: 80, functions: 80, lines: 80, statements: 80 }, './src/features/canvas/components/ConnectionLine.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 }, // Only getMinimumNodeHeight() is tested; the component is Tier 3 UI with no business logic './src/features/canvas/components/NodeOutputHandles.tsx': { branches: 0, functions: 10, lines: 30, statements: 30 }, './src/features/canvas/hooks/': { branches: 80, functions: 80, lines: 80, statements: 80 }, './src/features/generator/GenerateFlowDialog.tsx': { branches: 80, functions: 80, lines: 80, statements: 80 }, './src/features/node-editor/': { branches: 80, functions: 80, lines: 80, statements: 80 }, './src/features/node-palette/search.ts': { branches: 80, functions: 80, lines: 80, statements: 80 }, './src/infrastructure/': { branches: 80, functions: 80, lines: 80, statements: 80 } }, projects: [ // .test.ts → node (fast, no DOM) { ...baseConfig, displayName: 'unit', testEnvironment: 'node', testMatch: ['/src/**/*.test.ts'] }, // .test.tsx → jsdom (browser-like DOM for React components) { ...baseConfig, displayName: 'components', testEnvironment: '/src/__test_utils__/jest-environment-jsdom.js', testEnvironmentOptions: { customExportConditions: [''] }, testMatch: ['/src/**/*.test.tsx'], setupFilesAfterEnv: ['@testing-library/jest-dom'] } ] } ================================================ FILE: packages/agentflow/package.json ================================================ { "name": "@flowiseai/agentflow", "version": "0.0.0-dev.6", "description": "Embeddable React component for building and visualizing AI agent workflows", "license": "Apache-2.0", "repository": { "type": "git", "url": "https://github.com/FlowiseAI/Flowise.git", "directory": "packages/agentflow" }, "homepage": "https://github.com/FlowiseAI/Flowise/tree/main/packages/agentflow#readme", "bugs": { "url": "https://github.com/FlowiseAI/Flowise/issues" }, "keywords": [ "flowise", "flowiseai", "agentflow", "react", "llm", "ai", "agent", "workflow" ], "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" }, "main": "./dist/index.umd.js", "module": "./dist/index.js", "types": "./dist/index.d.ts", "exports": { ".": { "import": "./dist/index.js", "require": "./dist/index.umd.js", "types": "./dist/index.d.ts" }, "./flowise.css": "./dist/flowise.css" }, "files": [ "dist" ], "sideEffects": [ "dist/**/*.css" ], "scripts": { "build": "tsc && vite build", "clean": "rimraf dist", "dev": "vite", "dev:example": "vite --config examples/vite.config.ts", "format": "prettier --write \"{src,examples}/**/*.{ts,tsx,js,jsx,json,css,md}\"", "format:check": "prettier --check \"{src,examples}/**/*.{ts,tsx,js,jsx,json,css,md}\"", "lint": "eslint \"{src,examples/src}/**/*.{js,jsx,ts,tsx,json,md}\"", "lint:fix": "eslint \"{src,examples/src}/**/*.{js,jsx,ts,tsx,json,md}\" --fix", "test": "jest", "test:watch": "jest --watch", "test:coverage": "jest --coverage", "nuke": "rimraf dist node_modules .turbo", "prepublishOnly": "npm run clean && npm run build" }, "peerDependencies": { "@emotion/react": "^11.10.0", "@emotion/styled": "^11.10.0", "@mui/icons-material": "^5.0.0", "@mui/material": "^5.15.0", "react": "^18.2.0", "react-dom": "^18.2.0", "reactflow": "^11.5.0" }, "dependencies": { "@codemirror/lang-javascript": "^6.2.0", "@codemirror/lang-json": "^6.0.0", "@codemirror/lang-python": "^6.1.0", "@tabler/icons-react": "^3.7.0", "@tiptap/extension-code-block-lowlight": "^3.4.3", "@tiptap/extension-placeholder": "^2.11.5", "@tiptap/react": "^2.11.5", "@tiptap/starter-kit": "^2.11.5", "@uiw/codemirror-theme-sublime": "^4.21.0", "@uiw/codemirror-theme-vscode": "^4.21.0", "@uiw/react-codemirror": "^4.21.0", "axios": "^1.7.2", "flowise-react-json-view": "^1.21.7", "lodash": "^4.17.21", "lowlight": "^3.3.0", "uuid": "^10.0.0" }, "devDependencies": { "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^14.3.1", "@testing-library/user-event": "^14.5.2", "@types/jest": "^29.5.14", "@types/lodash": "^4.14.195", "@types/react": "^18.2.0", "@types/react-dom": "^18.2.0", "@typescript-eslint/eslint-plugin": "^8.18.2", "@typescript-eslint/parser": "^8.18.2", "@vitejs/plugin-react": "^4.2.0", "eslint-import-resolver-typescript": "4.4.4", "eslint-plugin-import": "^2.29.0", "eslint-plugin-simple-import-sort": "^12.0.0", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "rimraf": "^5.0.5", "ts-jest": "^29.3.2", "typescript": "^5.4.5", "vite": "^5.0.2", "vite-plugin-dts": "^3.7.0" } } ================================================ FILE: packages/agentflow/src/Agentflow.test.tsx ================================================ /** * Integration tests for Agentflow component * Focus on dark mode styling and theme integration */ import { createRef } from 'react' import { fireEvent, render, waitFor } from '@testing-library/react' import type { AgentFlowInstance, FlowData } from './core/types' import { Agentflow } from './Agentflow' // Mock external dependencies - implementations in __mocks__/ jest.mock('reactflow') jest.mock('axios') // Mock GenerateFlowDialog to expose callbacks for testing jest.mock('./features/generator', () => ({ GenerateFlowDialog: ({ open, onClose, onGenerated }: { open: boolean onClose: () => void onGenerated: (nodes: FlowData['nodes'], edges: FlowData['edges']) => void }) => open ? (
) : null })) describe('Agentflow Component', () => { const mockFlow: FlowData = { nodes: [ { id: 'test-node', type: 'agentflowNode', position: { x: 0, y: 0 }, data: { id: 'test-node', name: 'startAgentflow', label: 'Start', color: '#7EE787', outputAnchors: [] } } ], edges: [], viewport: { x: 0, y: 0, zoom: 1 } } const defaultProps = { apiBaseUrl: 'https://example.com', initialFlow: mockFlow } describe('Dark Mode Integration', () => { it('should render in light mode by default', async () => { const { container } = render() await waitFor(() => { const canvas = container.querySelector('.agentflow-canvas') expect(canvas).toBeInTheDocument() expect(canvas?.getAttribute('data-dark-mode')).toBe('false') }) }) it('should render in dark mode when isDarkMode is true', async () => { const { container } = render() await waitFor(() => { const canvas = container.querySelector('.agentflow-canvas') expect(canvas).toBeInTheDocument() expect(canvas?.getAttribute('data-dark-mode')).toBe('true') }) }) it('should apply dark mode class to container', async () => { const { container } = render() await waitFor(() => { const agentflowContainer = container.querySelector('.agentflow-container') expect(agentflowContainer).toBeInTheDocument() expect(agentflowContainer).toHaveClass('dark') }) }) it('should not apply dark class in light mode', async () => { const { container } = render() await waitFor(() => { const agentflowContainer = container.querySelector('.agentflow-container') expect(agentflowContainer).toBeInTheDocument() expect(agentflowContainer).not.toHaveClass('dark') }) }) it('should apply dark-mode-controls class to Controls component', async () => { const { getByTestId } = render() await waitFor(() => { expect(getByTestId('controls')).toHaveClass('dark-mode-controls') }) }) it('should not apply dark-mode-controls class in light mode', async () => { const { getByTestId } = render() await waitFor(() => { expect(getByTestId('controls')).not.toHaveClass('dark-mode-controls') }) }) }) describe('Theme Provider Integration', () => { it('should wrap content with ThemeProvider', async () => { const { container } = render() await waitFor(() => { expect(container.firstChild).toBeInTheDocument() }) }) it('should support theme switching', async () => { const { container, rerender } = render() await waitFor(() => { const canvas = container.querySelector('.agentflow-canvas') expect(canvas).toBeInTheDocument() }) const canvas = container.querySelector('.agentflow-canvas') expect(canvas?.getAttribute('data-dark-mode')).toBe('false') rerender() await waitFor(() => { expect(canvas?.getAttribute('data-dark-mode')).toBe('true') }) }) }) describe('Component Structure', () => { it('should render main container', async () => { const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) }) it('should render canvas area', async () => { const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-canvas')).toBeInTheDocument() }) }) it('should render ReactFlow components', async () => { const { getByTestId } = render() await waitFor(() => { expect(getByTestId('react-flow')).toBeInTheDocument() expect(getByTestId('controls')).toBeInTheDocument() expect(getByTestId('minimap')).toBeInTheDocument() expect(getByTestId('background')).toBeInTheDocument() }) }) }) describe('Header Rendering', () => { it('should render default header when showDefaultHeader is true', async () => { const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-header')).toBeInTheDocument() }) }) it('should not render default header when showDefaultHeader is false', async () => { const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) expect(container.querySelector('.agentflow-header')).not.toBeInTheDocument() }) it('should render custom header when renderHeader is provided', async () => { const customHeader = () =>
Custom Header
const { getByTestId } = render() await waitFor(() => { expect(getByTestId('custom-header')).toBeInTheDocument() }) }) }) describe('Read-Only Mode', () => { it('should support read-only mode', async () => { const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) }) it('should not show generate button in read-only mode', async () => { const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) // Generate button should not be rendered expect(container.querySelector('[aria-label="generate"]')).not.toBeInTheDocument() }) }) describe('Props Integration', () => { it('should accept apiBaseUrl prop', async () => { const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) }) it('should accept token prop', async () => { const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) }) it('should accept initialFlow prop', async () => { const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) }) it('should accept components filter prop', async () => { const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) }) }) describe('Callback Props', () => { it('should accept onFlowChange callback', async () => { const onFlowChange = jest.fn() const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) // Callback should be registered (actual invocation tested in flow handlers) }) it('should accept onSave callback', async () => { const onSave = jest.fn() const { container, getByText } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) // Find and click the save button const saveButton = getByText('Save') fireEvent.click(saveButton) // Verify the callback was called expect(onSave).toHaveBeenCalledTimes(1) expect(onSave).toHaveBeenCalledWith( expect.objectContaining({ nodes: expect.any(Array), edges: expect.any(Array) }) ) }) it('should accept onFlowGenerated callback', async () => { const onFlowGenerated = jest.fn() const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) // Callback should be registered }) }) describe('Keyboard Shortcuts', () => { it('should trigger save on Cmd+S', async () => { const onSave = jest.fn() const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) fireEvent.keyDown(document, { key: 's', metaKey: true }) expect(onSave).toHaveBeenCalledTimes(1) expect(onSave).toHaveBeenCalledWith( expect.objectContaining({ nodes: expect.any(Array), edges: expect.any(Array) }) ) }) it('should trigger save on Ctrl+S', async () => { const onSave = jest.fn() const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) fireEvent.keyDown(document, { key: 's', ctrlKey: true }) expect(onSave).toHaveBeenCalledTimes(1) }) it('should not trigger save on plain S key', async () => { const onSave = jest.fn() const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) fireEvent.keyDown(document, { key: 's' }) expect(onSave).not.toHaveBeenCalled() }) it('should not error on Cmd+S when no onSave callback is provided', async () => { const { container } = render() await waitFor(() => { expect(container.querySelector('.agentflow-container')).toBeInTheDocument() }) expect(() => { fireEvent.keyDown(document, { key: 's', metaKey: true }) }).not.toThrow() }) }) describe('Generate Flow', () => { it('should open generate dialog when button is clicked', async () => { const { container, getByTestId } = render() await waitFor(() => { expect(container.querySelector('[aria-label="generate"]')).toBeInTheDocument() }) fireEvent.click(container.querySelector('[aria-label="generate"]')!) await waitFor(() => { expect(getByTestId('generate-dialog')).toBeInTheDocument() }) }) it('should close generate dialog via onClose', async () => { const { container, getByTestId, queryByTestId } = render() await waitFor(() => { expect(container.querySelector('[aria-label="generate"]')).toBeInTheDocument() }) fireEvent.click(container.querySelector('[aria-label="generate"]')!) await waitFor(() => { expect(getByTestId('generate-dialog')).toBeInTheDocument() }) fireEvent.click(getByTestId('close-dialog')) await waitFor(() => { expect(queryByTestId('generate-dialog')).not.toBeInTheDocument() }) }) it('should call onFlowGenerated when flow is generated', async () => { const onFlowGenerated = jest.fn() const { container, getByTestId } = render() await waitFor(() => { expect(container.querySelector('[aria-label="generate"]')).toBeInTheDocument() }) fireEvent.click(container.querySelector('[aria-label="generate"]')!) await waitFor(() => { expect(getByTestId('generate-dialog')).toBeInTheDocument() }) fireEvent.click(getByTestId('trigger-generate')) await waitFor(() => { expect(onFlowGenerated).toHaveBeenCalledWith({ nodes: [], edges: [], viewport: { x: 0, y: 0, zoom: 1 } }) }) }) }) describe('Imperative Ref', () => { it('should expose agentflow instance via ref', async () => { const ref = createRef() render() await waitFor(() => { expect(ref.current).toBeDefined() expect(ref.current?.getFlow).toBeInstanceOf(Function) }) }) }) describe('CSS Variables Injection', () => { it('should inject CSS variables into document head', async () => { render() // CSS variables should be injected await waitFor(() => { const styleElement = document.getElementById('agentflow-css-variables') expect(styleElement).toBeInTheDocument() expect(styleElement?.textContent).toContain('--agentflow-canvas-bg') }) }) it('should update CSS variables when dark mode changes', async () => { const { rerender } = render() // Wait for initial async operations to complete await waitFor(() => { expect(document.getElementById('agentflow-css-variables')).toBeInTheDocument() }) const lightContent = document.getElementById('agentflow-css-variables')?.textContent rerender() // Wait for useEffect to update the CSS variables let darkContent: string | null | undefined await waitFor(() => { darkContent = document.getElementById('agentflow-css-variables')?.textContent expect(darkContent).toBeTruthy() expect(darkContent).not.toBe(lightContent) }) }) it('should clean up CSS variables on unmount', async () => { const { unmount } = render() await waitFor(() => { expect(document.getElementById('agentflow-css-variables')).toBeInTheDocument() }) unmount() expect(document.getElementById('agentflow-css-variables')).not.toBeInTheDocument() }) }) }) ================================================ FILE: packages/agentflow/src/Agentflow.tsx ================================================ import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react' import ReactFlow, { Background, Controls, MiniMap, ReactFlowProvider, useEdgesState, useNodesState } from 'reactflow' import { Alert, Snackbar } from '@mui/material' import { IconSparkles } from '@tabler/icons-react' import { tokens } from './core/theme' import type { AgentFlowInstance, AgentflowProps, FlowData, FlowDataCallback, FlowEdge, FlowNode } from './core/types' import { applyValidationErrorsToNodes, validateFlow } from './core/validation' import { AgentflowHeader, ConnectionLine, createHeaderProps, edgeTypes, nodeTypes, useDragAndDrop, useFlowHandlers, useFlowNodes } from './features/canvas' import { ValidationFeedback } from './features/canvas/components' import { GenerateFlowDialog } from './features/generator' import { EditNodeDialog } from './features/node-editor' import { AddNodesDrawer, StyledFab } from './features/node-palette' import { useAgentflowContext, useConfigContext } from './infrastructure/store' import { AgentflowProvider } from './AgentflowProvider' import { useAgentflow } from './useAgentflow' import 'reactflow/dist/style.css' import './features/canvas/canvas.css' /** * Internal canvas component that uses the contexts */ function AgentflowCanvas({ initialFlow, readOnly, onFlowChange, onSave, onFlowGenerated, showDefaultHeader = true, enableGenerator = true, showDefaultPalette = true, renderHeader, renderNodePalette }: { initialFlow?: FlowData readOnly?: boolean onFlowChange?: FlowDataCallback onSave?: FlowDataCallback onFlowGenerated?: FlowDataCallback showDefaultHeader?: boolean showDefaultPalette?: boolean enableGenerator?: boolean renderHeader?: AgentflowProps['renderHeader'] renderNodePalette?: AgentflowProps['renderNodePalette'] }) { const { state, syncNodesFromReactFlow, syncEdgesFromReactFlow, setDirty, setReactFlowInstance, closeEditDialog, registerLocalStateSetters, registerOnFlowChange } = useAgentflowContext() const { isDarkMode } = useConfigContext() const agentflow = useAgentflow() const reactFlowWrapper = useRef(null) // Memoize ReactFlow colors from theme tokens const reactFlowColors = useMemo(() => { const mode = isDarkMode ? 'dark' : 'light' return { minimapNode: tokens.colors.reactflow.minimap.node[mode], minimapNodeStroke: tokens.colors.reactflow.minimap.nodeStroke[mode], minimapBackground: tokens.colors.reactflow.minimap.background[mode], minimapMask: tokens.colors.reactflow.minimap.mask[mode], backgroundDots: tokens.colors.reactflow.background.dots[mode] } }, [isDarkMode]) const [nodes, setLocalNodes, onNodesChange] = useNodesState(initialFlow?.nodes || []) const [edges, setLocalEdges, onEdgesChange] = useEdgesState(initialFlow?.edges || []) const [showGenerateDialog, setShowGenerateDialog] = useState(false) // Constraint violation snackbar state const [snackbar, setSnackbar] = useState<{ open: boolean; message: string }>({ open: false, message: '' }) const handleConstraintViolation = useCallback((message: string) => { setSnackbar({ open: true, message }) }, []) const handleSnackbarClose = useCallback(() => { setSnackbar({ open: false, message: '' }) }, []) // Load available nodes const { availableNodes } = useFlowNodes() // Register local state setters with context on mount useEffect(() => { registerLocalStateSetters(setLocalNodes, setLocalEdges) }, [registerLocalStateSetters, setLocalNodes, setLocalEdges]) // Register onFlowChange callback so context-level updates (e.g. updateNodeData) // can notify the parent of flow changes useEffect(() => { registerOnFlowChange(onFlowChange) return () => registerOnFlowChange(undefined) }, [registerOnFlowChange, onFlowChange]) // Sync local ReactFlow state to context (when user interacts with canvas) useEffect(() => { syncNodesFromReactFlow(nodes as FlowNode[]) }, [nodes, syncNodesFromReactFlow]) useEffect(() => { syncEdgesFromReactFlow(edges as FlowEdge[]) }, [edges, syncEdgesFromReactFlow]) // Flow handlers const { handleConnect, handleNodesChange, handleNodeDragStop, handleEdgesChange, handleAddNode } = useFlowHandlers({ nodes: nodes as FlowNode[], edges: edges as FlowEdge[], setLocalNodes: setLocalNodes as React.Dispatch>, setLocalEdges: setLocalEdges as React.Dispatch>, onNodesChange, onEdgesChange, onFlowChange, availableNodes, onConstraintViolation: handleConstraintViolation }) // Drag and drop handlers const { handleDragOver, handleDrop } = useDragAndDrop({ nodes: nodes as FlowNode[], setLocalNodes: setLocalNodes as React.Dispatch>, reactFlowWrapper: reactFlowWrapper as React.RefObject, onConstraintViolation: handleConstraintViolation }) // Handle generated flow from dialog const handleFlowGenerated = useCallback( (generatedNodes: FlowData['nodes'], generatedEdges: FlowData['edges']) => { setLocalNodes(generatedNodes) setLocalEdges(generatedEdges) setDirty(true) if (onFlowGenerated) { onFlowGenerated({ nodes: generatedNodes, edges: generatedEdges, viewport: { x: 0, y: 0, zoom: 1 } }) } }, [setLocalNodes, setLocalEdges, setDirty, onFlowGenerated] ) // Handle save — run validation first and highlight problem nodes const handleSave = useCallback(() => { if (!onSave) return const flowNodes = nodes as FlowNode[] const flowEdges = edges as FlowEdge[] const result = validateFlow(flowNodes, flowEdges, availableNodes) // Update node border highlighting: set errors on failing nodes, clear errors on now-valid nodes setLocalNodes((prev) => applyValidationErrorsToNodes(prev as FlowNode[], result.errors) as FlowNode[]) if (!result.valid) { handleConstraintViolation('Flow has validation errors. Please fix them before saving.') return } onSave(agentflow.getFlow()) setDirty(false) }, [onSave, agentflow, setDirty, nodes, edges, availableNodes, setLocalNodes, handleConstraintViolation]) // Keyboard shortcut: Cmd+S / Ctrl+S to save useEffect(() => { const onKeyDown = (e: KeyboardEvent) => { if ((e.metaKey || e.ctrlKey) && e.key === 's') { e.preventDefault() handleSave() } } document.addEventListener('keydown', onKeyDown) return () => document.removeEventListener('keydown', onKeyDown) }, [handleSave]) // Header props const headerProps = createHeaderProps( state.chatflow?.name || 'Untitled', state.isDirty, handleSave, agentflow.toJSON, agentflow.validate ) // Palette props const paletteProps = { availableNodes, onAddNode: handleAddNode } return (
{/* Header */} {renderHeader ? renderHeader(headerProps) : showDefaultHeader ? : null}
{/* Node Palette - only render if custom renderNodePalette is provided */} {renderNodePalette && renderNodePalette(paletteProps)} {/* Canvas */}
{/* Add Nodes Drawer - positioned at top left */} {!readOnly && showDefaultPalette && ( handleAddNode(node.name)} /> )} {/* Generate Flow Button - positioned at top left, next to Add Nodes button (v2 style) */} {!readOnly && enableGenerator && ( setShowGenerateDialog(true)} sx={{ position: 'absolute', left: showDefaultPalette ? 70 : 20, // 70px offset = ~10px gap between buttons top: 20, zIndex: 1001 }} > )} {/* Validation Feedback - positioned at top right */} {!readOnly && ( >} /> )}
{/* Generate Flow Dialog */} setShowGenerateDialog(false)} onGenerated={handleFlowGenerated} /> {/* Edit Node Dialog */} {/* Constraint Violation Snackbar */} {snackbar.message}
) } /** * Main Agentflow component. * Renders an embeddable agentflow canvas with optional header and node palette. * * @example * ```tsx * import { Agentflow } from '@flowiseai/agentflow' * import '@flowiseai/agentflow/flowise.css' * * function App() { * return ( * * ) * } * ``` */ export const Agentflow = forwardRef(function Agentflow(props, ref) { const { apiBaseUrl, token, requestInterceptor, initialFlow, components, onFlowChange, onSave, onFlowGenerated, isDarkMode = false, readOnly = false, enableGenerator = true, renderHeader, renderNodePalette, showDefaultHeader = true, showDefaultPalette = true } = props return ( ) }) /** * Canvas component with ref forwarding */ const AgentflowCanvasWithRef = forwardRef< AgentFlowInstance, { initialFlow?: FlowData readOnly?: boolean onFlowChange?: FlowDataCallback onSave?: FlowDataCallback onFlowGenerated?: FlowDataCallback showDefaultHeader?: boolean showDefaultPalette?: boolean enableGenerator?: boolean renderHeader?: AgentflowProps['renderHeader'] renderNodePalette?: AgentflowProps['renderNodePalette'] } >(function AgentflowCanvasWithRef(props, ref) { const agentflow = useAgentflow() // Expose imperative methods via ref useImperativeHandle(ref, () => agentflow, [agentflow]) return }) export default Agentflow ================================================ FILE: packages/agentflow/src/AgentflowProvider.tsx ================================================ import { ReactNode, useEffect, useMemo } from 'react' import { ReactFlowProvider } from 'reactflow' import { ThemeProvider } from '@mui/material/styles' import { createAgentflowTheme, generateCSSVariables } from './core/theme' import type { FlowData, RequestInterceptor } from './core/types' import { AgentflowStateProvider, ApiProvider, ConfigProvider } from './infrastructure/store' interface AgentflowProviderProps { /** Flowise API server endpoint */ apiBaseUrl: string /** Authentication token for API calls */ token?: string /** * Optional callback to customize outgoing API requests. * Has access to full request config including auth tokens — only pass trusted code. */ requestInterceptor?: RequestInterceptor /** Whether to use dark mode (default: false) */ isDarkMode?: boolean /** Array of allowed node component names */ components?: string[] /** Whether the canvas is read-only */ readOnly?: boolean /** Initial flow data */ initialFlow?: FlowData /** Children to render */ children: ReactNode } /** * Provider component that wraps the entire Agentflow application. * Sets up all required contexts for API access, configuration, and state management. */ export function AgentflowProvider({ apiBaseUrl, token, requestInterceptor, isDarkMode = false, components, readOnly = false, initialFlow, children }: AgentflowProviderProps) { // Create MUI theme based on dark mode const theme = useMemo(() => createAgentflowTheme(isDarkMode), [isDarkMode]) // Inject CSS variables into DOM for use in CSS files. // Split into two effects: one for updates (runs on isDarkMode change) // and one for cleanup (runs only on unmount) to avoid a flash of // missing variables when toggling dark mode. const styleId = 'agentflow-css-variables' useEffect(() => { let style = document.getElementById(styleId) as HTMLStyleElement if (!style) { style = document.createElement('style') style.id = styleId document.head.appendChild(style) } style.textContent = `:root { ${generateCSSVariables(isDarkMode)} }` }, [isDarkMode]) useEffect(() => { return () => { const existingStyle = document.getElementById(styleId) if (existingStyle) { document.head.removeChild(existingStyle) } } }, []) return ( {children} ) } export default AgentflowProvider ================================================ FILE: packages/agentflow/src/__mocks__/@tiptap/extension-code-block-lowlight.ts ================================================ const CodeBlockLowlight = { configure: jest.fn(() => 'CodeBlockLowlight'), extend: jest.fn(() => 'CodeBlockLowlightExtended') } export default CodeBlockLowlight ================================================ FILE: packages/agentflow/src/__mocks__/@tiptap/extension-placeholder.ts ================================================ const Placeholder = { configure: jest.fn(() => 'Placeholder') } export default Placeholder ================================================ FILE: packages/agentflow/src/__mocks__/@tiptap/react.ts ================================================ import { createElement, forwardRef } from 'react' export const useEditor = (config?: Record) => ({ getHTML: () => (config?.content as string) ?? '

', setEditable: jest.fn(), commands: { focus: jest.fn(), setContent: jest.fn() }, _onUpdate: config?.onUpdate }) export const EditorContent = forwardRef(({ editor, ...rest }, ref) => createElement('div', { ref, 'data-testid': 'tiptap-editor-content', 'data-has-editor': !!editor, ...rest }) ) EditorContent.displayName = 'EditorContent' ================================================ FILE: packages/agentflow/src/__mocks__/@tiptap/starter-kit.ts ================================================ const StarterKit = { configure: jest.fn(() => 'StarterKit') } export default StarterKit ================================================ FILE: packages/agentflow/src/__mocks__/axios.ts ================================================ /** * Mock for axios library * * Prevents network errors in tests by mocking all HTTP requests. * Returns mock data for common API endpoints. */ const mockAxios: any = { create: jest.fn(function () { return mockAxios }), defaults: { headers: { common: {} } }, interceptors: { request: { use: jest.fn(), eject: jest.fn() }, response: { use: jest.fn(), eject: jest.fn() } }, get: jest.fn(() => Promise.resolve({ data: [] })), post: jest.fn(() => Promise.resolve({ data: {} })), put: jest.fn(() => Promise.resolve({ data: {} })), delete: jest.fn(() => Promise.resolve({ data: {} })), patch: jest.fn(() => Promise.resolve({ data: {} })), request: jest.fn(() => Promise.resolve({ data: {} })) } export default mockAxios ================================================ FILE: packages/agentflow/src/__mocks__/lowlight.ts ================================================ export const common = {} export const createLowlight = jest.fn(() => ({ register: jest.fn() })) ================================================ FILE: packages/agentflow/src/__mocks__/reactflow.tsx ================================================ /** * Mock for ReactFlow library * * Provides mock implementations of ReactFlow components and hooks for testing. * Prevents canvas/layout issues and provides stable references to avoid infinite loops. */ import React from 'react' const MockReactFlow = ({ children }: { children: React.ReactNode }) =>
{children}
// Mock components with forwardRef for MUI styled() compatibility const NodeToolbar = React.forwardRef(({ children, ...props }: any, ref: any) => (
{children}
)) NodeToolbar.displayName = 'NodeToolbar' const Handle = React.forwardRef(({ children, ...props }: any, ref: any) => (
{children}
)) Handle.displayName = 'Handle' export default MockReactFlow export const ReactFlowProvider = ({ children }: { children: React.ReactNode }) =>
{children}
export const Controls = ({ className }: { className?: string }) =>
export const MiniMap = () =>
export const Background = () =>
export { Handle, NodeToolbar } export const Position = { Left: 'left', Right: 'right', Top: 'top', Bottom: 'bottom' } // Use React's useState to maintain stable references and prevent infinite loops export const useNodesState = (initialNodes: any) => { const [nodes, setNodes] = React.useState(initialNodes || []) return [nodes, setNodes, jest.fn()] } export const useEdgesState = (initialEdges: any) => { const [edges, setEdges] = React.useState(initialEdges || []) return [edges, setEdges, jest.fn()] } export const useReactFlow = () => ({ screenToFlowPosition: jest.fn((pos) => pos), project: jest.fn((pos) => pos), setNodes: jest.fn(), setEdges: jest.fn(), getNodes: jest.fn(() => []), getEdges: jest.fn(() => []), getNode: jest.fn(), getEdge: jest.fn() }) // Hook to update node internals (used for dynamic handle positioning) export const useUpdateNodeInternals = () => jest.fn() // Hook to access ReactFlow store state export const useStore = (selector?: any) => (selector ? selector({}) : {}) // Change utilities - apply changes by returning the original array (sufficient for tests) export const applyNodeChanges = (changes: any[], nodes: any[]) => nodes export const applyEdgeChanges = (changes: any[], edges: any[]) => edges // Edge utilities export const addEdge = (connection: any, edges: any[]) => [...edges, connection] export const getBezierPath = jest.fn(({ sourceX, sourceY, targetX, targetY }: any) => [ `M ${sourceX},${sourceY} L ${targetX},${targetY}`, (sourceX + targetX) / 2, (sourceY + targetY) / 2 ]) export const EdgeLabelRenderer = ({ children }: { children: React.ReactNode }) =>
{children}
export const NodeResizer = () =>
================================================ FILE: packages/agentflow/src/__mocks__/styleMock.js ================================================ module.exports = {} ================================================ FILE: packages/agentflow/src/__test_utils__/factories.ts ================================================ import type { FlowEdge, FlowNode, NodeData } from '@/core/types' /** * Create a {@link FlowNode} with sensible defaults. * * The returned node uses `id` for every identity field (`id`, `data.id`, * `data.name`, `data.label`) so a single string is enough for most tests. * Pass `overrides` to customise any property. * * @example * makeFlowNode('a') * makeFlowNode('a', { type: 'agentFlow', selected: true }) * makeFlowNode('a', { data: { id: 'a', name: 'llmAgentflow', label: 'LLM' } }) */ export const makeFlowNode = (id: string, overrides?: Partial): FlowNode => ({ id, type: 'customNode', position: { x: 0, y: 0 }, data: { id, name: id, label: id }, ...overrides }) /** * Create a {@link FlowEdge} between two node ids. * * The edge `id` is derived as `"${source}-${target}"` by default. * * @example * makeFlowEdge('a', 'b') * makeFlowEdge('a', 'b', { selected: true, animated: true }) */ export const makeFlowEdge = (source: string, target: string, overrides?: Partial): FlowEdge => ({ id: `${source}-${target}`, source, target, type: 'default', ...overrides }) /** * Create a {@link NodeData} descriptor (the `data` payload of a node). * * Useful for testing palette search, node filtering, and `initNode`. * * @example * makeNodeData() * makeNodeData({ name: 'llmAgentflow', label: 'LLM', category: 'AI' }) */ export const makeNodeData = (overrides?: Partial): NodeData => ({ id: '', name: 'testNode', label: 'Test Node', ...overrides } as NodeData) ================================================ FILE: packages/agentflow/src/__test_utils__/jest-environment-jsdom.js ================================================ /** * Custom Jest environment for jsdom tests * * Prevents canvas native module from being loaded during test initialization. * The canvas package requires native compilation which often fails in CI/CD * environments. Since canvas is only optionally used by jsdom and not needed * for our React component tests, we mock it at the module require level. * * Note: This file must be CommonJS (require) because Jest environments * do not support ESM. */ const JSDOMEnvironment = require('jest-environment-jsdom').default // Mock canvas before jsdom tries to load it. // NOTE: This overrides Module.prototype.require globally for the entire test process. // Any module requiring 'canvas' (not just jsdom) will receive this mock. // This is acceptable because canvas is only an optional jsdom dependency and // is not used by any application code under test. const Module = require('module') const originalRequire = Module.prototype.require Module.prototype.require = function (id) { if (id === 'canvas') { return { createCanvas: () => ({ getContext: () => ({}), toBuffer: () => Buffer.from(''), toDataURL: () => '' }), createImageData: () => ({ data: [] }), loadImage: () => Promise.resolve({}), Image: class Image { constructor() { this.src = '' this.width = 0 this.height = 0 this.onload = null this.onerror = null this.naturalWidth = 0 this.naturalHeight = 0 } } } } return originalRequire.apply(this, arguments) } module.exports = JSDOMEnvironment ================================================ FILE: packages/agentflow/src/atoms/ArrayInput.test.tsx ================================================ import { fireEvent, render, screen } from '@testing-library/react' import type { InputParam, NodeData } from '@/core/types' import { ArrayInput } from './ArrayInput' // --- Mocks --- const mockOnDataChange = jest.fn() jest.mock('./NodeInputHandler', () => ({ NodeInputHandler: ({ inputParam, onDataChange }: { inputParam: InputParam data: NodeData onDataChange: (args: { inputParam: InputParam; newValue: unknown }) => void }) => (
onDataChange({ inputParam, newValue: e.target.value })} />
) })) jest.mock('@tabler/icons-react', () => ({ IconPlus: () => , IconTrash: () => })) describe('ArrayInput', () => { const mockInputParam: InputParam = { id: 'test-array', name: 'testArray', label: 'Test Item', type: 'array', array: [ { id: 'field1', name: 'field1', label: 'Field 1', type: 'string', default: '' } as InputParam, { id: 'field2', name: 'field2', label: 'Field 2', type: 'number', default: 0 } as InputParam ] } const mockNodeData: NodeData = { id: 'node-1', name: 'testNode', label: 'Test Node', inputValues: {} } as NodeData beforeEach(() => { jest.clearAllMocks() }) // Test 1: Render existing items it('should render existing items correctly', () => { const dataWithItems: NodeData = { ...mockNodeData, inputValues: { testArray: [ { field1: 'value1', field2: 10 }, { field1: 'value2', field2: 20 } ] } } as NodeData render() // Verify both items are rendered expect(screen.getByText('0')).toBeInTheDocument() expect(screen.getByText('1')).toBeInTheDocument() // Verify field handlers are rendered for both items expect(screen.getAllByTestId('input-handler-field1')).toHaveLength(2) expect(screen.getAllByTestId('input-handler-field2')).toHaveLength(2) }) // Test 2: Render Add button it('should render Add button with correct label', () => { render() const addButton = screen.getByRole('button', { name: /Add Test Item/i }) expect(addButton).toBeInTheDocument() expect(screen.getByTestId('icon-plus')).toBeInTheDocument() }) // Test 3: Add new item it('should add new item and call onDataChange with new array', () => { render() const addButton = screen.getByRole('button', { name: /Add Test Item/i }) fireEvent.click(addButton) // Verify onDataChange was called with new array containing default values expect(mockOnDataChange).toHaveBeenCalledWith({ inputParam: mockInputParam, newValue: [{ field1: '', field2: 0 }] }) }) // Test 4: Delete item it('should delete item and verify item removed from array', () => { const dataWithItems: NodeData = { ...mockNodeData, inputValues: { testArray: [ { field1: 'value1', field2: 10 }, { field1: 'value2', field2: 20 } ] } } as NodeData render() // Get all delete buttons (IconTrash buttons) const deleteButtons = screen.getAllByTitle('Delete') // Click the first delete button fireEvent.click(deleteButtons[0]) // Verify onDataChange was called with updated array (first item removed) expect(mockOnDataChange).toHaveBeenCalledWith({ inputParam: mockInputParam, newValue: [{ field1: 'value2', field2: 20 }] }) }) // Test 5: Handle field changes it('should handle nested field changes and update parent array', () => { const dataWithItems: NodeData = { ...mockNodeData, inputValues: { testArray: [{ field1: 'initial', field2: 5 }] } } as NodeData render() // Change field1 value const field1Input = screen.getByTestId('input-field1') fireEvent.change(field1Input, { target: { value: 'updated' } }) // Verify parent array was updated expect(mockOnDataChange).toHaveBeenCalledWith({ inputParam: mockInputParam, newValue: [{ field1: 'updated', field2: 5 }] }) }) // Test 6: Empty array initialization it('should render with empty array and only show Add button', () => { render() // Verify no items are rendered expect(screen.queryByText('0')).not.toBeInTheDocument() // Verify Add button is present expect(screen.getByRole('button', { name: /Add Test Item/i })).toBeInTheDocument() }) // Test 7: Respect disabled prop it('should disable buttons when disabled prop is true', () => { const dataWithItems: NodeData = { ...mockNodeData, inputValues: { testArray: [{ field1: 'value1', field2: 10 }] } } as NodeData render() // Verify Add button is disabled const addButton = screen.getByRole('button', { name: /Add Test Item/i }) expect(addButton).toBeDisabled() // Verify Delete button is disabled const deleteButton = screen.getByTitle('Delete') expect(deleteButton).toBeDisabled() }) // Test 8: Filter hidden fields it('should not render fields with display set to false', () => { const inputParamWithHiddenField: InputParam = { ...mockInputParam, array: [ { id: 'visible', name: 'visible', label: 'Visible Field', type: 'string', display: true } as InputParam, { id: 'hidden', name: 'hidden', label: 'Hidden Field', type: 'string', display: false } as InputParam ] } const dataWithItems: NodeData = { ...mockNodeData, inputValues: { testArray: [{ visible: 'test', hidden: 'should-not-show' }] } } as NodeData render() // Verify visible field is rendered expect(screen.getByTestId('input-handler-visible')).toBeInTheDocument() // Verify hidden field is NOT rendered expect(screen.queryByTestId('input-handler-hidden')).not.toBeInTheDocument() }) // Test 9: Multiple items it('should render multiple items with correct indices', () => { const dataWithMultipleItems: NodeData = { ...mockNodeData, inputValues: { testArray: [ { field1: 'item1', field2: 1 }, { field1: 'item2', field2: 2 }, { field1: 'item3', field2: 3 }, { field1: 'item4', field2: 4 } ] } } as NodeData render() // Verify all indices are shown expect(screen.getByText('0')).toBeInTheDocument() expect(screen.getByText('1')).toBeInTheDocument() expect(screen.getByText('2')).toBeInTheDocument() expect(screen.getByText('3')).toBeInTheDocument() // Verify all field handlers are rendered (4 items * 2 fields each = 8 handlers) expect(screen.getAllByTestId('input-handler-field1')).toHaveLength(4) expect(screen.getAllByTestId('input-handler-field2')).toHaveLength(4) }) // Test 10: Default values it('should initialize new items with field default values', () => { const inputParamWithDefaults: InputParam = { id: 'test-array', name: 'testArray', label: 'Test Item', type: 'array', array: [ { id: 'name', name: 'name', label: 'Name', type: 'string', default: 'John Doe' } as InputParam, { id: 'age', name: 'age', label: 'Age', type: 'number', default: 25 } as InputParam, { id: 'active', name: 'active', label: 'Active', type: 'boolean', default: true } as InputParam ] } render() const addButton = screen.getByRole('button', { name: /Add Test Item/i }) fireEvent.click(addButton) // Verify new item initialized with correct default values expect(mockOnDataChange).toHaveBeenCalledWith({ inputParam: inputParamWithDefaults, newValue: [{ name: 'John Doe', age: 25, active: true }] }) }) // minItems constraint it('should respect minItems constraint and disable delete when minimum reached', () => { const inputParamWithMinItems: InputParam = { ...mockInputParam, minItems: 2 } const dataWithItems: NodeData = { ...mockNodeData, inputValues: { testArray: [ { field1: 'value1', field2: 10 }, { field1: 'value2', field2: 20 } ] } } as NodeData render() // Both delete buttons should be disabled when at minItems limit const deleteButtons = screen.getAllByTitle('Delete') expect(deleteButtons[0]).toBeDisabled() expect(deleteButtons[1]).toBeDisabled() }) // Test 11: Type-specific defaults when no explicit default is provided it('should initialize new items with type-appropriate defaults when no default is specified', () => { const inputParamWithTypes: InputParam = { id: 'typed-array', name: 'testArray', label: 'Test Item', type: 'array', array: [ { id: 'str', name: 'str', label: 'String', type: 'string' } as InputParam, { id: 'num', name: 'num', label: 'Number', type: 'number' } as InputParam, { id: 'bool', name: 'bool', label: 'Boolean', type: 'boolean' } as InputParam, { id: 'arr', name: 'arr', label: 'Array', type: 'array' } as InputParam ] } render() fireEvent.click(screen.getByRole('button', { name: /Add Test Item/i })) expect(mockOnDataChange).toHaveBeenCalledWith({ inputParam: inputParamWithTypes, newValue: [{ str: '', num: 0, bool: false, arr: [] }] }) }) // Test 12: itemParameters prop overrides inputParam.array display flags it('should use itemParameters prop for field visibility when provided, ignoring inputParam.array display flags', () => { // inputParam.array has both fields with no display flag (both would show) const dataWithItem: NodeData = { ...mockNodeData, inputValues: { testArray: [{ field1: 'value', field2: 10 }] } } as NodeData // Parent (EditNodeDialog) has evaluated field2 as hidden const itemParameters: InputParam[][] = [ [ { id: 'field1', name: 'field1', label: 'Field 1', type: 'string', display: true } as InputParam, { id: 'field2', name: 'field2', label: 'Field 2', type: 'number', display: false } as InputParam ] ] render( ) // field1 visible per itemParameters expect(screen.getByTestId('input-handler-field1')).toBeInTheDocument() // field2 hidden per itemParameters even though inputParam.array has no display flag expect(screen.queryByTestId('input-handler-field2')).not.toBeInTheDocument() }) // Test reading minItems from inputParam it('should read minItems from inputParam', () => { const inputParamWithMinItems: InputParam = { ...mockInputParam, minItems: 1 } const dataWithOneItem: NodeData = { ...mockNodeData, inputValues: { testArray: [{ field1: 'value1', field2: 10 }] } } as NodeData render() // Delete button should be disabled when at minItems limit const deleteButton = screen.getByTitle('Delete') expect(deleteButton).toBeDisabled() }) }) ================================================ FILE: packages/agentflow/src/atoms/ArrayInput.tsx ================================================ import { type ComponentType, useCallback, useMemo } from 'react' import { Box, Button, Chip, IconButton } from '@mui/material' import { useTheme } from '@mui/material/styles' import { IconPlus, IconTrash } from '@tabler/icons-react' import type { InputParam, NodeData } from '@/core/types' import { type AsyncInputProps, type ConfigInputComponentProps, NodeInputHandler } from './NodeInputHandler' import { useStableKeys } from './useStableKeys' export interface ArrayInputProps { inputParam: InputParam data: NodeData disabled?: boolean onDataChange?: (params: { inputParam: InputParam; newValue: unknown }) => void itemParameters?: InputParam[][] AsyncInputComponent?: ComponentType ConfigInputComponent?: ComponentType onConfigChange?: ( configKey: string, configValues: Record, arrayContext?: { parentParamName: string; arrayIndex: number } ) => void } export function ArrayInput({ inputParam, data, disabled = false, onDataChange, itemParameters: itemParametersProp, AsyncInputComponent, ConfigInputComponent, onConfigChange }: ArrayInputProps) { const theme = useTheme() // Derive array items directly from props (single source of truth) // Memoized to prevent unnecessary re-renders of child hooks const arrayItems = useMemo( () => (Array.isArray(data.inputValues?.[inputParam.name]) ? (data.inputValues[inputParam.name] as Record[]) : []), [data.inputValues, inputParam.name] ) const { keys: effectiveKeys, removeKey } = useStableKeys(arrayItems.length, 'item') // Use pre-computed itemParameters // Falls back to raw field definitions for nested arrays without show/hide conditions. const itemParameters = useMemo( () => itemParametersProp ?? arrayItems.map(() => inputParam.array || []), [itemParametersProp, arrayItems, inputParam.array] ) // Handle changes to individual fields within array items const handleItemInputChange = useCallback( (itemIndex: number, changedParam: InputParam, newValue: unknown) => { const updatedArrayItems = [...arrayItems] const updatedItem = { ...updatedArrayItems[itemIndex] } // Update the specific field updatedItem[changedParam.name] = newValue updatedArrayItems[itemIndex] = updatedItem // Notify parent of change (parent will update props, causing re-render) onDataChange?.({ inputParam, newValue: updatedArrayItems }) }, [arrayItems, inputParam, onDataChange] ) // Add new array item const handleAddItem = useCallback(() => { // Initialize new item with type-appropriate default values const newItem: Record = {} if (inputParam.array) { for (const field of inputParam.array) { if (field.default !== undefined) { newItem[field.name] = field.default } else { switch (field.type) { case 'number': newItem[field.name] = 0 break case 'boolean': newItem[field.name] = false break case 'array': newItem[field.name] = [] break default: newItem[field.name] = '' } } } } const updatedArrayItems = [...arrayItems, newItem] // Notify parent of change (parent will update props, causing re-render) onDataChange?.({ inputParam, newValue: updatedArrayItems }) }, [arrayItems, inputParam, onDataChange]) // Delete array item const handleDeleteItem = useCallback( (indexToDelete: number) => { const updatedArrayItems = arrayItems.filter((_, i) => i !== indexToDelete) removeKey(indexToDelete) // Notify parent of change (parent will update props, causing re-render) onDataChange?.({ inputParam, newValue: updatedArrayItems }) }, [arrayItems, inputParam, onDataChange, removeKey] ) // Pre-compute stable per-item onDataChange handlers to avoid new closures on every render const itemHandlers = useMemo( () => arrayItems.map((_, index) => ({ inputParam: changedParam, newValue }: { inputParam: InputParam; newValue: unknown }) => { handleItemInputChange(index, changedParam, newValue) }), [arrayItems, handleItemInputChange] ) // Check if item can be deleted based on minItems constraint const canDeleteItem = !inputParam.minItems || arrayItems.length > inputParam.minItems return ( <> {/* Render each array item */} {arrayItems.map((itemValues, index) => { // Create item-specific data context for nested NodeInputHandler const itemData: NodeData = { ...data, inputValues: itemValues } return ( {/* Delete button */} handleDeleteItem(index)} disabled={disabled || !canDeleteItem} sx={{ position: 'absolute', height: 35, width: 35, right: 10, top: 10, '&:hover': { color: theme.palette.error.main }, ...(!canDeleteItem && { opacity: 0.3, cursor: 'not-allowed' }) }} > {/* Index chip */} {/* Render input fields for array item */} {itemParameters[index] ?.filter((param) => param.display !== false) .map((param, _) => ( ))} ) })} {/* Add item button */} ) } export default ArrayInput ================================================ FILE: packages/agentflow/src/atoms/CodeInput.test.tsx ================================================ import { render, screen } from '@testing-library/react' import { CodeInput } from './CodeInput' // Mock CodeMirror — jsdom doesn't support it jest.mock('@uiw/react-codemirror', () => { const MockCodeMirror = ({ value, readOnly, height }: { value: string; readOnly?: boolean; height?: string }) => (