@xdelivered/emberflow 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +153 -0
- package/bin/commands.test.ts +185 -0
- package/bin/commands.ts +306 -0
- package/bin/emberflow.mjs +38 -0
- package/bin/init.test.ts +165 -0
- package/bin/init.ts +297 -0
- package/bin/runtime.mjs +105 -0
- package/bin/runtime.test.ts +167 -0
- package/bin/skillTargets.test.ts +108 -0
- package/bin/skillTargets.ts +36 -0
- package/bin/skillTemplates.test.ts +37 -0
- package/bin/tsconfig.json +23 -0
- package/dist/bin/commands.d.ts +24 -0
- package/dist/bin/commands.js +252 -0
- package/dist/bin/init.d.ts +17 -0
- package/dist/bin/init.js +241 -0
- package/dist/bin/runtime.d.mts +39 -0
- package/dist/bin/runtime.mjs +96 -0
- package/dist/bin/skillTargets.d.ts +13 -0
- package/dist/bin/skillTargets.js +22 -0
- package/dist/server/agents/claudeAdapter.d.ts +8 -0
- package/dist/server/agents/claudeAdapter.js +190 -0
- package/dist/server/agents/claudeParse.d.ts +2 -0
- package/dist/server/agents/claudeParse.js +162 -0
- package/dist/server/agents/codexAdapter.d.ts +13 -0
- package/dist/server/agents/codexAdapter.js +174 -0
- package/dist/server/agents/codexParse.d.ts +2 -0
- package/dist/server/agents/codexParse.js +74 -0
- package/dist/server/agents/detect.d.ts +23 -0
- package/dist/server/agents/detect.js +35 -0
- package/dist/server/agents/gitScope.d.ts +24 -0
- package/dist/server/agents/gitScope.js +95 -0
- package/dist/server/agents/modelRejectionHint.d.ts +8 -0
- package/dist/server/agents/modelRejectionHint.js +12 -0
- package/dist/server/agents/prompt.d.ts +79 -0
- package/dist/server/agents/prompt.js +364 -0
- package/dist/server/agents/runManager.d.ts +90 -0
- package/dist/server/agents/runManager.js +259 -0
- package/dist/server/agents/types.d.ts +15 -0
- package/dist/server/agents/types.js +1 -0
- package/dist/server/apiStore.d.ts +60 -0
- package/dist/server/apiStore.js +249 -0
- package/dist/server/auth/enforce.d.ts +1 -0
- package/dist/server/auth/enforce.js +6 -0
- package/dist/server/auth/types.d.ts +1 -0
- package/dist/server/auth/types.js +1 -0
- package/dist/server/auth/verifiers.d.ts +1 -0
- package/dist/server/auth/verifiers.js +4 -0
- package/dist/server/authAttach.d.ts +19 -0
- package/dist/server/authAttach.js +79 -0
- package/dist/server/cli.d.ts +7 -0
- package/dist/server/cli.js +804 -0
- package/dist/server/client.d.ts +130 -0
- package/dist/server/client.js +247 -0
- package/dist/server/environments.d.ts +103 -0
- package/dist/server/environments.js +486 -0
- package/dist/server/flowStore.d.ts +37 -0
- package/dist/server/flowStore.js +117 -0
- package/dist/server/httpOperations.d.ts +32 -0
- package/dist/server/httpOperations.js +62 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1022 -0
- package/dist/server/infrastructure.d.ts +51 -0
- package/dist/server/infrastructure.js +116 -0
- package/dist/server/login.d.ts +21 -0
- package/dist/server/login.js +44 -0
- package/dist/server/mcp.d.ts +1 -0
- package/dist/server/mcp.js +182 -0
- package/dist/server/migrateFlows.d.ts +8 -0
- package/dist/server/migrateFlows.js +25 -0
- package/dist/server/mockHandler.d.ts +15 -0
- package/dist/server/mockHandler.js +35 -0
- package/dist/server/nodesPayload.d.ts +14 -0
- package/dist/server/nodesPayload.js +14 -0
- package/dist/server/normalizeFlow.d.ts +21 -0
- package/dist/server/normalizeFlow.js +48 -0
- package/dist/server/openBrowser.d.ts +8 -0
- package/dist/server/openBrowser.js +16 -0
- package/dist/server/operationResult.d.ts +12 -0
- package/dist/server/operationResult.js +26 -0
- package/dist/server/pathGuard.d.ts +1 -0
- package/dist/server/pathGuard.js +16 -0
- package/dist/server/pathSafety.d.ts +20 -0
- package/dist/server/pathSafety.js +35 -0
- package/dist/server/projectConfig.d.ts +47 -0
- package/dist/server/projectConfig.js +61 -0
- package/dist/server/projectMode.d.ts +26 -0
- package/dist/server/projectMode.js +44 -0
- package/dist/server/redact.d.ts +6 -0
- package/dist/server/redact.js +37 -0
- package/dist/server/runRegistry.d.ts +84 -0
- package/dist/server/runRegistry.js +200 -0
- package/dist/server/runtime/RuntimeAdapter.d.ts +22 -0
- package/dist/server/runtime/RuntimeAdapter.js +1 -0
- package/dist/server/runtime/expressAdapter.d.ts +19 -0
- package/dist/server/runtime/expressAdapter.js +56 -0
- package/dist/server/scenarioTest.d.ts +14 -0
- package/dist/server/scenarioTest.js +66 -0
- package/dist/server/subflowRunner.d.ts +32 -0
- package/dist/server/subflowRunner.js +72 -0
- package/dist/server/testRunner.d.ts +70 -0
- package/dist/server/testRunner.js +151 -0
- package/dist/src/config.d.ts +3 -0
- package/dist/src/config.js +2 -0
- package/dist/src/engine/authVerify.d.ts +33 -0
- package/dist/src/engine/authVerify.js +63 -0
- package/dist/src/engine/diagnostics.d.ts +62 -0
- package/dist/src/engine/diagnostics.js +148 -0
- package/dist/src/engine/executor.d.ts +151 -0
- package/dist/src/engine/executor.js +684 -0
- package/dist/src/engine/httpError.d.ts +7 -0
- package/dist/src/engine/httpError.js +14 -0
- package/dist/src/engine/index.d.ts +11 -0
- package/dist/src/engine/index.js +11 -0
- package/dist/src/engine/output.d.ts +11 -0
- package/dist/src/engine/output.js +20 -0
- package/dist/src/engine/publish.d.ts +30 -0
- package/dist/src/engine/publish.js +95 -0
- package/dist/src/engine/registry.d.ts +34 -0
- package/dist/src/engine/registry.js +67 -0
- package/dist/src/engine/scenarios.d.ts +12 -0
- package/dist/src/engine/scenarios.js +19 -0
- package/dist/src/engine/schemaCheck.d.ts +4 -0
- package/dist/src/engine/schemaCheck.js +34 -0
- package/dist/src/engine/trace.d.ts +12 -0
- package/dist/src/engine/trace.js +12 -0
- package/dist/src/engine/types.d.ts +308 -0
- package/dist/src/engine/types.js +1 -0
- package/dist/src/engine/validation.d.ts +26 -0
- package/dist/src/engine/validation.js +318 -0
- package/dist/src/flows/anomaly-flows.d.ts +23 -0
- package/dist/src/flows/anomaly-flows.js +151 -0
- package/dist/src/flows/city-sweep-flow.d.ts +10 -0
- package/dist/src/flows/city-sweep-flow.js +127 -0
- package/dist/src/flows/login-flow.d.ts +13 -0
- package/dist/src/flows/login-flow.js +145 -0
- package/dist/src/flows/pradar-flows.d.ts +5 -0
- package/dist/src/flows/pradar-flows.js +375 -0
- package/dist/src/flows/weather-flow.d.ts +12 -0
- package/dist/src/flows/weather-flow.js +150 -0
- package/dist/src/lib/pathParams.d.ts +3 -0
- package/dist/src/lib/pathParams.js +6 -0
- package/dist/src/nodes/anomaly.d.ts +2 -0
- package/dist/src/nodes/anomaly.js +556 -0
- package/dist/src/nodes/flow-control.d.ts +7 -0
- package/dist/src/nodes/flow-control.js +270 -0
- package/dist/src/nodes/index.d.ts +3 -0
- package/dist/src/nodes/index.js +20 -0
- package/dist/src/nodes/login.d.ts +7 -0
- package/dist/src/nodes/login.js +158 -0
- package/dist/src/nodes/loops.d.ts +11 -0
- package/dist/src/nodes/loops.js +60 -0
- package/dist/src/nodes/pradar/index.d.ts +7 -0
- package/dist/src/nodes/pradar/index.js +9 -0
- package/dist/src/nodes/pradar/logic.d.ts +189 -0
- package/dist/src/nodes/pradar/logic.js +370 -0
- package/dist/src/nodes/pradar/nodes.d.ts +42 -0
- package/dist/src/nodes/pradar/nodes.js +801 -0
- package/dist/src/nodes/requireAuth.d.ts +20 -0
- package/dist/src/nodes/requireAuth.js +48 -0
- package/dist/src/nodes/response.d.ts +8 -0
- package/dist/src/nodes/response.js +33 -0
- package/dist/src/nodes/weather.d.ts +33 -0
- package/dist/src/nodes/weather.js +260 -0
- package/package.json +92 -0
- package/server/agentRoute.test.ts +157 -0
- package/server/agents/__fixtures__/fake-claude-writer.mjs +23 -0
- package/server/agents/__fixtures__/fake-claude.mjs +55 -0
- package/server/agents/__fixtures__/fake-codex-writer.mjs +27 -0
- package/server/agents/__fixtures__/fake-codex.mjs +52 -0
- package/server/agents/__fixtures__/fake-version-empty.mjs +3 -0
- package/server/agents/__fixtures__/fake-version-fail.mjs +4 -0
- package/server/agents/__fixtures__/fake-version-garbage.mjs +4 -0
- package/server/agents/__fixtures__/fake-version-good.mjs +4 -0
- package/server/agents/__fixtures__/fake-version-hang.mjs +3 -0
- package/server/agents/claudeAdapter.test.ts +127 -0
- package/server/agents/claudeAdapter.ts +212 -0
- package/server/agents/claudeParse.ts +193 -0
- package/server/agents/codexAdapter.test.ts +125 -0
- package/server/agents/codexAdapter.ts +198 -0
- package/server/agents/codexParse.test.ts +58 -0
- package/server/agents/codexParse.ts +126 -0
- package/server/agents/detect.test.ts +65 -0
- package/server/agents/detect.ts +43 -0
- package/server/agents/gitScope.test.ts +129 -0
- package/server/agents/gitScope.ts +110 -0
- package/server/agents/modelRejectionHint.test.ts +30 -0
- package/server/agents/modelRejectionHint.ts +14 -0
- package/server/agents/prompt.test.ts +613 -0
- package/server/agents/prompt.ts +527 -0
- package/server/agents/runManager.test.ts +251 -0
- package/server/agents/runManager.ts +286 -0
- package/server/agents/types.ts +17 -0
- package/server/apiMount.test.ts +591 -0
- package/server/apiStore.test.ts +324 -0
- package/server/apiStore.ts +241 -0
- package/server/auth/enforce.test.ts +61 -0
- package/server/auth/enforce.ts +6 -0
- package/server/auth/types.ts +5 -0
- package/server/auth/verifiers.test.ts +37 -0
- package/server/auth/verifiers.ts +9 -0
- package/server/authAttach.test.ts +175 -0
- package/server/authAttach.ts +99 -0
- package/server/cli.ts +847 -0
- package/server/cliAuth.test.ts +229 -0
- package/server/cliCreate.test.ts +131 -0
- package/server/cliDoctor.test.ts +326 -0
- package/server/cliTest.test.ts +735 -0
- package/server/client.ts +314 -0
- package/server/demoProject.test.ts +29 -0
- package/server/diagnosticsRoute.test.ts +169 -0
- package/server/environments.test.ts +620 -0
- package/server/environments.ts +603 -0
- package/server/environmentsRoute.test.ts +385 -0
- package/server/errorWorkflow.test.ts +205 -0
- package/server/flowStore.test.ts +84 -0
- package/server/flowStore.ts +125 -0
- package/server/httpOperations.test.ts +377 -0
- package/server/httpOperations.ts +96 -0
- package/server/index.ts +1111 -0
- package/server/infrastructure.test.ts +154 -0
- package/server/infrastructure.ts +161 -0
- package/server/infrastructureRoute.test.ts +105 -0
- package/server/login.test.ts +153 -0
- package/server/login.ts +67 -0
- package/server/mcp.ts +278 -0
- package/server/migrateFlows.test.ts +55 -0
- package/server/migrateFlows.ts +23 -0
- package/server/mockHandler.test.ts +138 -0
- package/server/mockHandler.ts +52 -0
- package/server/mockRun.test.ts +367 -0
- package/server/mockServe.test.ts +467 -0
- package/server/nodesPayload.test.ts +29 -0
- package/server/nodesPayload.ts +26 -0
- package/server/normalizeFlow.test.ts +80 -0
- package/server/normalizeFlow.ts +59 -0
- package/server/openBrowser.test.ts +20 -0
- package/server/openBrowser.ts +22 -0
- package/server/operationResult.test.ts +67 -0
- package/server/operationResult.ts +27 -0
- package/server/pathGuard.test.ts +19 -0
- package/server/pathGuard.ts +12 -0
- package/server/pathSafety.test.ts +38 -0
- package/server/pathSafety.ts +33 -0
- package/server/projectConfig.test.ts +67 -0
- package/server/projectConfig.ts +101 -0
- package/server/projectMode.test.ts +106 -0
- package/server/projectMode.ts +59 -0
- package/server/redact.test.ts +88 -0
- package/server/redact.ts +35 -0
- package/server/redactEgress.test.ts +281 -0
- package/server/runRegistry.ts +270 -0
- package/server/runsAuth.test.ts +119 -0
- package/server/runtime/RuntimeAdapter.ts +24 -0
- package/server/runtime/expressAdapter.test.ts +38 -0
- package/server/runtime/expressAdapter.ts +70 -0
- package/server/scenarioTest.test.ts +148 -0
- package/server/scenarioTest.ts +88 -0
- package/server/setupStatus.test.ts +127 -0
- package/server/subflowRunner.ts +104 -0
- package/server/testRunner.ts +216 -0
- package/server/tsconfig.json +20 -0
- package/server/workflowTestRoute.test.ts +297 -0
- package/src/App.tsx +233 -0
- package/src/components/AgentConsole.tsx +461 -0
- package/src/components/BranchRulesEditor.tsx +156 -0
- package/src/components/CreateModal.tsx +275 -0
- package/src/components/Dock.tsx +487 -0
- package/src/components/EnvironmentDialog.tsx +569 -0
- package/src/components/EnvironmentPicker.tsx +357 -0
- package/src/components/EnvironmentsDialog.tsx +144 -0
- package/src/components/ExecutionPager.tsx +67 -0
- package/src/components/InfraPanel.test.tsx +103 -0
- package/src/components/InfraPanel.tsx +171 -0
- package/src/components/Inspector.tsx +1182 -0
- package/src/components/Json.tsx +50 -0
- package/src/components/JsonModal.tsx +52 -0
- package/src/components/LogMessage.tsx +61 -0
- package/src/components/NodeRunModal.tsx +213 -0
- package/src/components/RunLogPanel.tsx +397 -0
- package/src/components/RunbookView.tsx +1085 -0
- package/src/components/Scenarios.tsx +476 -0
- package/src/components/SettingsDialog.tsx +229 -0
- package/src/components/Sidebar.tsx +436 -0
- package/src/components/StatusBar.tsx +302 -0
- package/src/components/Toolbar.tsx +663 -0
- package/src/components/WelcomeDialog.test.tsx +107 -0
- package/src/components/WelcomeDialog.tsx +412 -0
- package/src/components/agentMarkdown.test.tsx +91 -0
- package/src/components/agentMarkdown.tsx +158 -0
- package/src/components/ui/badge.tsx +31 -0
- package/src/components/ui/button.tsx +46 -0
- package/src/components/ui/combobox.tsx +114 -0
- package/src/components/ui/command.tsx +82 -0
- package/src/components/ui/dialog.tsx +73 -0
- package/src/components/ui/input.tsx +20 -0
- package/src/components/ui/popover.tsx +32 -0
- package/src/components/ui/resizable.tsx +44 -0
- package/src/components/ui/tabs.tsx +36 -0
- package/src/config.ts +4 -0
- package/src/engine/authVerify.ts +81 -0
- package/src/engine/diagnostics.test.ts +437 -0
- package/src/engine/diagnostics.ts +211 -0
- package/src/engine/executor.test.ts +1339 -0
- package/src/engine/executor.ts +840 -0
- package/src/engine/httpError.test.ts +12 -0
- package/src/engine/httpError.ts +16 -0
- package/src/engine/index.ts +11 -0
- package/src/engine/output.ts +21 -0
- package/src/engine/publish.test.ts +176 -0
- package/src/engine/publish.ts +127 -0
- package/src/engine/registry.test.ts +64 -0
- package/src/engine/registry.ts +80 -0
- package/src/engine/scenarios.test.ts +55 -0
- package/src/engine/scenarios.ts +29 -0
- package/src/engine/schemaCheck.test.ts +21 -0
- package/src/engine/schemaCheck.ts +35 -0
- package/src/engine/trace.test.ts +19 -0
- package/src/engine/trace.ts +23 -0
- package/src/engine/types.test.ts +22 -0
- package/src/engine/types.ts +316 -0
- package/src/engine/validation.test.ts +314 -0
- package/src/engine/validation.ts +354 -0
- package/src/flows/anomaly-flows.test.ts +81 -0
- package/src/flows/anomaly-flows.ts +202 -0
- package/src/flows/city-sweep-flow.ts +131 -0
- package/src/flows/flows.test.ts +30 -0
- package/src/flows/login-flow.ts +150 -0
- package/src/flows/pradar-flows.test.ts +204 -0
- package/src/flows/pradar-flows.ts +419 -0
- package/src/flows/weather-flow.ts +154 -0
- package/src/globals.css +147 -0
- package/src/lib/pathParams.test.ts +24 -0
- package/src/lib/pathParams.ts +6 -0
- package/src/lib/registerLens.test.ts +79 -0
- package/src/lib/registerLens.ts +59 -0
- package/src/lib/runbookModel.test.ts +61 -0
- package/src/lib/runbookModel.ts +290 -0
- package/src/lib/runbookProjection.test.ts +417 -0
- package/src/lib/runbookProjection.ts +254 -0
- package/src/lib/useTailAnchor.ts +53 -0
- package/src/lib/utils.ts +7 -0
- package/src/main.tsx +13 -0
- package/src/nodes/anomaly.test.ts +98 -0
- package/src/nodes/anomaly.ts +637 -0
- package/src/nodes/effects-scan.test.ts +44 -0
- package/src/nodes/flow-control.test.ts +280 -0
- package/src/nodes/flow-control.ts +305 -0
- package/src/nodes/index.ts +22 -0
- package/src/nodes/login.test.ts +81 -0
- package/src/nodes/login.ts +186 -0
- package/src/nodes/loops.ts +69 -0
- package/src/nodes/pradar/index.ts +11 -0
- package/src/nodes/pradar/logic.test.ts +288 -0
- package/src/nodes/pradar/logic.ts +582 -0
- package/src/nodes/pradar/nodes.test.ts +146 -0
- package/src/nodes/pradar/nodes.ts +955 -0
- package/src/nodes/requireAuth.test.ts +75 -0
- package/src/nodes/requireAuth.ts +55 -0
- package/src/nodes/response.test.ts +33 -0
- package/src/nodes/response.ts +39 -0
- package/src/nodes/traceDetail.test.ts +39 -0
- package/src/nodes/weather.test.ts +65 -0
- package/src/nodes/weather.ts +306 -0
- package/src/store/agentClient.test.ts +103 -0
- package/src/store/agentClient.ts +131 -0
- package/src/store/apiTree.test.ts +17 -0
- package/src/store/apiTree.ts +73 -0
- package/src/store/builderStore.test.ts +1234 -0
- package/src/store/builderStore.ts +1879 -0
- package/src/store/infraClient.ts +63 -0
- package/src/store/nodeMeta.test.ts +24 -0
- package/src/store/nodeMeta.ts +21 -0
- package/src/store/persistence.test.ts +15 -0
- package/src/store/persistence.ts +54 -0
- package/src/store/serverRunner.ts +381 -0
- package/src/store/setupClient.ts +57 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-500-normal-Ael50iVv.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-500-normal-Bq9vWWag.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-500-normal-BIfNGwUT.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-cyrillic-ext-500-normal-BqneJy0T.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-500-normal-CB9ihrfo.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-ext-500-normal-CAhNIIs5.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-latin-ext-500-normal-CZ70TYgx.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
- package/studio-dist/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-vietnamese-500-normal-C8zxqsMH.woff +0 -0
- package/studio-dist/assets/ibm-plex-mono-vietnamese-500-normal-DZ4AoWbu.woff2 +0 -0
- package/studio-dist/assets/index-DNJwW-hM.css +1 -0
- package/studio-dist/assets/index-O26dKRjW.js +65 -0
- package/studio-dist/assets/inter-cyrillic-ext-wght-normal-BOeWTOD4.woff2 +0 -0
- package/studio-dist/assets/inter-cyrillic-wght-normal-DqGufNeO.woff2 +0 -0
- package/studio-dist/assets/inter-greek-ext-wght-normal-DlzME5K_.woff2 +0 -0
- package/studio-dist/assets/inter-greek-wght-normal-CkhJZR-_.woff2 +0 -0
- package/studio-dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/studio-dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/studio-dist/assets/inter-vietnamese-wght-normal-CBcvBZtf.woff2 +0 -0
- package/studio-dist/favicon.svg +1 -0
- package/studio-dist/icons.svg +24 -0
- package/studio-dist/index.html +14 -0
- package/templates/skills/emberflow-basics/SKILL.md +316 -0
- package/templates/skills/emberflow-model-process/SKILL.md +209 -0
- package/templates/skills/emberflow-new-workflow/SKILL.md +211 -0
- package/templates/skills/emberflow-review-workflow/SKILL.md +148 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { getByPath } from '../engine/index.js';
|
|
2
|
+
const CONDITIONAL_OPS = new Set([
|
|
3
|
+
'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'contains', 'exists', 'truthy',
|
|
4
|
+
]);
|
|
5
|
+
/**
|
|
6
|
+
* Only numbers and non-empty numeric strings take part in numeric coercion —
|
|
7
|
+
* Number(null), Number(''), and Number([]) are all 0, which would make
|
|
8
|
+
* `eq 0` match null/''/[] and `gt -1` match null.
|
|
9
|
+
*/
|
|
10
|
+
function asComparableNumber(v) {
|
|
11
|
+
if (typeof v === 'number')
|
|
12
|
+
return v;
|
|
13
|
+
if (typeof v === 'string' && v.trim() !== '')
|
|
14
|
+
return Number(v);
|
|
15
|
+
return NaN;
|
|
16
|
+
}
|
|
17
|
+
/** eq/neq base: strict equality, plus numeric-looking equality (`Number()` on both sides). */
|
|
18
|
+
function looksEqual(input, comparand) {
|
|
19
|
+
if (input === comparand)
|
|
20
|
+
return true;
|
|
21
|
+
const a = asComparableNumber(input);
|
|
22
|
+
const b = asComparableNumber(comparand);
|
|
23
|
+
return !Number.isNaN(a) && !Number.isNaN(b) && a === b;
|
|
24
|
+
}
|
|
25
|
+
function numericMatch(op, input, comparand) {
|
|
26
|
+
const a = asComparableNumber(input);
|
|
27
|
+
const b = asComparableNumber(comparand);
|
|
28
|
+
if (Number.isNaN(a) || Number.isNaN(b))
|
|
29
|
+
return false;
|
|
30
|
+
switch (op) {
|
|
31
|
+
case 'gt': return a > b;
|
|
32
|
+
case 'gte': return a >= b;
|
|
33
|
+
case 'lt': return a < b;
|
|
34
|
+
case 'lte': return a <= b;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function ruleMatches(op, input, comparand) {
|
|
38
|
+
switch (op) {
|
|
39
|
+
case 'eq': return looksEqual(input, comparand);
|
|
40
|
+
case 'neq': return !looksEqual(input, comparand);
|
|
41
|
+
case 'gt':
|
|
42
|
+
case 'gte':
|
|
43
|
+
case 'lt':
|
|
44
|
+
case 'lte':
|
|
45
|
+
return numericMatch(op, input, comparand);
|
|
46
|
+
case 'contains':
|
|
47
|
+
if (typeof input === 'string')
|
|
48
|
+
return input.includes(String(comparand));
|
|
49
|
+
if (Array.isArray(input))
|
|
50
|
+
return input.includes(comparand);
|
|
51
|
+
return false;
|
|
52
|
+
case 'exists':
|
|
53
|
+
return input !== undefined && input !== null;
|
|
54
|
+
case 'truthy':
|
|
55
|
+
return Boolean(input);
|
|
56
|
+
default:
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Flow-control nodes. Route reads a field from its input object and emits
|
|
62
|
+
* `$branch`; the executor then skips downstream nodes hanging off untaken
|
|
63
|
+
* branch handles (edge.sourceHandle = branch name).
|
|
64
|
+
*/
|
|
65
|
+
export function registerFlowControlNodes(registry) {
|
|
66
|
+
registry.register({
|
|
67
|
+
type: 'Input',
|
|
68
|
+
label: 'Input',
|
|
69
|
+
description: 'Entry point — emits the payload the run was invoked with (falling back to configured defaults).',
|
|
70
|
+
simpleDescription: 'Starts the run with its input data',
|
|
71
|
+
category: 'input',
|
|
72
|
+
traceKind: 'compute',
|
|
73
|
+
tags: ['entry'],
|
|
74
|
+
configSchema: {
|
|
75
|
+
fields: [
|
|
76
|
+
{ name: 'fields', type: 'array' },
|
|
77
|
+
{ name: 'defaults', type: 'object' },
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
// Dynamic — the emitted shape depends on the configured fields.
|
|
81
|
+
outputSchema: { fields: [] },
|
|
82
|
+
}, async (ctx) => {
|
|
83
|
+
const merged = {
|
|
84
|
+
...(ctx.config.defaults ?? {}),
|
|
85
|
+
...ctx.runInput,
|
|
86
|
+
};
|
|
87
|
+
const declared = Array.isArray(ctx.config.fields)
|
|
88
|
+
? ctx.config.fields
|
|
89
|
+
: [];
|
|
90
|
+
const missing = declared
|
|
91
|
+
.filter((f) => f.required && merged[f.name] === undefined)
|
|
92
|
+
.map((f) => f.name);
|
|
93
|
+
if (missing.length) {
|
|
94
|
+
throw new Error(`Missing required input field(s): ${missing.join(', ')}`);
|
|
95
|
+
}
|
|
96
|
+
const summary = JSON.stringify(merged);
|
|
97
|
+
// Full JSON, untruncated: the log UI renders parseable payloads as
|
|
98
|
+
// collapsible highlighted blocks — a sliced tail breaks the parse and
|
|
99
|
+
// regresses to a wall of escaped text.
|
|
100
|
+
ctx.log('info', `Run input: ${summary}`);
|
|
101
|
+
return merged;
|
|
102
|
+
});
|
|
103
|
+
registry.register({
|
|
104
|
+
type: 'Environment',
|
|
105
|
+
label: 'Environment',
|
|
106
|
+
description: 'Reports the environment this run targets. Emits `environment` (the run\'s target environment name, e.g. "prod"; "local" when the run carries none) and `isProd` (a convenience boolean, true only when environment === "prod"). PORT NOTE: the name comes from the run\'s target environment threaded through node ctx (ctx.environment) — it is undefined for browser/in-tab runs, which report "local". `isProd` exists so the common case (branch on "is this production?") is a one-field Conditional; branch on `environment` directly for finer-grained routing.',
|
|
107
|
+
simpleDescription: 'Reports which environment this run targets, so steps can branch on it.',
|
|
108
|
+
category: 'logic',
|
|
109
|
+
traceKind: 'compute',
|
|
110
|
+
tags: ['branching'],
|
|
111
|
+
// No inputs — the environment is read from the run context.
|
|
112
|
+
inputSchema: { fields: [] },
|
|
113
|
+
outputSchema: {
|
|
114
|
+
fields: [
|
|
115
|
+
{ name: 'environment', type: 'string' },
|
|
116
|
+
{ name: 'isProd', type: 'boolean' },
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
}, async (ctx) => {
|
|
120
|
+
const environment = ctx.environment ?? 'local';
|
|
121
|
+
const isProd = environment === 'prod';
|
|
122
|
+
ctx.log('info', `Environment: ${environment} (isProd=${isProd})`);
|
|
123
|
+
return { environment, isProd };
|
|
124
|
+
});
|
|
125
|
+
registry.register({
|
|
126
|
+
type: 'Route',
|
|
127
|
+
label: 'Route',
|
|
128
|
+
description: 'Branches the flow on a field of its input. Edges leaving a named branch handle only run when that branch matches.',
|
|
129
|
+
simpleDescription: 'Sends the data down a different path based on one value',
|
|
130
|
+
category: 'logic',
|
|
131
|
+
traceKind: 'compute',
|
|
132
|
+
tags: ['branching'],
|
|
133
|
+
inputSchema: {
|
|
134
|
+
fields: [{ name: 'value', type: 'object', required: true }],
|
|
135
|
+
},
|
|
136
|
+
configSchema: {
|
|
137
|
+
fields: [
|
|
138
|
+
{ name: 'field', type: 'string', required: true },
|
|
139
|
+
{ name: 'branches', type: 'array', required: true },
|
|
140
|
+
{ name: 'fallback', type: 'string' },
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
outputSchema: {
|
|
144
|
+
fields: [{ name: '$branch', type: 'string' }],
|
|
145
|
+
},
|
|
146
|
+
}, async (ctx) => {
|
|
147
|
+
const value = (ctx.input.value ?? {});
|
|
148
|
+
const field = String(ctx.config.field ?? '');
|
|
149
|
+
const branches = Array.isArray(ctx.config.branches)
|
|
150
|
+
? ctx.config.branches.map(String)
|
|
151
|
+
: [];
|
|
152
|
+
const raw = getByPath(value, field);
|
|
153
|
+
const candidate = String(raw);
|
|
154
|
+
let branch = branches.includes(candidate) ? candidate : undefined;
|
|
155
|
+
if (branch === undefined && typeof ctx.config.fallback === 'string' && ctx.config.fallback) {
|
|
156
|
+
branch = ctx.config.fallback;
|
|
157
|
+
}
|
|
158
|
+
if (branch === undefined) {
|
|
159
|
+
throw new Error(`Route: "${field}" resolved to "${candidate}", which matches no branch and no fallback is set`);
|
|
160
|
+
}
|
|
161
|
+
ctx.log('info', `Routing ${field}=${candidate} → branch "${branch}"`);
|
|
162
|
+
return { ...value, $branch: branch };
|
|
163
|
+
});
|
|
164
|
+
registry.register({
|
|
165
|
+
type: 'Conditional',
|
|
166
|
+
label: 'Conditional',
|
|
167
|
+
description: 'Branches the flow on an ordered set of rules evaluated against its input. The first matching rule wins; edges leaving a named branch handle only run when that branch matches.',
|
|
168
|
+
simpleDescription: 'Chooses a path based on the data',
|
|
169
|
+
category: 'logic',
|
|
170
|
+
traceKind: 'compute',
|
|
171
|
+
tags: ['branching'],
|
|
172
|
+
inputSchema: {
|
|
173
|
+
fields: [{ name: 'value', type: 'object', required: true }],
|
|
174
|
+
},
|
|
175
|
+
configSchema: {
|
|
176
|
+
fields: [
|
|
177
|
+
{ name: 'branches', type: 'array', required: true },
|
|
178
|
+
{ name: 'fallback', type: 'string' },
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
outputSchema: {
|
|
182
|
+
fields: [{ name: '$branch', type: 'string' }],
|
|
183
|
+
},
|
|
184
|
+
}, async (ctx) => {
|
|
185
|
+
const value = ctx.input.value;
|
|
186
|
+
const rules = Array.isArray(ctx.config.branches) ? ctx.config.branches : [];
|
|
187
|
+
let branch;
|
|
188
|
+
for (const raw of rules) {
|
|
189
|
+
const rule = (raw !== null && typeof raw === 'object' ? raw : {});
|
|
190
|
+
const name = typeof rule.name === 'string' && rule.name ? rule.name : undefined;
|
|
191
|
+
const op = typeof rule.op === 'string' ? rule.op : undefined;
|
|
192
|
+
if (!name || !op || !CONDITIONAL_OPS.has(op)) {
|
|
193
|
+
ctx.log('warn', `Conditional: skipping malformed rule ${JSON.stringify(raw)}`);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (ruleMatches(op, value, rule.value)) {
|
|
197
|
+
branch = name;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (branch === undefined && typeof ctx.config.fallback === 'string' && ctx.config.fallback) {
|
|
202
|
+
branch = ctx.config.fallback;
|
|
203
|
+
}
|
|
204
|
+
if (branch === undefined) {
|
|
205
|
+
throw new Error('Conditional: no rule matched and no fallback is set');
|
|
206
|
+
}
|
|
207
|
+
ctx.log('info', `Conditional matched → branch "${branch}"`);
|
|
208
|
+
return { value, $branch: branch };
|
|
209
|
+
});
|
|
210
|
+
registry.register({
|
|
211
|
+
type: 'Merge',
|
|
212
|
+
label: 'Merge',
|
|
213
|
+
description: 'Coalesces converging branch arms into one value: emits `value` = the first of its mapped inputs that is neither undefined nor null, in inputMap declaration order. PORT NOTE: the engine leaves an inputMap field undefined when its source node was skipped (an untaken branch arm), so wiring one input per arm makes `value` resolve to whichever arm actually ran. Use it as the join point after a Conditional whose arms each produce the same downstream value from a DIFFERENT node.',
|
|
214
|
+
simpleDescription: 'Joins branch paths — passes on whichever arm produced a value.',
|
|
215
|
+
category: 'logic',
|
|
216
|
+
traceKind: 'compute',
|
|
217
|
+
tags: ['branching'],
|
|
218
|
+
// Free-form: the converging arm values are supplied via inputMap, one
|
|
219
|
+
// field per arm; declaration order sets coalesce priority.
|
|
220
|
+
inputSchema: { fields: [] },
|
|
221
|
+
outputSchema: {
|
|
222
|
+
fields: [{ name: 'value', type: 'object' }],
|
|
223
|
+
},
|
|
224
|
+
}, async (ctx) => {
|
|
225
|
+
const entries = Object.entries(ctx.input);
|
|
226
|
+
const chosen = entries.find(([, v]) => v !== undefined && v !== null);
|
|
227
|
+
if (!chosen) {
|
|
228
|
+
ctx.log('warn', 'Merge: no incoming arm produced a value');
|
|
229
|
+
return { value: undefined };
|
|
230
|
+
}
|
|
231
|
+
ctx.log('info', `Merge: passing on value from "${chosen[0]}"`);
|
|
232
|
+
return { value: chosen[1] };
|
|
233
|
+
});
|
|
234
|
+
registry.register({
|
|
235
|
+
type: 'Subflow',
|
|
236
|
+
label: 'Subflow',
|
|
237
|
+
description: 'Runs another workflow to completion with the mapped input, then emits that child run\'s collected output.',
|
|
238
|
+
simpleDescription: 'Runs another workflow and uses its result',
|
|
239
|
+
category: 'logic',
|
|
240
|
+
traceKind: 'compute',
|
|
241
|
+
tags: ['subflow'],
|
|
242
|
+
// Free-form input: whatever is mapped onto this node becomes the child
|
|
243
|
+
// run's invocation payload (like an Input node's run input).
|
|
244
|
+
inputSchema: { fields: [] },
|
|
245
|
+
configSchema: {
|
|
246
|
+
fields: [{ name: 'workflowId', type: 'string', required: true }],
|
|
247
|
+
},
|
|
248
|
+
// Dynamic — the emitted shape is the child flow's Result output.
|
|
249
|
+
outputSchema: { fields: [] },
|
|
250
|
+
}, async (ctx) => {
|
|
251
|
+
const workflowId = String(ctx.config.workflowId ?? '');
|
|
252
|
+
if (!workflowId)
|
|
253
|
+
throw new Error('Subflow: no workflowId configured');
|
|
254
|
+
if (!ctx.runSubflow) {
|
|
255
|
+
throw new Error('subflows need a host that can look up workflows');
|
|
256
|
+
}
|
|
257
|
+
ctx.log('info', `Running subflow "${workflowId}"`);
|
|
258
|
+
const result = await ctx.runSubflow(workflowId, ctx.input);
|
|
259
|
+
if (result.status === 'failed') {
|
|
260
|
+
throw new Error(result.error ?? 'subflow failed');
|
|
261
|
+
}
|
|
262
|
+
const output = result.output;
|
|
263
|
+
// Spread a plain object so downstream nodes can map its fields directly;
|
|
264
|
+
// wrap anything else under `output`.
|
|
265
|
+
if (output !== null && typeof output === 'object' && !Array.isArray(output)) {
|
|
266
|
+
return { ...output };
|
|
267
|
+
}
|
|
268
|
+
return { output };
|
|
269
|
+
});
|
|
270
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createLoginRegistry } from './login.js';
|
|
2
|
+
import { registerWeatherNodes } from './weather.js';
|
|
3
|
+
import { registerAnomalyNodes } from './anomaly.js';
|
|
4
|
+
import { registerFlowControlNodes } from './flow-control.js';
|
|
5
|
+
import { registerLoopNodes } from './loops.js';
|
|
6
|
+
import { registerPradarNodesModule } from './pradar/index.js';
|
|
7
|
+
import { registerResponseNodes } from './response.js';
|
|
8
|
+
import { registerRequireAuthNode } from './requireAuth.js';
|
|
9
|
+
/** All built-in nodes: login examples, Open-Meteo weather, anomaly-detection API, EV charging demo, HTTP Response, requireAuth. */
|
|
10
|
+
export function createDefaultRegistry(delayMs) {
|
|
11
|
+
const registry = createLoginRegistry(delayMs);
|
|
12
|
+
registerWeatherNodes(registry);
|
|
13
|
+
registerAnomalyNodes(registry);
|
|
14
|
+
registerFlowControlNodes(registry);
|
|
15
|
+
registerLoopNodes(registry);
|
|
16
|
+
registerPradarNodesModule(registry);
|
|
17
|
+
registerResponseNodes(registry);
|
|
18
|
+
registerRequireAuthNode(registry);
|
|
19
|
+
return registry;
|
|
20
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { NodeRegistry } from '../engine/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Build a NodeRegistry populated with the five login example nodes.
|
|
4
|
+
* `delayMs` is injected into every implementation via `await sleep(delayMs)`
|
|
5
|
+
* so tests can run with no delay by passing `0`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createLoginRegistry(delayMs?: number): NodeRegistry;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { NodeRegistry } from '../engine/index.js';
|
|
2
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
3
|
+
/** Strip the `user-` prefix from a userId to get the username part. */
|
|
4
|
+
function usernamePart(userId) {
|
|
5
|
+
return userId.startsWith('user-') ? userId.slice('user-'.length) : userId;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Build a NodeRegistry populated with the five login example nodes.
|
|
9
|
+
* `delayMs` is injected into every implementation via `await sleep(delayMs)`
|
|
10
|
+
* so tests can run with no delay by passing `0`.
|
|
11
|
+
*/
|
|
12
|
+
export function createLoginRegistry(delayMs = 300) {
|
|
13
|
+
const registry = new NodeRegistry();
|
|
14
|
+
registry.register({
|
|
15
|
+
type: 'ValidateCredentials',
|
|
16
|
+
label: 'Validate Credentials',
|
|
17
|
+
description: 'Validates a username and password.',
|
|
18
|
+
category: 'auth',
|
|
19
|
+
traceKind: 'compute',
|
|
20
|
+
inputSchema: {
|
|
21
|
+
fields: [
|
|
22
|
+
{ name: 'username', type: 'string', required: true },
|
|
23
|
+
{ name: 'password', type: 'string', required: true },
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
outputSchema: {
|
|
27
|
+
fields: [
|
|
28
|
+
{ name: 'userId', type: 'string' },
|
|
29
|
+
{ name: 'username', type: 'string' },
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
}, async (ctx) => {
|
|
33
|
+
await sleep(delayMs);
|
|
34
|
+
const username = String(ctx.input.username ?? '');
|
|
35
|
+
const password = String(ctx.input.password ?? '');
|
|
36
|
+
if (password.length < 4) {
|
|
37
|
+
throw new Error('Password too short');
|
|
38
|
+
}
|
|
39
|
+
ctx.log('info', `Credentials accepted for ${username}`);
|
|
40
|
+
return { userId: `user-${username}`, username };
|
|
41
|
+
});
|
|
42
|
+
registry.register({
|
|
43
|
+
type: 'FetchUser',
|
|
44
|
+
label: 'Fetch User',
|
|
45
|
+
description: 'Fetches a user record derived from a userId.',
|
|
46
|
+
category: 'data',
|
|
47
|
+
traceKind: 'compute',
|
|
48
|
+
inputSchema: {
|
|
49
|
+
fields: [{ name: 'userId', type: 'string', required: true }],
|
|
50
|
+
},
|
|
51
|
+
outputSchema: {
|
|
52
|
+
fields: [
|
|
53
|
+
{ name: 'id', type: 'string' },
|
|
54
|
+
{ name: 'name', type: 'string' },
|
|
55
|
+
{ name: 'plan', type: 'enum', enumValues: ['free', 'pro'] },
|
|
56
|
+
{ name: 'isNew', type: 'boolean' },
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
}, async (ctx) => {
|
|
60
|
+
await sleep(delayMs);
|
|
61
|
+
const userId = String(ctx.input.userId ?? '');
|
|
62
|
+
const name = usernamePart(userId);
|
|
63
|
+
const plan = name.includes('pro') ? 'pro' : 'free';
|
|
64
|
+
const isNew = name.startsWith('new');
|
|
65
|
+
ctx.log('info', `Fetched user ${name}: plan=${plan}, isNew=${isNew}`);
|
|
66
|
+
return { id: userId, name, plan, isNew };
|
|
67
|
+
});
|
|
68
|
+
registry.register({
|
|
69
|
+
type: 'CheckPlan',
|
|
70
|
+
label: 'Check Plan',
|
|
71
|
+
description: 'Resolves the feature set for a user plan.',
|
|
72
|
+
category: 'logic',
|
|
73
|
+
traceKind: 'compute',
|
|
74
|
+
inputSchema: {
|
|
75
|
+
fields: [{ name: 'user', type: 'object', required: true }],
|
|
76
|
+
},
|
|
77
|
+
outputSchema: {
|
|
78
|
+
fields: [
|
|
79
|
+
{ name: 'plan', type: 'enum', enumValues: ['free', 'pro'] },
|
|
80
|
+
{ name: 'features', type: 'array' },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
}, async (ctx) => {
|
|
84
|
+
await sleep(delayMs);
|
|
85
|
+
const user = (ctx.input.user ?? {});
|
|
86
|
+
const plan = user.plan ?? 'free';
|
|
87
|
+
const features = plan === 'pro' ? ['sso', 'audit-log', 'priority-support'] : ['basic'];
|
|
88
|
+
ctx.log('info', `Plan ${plan} resolves to features: ${features.join(', ')}`);
|
|
89
|
+
return { plan, features };
|
|
90
|
+
});
|
|
91
|
+
registry.register({
|
|
92
|
+
type: 'WelcomeUser',
|
|
93
|
+
label: 'Welcome User',
|
|
94
|
+
description: 'Greets a freshly created user by name.',
|
|
95
|
+
category: 'auth',
|
|
96
|
+
traceKind: 'compute',
|
|
97
|
+
inputSchema: {
|
|
98
|
+
fields: [{ name: 'user', type: 'object', required: true }],
|
|
99
|
+
},
|
|
100
|
+
outputSchema: {
|
|
101
|
+
fields: [
|
|
102
|
+
{ name: 'message', type: 'string' },
|
|
103
|
+
{ name: 'userId', type: 'string' },
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
}, async (ctx) => {
|
|
107
|
+
await sleep(delayMs);
|
|
108
|
+
const user = (ctx.input.user ?? {});
|
|
109
|
+
const message = `Welcome aboard, ${user.name}!`;
|
|
110
|
+
ctx.log('info', message);
|
|
111
|
+
return { message, userId: user.id };
|
|
112
|
+
});
|
|
113
|
+
registry.register({
|
|
114
|
+
type: 'IssueToken',
|
|
115
|
+
label: 'Issue Token',
|
|
116
|
+
description: 'Issues an access token for a userId.',
|
|
117
|
+
category: 'auth',
|
|
118
|
+
traceKind: 'compute',
|
|
119
|
+
inputSchema: {
|
|
120
|
+
fields: [
|
|
121
|
+
{ name: 'userId', type: 'string', required: true },
|
|
122
|
+
{ name: 'plan', type: 'enum', enumValues: ['free', 'pro'] },
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
outputSchema: {
|
|
126
|
+
fields: [
|
|
127
|
+
{ name: 'token', type: 'string' },
|
|
128
|
+
{ name: 'issuedTo', type: 'string' },
|
|
129
|
+
{ name: 'plan', type: 'string' },
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
}, async (ctx) => {
|
|
133
|
+
await sleep(delayMs);
|
|
134
|
+
const userId = String(ctx.input.userId ?? '');
|
|
135
|
+
const plan = String(ctx.input.plan ?? 'free');
|
|
136
|
+
ctx.log('info', `Token issued for plan=${plan}`);
|
|
137
|
+
return { token: `tok_${userId}`, issuedTo: userId, plan };
|
|
138
|
+
});
|
|
139
|
+
registry.register({
|
|
140
|
+
type: 'Result',
|
|
141
|
+
label: 'Result',
|
|
142
|
+
description: 'Terminal node that passes its input through and displays it on the canvas.',
|
|
143
|
+
category: 'output',
|
|
144
|
+
traceKind: 'compute',
|
|
145
|
+
tags: ['display'],
|
|
146
|
+
inputSchema: {
|
|
147
|
+
fields: [{ name: 'data', type: 'object' }],
|
|
148
|
+
},
|
|
149
|
+
outputSchema: {
|
|
150
|
+
fields: [{ name: 'data', type: 'object' }],
|
|
151
|
+
},
|
|
152
|
+
}, async (ctx) => {
|
|
153
|
+
await sleep(delayMs);
|
|
154
|
+
ctx.log('info', 'Result collected');
|
|
155
|
+
return ctx.input;
|
|
156
|
+
});
|
|
157
|
+
return registry;
|
|
158
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { NodeRegistry } from '../engine/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* ForEach / Collect loop-region nodes. Iteration itself is owned by the
|
|
4
|
+
* executor (see FlowRun's loop machinery in ../engine/executor.ts) — these
|
|
5
|
+
* implementations exist so the node type is registered (canvas palette,
|
|
6
|
+
* schema-driven inspector fields, isolated single-node runs) and so an
|
|
7
|
+
* isolated run of just this node doesn't crash. In a real flow run the
|
|
8
|
+
* executor never calls these; it drives iteration itself and writes
|
|
9
|
+
* per-iteration / final output directly onto the node's run state.
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerLoopNodes(registry: NodeRegistry): void;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ForEach / Collect loop-region nodes. Iteration itself is owned by the
|
|
3
|
+
* executor (see FlowRun's loop machinery in ../engine/executor.ts) — these
|
|
4
|
+
* implementations exist so the node type is registered (canvas palette,
|
|
5
|
+
* schema-driven inspector fields, isolated single-node runs) and so an
|
|
6
|
+
* isolated run of just this node doesn't crash. In a real flow run the
|
|
7
|
+
* executor never calls these; it drives iteration itself and writes
|
|
8
|
+
* per-iteration / final output directly onto the node's run state.
|
|
9
|
+
*/
|
|
10
|
+
export function registerLoopNodes(registry) {
|
|
11
|
+
registry.register({
|
|
12
|
+
type: 'ForEach',
|
|
13
|
+
label: 'For Each',
|
|
14
|
+
description: 'Iterates over an array, running the downstream loop body once per item (or per batch). Paired with exactly one Collect node.',
|
|
15
|
+
simpleDescription: 'Repeats the next steps for each item in a list',
|
|
16
|
+
category: 'flow',
|
|
17
|
+
traceKind: 'compute',
|
|
18
|
+
tags: ['branching', 'loop'],
|
|
19
|
+
inputSchema: {
|
|
20
|
+
fields: [{ name: 'items', type: 'array', required: true }],
|
|
21
|
+
},
|
|
22
|
+
configSchema: {
|
|
23
|
+
fields: [
|
|
24
|
+
{ name: 'batchSize', type: 'number', description: 'Items per iteration (default 1).' },
|
|
25
|
+
{ name: 'maxIterations', type: 'number', description: 'Optional cap; extra iterations are truncated with a warning.' },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
outputSchema: {
|
|
29
|
+
fields: [
|
|
30
|
+
{ name: 'item', type: 'object', description: 'Single element (batchSize 1) or a chunk array otherwise.' },
|
|
31
|
+
{ name: 'index', type: 'number' },
|
|
32
|
+
{ name: 'total', type: 'number' },
|
|
33
|
+
],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
// Passthrough stub only — the executor owns real iteration and never
|
|
37
|
+
// invokes this for a node of type ForEach inside a valid loop region.
|
|
38
|
+
async (ctx) => ctx.input);
|
|
39
|
+
registry.register({
|
|
40
|
+
type: 'Collect',
|
|
41
|
+
label: 'Collect',
|
|
42
|
+
description: 'Gathers each loop iteration\'s mapped value into an array once its paired ForEach finishes iterating.',
|
|
43
|
+
simpleDescription: 'Collects the results from the repeated steps into a list',
|
|
44
|
+
category: 'flow',
|
|
45
|
+
traceKind: 'compute',
|
|
46
|
+
tags: ['loop'],
|
|
47
|
+
inputSchema: {
|
|
48
|
+
fields: [{ name: 'value', type: 'object', required: false }],
|
|
49
|
+
},
|
|
50
|
+
outputSchema: {
|
|
51
|
+
fields: [
|
|
52
|
+
{ name: 'items', type: 'array' },
|
|
53
|
+
{ name: 'count', type: 'number' },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
// Stub — the executor overrides this with the accumulated results in a
|
|
58
|
+
// real run. Only exercised for an isolated run of this node in isolation.
|
|
59
|
+
async () => ({ items: [], count: 0 }));
|
|
60
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { NodeRegistry } from '../../engine/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* EV charge scheduler nodes for the EV charging demo. Pure decision logic lives
|
|
4
|
+
* in ./logic; ./nodes wraps each function as a registry node. The vehicle /
|
|
5
|
+
* push-notification effect nodes are simulated (see their PORT NOTEs).
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerPradarNodesModule(registry: NodeRegistry): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { registerPradarNodes } from './nodes.js';
|
|
2
|
+
/**
|
|
3
|
+
* EV charge scheduler nodes for the EV charging demo. Pure decision logic lives
|
|
4
|
+
* in ./logic; ./nodes wraps each function as a registry node. The vehicle /
|
|
5
|
+
* push-notification effect nodes are simulated (see their PORT NOTEs).
|
|
6
|
+
*/
|
|
7
|
+
export function registerPradarNodesModule(registry) {
|
|
8
|
+
registerPradarNodes(registry);
|
|
9
|
+
}
|