@synergenius/flow-weaver 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 +122 -0
- package/README.md +315 -0
- package/dist/annotation-generator.d.ts +45 -0
- package/dist/annotation-generator.js +557 -0
- package/dist/api/builder.d.ts +223 -0
- package/dist/api/builder.js +345 -0
- package/dist/api/compile.d.ts +92 -0
- package/dist/api/compile.js +149 -0
- package/dist/api/extract-types.d.ts +29 -0
- package/dist/api/extract-types.js +57 -0
- package/dist/api/generate-in-place.d.ts +73 -0
- package/dist/api/generate-in-place.js +1353 -0
- package/dist/api/generate.d.ts +83 -0
- package/dist/api/generate.js +510 -0
- package/dist/api/helpers.d.ts +248 -0
- package/dist/api/helpers.js +285 -0
- package/dist/api/index.d.ts +46 -0
- package/dist/api/index.js +45 -0
- package/dist/api/inline-runtime.d.ts +27 -0
- package/dist/api/inline-runtime.js +551 -0
- package/dist/api/manipulation/connections.d.ts +79 -0
- package/dist/api/manipulation/connections.js +151 -0
- package/dist/api/manipulation/index.d.ts +34 -0
- package/dist/api/manipulation/index.js +41 -0
- package/dist/api/manipulation/node-types.d.ts +123 -0
- package/dist/api/manipulation/node-types.js +200 -0
- package/dist/api/manipulation/nodes.d.ts +144 -0
- package/dist/api/manipulation/nodes.js +333 -0
- package/dist/api/manipulation/ports.d.ts +59 -0
- package/dist/api/manipulation/ports.js +228 -0
- package/dist/api/manipulation/scopes.d.ts +52 -0
- package/dist/api/manipulation/scopes.js +156 -0
- package/dist/api/manipulation/validation.d.ts +6 -0
- package/dist/api/manipulation/validation.js +6 -0
- package/dist/api/manipulation/workflow.d.ts +81 -0
- package/dist/api/manipulation/workflow.js +116 -0
- package/dist/api/manipulation.d.ts +8 -0
- package/dist/api/manipulation.js +8 -0
- package/dist/api/parse.d.ts +48 -0
- package/dist/api/parse.js +110 -0
- package/dist/api/patterns.d.ts +112 -0
- package/dist/api/patterns.js +306 -0
- package/dist/api/query.d.ts +429 -0
- package/dist/api/query.js +816 -0
- package/dist/api/templates.d.ts +98 -0
- package/dist/api/templates.js +117 -0
- package/dist/api/transform.d.ts +31 -0
- package/dist/api/transform.js +40 -0
- package/dist/api/validate.d.ts +25 -0
- package/dist/api/validate.js +39 -0
- package/dist/api/workflow-file-operations.d.ts +29 -0
- package/dist/api/workflow-file-operations.js +180 -0
- package/dist/ast/builder.d.ts +210 -0
- package/dist/ast/builder.js +395 -0
- package/dist/ast/index.d.ts +5 -0
- package/dist/ast/index.js +5 -0
- package/dist/ast/serialization-node.d.ts +6 -0
- package/dist/ast/serialization-node.js +30 -0
- package/dist/ast/serialization.d.ts +43 -0
- package/dist/ast/serialization.js +134 -0
- package/dist/ast/types.d.ts +852 -0
- package/dist/ast/types.js +2 -0
- package/dist/ast/workflow-utils.d.ts +54 -0
- package/dist/ast/workflow-utils.js +114 -0
- package/dist/body-generator.d.ts +31 -0
- package/dist/body-generator.js +35 -0
- package/dist/built-in-nodes/delay.d.ts +11 -0
- package/dist/built-in-nodes/delay.js +29 -0
- package/dist/built-in-nodes/index.d.ts +5 -0
- package/dist/built-in-nodes/index.js +4 -0
- package/dist/built-in-nodes/invoke-workflow.d.ts +13 -0
- package/dist/built-in-nodes/invoke-workflow.js +25 -0
- package/dist/built-in-nodes/mock-types.d.ts +18 -0
- package/dist/built-in-nodes/mock-types.js +12 -0
- package/dist/built-in-nodes/wait-for-event.d.ts +13 -0
- package/dist/built-in-nodes/wait-for-event.js +25 -0
- package/dist/chevrotain-parser/connect-parser.d.ts +24 -0
- package/dist/chevrotain-parser/connect-parser.js +98 -0
- package/dist/chevrotain-parser/grammar-diagrams.d.ts +29 -0
- package/dist/chevrotain-parser/grammar-diagrams.js +264 -0
- package/dist/chevrotain-parser/index.d.ts +25 -0
- package/dist/chevrotain-parser/index.js +27 -0
- package/dist/chevrotain-parser/map-parser.d.ts +33 -0
- package/dist/chevrotain-parser/map-parser.js +130 -0
- package/dist/chevrotain-parser/node-parser.d.ts +36 -0
- package/dist/chevrotain-parser/node-parser.js +466 -0
- package/dist/chevrotain-parser/path-parser.d.ts +28 -0
- package/dist/chevrotain-parser/path-parser.js +118 -0
- package/dist/chevrotain-parser/port-parser.d.ts +36 -0
- package/dist/chevrotain-parser/port-parser.js +442 -0
- package/dist/chevrotain-parser/position-parser.d.ts +20 -0
- package/dist/chevrotain-parser/position-parser.js +83 -0
- package/dist/chevrotain-parser/scope-parser.d.ts +19 -0
- package/dist/chevrotain-parser/scope-parser.js +104 -0
- package/dist/chevrotain-parser/tokens.d.ts +78 -0
- package/dist/chevrotain-parser/tokens.js +384 -0
- package/dist/chevrotain-parser/trigger-cancel-parser.d.ts +50 -0
- package/dist/chevrotain-parser/trigger-cancel-parser.js +282 -0
- package/dist/cli/commands/changelog.d.ts +13 -0
- package/dist/cli/commands/changelog.js +135 -0
- package/dist/cli/commands/compile.d.ts +64 -0
- package/dist/cli/commands/compile.js +278 -0
- package/dist/cli/commands/create.d.ts +33 -0
- package/dist/cli/commands/create.js +147 -0
- package/dist/cli/commands/describe.d.ts +68 -0
- package/dist/cli/commands/describe.js +377 -0
- package/dist/cli/commands/dev.d.ts +32 -0
- package/dist/cli/commands/dev.js +384 -0
- package/dist/cli/commands/diagram.d.ts +13 -0
- package/dist/cli/commands/diagram.js +33 -0
- package/dist/cli/commands/diff.d.ts +11 -0
- package/dist/cli/commands/diff.js +59 -0
- package/dist/cli/commands/doctor.d.ts +57 -0
- package/dist/cli/commands/doctor.js +719 -0
- package/dist/cli/commands/export.d.ts +57 -0
- package/dist/cli/commands/export.js +163 -0
- package/dist/cli/commands/grammar.d.ts +9 -0
- package/dist/cli/commands/grammar.js +39 -0
- package/dist/cli/commands/init.d.ts +59 -0
- package/dist/cli/commands/init.js +435 -0
- package/dist/cli/commands/listen.d.ts +16 -0
- package/dist/cli/commands/listen.js +39 -0
- package/dist/cli/commands/market.d.ts +52 -0
- package/dist/cli/commands/market.js +436 -0
- package/dist/cli/commands/migrate.d.ts +13 -0
- package/dist/cli/commands/migrate.js +89 -0
- package/dist/cli/commands/openapi.d.ts +37 -0
- package/dist/cli/commands/openapi.js +67 -0
- package/dist/cli/commands/pattern.d.ts +34 -0
- package/dist/cli/commands/pattern.js +185 -0
- package/dist/cli/commands/plugin.d.ts +16 -0
- package/dist/cli/commands/plugin.js +176 -0
- package/dist/cli/commands/run.d.ts +49 -0
- package/dist/cli/commands/run.js +191 -0
- package/dist/cli/commands/serve.d.ts +45 -0
- package/dist/cli/commands/serve.js +81 -0
- package/dist/cli/commands/templates.d.ts +8 -0
- package/dist/cli/commands/templates.js +54 -0
- package/dist/cli/commands/ui.d.ts +16 -0
- package/dist/cli/commands/ui.js +130 -0
- package/dist/cli/commands/validate.d.ts +12 -0
- package/dist/cli/commands/validate.js +247 -0
- package/dist/cli/commands/watch.d.ts +9 -0
- package/dist/cli/commands/watch.js +70 -0
- package/dist/cli/flow-weaver.mjs +92924 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.js +742 -0
- package/dist/cli/templates/ai/mock-provider.d.ts +7 -0
- package/dist/cli/templates/ai/mock-provider.js +64 -0
- package/dist/cli/templates/ai/types.d.ts +47 -0
- package/dist/cli/templates/ai/types.js +5 -0
- package/dist/cli/templates/approvals/index.d.ts +15 -0
- package/dist/cli/templates/approvals/index.js +241 -0
- package/dist/cli/templates/index.d.ts +102 -0
- package/dist/cli/templates/index.js +101 -0
- package/dist/cli/templates/nodes/agent-router.d.ts +3 -0
- package/dist/cli/templates/nodes/agent-router.js +114 -0
- package/dist/cli/templates/nodes/aggregator.d.ts +7 -0
- package/dist/cli/templates/nodes/aggregator.js +63 -0
- package/dist/cli/templates/nodes/conversation-memory.d.ts +3 -0
- package/dist/cli/templates/nodes/conversation-memory.js +85 -0
- package/dist/cli/templates/nodes/http.d.ts +7 -0
- package/dist/cli/templates/nodes/http.js +80 -0
- package/dist/cli/templates/nodes/human-approval.d.ts +3 -0
- package/dist/cli/templates/nodes/human-approval.js +110 -0
- package/dist/cli/templates/nodes/json-extractor.d.ts +3 -0
- package/dist/cli/templates/nodes/json-extractor.js +119 -0
- package/dist/cli/templates/nodes/llm-call.d.ts +3 -0
- package/dist/cli/templates/nodes/llm-call.js +106 -0
- package/dist/cli/templates/nodes/prompt-template.d.ts +3 -0
- package/dist/cli/templates/nodes/prompt-template.js +52 -0
- package/dist/cli/templates/nodes/rag-retriever.d.ts +3 -0
- package/dist/cli/templates/nodes/rag-retriever.js +128 -0
- package/dist/cli/templates/nodes/tool-executor.d.ts +3 -0
- package/dist/cli/templates/nodes/tool-executor.js +108 -0
- package/dist/cli/templates/nodes/transformer.d.ts +7 -0
- package/dist/cli/templates/nodes/transformer.js +68 -0
- package/dist/cli/templates/nodes/validator.d.ts +7 -0
- package/dist/cli/templates/nodes/validator.js +62 -0
- package/dist/cli/templates/providers/index.d.ts +14 -0
- package/dist/cli/templates/providers/index.js +239 -0
- package/dist/cli/templates/shared/approval-types.d.ts +9 -0
- package/dist/cli/templates/shared/approval-types.js +31 -0
- package/dist/cli/templates/shared/llm-types.d.ts +15 -0
- package/dist/cli/templates/shared/llm-types.js +104 -0
- package/dist/cli/templates/workflows/aggregator.d.ts +7 -0
- package/dist/cli/templates/workflows/aggregator.js +104 -0
- package/dist/cli/templates/workflows/ai-agent-durable.d.ts +8 -0
- package/dist/cli/templates/workflows/ai-agent-durable.js +338 -0
- package/dist/cli/templates/workflows/ai-agent.d.ts +31 -0
- package/dist/cli/templates/workflows/ai-agent.js +326 -0
- package/dist/cli/templates/workflows/ai-chat.d.ts +7 -0
- package/dist/cli/templates/workflows/ai-chat.js +169 -0
- package/dist/cli/templates/workflows/ai-pipeline-durable.d.ts +8 -0
- package/dist/cli/templates/workflows/ai-pipeline-durable.js +330 -0
- package/dist/cli/templates/workflows/ai-rag.d.ts +7 -0
- package/dist/cli/templates/workflows/ai-rag.js +186 -0
- package/dist/cli/templates/workflows/ai-react.d.ts +7 -0
- package/dist/cli/templates/workflows/ai-react.js +294 -0
- package/dist/cli/templates/workflows/conditional.d.ts +12 -0
- package/dist/cli/templates/workflows/conditional.js +142 -0
- package/dist/cli/templates/workflows/error-handler.d.ts +7 -0
- package/dist/cli/templates/workflows/error-handler.js +147 -0
- package/dist/cli/templates/workflows/foreach.d.ts +7 -0
- package/dist/cli/templates/workflows/foreach.js +143 -0
- package/dist/cli/templates/workflows/sequential.d.ts +7 -0
- package/dist/cli/templates/workflows/sequential.js +198 -0
- package/dist/cli/templates/workflows/webhook.d.ts +7 -0
- package/dist/cli/templates/workflows/webhook.js +161 -0
- package/dist/cli/utils/logger.d.ts +15 -0
- package/dist/cli/utils/logger.js +46 -0
- package/dist/constants.d.ts +100 -0
- package/dist/constants.js +125 -0
- package/dist/defaults.d.ts +3 -0
- package/dist/defaults.js +3 -0
- package/dist/deployment/config/defaults.d.ts +29 -0
- package/dist/deployment/config/defaults.js +98 -0
- package/dist/deployment/config/loader.d.ts +24 -0
- package/dist/deployment/config/loader.js +236 -0
- package/dist/deployment/config/types.d.ts +117 -0
- package/dist/deployment/config/types.js +5 -0
- package/dist/deployment/core/adapters.d.ts +90 -0
- package/dist/deployment/core/adapters.js +251 -0
- package/dist/deployment/core/executor.d.ts +62 -0
- package/dist/deployment/core/executor.js +197 -0
- package/dist/deployment/core/formatters.d.ts +57 -0
- package/dist/deployment/core/formatters.js +170 -0
- package/dist/deployment/index.d.ts +31 -0
- package/dist/deployment/index.js +48 -0
- package/dist/deployment/openapi/generator.d.ts +146 -0
- package/dist/deployment/openapi/generator.js +347 -0
- package/dist/deployment/openapi/schema-converter.d.ts +49 -0
- package/dist/deployment/openapi/schema-converter.js +192 -0
- package/dist/deployment/targets/base.d.ts +316 -0
- package/dist/deployment/targets/base.js +823 -0
- package/dist/deployment/targets/cloudflare.d.ts +23 -0
- package/dist/deployment/targets/cloudflare.js +1125 -0
- package/dist/deployment/targets/inngest.d.ts +38 -0
- package/dist/deployment/targets/inngest.js +926 -0
- package/dist/deployment/targets/lambda.d.ts +23 -0
- package/dist/deployment/targets/lambda.js +1289 -0
- package/dist/deployment/targets/vercel.d.ts +23 -0
- package/dist/deployment/targets/vercel.js +886 -0
- package/dist/deployment/types.d.ts +183 -0
- package/dist/deployment/types.js +8 -0
- package/dist/diagram/geometry.d.ts +26 -0
- package/dist/diagram/geometry.js +850 -0
- package/dist/diagram/index.d.ts +16 -0
- package/dist/diagram/index.js +42 -0
- package/dist/diagram/layout.d.ts +11 -0
- package/dist/diagram/layout.js +143 -0
- package/dist/diagram/orthogonal-router.d.ts +79 -0
- package/dist/diagram/orthogonal-router.js +568 -0
- package/dist/diagram/renderer.d.ts +3 -0
- package/dist/diagram/renderer.js +207 -0
- package/dist/diagram/theme.d.ts +20 -0
- package/dist/diagram/theme.js +189 -0
- package/dist/diagram/types.d.ts +70 -0
- package/dist/diagram/types.js +2 -0
- package/dist/diff/WorkflowDiffer.d.ts +13 -0
- package/dist/diff/WorkflowDiffer.js +429 -0
- package/dist/diff/formatDiff.d.ts +10 -0
- package/dist/diff/formatDiff.js +220 -0
- package/dist/diff/impact.d.ts +29 -0
- package/dist/diff/impact.js +119 -0
- package/dist/diff/index.d.ts +10 -0
- package/dist/diff/index.js +9 -0
- package/dist/diff/types.d.ts +138 -0
- package/dist/diff/types.js +35 -0
- package/dist/doc-metadata/extractors/annotations.d.ts +56 -0
- package/dist/doc-metadata/extractors/annotations.js +337 -0
- package/dist/doc-metadata/extractors/cli-commands.d.ts +17 -0
- package/dist/doc-metadata/extractors/cli-commands.js +355 -0
- package/dist/doc-metadata/extractors/mcp-tools.d.ts +16 -0
- package/dist/doc-metadata/extractors/mcp-tools.js +689 -0
- package/dist/doc-metadata/extractors/plugin-api.d.ts +19 -0
- package/dist/doc-metadata/extractors/plugin-api.js +279 -0
- package/dist/doc-metadata/index.d.ts +5 -0
- package/dist/doc-metadata/index.js +4 -0
- package/dist/doc-metadata/types.d.ts +120 -0
- package/dist/doc-metadata/types.js +5 -0
- package/dist/editor-completions/annotationValues.d.ts +12 -0
- package/dist/editor-completions/annotationValues.js +138 -0
- package/dist/editor-completions/contextParser.d.ts +40 -0
- package/dist/editor-completions/contextParser.js +410 -0
- package/dist/editor-completions/dataTypes.d.ts +16 -0
- package/dist/editor-completions/dataTypes.js +95 -0
- package/dist/editor-completions/goToDefinition.d.ts +27 -0
- package/dist/editor-completions/goToDefinition.js +112 -0
- package/dist/editor-completions/index.d.ts +39 -0
- package/dist/editor-completions/index.js +181 -0
- package/dist/editor-completions/jsDocAnnotations.d.ts +29 -0
- package/dist/editor-completions/jsDocAnnotations.js +357 -0
- package/dist/editor-completions/modifierCompletions.d.ts +17 -0
- package/dist/editor-completions/modifierCompletions.js +197 -0
- package/dist/editor-completions/types.d.ts +119 -0
- package/dist/editor-completions/types.js +8 -0
- package/dist/export/index.d.ts +68 -0
- package/dist/export/index.js +1074 -0
- package/dist/export/templates.d.ts +24 -0
- package/dist/export/templates.js +186 -0
- package/dist/friendly-errors.d.ts +35 -0
- package/dist/friendly-errors.js +375 -0
- package/dist/function-like.d.ts +38 -0
- package/dist/function-like.js +83 -0
- package/dist/generated-branding.d.ts +16 -0
- package/dist/generated-branding.js +22 -0
- package/dist/generator/async-detection.d.ts +27 -0
- package/dist/generator/async-detection.js +56 -0
- package/dist/generator/code-utils.d.ts +76 -0
- package/dist/generator/code-utils.js +410 -0
- package/dist/generator/control-flow.d.ts +54 -0
- package/dist/generator/control-flow.js +284 -0
- package/dist/generator/inngest.d.ts +53 -0
- package/dist/generator/inngest.js +1126 -0
- package/dist/generator/scope-function-generator.d.ts +78 -0
- package/dist/generator/scope-function-generator.js +360 -0
- package/dist/generator/unified.d.ts +42 -0
- package/dist/generator/unified.js +1504 -0
- package/dist/generator.d.ts +54 -0
- package/dist/generator.js +100 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +89 -0
- package/dist/jsdoc-parser.d.ts +308 -0
- package/dist/jsdoc-parser.js +923 -0
- package/dist/jsdoc-port-sync/constants.d.ts +41 -0
- package/dist/jsdoc-port-sync/constants.js +103 -0
- package/dist/jsdoc-port-sync/diff.d.ts +76 -0
- package/dist/jsdoc-port-sync/diff.js +319 -0
- package/dist/jsdoc-port-sync/index.d.ts +42 -0
- package/dist/jsdoc-port-sync/index.js +45 -0
- package/dist/jsdoc-port-sync/port-parser.d.ts +68 -0
- package/dist/jsdoc-port-sync/port-parser.js +579 -0
- package/dist/jsdoc-port-sync/rename.d.ts +21 -0
- package/dist/jsdoc-port-sync/rename.js +256 -0
- package/dist/jsdoc-port-sync/signature-parser.d.ts +104 -0
- package/dist/jsdoc-port-sync/signature-parser.js +559 -0
- package/dist/jsdoc-port-sync/sync.d.ts +36 -0
- package/dist/jsdoc-port-sync/sync.js +644 -0
- package/dist/jsdoc-port-sync.d.ts +10 -0
- package/dist/jsdoc-port-sync.js +10 -0
- package/dist/marketplace/index.d.ts +11 -0
- package/dist/marketplace/index.js +10 -0
- package/dist/marketplace/manifest.d.ts +32 -0
- package/dist/marketplace/manifest.js +176 -0
- package/dist/marketplace/registry.d.ts +30 -0
- package/dist/marketplace/registry.js +100 -0
- package/dist/marketplace/types.d.ts +154 -0
- package/dist/marketplace/types.js +9 -0
- package/dist/marketplace/validator.d.ts +13 -0
- package/dist/marketplace/validator.js +131 -0
- package/dist/mcp/auto-registration.d.ts +3 -0
- package/dist/mcp/auto-registration.js +62 -0
- package/dist/mcp/editor-connection.d.ts +50 -0
- package/dist/mcp/editor-connection.js +125 -0
- package/dist/mcp/event-buffer.d.ts +62 -0
- package/dist/mcp/event-buffer.js +150 -0
- package/dist/mcp/index.d.ts +12 -0
- package/dist/mcp/index.js +11 -0
- package/dist/mcp/resources.d.ts +14 -0
- package/dist/mcp/resources.js +55 -0
- package/dist/mcp/response-utils.d.ts +63 -0
- package/dist/mcp/response-utils.js +89 -0
- package/dist/mcp/server.d.ts +4 -0
- package/dist/mcp/server.js +99 -0
- package/dist/mcp/tools-diagram.d.ts +8 -0
- package/dist/mcp/tools-diagram.js +53 -0
- package/dist/mcp/tools-editor.d.ts +5 -0
- package/dist/mcp/tools-editor.js +190 -0
- package/dist/mcp/tools-export.d.ts +9 -0
- package/dist/mcp/tools-export.js +180 -0
- package/dist/mcp/tools-marketplace.d.ts +9 -0
- package/dist/mcp/tools-marketplace.js +132 -0
- package/dist/mcp/tools-pattern.d.ts +3 -0
- package/dist/mcp/tools-pattern.js +783 -0
- package/dist/mcp/tools-query.d.ts +3 -0
- package/dist/mcp/tools-query.js +364 -0
- package/dist/mcp/tools-template.d.ts +10 -0
- package/dist/mcp/tools-template.js +119 -0
- package/dist/mcp/types.d.ts +70 -0
- package/dist/mcp/types.js +8 -0
- package/dist/mcp/workflow-executor.d.ts +47 -0
- package/dist/mcp/workflow-executor.js +133 -0
- package/dist/migration/registry.d.ts +30 -0
- package/dist/migration/registry.js +29 -0
- package/dist/node-types-generator.d.ts +49 -0
- package/dist/node-types-generator.js +139 -0
- package/dist/npm-packages.d.ts +56 -0
- package/dist/npm-packages.js +255 -0
- package/dist/parser.d.ts +204 -0
- package/dist/parser.js +2100 -0
- package/dist/plugin/PluginPanel.d.ts +12 -0
- package/dist/plugin/PluginPanel.js +5 -0
- package/dist/plugin/index.d.ts +13 -0
- package/dist/plugin/index.js +14 -0
- package/dist/plugin/types.d.ts +75 -0
- package/dist/plugin/types.js +8 -0
- package/dist/resolve-package-types.d.ts +17 -0
- package/dist/resolve-package-types.js +123 -0
- package/dist/runtime/CancellationError.d.ts +11 -0
- package/dist/runtime/CancellationError.js +20 -0
- package/dist/runtime/ExecutionContext.d.ts +146 -0
- package/dist/runtime/ExecutionContext.js +235 -0
- package/dist/runtime/builtin-functions.d.ts +8 -0
- package/dist/runtime/builtin-functions.js +549 -0
- package/dist/runtime/events.d.ts +50 -0
- package/dist/runtime/events.js +2 -0
- package/dist/runtime/function-registry.d.ts +59 -0
- package/dist/runtime/function-registry.js +66 -0
- package/dist/runtime/index.d.ts +7 -0
- package/dist/runtime/index.js +7 -0
- package/dist/runtime/parameter-resolver.d.ts +62 -0
- package/dist/runtime/parameter-resolver.js +113 -0
- package/dist/server/index.d.ts +7 -0
- package/dist/server/index.js +6 -0
- package/dist/server/types.d.ts +93 -0
- package/dist/server/types.js +5 -0
- package/dist/server/webhook-server.d.ts +50 -0
- package/dist/server/webhook-server.js +269 -0
- package/dist/server/workflow-registry.d.ts +61 -0
- package/dist/server/workflow-registry.js +202 -0
- package/dist/shared-project.d.ts +9 -0
- package/dist/shared-project.js +28 -0
- package/dist/sugar-optimizer.d.ts +40 -0
- package/dist/sugar-optimizer.js +387 -0
- package/dist/testing/assertions.d.ts +51 -0
- package/dist/testing/assertions.js +127 -0
- package/dist/testing/index.d.ts +30 -0
- package/dist/testing/index.js +24 -0
- package/dist/testing/mock-approval.d.ts +81 -0
- package/dist/testing/mock-approval.js +98 -0
- package/dist/testing/mock-llm.d.ts +124 -0
- package/dist/testing/mock-llm.js +119 -0
- package/dist/testing/recorder.d.ts +72 -0
- package/dist/testing/recorder.js +70 -0
- package/dist/testing/replayer.d.ts +56 -0
- package/dist/testing/replayer.js +143 -0
- package/dist/testing/token-tracker.d.ts +71 -0
- package/dist/testing/token-tracker.js +94 -0
- package/dist/type-checker.d.ts +42 -0
- package/dist/type-checker.js +190 -0
- package/dist/type-mappings.d.ts +29 -0
- package/dist/type-mappings.js +125 -0
- package/dist/types/branded-ports.d.ts +151 -0
- package/dist/types/branded-ports.js +121 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.js +5 -0
- package/dist/types.d.ts +139 -0
- package/dist/types.js +15 -0
- package/dist/utils/error-utils.d.ts +15 -0
- package/dist/utils/error-utils.js +27 -0
- package/dist/utils/lru-cache.d.ts +15 -0
- package/dist/utils/lru-cache.js +40 -0
- package/dist/utils/port-ordering.d.ts +26 -0
- package/dist/utils/port-ordering.js +88 -0
- package/dist/utils/port-tag-utils.d.ts +23 -0
- package/dist/utils/port-tag-utils.js +41 -0
- package/dist/utils/string-distance.d.ts +14 -0
- package/dist/utils/string-distance.js +56 -0
- package/dist/validation/agent-detection.d.ts +33 -0
- package/dist/validation/agent-detection.js +115 -0
- package/dist/validation/agent-rules.d.ts +48 -0
- package/dist/validation/agent-rules.js +262 -0
- package/dist/validator.d.ts +92 -0
- package/dist/validator.js +970 -0
- package/package.json +109 -0
|
@@ -0,0 +1,1126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inngest Deep Code Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates Inngest function code with per-node `step.run()` wrapping,
|
|
5
|
+
* giving each node individual durability, retries, and checkpointing.
|
|
6
|
+
*
|
|
7
|
+
* This is a standalone generator alongside unified.ts — it shares the
|
|
8
|
+
* control-flow analysis layer but produces fundamentally different output:
|
|
9
|
+
* - Local `const` variables instead of `ctx.setVariable()/getVariable()`
|
|
10
|
+
* - `step.run()` per non-expression node for durability
|
|
11
|
+
* - `Promise.all()` for parallel independent nodes
|
|
12
|
+
* - Indexed `step.run()` for forEach/scoped iteration
|
|
13
|
+
* - Branching chain flattening for multi-way routing
|
|
14
|
+
*
|
|
15
|
+
* @module generator/inngest
|
|
16
|
+
*/
|
|
17
|
+
import { toValidIdentifier } from './code-utils.js';
|
|
18
|
+
import { buildControlFlowGraph, detectBranchingChains, findAllBranchingNodes, findNodesInBranch, performKahnsTopologicalSort, isPerPortScopedChild, } from './control-flow.js';
|
|
19
|
+
import { RESERVED_PORT_NAMES, isStartNode, isExitNode, isExecutePort, isSuccessPort, isFailurePort, } from '../constants.js';
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
// Built-in Node Detection
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
const BUILTIN_IMPORT_PREFIX = '@synergenius/flow-weaver/built-in-nodes';
|
|
24
|
+
const BUILT_IN_HANDLERS = {
|
|
25
|
+
delay: 'delay',
|
|
26
|
+
waitForEvent: 'waitForEvent',
|
|
27
|
+
invokeWorkflow: 'invokeWorkflow',
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Check if a node type is a built-in node.
|
|
31
|
+
* Returns the built-in name (e.g. 'delay') or false.
|
|
32
|
+
*/
|
|
33
|
+
function isBuiltInNode(nodeType) {
|
|
34
|
+
// Primary: check import source
|
|
35
|
+
if (nodeType.importSource?.startsWith(BUILTIN_IMPORT_PREFIX)) {
|
|
36
|
+
return nodeType.functionName in BUILT_IN_HANDLERS ? nodeType.functionName : false;
|
|
37
|
+
}
|
|
38
|
+
// Fallback for test fixtures / same-file definitions:
|
|
39
|
+
// Check if function name matches AND the node has the exact built-in signature
|
|
40
|
+
if (nodeType.functionName in BUILT_IN_HANDLERS) {
|
|
41
|
+
return verifyBuiltInSignature(nodeType) ? nodeType.functionName : false;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Verify a node type has the exact built-in signature by checking its input port names.
|
|
47
|
+
*/
|
|
48
|
+
function verifyBuiltInSignature(nodeType) {
|
|
49
|
+
const inputNames = Object.keys(nodeType.inputs).filter((n) => n !== 'execute');
|
|
50
|
+
switch (nodeType.functionName) {
|
|
51
|
+
case 'delay':
|
|
52
|
+
return inputNames.length === 1 && inputNames[0] === 'duration';
|
|
53
|
+
case 'waitForEvent':
|
|
54
|
+
return inputNames.includes('eventName');
|
|
55
|
+
case 'invokeWorkflow':
|
|
56
|
+
return inputNames.includes('functionId') && inputNames.includes('payload');
|
|
57
|
+
default:
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Typed Event Schema (Feature 1)
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
/**
|
|
65
|
+
* Generate Zod event schema from workflow start ports (populated by @param).
|
|
66
|
+
*/
|
|
67
|
+
function generateEventSchema(workflow, eventName) {
|
|
68
|
+
const lines = [];
|
|
69
|
+
const schemaFields = [];
|
|
70
|
+
// workflow.startPorts maps @param annotations
|
|
71
|
+
for (const [name, port] of Object.entries(workflow.startPorts || {})) {
|
|
72
|
+
if (name === 'execute')
|
|
73
|
+
continue; // Skip execute port
|
|
74
|
+
const zodType = mapTypeToZod(port.tsType || port.dataType);
|
|
75
|
+
schemaFields.push(` ${name}: ${zodType},`);
|
|
76
|
+
}
|
|
77
|
+
if (schemaFields.length === 0)
|
|
78
|
+
return [];
|
|
79
|
+
const varName = toValidIdentifier(workflow.functionName) + 'Event';
|
|
80
|
+
lines.push(`const ${varName} = {`);
|
|
81
|
+
lines.push(` name: '${eventName}',`);
|
|
82
|
+
lines.push(` schema: z.object({`);
|
|
83
|
+
lines.push(` data: z.object({`);
|
|
84
|
+
lines.push(...schemaFields);
|
|
85
|
+
lines.push(` }),`);
|
|
86
|
+
lines.push(` }),`);
|
|
87
|
+
lines.push(`};`);
|
|
88
|
+
lines.push('');
|
|
89
|
+
return lines;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Map TypeScript/Flow Weaver types to Zod schema types.
|
|
93
|
+
*/
|
|
94
|
+
function mapTypeToZod(type) {
|
|
95
|
+
if (!type)
|
|
96
|
+
return 'z.unknown()';
|
|
97
|
+
const t = type.trim().toLowerCase();
|
|
98
|
+
if (t === 'string')
|
|
99
|
+
return 'z.string()';
|
|
100
|
+
if (t === 'number')
|
|
101
|
+
return 'z.number()';
|
|
102
|
+
if (t === 'boolean')
|
|
103
|
+
return 'z.boolean()';
|
|
104
|
+
if (t === 'string[]')
|
|
105
|
+
return 'z.array(z.string())';
|
|
106
|
+
if (t === 'number[]')
|
|
107
|
+
return 'z.array(z.number())';
|
|
108
|
+
if (t === 'object' || t.startsWith('record<'))
|
|
109
|
+
return 'z.record(z.unknown())';
|
|
110
|
+
return `z.unknown() /* ${type} */`;
|
|
111
|
+
}
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// Helpers
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
/** Convert camelCase/PascalCase to kebab-case for Inngest IDs */
|
|
116
|
+
function toKebabCase(name) {
|
|
117
|
+
return name
|
|
118
|
+
.replace(/([a-z])([A-Z])/g, '$1-$2')
|
|
119
|
+
.replace(/[^a-zA-Z0-9-]/g, '-')
|
|
120
|
+
.replace(/-+/g, '-')
|
|
121
|
+
.toLowerCase();
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Resolve a port's value source for a given node instance.
|
|
125
|
+
*
|
|
126
|
+
* Unlike `buildNodeArgumentsWithContext` in code-utils.ts which emits
|
|
127
|
+
* `ctx.getVariable()` calls, this returns a plain JS expression referencing
|
|
128
|
+
* local `const` variables produced by earlier `step.run()` calls.
|
|
129
|
+
*/
|
|
130
|
+
function resolvePortValue(portName, instanceId, nodeType, workflow, _nodeTypes) {
|
|
131
|
+
const safeId = toValidIdentifier(instanceId);
|
|
132
|
+
const portDef = nodeType.inputs[portName];
|
|
133
|
+
const instance = workflow.instances.find((i) => i.id === instanceId);
|
|
134
|
+
// Check for instance-level expression override
|
|
135
|
+
const instancePortConfig = instance?.config?.portConfigs?.find((pc) => pc.portName === portName && (pc.direction == null || pc.direction === 'INPUT'));
|
|
136
|
+
if (instancePortConfig?.expression !== undefined) {
|
|
137
|
+
const expr = String(instancePortConfig.expression);
|
|
138
|
+
const isFunction = expr.includes('=>') || expr.trim().startsWith('function');
|
|
139
|
+
if (isFunction) {
|
|
140
|
+
return `await (${expr})()`;
|
|
141
|
+
}
|
|
142
|
+
return expr;
|
|
143
|
+
}
|
|
144
|
+
// Check for connections
|
|
145
|
+
const connections = workflow.connections.filter((conn) => conn.to.node === instanceId && conn.to.port === portName
|
|
146
|
+
&& !conn.from.scope && !conn.to.scope);
|
|
147
|
+
if (connections.length > 0) {
|
|
148
|
+
if (connections.length === 1) {
|
|
149
|
+
const conn = connections[0];
|
|
150
|
+
const sourceNode = conn.from.node;
|
|
151
|
+
const sourcePort = conn.from.port;
|
|
152
|
+
if (isStartNode(sourceNode)) {
|
|
153
|
+
return `event.data.${sourcePort}`;
|
|
154
|
+
}
|
|
155
|
+
const safeSource = toValidIdentifier(sourceNode);
|
|
156
|
+
return `${safeSource}_result.${sourcePort}`;
|
|
157
|
+
}
|
|
158
|
+
// Multiple connections — use first non-undefined (fan-in)
|
|
159
|
+
const attempts = connections.map((conn) => {
|
|
160
|
+
const sourceNode = conn.from.node;
|
|
161
|
+
const sourcePort = conn.from.port;
|
|
162
|
+
if (isStartNode(sourceNode)) {
|
|
163
|
+
return `event.data.${sourcePort}`;
|
|
164
|
+
}
|
|
165
|
+
const safeSource = toValidIdentifier(sourceNode);
|
|
166
|
+
return `${safeSource}_result?.${sourcePort}`;
|
|
167
|
+
});
|
|
168
|
+
return attempts.join(' ?? ');
|
|
169
|
+
}
|
|
170
|
+
// Check for node type expression
|
|
171
|
+
if (portDef?.expression) {
|
|
172
|
+
const expr = portDef.expression;
|
|
173
|
+
const isFunction = expr.includes('=>') || expr.trim().startsWith('function');
|
|
174
|
+
if (isFunction) {
|
|
175
|
+
return `await (${expr})()`;
|
|
176
|
+
}
|
|
177
|
+
return expr;
|
|
178
|
+
}
|
|
179
|
+
// Default value
|
|
180
|
+
if (portDef?.default !== undefined) {
|
|
181
|
+
return JSON.stringify(portDef.default);
|
|
182
|
+
}
|
|
183
|
+
// Optional port
|
|
184
|
+
if (portDef?.optional) {
|
|
185
|
+
return 'undefined';
|
|
186
|
+
}
|
|
187
|
+
// No source — undefined with comment
|
|
188
|
+
return `undefined /* no source for ${safeId}.${portName} */`;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Build the argument list for calling a node function.
|
|
192
|
+
* Returns array of JS expression strings to pass as function arguments.
|
|
193
|
+
*/
|
|
194
|
+
function buildNodeArgs(instanceId, nodeType, workflow, nodeTypes) {
|
|
195
|
+
const args = [];
|
|
196
|
+
// Handle execute port (first arg for non-expression nodes)
|
|
197
|
+
if (!nodeType.expression) {
|
|
198
|
+
const executeConns = workflow.connections.filter((conn) => conn.to.node === instanceId && conn.to.port === 'execute'
|
|
199
|
+
&& !conn.from.scope && !conn.to.scope);
|
|
200
|
+
if (executeConns.length > 0) {
|
|
201
|
+
const conn = executeConns[0];
|
|
202
|
+
if (isStartNode(conn.from.node)) {
|
|
203
|
+
args.push('true');
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
// Delay nodes (step.sleep) have no result variable — use literal values
|
|
207
|
+
const sourceNt = getNodeType(conn.from.node, workflow, nodeTypes);
|
|
208
|
+
if (sourceNt && isBuiltInNode(sourceNt) === 'delay') {
|
|
209
|
+
args.push(conn.from.port === 'onSuccess' ? 'true' : 'false');
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
const safeSource = toValidIdentifier(conn.from.node);
|
|
213
|
+
args.push(`${safeSource}_result.${conn.from.port}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
args.push('true');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// Handle data ports
|
|
222
|
+
for (const portName of Object.keys(nodeType.inputs)) {
|
|
223
|
+
if (isExecutePort(portName))
|
|
224
|
+
continue;
|
|
225
|
+
if (nodeType.inputs[portName].scope)
|
|
226
|
+
continue; // Skip scoped ports
|
|
227
|
+
const value = resolvePortValue(portName, instanceId, nodeType, workflow, nodeTypes);
|
|
228
|
+
args.push(value);
|
|
229
|
+
}
|
|
230
|
+
return args;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Look up a node type for an instance.
|
|
234
|
+
*/
|
|
235
|
+
function getNodeType(instanceId, workflow, nodeTypes) {
|
|
236
|
+
const instance = workflow.instances.find((i) => i.id === instanceId);
|
|
237
|
+
if (!instance)
|
|
238
|
+
return undefined;
|
|
239
|
+
return nodeTypes.find((nt) => nt.name === instance.nodeType || nt.functionName === instance.nodeType);
|
|
240
|
+
}
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
// Parallel Detection
|
|
243
|
+
// ---------------------------------------------------------------------------
|
|
244
|
+
/**
|
|
245
|
+
* Detect parallelizable groups within a list of node IDs.
|
|
246
|
+
*
|
|
247
|
+
* For each node, compute its direct predecessors within the given set.
|
|
248
|
+
* Nodes with identical predecessor sets can execute in parallel.
|
|
249
|
+
*
|
|
250
|
+
* Returns an ordered list of groups preserving topological order.
|
|
251
|
+
*/
|
|
252
|
+
function detectParallelInList(nodeIds, workflow, nodeTypes) {
|
|
253
|
+
if (nodeIds.length <= 1)
|
|
254
|
+
return nodeIds.map((n) => [n]);
|
|
255
|
+
// Build mini-CFG: for each node, which other nodes in the list feed into it?
|
|
256
|
+
const predecessors = new Map();
|
|
257
|
+
const nodeSet = new Set(nodeIds);
|
|
258
|
+
for (const nodeId of nodeIds) {
|
|
259
|
+
const preds = new Set();
|
|
260
|
+
for (const conn of workflow.connections) {
|
|
261
|
+
if (conn.to.node !== nodeId)
|
|
262
|
+
continue;
|
|
263
|
+
if (conn.from.scope || conn.to.scope)
|
|
264
|
+
continue;
|
|
265
|
+
const fromNode = conn.from.node;
|
|
266
|
+
if (nodeSet.has(fromNode)) {
|
|
267
|
+
preds.add(fromNode);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
predecessors.set(nodeId, preds);
|
|
271
|
+
}
|
|
272
|
+
// Group by predecessor set (serialized for comparison)
|
|
273
|
+
const groups = [];
|
|
274
|
+
const processed = new Set();
|
|
275
|
+
for (const nodeId of nodeIds) {
|
|
276
|
+
if (processed.has(nodeId))
|
|
277
|
+
continue;
|
|
278
|
+
const preds = predecessors.get(nodeId);
|
|
279
|
+
const predsKey = Array.from(preds).sort().join(',');
|
|
280
|
+
const parallel = [nodeId];
|
|
281
|
+
for (const other of nodeIds) {
|
|
282
|
+
if (other === nodeId || processed.has(other))
|
|
283
|
+
continue;
|
|
284
|
+
const otherPreds = predecessors.get(other);
|
|
285
|
+
const otherKey = Array.from(otherPreds).sort().join(',');
|
|
286
|
+
if (predsKey === otherKey) {
|
|
287
|
+
parallel.push(other);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
for (const n of parallel) {
|
|
291
|
+
processed.add(n);
|
|
292
|
+
}
|
|
293
|
+
groups.push(parallel);
|
|
294
|
+
}
|
|
295
|
+
return groups;
|
|
296
|
+
}
|
|
297
|
+
// ---------------------------------------------------------------------------
|
|
298
|
+
// Code Generation — Core Emitters
|
|
299
|
+
// ---------------------------------------------------------------------------
|
|
300
|
+
/**
|
|
301
|
+
* Generate a step.run() call for a durable node.
|
|
302
|
+
*/
|
|
303
|
+
function generateStepRunCall(instanceId, nodeType, workflow, nodeTypes, indent) {
|
|
304
|
+
const args = buildNodeArgs(instanceId, nodeType, workflow, nodeTypes);
|
|
305
|
+
const safeId = toValidIdentifier(instanceId);
|
|
306
|
+
const fnCall = `${nodeType.functionName}(${args.join(', ')})`;
|
|
307
|
+
const awaitPrefix = nodeType.isAsync ? 'await ' : '';
|
|
308
|
+
return `${indent}${safeId}_result = await step.run('${instanceId}', async () => {\n` +
|
|
309
|
+
`${indent} return ${awaitPrefix}${fnCall};\n` +
|
|
310
|
+
`${indent}});`;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Generate an inline call for an expression node (no step.run wrapper).
|
|
314
|
+
*/
|
|
315
|
+
function generateExpressionCall(instanceId, nodeType, workflow, nodeTypes, indent) {
|
|
316
|
+
const args = buildNodeArgs(instanceId, nodeType, workflow, nodeTypes);
|
|
317
|
+
const safeId = toValidIdentifier(instanceId);
|
|
318
|
+
const fnCall = `${nodeType.functionName}(${args.join(', ')})`;
|
|
319
|
+
const awaitPrefix = nodeType.isAsync ? 'await ' : '';
|
|
320
|
+
return `${indent}${safeId}_result = ${awaitPrefix}${fnCall};`;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Emit the step.run or expression call for a single node.
|
|
324
|
+
* Built-in nodes (delay, waitForEvent, invokeWorkflow) are emitted with their
|
|
325
|
+
* corresponding Inngest step primitives instead of step.run().
|
|
326
|
+
*/
|
|
327
|
+
function emitNodeCall(nodeId, nodeType, workflow, nodeTypes, indent, lines) {
|
|
328
|
+
const builtIn = isBuiltInNode(nodeType);
|
|
329
|
+
if (builtIn === 'delay') {
|
|
330
|
+
const args = buildNodeArgs(nodeId, nodeType, workflow, nodeTypes);
|
|
331
|
+
const durationArg = args[1]; // args[0] is execute=true, args[1] is duration
|
|
332
|
+
lines.push(`${indent}await step.sleep('${nodeId}', ${durationArg});`);
|
|
333
|
+
lines.push('');
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
if (builtIn === 'waitForEvent') {
|
|
337
|
+
const safeId = toValidIdentifier(nodeId);
|
|
338
|
+
const args = buildNodeArgs(nodeId, nodeType, workflow, nodeTypes);
|
|
339
|
+
const eventNameArg = args[1]; // execute=args[0], eventName=args[1]
|
|
340
|
+
const matchArg = args[2]; // optional
|
|
341
|
+
const timeoutArg = args[3]; // optional
|
|
342
|
+
lines.push(`${indent}const ${safeId}_raw = await step.waitForEvent('${nodeId}', {`);
|
|
343
|
+
lines.push(`${indent} event: ${eventNameArg},`);
|
|
344
|
+
if (matchArg && matchArg !== 'undefined') {
|
|
345
|
+
lines.push(`${indent} match: ${matchArg},`);
|
|
346
|
+
}
|
|
347
|
+
if (timeoutArg && timeoutArg !== 'undefined') {
|
|
348
|
+
lines.push(`${indent} timeout: ${timeoutArg},`);
|
|
349
|
+
}
|
|
350
|
+
lines.push(`${indent}});`);
|
|
351
|
+
lines.push(`${indent}${safeId}_result = ${safeId}_raw`);
|
|
352
|
+
lines.push(`${indent} ? { onSuccess: true, onFailure: false, eventData: ${safeId}_raw.data }`);
|
|
353
|
+
lines.push(`${indent} : { onSuccess: false, onFailure: true, eventData: {} };`);
|
|
354
|
+
lines.push('');
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (builtIn === 'invokeWorkflow') {
|
|
358
|
+
const safeId = toValidIdentifier(nodeId);
|
|
359
|
+
const args = buildNodeArgs(nodeId, nodeType, workflow, nodeTypes);
|
|
360
|
+
const functionIdArg = args[1];
|
|
361
|
+
const payloadArg = args[2];
|
|
362
|
+
const timeoutArg = args[3];
|
|
363
|
+
lines.push(`${indent}try {`);
|
|
364
|
+
lines.push(`${indent} ${safeId}_result = await step.invoke('${nodeId}', {`);
|
|
365
|
+
lines.push(`${indent} function: ${functionIdArg},`);
|
|
366
|
+
lines.push(`${indent} data: ${payloadArg},`);
|
|
367
|
+
if (timeoutArg && timeoutArg !== 'undefined') {
|
|
368
|
+
lines.push(`${indent} timeout: ${timeoutArg},`);
|
|
369
|
+
}
|
|
370
|
+
lines.push(`${indent} });`);
|
|
371
|
+
lines.push(`${indent} ${safeId}_result = { onSuccess: true, onFailure: false, result: ${safeId}_result };`);
|
|
372
|
+
lines.push(`${indent}} catch (err) {`);
|
|
373
|
+
lines.push(`${indent} ${safeId}_result = { onSuccess: false, onFailure: true, result: {} };`);
|
|
374
|
+
lines.push(`${indent}}`);
|
|
375
|
+
lines.push('');
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
if (nodeType.expression) {
|
|
379
|
+
lines.push(generateExpressionCall(nodeId, nodeType, workflow, nodeTypes, indent));
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
lines.push(generateStepRunCall(nodeId, nodeType, workflow, nodeTypes, indent));
|
|
383
|
+
}
|
|
384
|
+
lines.push('');
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Ensure all expression node dependencies for a given node are emitted before it.
|
|
388
|
+
* Expression nodes are pure functions that can be safely emitted inline wherever needed.
|
|
389
|
+
*/
|
|
390
|
+
function ensureExpressionDependencies(nodeId, workflow, nodeTypes, indent, lines, generatedNodes) {
|
|
391
|
+
for (const conn of workflow.connections) {
|
|
392
|
+
if (conn.to.node !== nodeId)
|
|
393
|
+
continue;
|
|
394
|
+
if (conn.from.scope || conn.to.scope)
|
|
395
|
+
continue;
|
|
396
|
+
const fromNode = conn.from.node;
|
|
397
|
+
if (isStartNode(fromNode) || isExitNode(fromNode))
|
|
398
|
+
continue;
|
|
399
|
+
if (generatedNodes.has(fromNode))
|
|
400
|
+
continue;
|
|
401
|
+
const nt = getNodeType(fromNode, workflow, nodeTypes);
|
|
402
|
+
if (!nt || !nt.expression)
|
|
403
|
+
continue;
|
|
404
|
+
// Recursively ensure this expression's own dependencies first
|
|
405
|
+
ensureExpressionDependencies(fromNode, workflow, nodeTypes, indent, lines, generatedNodes);
|
|
406
|
+
if (generatedNodes.has(fromNode))
|
|
407
|
+
continue;
|
|
408
|
+
// Emit the expression node inline
|
|
409
|
+
generatedNodes.add(fromNode);
|
|
410
|
+
lines.push(generateExpressionCall(fromNode, nt, workflow, nodeTypes, indent));
|
|
411
|
+
lines.push('');
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Emit the if/else branching body for a branching node (without the step.run call).
|
|
416
|
+
* Used after Promise.all to emit branching bodies separately from the step execution.
|
|
417
|
+
*/
|
|
418
|
+
function emitBranchingBody(nodeId, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes) {
|
|
419
|
+
const safeId = toValidIdentifier(nodeId);
|
|
420
|
+
const region = branchRegions.get(nodeId);
|
|
421
|
+
if (!region)
|
|
422
|
+
return;
|
|
423
|
+
const hasSuccessBranch = region.successNodes.size > 0;
|
|
424
|
+
const hasFailureBranch = region.failureNodes.size > 0;
|
|
425
|
+
if (!hasSuccessBranch && !hasFailureBranch)
|
|
426
|
+
return;
|
|
427
|
+
// Delay nodes (step.sleep) always succeed — emit success branch directly, no if/else
|
|
428
|
+
const branchNodeType = getNodeType(nodeId, workflow, nodeTypes);
|
|
429
|
+
if (branchNodeType && isBuiltInNode(branchNodeType) === 'delay') {
|
|
430
|
+
if (hasSuccessBranch) {
|
|
431
|
+
const successOrder = getOrderedNodes(Array.from(region.successNodes), workflow, nodeTypes);
|
|
432
|
+
generateNodeBlock(successOrder, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes);
|
|
433
|
+
}
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
lines.push(`${indent}if (${safeId}_result.onSuccess) {`);
|
|
437
|
+
if (hasSuccessBranch) {
|
|
438
|
+
const successOrder = getOrderedNodes(Array.from(region.successNodes), workflow, nodeTypes);
|
|
439
|
+
generateNodeBlock(successOrder, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent + ' ', lines, generatedNodes);
|
|
440
|
+
}
|
|
441
|
+
if (hasFailureBranch) {
|
|
442
|
+
lines.push(`${indent}} else {`);
|
|
443
|
+
const failureOrder = getOrderedNodes(Array.from(region.failureNodes), workflow, nodeTypes);
|
|
444
|
+
generateNodeBlock(failureOrder, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent + ' ', lines, generatedNodes);
|
|
445
|
+
lines.push(`${indent}}`);
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
lines.push(`${indent}}`);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Emit a Promise.all block for 2+ parallel nodes.
|
|
453
|
+
* Delay nodes are excluded and emitted separately (step.sleep returns void).
|
|
454
|
+
* waitForEvent/invokeWorkflow get their Inngest step primitives instead of step.run.
|
|
455
|
+
*/
|
|
456
|
+
function emitPromiseAll(nodeIds, workflow, nodeTypes, indent, lines, generatedNodes) {
|
|
457
|
+
// Separate delay nodes from the group (step.sleep returns void, breaks destructuring)
|
|
458
|
+
const delayNodes = [];
|
|
459
|
+
const nonDelayNodes = [];
|
|
460
|
+
for (const nodeId of nodeIds) {
|
|
461
|
+
const nt = getNodeType(nodeId, workflow, nodeTypes);
|
|
462
|
+
if (nt && isBuiltInNode(nt) === 'delay') {
|
|
463
|
+
delayNodes.push(nodeId);
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
nonDelayNodes.push(nodeId);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
// Emit delay nodes sequentially first
|
|
470
|
+
for (const delayId of delayNodes) {
|
|
471
|
+
generatedNodes.add(delayId);
|
|
472
|
+
const nt = getNodeType(delayId, workflow, nodeTypes);
|
|
473
|
+
emitNodeCall(delayId, nt, workflow, nodeTypes, indent, lines);
|
|
474
|
+
}
|
|
475
|
+
// If only 1 non-delay node remains, emit it directly
|
|
476
|
+
if (nonDelayNodes.length === 1) {
|
|
477
|
+
const nodeId = nonDelayNodes[0];
|
|
478
|
+
generatedNodes.add(nodeId);
|
|
479
|
+
const nt = getNodeType(nodeId, workflow, nodeTypes);
|
|
480
|
+
emitNodeCall(nodeId, nt, workflow, nodeTypes, indent, lines);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
if (nonDelayNodes.length === 0)
|
|
484
|
+
return;
|
|
485
|
+
const destructured = [];
|
|
486
|
+
const stepCalls = [];
|
|
487
|
+
for (const nodeId of nonDelayNodes) {
|
|
488
|
+
generatedNodes.add(nodeId);
|
|
489
|
+
const nt = getNodeType(nodeId, workflow, nodeTypes);
|
|
490
|
+
const safeId = toValidIdentifier(nodeId);
|
|
491
|
+
const builtIn = isBuiltInNode(nt);
|
|
492
|
+
if (builtIn === 'waitForEvent') {
|
|
493
|
+
const args = buildNodeArgs(nodeId, nt, workflow, nodeTypes);
|
|
494
|
+
const eventNameArg = args[1];
|
|
495
|
+
const matchArg = args[2];
|
|
496
|
+
const timeoutArg = args[3];
|
|
497
|
+
let waitCall = `${indent} step.waitForEvent('${nodeId}', { event: ${eventNameArg}`;
|
|
498
|
+
if (matchArg && matchArg !== 'undefined')
|
|
499
|
+
waitCall += `, match: ${matchArg}`;
|
|
500
|
+
if (timeoutArg && timeoutArg !== 'undefined')
|
|
501
|
+
waitCall += `, timeout: ${timeoutArg}`;
|
|
502
|
+
waitCall += ` })`;
|
|
503
|
+
stepCalls.push(waitCall);
|
|
504
|
+
}
|
|
505
|
+
else if (builtIn === 'invokeWorkflow') {
|
|
506
|
+
const args = buildNodeArgs(nodeId, nt, workflow, nodeTypes);
|
|
507
|
+
const functionIdArg = args[1];
|
|
508
|
+
const payloadArg = args[2];
|
|
509
|
+
const timeoutArg = args[3];
|
|
510
|
+
let invokeCall = `${indent} step.invoke('${nodeId}', { function: ${functionIdArg}, data: ${payloadArg}`;
|
|
511
|
+
if (timeoutArg && timeoutArg !== 'undefined')
|
|
512
|
+
invokeCall += `, timeout: ${timeoutArg}`;
|
|
513
|
+
invokeCall += ` })`;
|
|
514
|
+
stepCalls.push(invokeCall);
|
|
515
|
+
}
|
|
516
|
+
else if (nt.expression) {
|
|
517
|
+
const args = buildNodeArgs(nodeId, nt, workflow, nodeTypes);
|
|
518
|
+
const fnCall = `${nt.functionName}(${args.join(', ')})`;
|
|
519
|
+
stepCalls.push(`${indent} Promise.resolve(${fnCall})`);
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
const args = buildNodeArgs(nodeId, nt, workflow, nodeTypes);
|
|
523
|
+
const fnCall = `${nt.functionName}(${args.join(', ')})`;
|
|
524
|
+
const awaitPrefix = nt.isAsync ? 'await ' : '';
|
|
525
|
+
stepCalls.push(`${indent} step.run('${nodeId}', async () => ${awaitPrefix}${fnCall})`);
|
|
526
|
+
}
|
|
527
|
+
destructured.push(`${safeId}_result`);
|
|
528
|
+
}
|
|
529
|
+
lines.push(`${indent}[${destructured.join(', ')}] = await Promise.all([`);
|
|
530
|
+
lines.push(stepCalls.join(',\n'));
|
|
531
|
+
lines.push(`${indent}]);`);
|
|
532
|
+
lines.push('');
|
|
533
|
+
}
|
|
534
|
+
// ---------------------------------------------------------------------------
|
|
535
|
+
// Code Generation — forEach / Scoped Iteration
|
|
536
|
+
// ---------------------------------------------------------------------------
|
|
537
|
+
/**
|
|
538
|
+
* Generate code for forEach/scoped iteration patterns.
|
|
539
|
+
*
|
|
540
|
+
* Per-port scoped children execute inside a loop with indexed step names
|
|
541
|
+
* for per-item durability: step.run(`processItem-${i}`, ...).
|
|
542
|
+
*/
|
|
543
|
+
function generateForEachScope(parentId, parentNodeType, scopeName, workflow, nodeTypes, indent, lines) {
|
|
544
|
+
const safeParent = toValidIdentifier(parentId);
|
|
545
|
+
// Find child instances in this scope
|
|
546
|
+
const childInstances = workflow.instances.filter((inst) => {
|
|
547
|
+
if (!inst.parent)
|
|
548
|
+
return false;
|
|
549
|
+
return inst.parent.id === parentId && inst.parent.scope === scopeName;
|
|
550
|
+
});
|
|
551
|
+
if (childInstances.length === 0)
|
|
552
|
+
return;
|
|
553
|
+
// Find the output port that provides items to iterate
|
|
554
|
+
// Look for scoped output ports (these are parameters TO children)
|
|
555
|
+
const scopedOutputPorts = Object.entries(parentNodeType.outputs).filter(([_name, portDef]) => portDef.scope === scopeName);
|
|
556
|
+
// The 'item' port (or similar) carries the current iteration value
|
|
557
|
+
const itemPort = scopedOutputPorts.find(([name]) => name !== 'start' && name !== 'success' && name !== 'failure');
|
|
558
|
+
if (!itemPort) {
|
|
559
|
+
// No item port — just a simple callback scope, not forEach
|
|
560
|
+
lines.push(`${indent}// Scope '${scopeName}' for ${parentId} (callback pattern)`);
|
|
561
|
+
for (const child of childInstances) {
|
|
562
|
+
const childNt = getNodeType(child.id, workflow, nodeTypes);
|
|
563
|
+
if (!childNt)
|
|
564
|
+
continue;
|
|
565
|
+
lines.push(`${indent}const ${toValidIdentifier(child.id)}_result = await step.run('${child.id}', async () => {`);
|
|
566
|
+
const args = buildNodeArgs(child.id, childNt, workflow, nodeTypes);
|
|
567
|
+
const fnCall = `${childNt.functionName}(${args.join(', ')})`;
|
|
568
|
+
const awaitPrefix = childNt.isAsync ? 'await ' : '';
|
|
569
|
+
lines.push(`${indent} return ${awaitPrefix}${fnCall};`);
|
|
570
|
+
lines.push(`${indent}});`);
|
|
571
|
+
lines.push('');
|
|
572
|
+
}
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
// Find the source that provides the array to iterate
|
|
576
|
+
// The parent's result should have the items
|
|
577
|
+
const [itemPortName] = itemPort;
|
|
578
|
+
const arraySource = `${safeParent}_result.${itemPortName}`;
|
|
579
|
+
// Generate the loop with indexed step names
|
|
580
|
+
lines.push(`${indent}const ${safeParent}_${scopeName}_results = [];`);
|
|
581
|
+
lines.push(`${indent}for (let __i__ = 0; __i__ < ${arraySource}.length; __i__++) {`);
|
|
582
|
+
lines.push(`${indent} const __item__ = ${arraySource}[__i__];`);
|
|
583
|
+
for (const child of childInstances) {
|
|
584
|
+
const childNt = getNodeType(child.id, workflow, nodeTypes);
|
|
585
|
+
if (!childNt)
|
|
586
|
+
continue;
|
|
587
|
+
const safeChild = toValidIdentifier(child.id);
|
|
588
|
+
// Build args, replacing the scoped connection with __item__
|
|
589
|
+
const args = [];
|
|
590
|
+
if (!childNt.expression) {
|
|
591
|
+
args.push('true'); // execute = true
|
|
592
|
+
}
|
|
593
|
+
for (const portName of Object.keys(childNt.inputs)) {
|
|
594
|
+
if (isExecutePort(portName))
|
|
595
|
+
continue;
|
|
596
|
+
if (childNt.inputs[portName].scope)
|
|
597
|
+
continue;
|
|
598
|
+
// Check if this port connects from the scope's item port
|
|
599
|
+
const scopedConn = workflow.connections.find((conn) => conn.to.node === child.id && conn.to.port === portName
|
|
600
|
+
&& conn.from.node === parentId && conn.from.port === itemPortName);
|
|
601
|
+
if (scopedConn) {
|
|
602
|
+
args.push('__item__');
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
args.push(resolvePortValue(portName, child.id, childNt, workflow, nodeTypes));
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
const fnCall = `${childNt.functionName}(${args.join(', ')})`;
|
|
609
|
+
const awaitPrefix = childNt.isAsync ? 'await ' : '';
|
|
610
|
+
if (childNt.expression) {
|
|
611
|
+
lines.push(`${indent} const ${safeChild}_result = ${awaitPrefix}${fnCall};`);
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
lines.push(`${indent} const ${safeChild}_result = await step.run(\`${child.id}-\${__i__}\`, async () => {`);
|
|
615
|
+
lines.push(`${indent} return ${awaitPrefix}${fnCall};`);
|
|
616
|
+
lines.push(`${indent} });`);
|
|
617
|
+
}
|
|
618
|
+
lines.push(`${indent} ${safeParent}_${scopeName}_results.push(${safeChild}_result);`);
|
|
619
|
+
}
|
|
620
|
+
lines.push(`${indent}}`);
|
|
621
|
+
lines.push('');
|
|
622
|
+
}
|
|
623
|
+
// ---------------------------------------------------------------------------
|
|
624
|
+
// Code Generation — Block Generation with Parallelism & Branching
|
|
625
|
+
// ---------------------------------------------------------------------------
|
|
626
|
+
/**
|
|
627
|
+
* Generate code for a set of nodes, handling branching, parallelism, and chains.
|
|
628
|
+
*
|
|
629
|
+
* This is the recursive core called for top-level nodes and branch bodies.
|
|
630
|
+
*/
|
|
631
|
+
function generateNodeBlock(nodeIds, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes) {
|
|
632
|
+
// Filter to ungenerated real nodes
|
|
633
|
+
const remaining = nodeIds.filter((n) => !generatedNodes.has(n) && !isStartNode(n) && !isExitNode(n));
|
|
634
|
+
if (remaining.length === 0)
|
|
635
|
+
return;
|
|
636
|
+
// Detect parallelism within this block
|
|
637
|
+
const groups = detectParallelInList(remaining, workflow, nodeTypes);
|
|
638
|
+
for (const group of groups) {
|
|
639
|
+
const eligible = group.filter((n) => !generatedNodes.has(n));
|
|
640
|
+
if (eligible.length === 0)
|
|
641
|
+
continue;
|
|
642
|
+
if (eligible.length >= 2) {
|
|
643
|
+
// Check if all are expression nodes (no need for Promise.all)
|
|
644
|
+
const allExpr = eligible.every((n) => {
|
|
645
|
+
const nt = getNodeType(n, workflow, nodeTypes);
|
|
646
|
+
return nt?.expression;
|
|
647
|
+
});
|
|
648
|
+
if (allExpr) {
|
|
649
|
+
for (const nodeId of eligible) {
|
|
650
|
+
emitSingleNode(nodeId, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
// Separate expression nodes, chain heads, and parallelizable step.run nodes
|
|
655
|
+
const exprNodes = eligible.filter((n) => {
|
|
656
|
+
const nt = getNodeType(n, workflow, nodeTypes);
|
|
657
|
+
return nt?.expression;
|
|
658
|
+
});
|
|
659
|
+
const chainHeadNodes = eligible.filter((n) => {
|
|
660
|
+
const nt = getNodeType(n, workflow, nodeTypes);
|
|
661
|
+
return nt && !nt.expression && branchingChains.has(n);
|
|
662
|
+
});
|
|
663
|
+
const parallelStepNodes = eligible.filter((n) => {
|
|
664
|
+
const nt = getNodeType(n, workflow, nodeTypes);
|
|
665
|
+
return nt && !nt.expression && !branchingChains.has(n);
|
|
666
|
+
});
|
|
667
|
+
// Emit expression nodes individually first (may be data dependencies)
|
|
668
|
+
for (const nodeId of exprNodes) {
|
|
669
|
+
emitSingleNode(nodeId, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes);
|
|
670
|
+
}
|
|
671
|
+
// Ensure expression dependencies for all parallel step nodes
|
|
672
|
+
for (const nodeId of parallelStepNodes) {
|
|
673
|
+
ensureExpressionDependencies(nodeId, workflow, nodeTypes, indent, lines, generatedNodes);
|
|
674
|
+
}
|
|
675
|
+
// Emit step.run nodes via Promise.all (includes branching nodes)
|
|
676
|
+
if (parallelStepNodes.length >= 2) {
|
|
677
|
+
emitPromiseAll(parallelStepNodes, workflow, nodeTypes, indent, lines, generatedNodes);
|
|
678
|
+
// After Promise.all, emit branching bodies for any branching nodes
|
|
679
|
+
for (const nodeId of parallelStepNodes) {
|
|
680
|
+
if (branchingNodes.has(nodeId) && branchRegions.has(nodeId)) {
|
|
681
|
+
emitBranchingBody(nodeId, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
else {
|
|
686
|
+
for (const nodeId of parallelStepNodes) {
|
|
687
|
+
emitSingleNode(nodeId, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes);
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
// Emit chain head nodes sequentially (they manage their own chain)
|
|
691
|
+
for (const nodeId of chainHeadNodes) {
|
|
692
|
+
emitSingleNode(nodeId, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
// Single node — standard emission
|
|
698
|
+
for (const nodeId of eligible) {
|
|
699
|
+
emitSingleNode(nodeId, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Emit code for a single node — dispatches to the right emitter.
|
|
706
|
+
*/
|
|
707
|
+
function emitSingleNode(nodeId, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes) {
|
|
708
|
+
if (generatedNodes.has(nodeId))
|
|
709
|
+
return;
|
|
710
|
+
const nodeType = getNodeType(nodeId, workflow, nodeTypes);
|
|
711
|
+
if (!nodeType)
|
|
712
|
+
return;
|
|
713
|
+
// Skip chain members — they'll be emitted by their chain head
|
|
714
|
+
if (chainMembers.has(nodeId))
|
|
715
|
+
return;
|
|
716
|
+
// Ensure expression node dependencies are emitted first
|
|
717
|
+
ensureExpressionDependencies(nodeId, workflow, nodeTypes, indent, lines, generatedNodes);
|
|
718
|
+
generatedNodes.add(nodeId);
|
|
719
|
+
// Check if this is the head of a branching chain
|
|
720
|
+
const chain = branchingChains.get(nodeId);
|
|
721
|
+
if (chain && branchingNodes.has(nodeId)) {
|
|
722
|
+
generateBranchingChain(chain, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes);
|
|
723
|
+
return;
|
|
724
|
+
}
|
|
725
|
+
// Check for forEach/scoped children
|
|
726
|
+
const hasPerPortScopedChildren = workflow.instances.some((inst) => inst.parent && inst.parent.id === nodeId
|
|
727
|
+
&& isPerPortScopedChild(inst, workflow, nodeTypes));
|
|
728
|
+
if (branchingNodes.has(nodeId) && branchRegions.has(nodeId)) {
|
|
729
|
+
generateBranchingNode(nodeId, nodeType, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes);
|
|
730
|
+
}
|
|
731
|
+
else {
|
|
732
|
+
emitNodeCall(nodeId, nodeType, workflow, nodeTypes, indent, lines);
|
|
733
|
+
}
|
|
734
|
+
// Emit scoped children (forEach) after the parent node
|
|
735
|
+
if (hasPerPortScopedChildren) {
|
|
736
|
+
const scopeNames = new Set();
|
|
737
|
+
if (nodeType.scope)
|
|
738
|
+
scopeNames.add(nodeType.scope);
|
|
739
|
+
if (nodeType.scopes) {
|
|
740
|
+
for (const s of nodeType.scopes)
|
|
741
|
+
scopeNames.add(s);
|
|
742
|
+
}
|
|
743
|
+
// Also collect from port definitions
|
|
744
|
+
for (const portDef of Object.values(nodeType.outputs)) {
|
|
745
|
+
if (portDef.scope)
|
|
746
|
+
scopeNames.add(portDef.scope);
|
|
747
|
+
}
|
|
748
|
+
for (const portDef of Object.values(nodeType.inputs)) {
|
|
749
|
+
if (portDef.scope)
|
|
750
|
+
scopeNames.add(portDef.scope);
|
|
751
|
+
}
|
|
752
|
+
scopeNames.forEach((scopeName) => {
|
|
753
|
+
generateForEachScope(nodeId, nodeType, scopeName, workflow, nodeTypes, indent, lines);
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Generate code for a branching node (has onSuccess/onFailure connections).
|
|
759
|
+
*/
|
|
760
|
+
function generateBranchingNode(nodeId, nodeType, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes) {
|
|
761
|
+
// Generate the step.run / expression call for this node
|
|
762
|
+
emitNodeCall(nodeId, nodeType, workflow, nodeTypes, indent, lines);
|
|
763
|
+
// Emit the if/else branching body
|
|
764
|
+
emitBranchingBody(nodeId, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes);
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* Generate a chain of branching nodes as flat if/else if/else.
|
|
768
|
+
*
|
|
769
|
+
* Chains are sequential branching nodes where one direction has exactly one
|
|
770
|
+
* branching child and the other has zero. Flattening reduces nesting depth.
|
|
771
|
+
*
|
|
772
|
+
* Generated structure:
|
|
773
|
+
* step.run(A)
|
|
774
|
+
* if (!A.onSuccess) { ...A failure body... }
|
|
775
|
+
* step.run(B) // B is in A's success path
|
|
776
|
+
* else if (!B.onSuccess) { ...B failure body... }
|
|
777
|
+
* else { ...last node's success body... }
|
|
778
|
+
*/
|
|
779
|
+
function generateBranchingChain(chain, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes) {
|
|
780
|
+
for (let i = 0; i < chain.length; i++) {
|
|
781
|
+
const nodeId = chain[i];
|
|
782
|
+
const safeId = toValidIdentifier(nodeId);
|
|
783
|
+
const nodeType = getNodeType(nodeId, workflow, nodeTypes);
|
|
784
|
+
// Ensure expression dependencies before emitting this chain node
|
|
785
|
+
ensureExpressionDependencies(nodeId, workflow, nodeTypes, indent, lines, generatedNodes);
|
|
786
|
+
generatedNodes.add(nodeId);
|
|
787
|
+
// Emit step.run / expression call for this chain node
|
|
788
|
+
if (nodeType) {
|
|
789
|
+
emitNodeCall(nodeId, nodeType, workflow, nodeTypes, indent, lines);
|
|
790
|
+
}
|
|
791
|
+
const region = branchRegions.get(nodeId);
|
|
792
|
+
if (!region)
|
|
793
|
+
continue;
|
|
794
|
+
const hasSuccessBranch = region.successNodes.size > 0;
|
|
795
|
+
const hasFailureBranch = region.failureNodes.size > 0;
|
|
796
|
+
if (!hasSuccessBranch && !hasFailureBranch)
|
|
797
|
+
continue;
|
|
798
|
+
const nextInChain = i + 1 < chain.length ? chain[i + 1] : null;
|
|
799
|
+
const isLast = !nextInChain;
|
|
800
|
+
const chainViaSuccess = nextInChain && region.successNodes.has(nextInChain);
|
|
801
|
+
const chainViaFailure = nextInChain && region.failureNodes.has(nextInChain);
|
|
802
|
+
if (isLast) {
|
|
803
|
+
// Delay nodes (step.sleep) always succeed — emit success branch directly, no if/else
|
|
804
|
+
if (nodeType && isBuiltInNode(nodeType) === 'delay') {
|
|
805
|
+
if (hasSuccessBranch) {
|
|
806
|
+
const successOrder = getOrderedNodes(Array.from(region.successNodes), workflow, nodeTypes);
|
|
807
|
+
generateNodeBlock(successOrder, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
else if (hasSuccessBranch || hasFailureBranch) {
|
|
811
|
+
// Last node in chain — emit standard branching for both sides
|
|
812
|
+
lines.push(`${indent}if (${safeId}_result.onSuccess) {`);
|
|
813
|
+
if (hasSuccessBranch) {
|
|
814
|
+
const successOrder = getOrderedNodes(Array.from(region.successNodes), workflow, nodeTypes);
|
|
815
|
+
generateNodeBlock(successOrder, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent + ' ', lines, generatedNodes);
|
|
816
|
+
}
|
|
817
|
+
if (hasFailureBranch) {
|
|
818
|
+
lines.push(`${indent}} else {`);
|
|
819
|
+
const failureOrder = getOrderedNodes(Array.from(region.failureNodes), workflow, nodeTypes);
|
|
820
|
+
generateNodeBlock(failureOrder, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent + ' ', lines, generatedNodes);
|
|
821
|
+
}
|
|
822
|
+
lines.push(`${indent}}`);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
else if (chainViaSuccess) {
|
|
826
|
+
// Chain continues through success path; emit failure branch if it exists
|
|
827
|
+
if (hasFailureBranch) {
|
|
828
|
+
lines.push(`${indent}if (!${safeId}_result.onSuccess) {`);
|
|
829
|
+
const failureOrder = getOrderedNodes(Array.from(region.failureNodes), workflow, nodeTypes);
|
|
830
|
+
generateNodeBlock(failureOrder, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent + ' ', lines, generatedNodes);
|
|
831
|
+
lines.push(`${indent}}`);
|
|
832
|
+
}
|
|
833
|
+
// Built-in nodes (delay, waitForEvent, invokeWorkflow) bypass the execute flag,
|
|
834
|
+
// so the chain continuation must be explicitly guarded.
|
|
835
|
+
const nextNt = getNodeType(nextInChain, workflow, nodeTypes);
|
|
836
|
+
if (nextNt && isBuiltInNode(nextNt)) {
|
|
837
|
+
lines.push(`${indent}if (${safeId}_result.onSuccess) {`);
|
|
838
|
+
const remainingChain = chain.slice(i + 1);
|
|
839
|
+
generateBranchingChain(remainingChain, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent + ' ', lines, generatedNodes);
|
|
840
|
+
lines.push(`${indent}}`);
|
|
841
|
+
return; // Remaining chain already generated inside guard
|
|
842
|
+
}
|
|
843
|
+
// For normal nodes, execute flag handles it — continue flat
|
|
844
|
+
}
|
|
845
|
+
else if (chainViaFailure) {
|
|
846
|
+
// Chain continues through failure path; emit success branch if it exists
|
|
847
|
+
if (hasSuccessBranch) {
|
|
848
|
+
lines.push(`${indent}if (${safeId}_result.onSuccess) {`);
|
|
849
|
+
const successOrder = getOrderedNodes(Array.from(region.successNodes), workflow, nodeTypes);
|
|
850
|
+
generateNodeBlock(successOrder, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent + ' ', lines, generatedNodes);
|
|
851
|
+
lines.push(`${indent}}`);
|
|
852
|
+
}
|
|
853
|
+
// Built-in nodes bypass the execute flag — guard the chain continuation
|
|
854
|
+
const nextNtF = getNodeType(nextInChain, workflow, nodeTypes);
|
|
855
|
+
if (nextNtF && isBuiltInNode(nextNtF)) {
|
|
856
|
+
lines.push(`${indent}if (!${safeId}_result.onSuccess) {`);
|
|
857
|
+
const remainingChain = chain.slice(i + 1);
|
|
858
|
+
generateBranchingChain(remainingChain, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent + ' ', lines, generatedNodes);
|
|
859
|
+
lines.push(`${indent}}`);
|
|
860
|
+
return; // Remaining chain already generated inside guard
|
|
861
|
+
}
|
|
862
|
+
// For normal nodes, execute flag handles it — continue flat
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Order nodes by topological sort within a subset.
|
|
868
|
+
*/
|
|
869
|
+
function getOrderedNodes(nodeIds, workflow, nodeTypes) {
|
|
870
|
+
if (nodeIds.length <= 1)
|
|
871
|
+
return nodeIds;
|
|
872
|
+
const cfg = buildControlFlowGraph(workflow, nodeTypes);
|
|
873
|
+
const fullOrder = performKahnsTopologicalSort(cfg);
|
|
874
|
+
const nodeSet = new Set(nodeIds);
|
|
875
|
+
return fullOrder.filter((n) => nodeSet.has(n));
|
|
876
|
+
}
|
|
877
|
+
/**
|
|
878
|
+
* Collect exit port values and build the return statement.
|
|
879
|
+
*/
|
|
880
|
+
function generateReturnStatement(workflow, indent) {
|
|
881
|
+
const exitConnections = workflow.connections.filter((conn) => isExitNode(conn.to.node));
|
|
882
|
+
if (exitConnections.length === 0) {
|
|
883
|
+
return `${indent}return {};`;
|
|
884
|
+
}
|
|
885
|
+
const props = [];
|
|
886
|
+
const seen = new Set();
|
|
887
|
+
for (const conn of exitConnections) {
|
|
888
|
+
const exitPort = conn.to.port;
|
|
889
|
+
if (seen.has(exitPort))
|
|
890
|
+
continue;
|
|
891
|
+
seen.add(exitPort);
|
|
892
|
+
const sourceNode = conn.from.node;
|
|
893
|
+
const sourcePort = conn.from.port;
|
|
894
|
+
if (isStartNode(sourceNode)) {
|
|
895
|
+
props.push(`${exitPort}: event.data.${sourcePort}`);
|
|
896
|
+
}
|
|
897
|
+
else {
|
|
898
|
+
const safeSource = toValidIdentifier(sourceNode);
|
|
899
|
+
props.push(`${exitPort}: ${safeSource}_result?.${sourcePort}`);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
return `${indent}return { ${props.join(', ')} };`;
|
|
903
|
+
}
|
|
904
|
+
// ---------------------------------------------------------------------------
|
|
905
|
+
// Main Generator
|
|
906
|
+
// ---------------------------------------------------------------------------
|
|
907
|
+
/**
|
|
908
|
+
* Generate an Inngest function from a workflow AST.
|
|
909
|
+
*
|
|
910
|
+
* Produces a complete TypeScript module with:
|
|
911
|
+
* - Import statements (Inngest SDK + node type functions)
|
|
912
|
+
* - `inngest.createFunction()` with per-node `step.run()` calls
|
|
913
|
+
* - Parallel execution via `Promise.all` where safe
|
|
914
|
+
* - Branching via if/else for onSuccess/onFailure
|
|
915
|
+
* - Chain flattening for sequential branching (3-way routing)
|
|
916
|
+
* - Indexed `step.run()` for forEach iteration
|
|
917
|
+
*
|
|
918
|
+
* @param workflow - The workflow AST to generate from
|
|
919
|
+
* @param nodeTypes - All available node type definitions
|
|
920
|
+
* @param options - Generation options (service name, trigger, retries, etc.)
|
|
921
|
+
* @returns Complete TypeScript source code string
|
|
922
|
+
*/
|
|
923
|
+
export function generateInngestFunction(workflow, nodeTypes, options) {
|
|
924
|
+
const serviceName = options?.serviceName ?? toKebabCase(workflow.functionName);
|
|
925
|
+
const functionId = toKebabCase(workflow.functionName);
|
|
926
|
+
const triggerEvent = options?.triggerEvent ?? `fw/${functionId}.execute`;
|
|
927
|
+
const retries = workflow.options?.retries ?? options?.retries ?? 3;
|
|
928
|
+
const lines = [];
|
|
929
|
+
// -- Imports --
|
|
930
|
+
lines.push(`import { Inngest } from 'inngest';`);
|
|
931
|
+
if (options?.typedEvents) {
|
|
932
|
+
lines.push(`import { z } from 'zod';`);
|
|
933
|
+
}
|
|
934
|
+
if (options?.serveHandler && options?.framework) {
|
|
935
|
+
const importMap = {
|
|
936
|
+
next: 'inngest/next',
|
|
937
|
+
express: 'inngest/express',
|
|
938
|
+
hono: 'inngest/hono',
|
|
939
|
+
fastify: 'inngest/fastify',
|
|
940
|
+
remix: 'inngest/remix',
|
|
941
|
+
};
|
|
942
|
+
lines.push(`import { serve } from '${importMap[options.framework]}';`);
|
|
943
|
+
}
|
|
944
|
+
lines.push('');
|
|
945
|
+
// Collect node type imports (deduplicate by function name)
|
|
946
|
+
const importedFunctions = new Set();
|
|
947
|
+
for (const instance of workflow.instances) {
|
|
948
|
+
if (isPerPortScopedChild(instance, workflow, nodeTypes))
|
|
949
|
+
continue;
|
|
950
|
+
const nodeType = nodeTypes.find((nt) => nt.name === instance.nodeType || nt.functionName === instance.nodeType);
|
|
951
|
+
if (nodeType && !importedFunctions.has(nodeType.functionName)) {
|
|
952
|
+
if (isBuiltInNode(nodeType))
|
|
953
|
+
continue; // Skip built-in nodes — no user import
|
|
954
|
+
importedFunctions.add(nodeType.functionName);
|
|
955
|
+
lines.push(`import { ${nodeType.functionName} } from './node-types/${nodeType.functionName}.js';`);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
lines.push('');
|
|
959
|
+
// -- Inngest client --
|
|
960
|
+
lines.push(`const inngest = new Inngest({ id: '${serviceName}' });`);
|
|
961
|
+
lines.push('');
|
|
962
|
+
// -- Typed event schema (Feature 1) --
|
|
963
|
+
if (options?.typedEvents) {
|
|
964
|
+
const schemaEventName = workflow.options?.trigger?.event ?? triggerEvent;
|
|
965
|
+
const schemaLines = generateEventSchema(workflow, schemaEventName);
|
|
966
|
+
if (schemaLines.length > 0) {
|
|
967
|
+
lines.push(...schemaLines);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
// -- Function definition --
|
|
971
|
+
const fnVar = `${toValidIdentifier(workflow.functionName)}Fn`;
|
|
972
|
+
const configEntries = [
|
|
973
|
+
`id: '${functionId}'`,
|
|
974
|
+
`retries: ${retries}`,
|
|
975
|
+
];
|
|
976
|
+
// Add timeout from workflow options
|
|
977
|
+
if (workflow.options?.timeout) {
|
|
978
|
+
configEntries.push(`timeouts: { finish: '${workflow.options.timeout}' }`);
|
|
979
|
+
}
|
|
980
|
+
// Add throttle from workflow options
|
|
981
|
+
if (workflow.options?.throttle) {
|
|
982
|
+
const t = workflow.options.throttle;
|
|
983
|
+
const throttleConfig = [`limit: ${t.limit}`];
|
|
984
|
+
if (t.period)
|
|
985
|
+
throttleConfig.push(`period: '${t.period}'`);
|
|
986
|
+
configEntries.push(`throttle: { ${throttleConfig.join(', ')} }`);
|
|
987
|
+
}
|
|
988
|
+
// Add cancelOn from workflow options
|
|
989
|
+
if (workflow.options?.cancelOn) {
|
|
990
|
+
const c = workflow.options.cancelOn;
|
|
991
|
+
const cancelConfig = [`event: '${c.event}'`];
|
|
992
|
+
if (c.match) {
|
|
993
|
+
cancelConfig.push(`match: '${c.match}'`);
|
|
994
|
+
}
|
|
995
|
+
if (c.timeout) {
|
|
996
|
+
cancelConfig.push(`timeout: '${c.timeout}'`);
|
|
997
|
+
}
|
|
998
|
+
configEntries.push(`cancelOn: [{ ${cancelConfig.join(', ')} }]`);
|
|
999
|
+
}
|
|
1000
|
+
if (options?.functionConfig) {
|
|
1001
|
+
for (const [key, value] of Object.entries(options.functionConfig)) {
|
|
1002
|
+
if (key !== 'id' && key !== 'retries') {
|
|
1003
|
+
configEntries.push(`${key}: ${JSON.stringify(value)}`);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
lines.push(`export const ${fnVar} = inngest.createFunction(`);
|
|
1008
|
+
lines.push(` { ${configEntries.join(', ')} },`);
|
|
1009
|
+
// Trigger emission (Feature 2)
|
|
1010
|
+
const trigger = workflow.options?.trigger;
|
|
1011
|
+
if (trigger?.cron && trigger?.event) {
|
|
1012
|
+
lines.push(` { event: '${trigger.event}' },`);
|
|
1013
|
+
}
|
|
1014
|
+
else if (trigger?.cron) {
|
|
1015
|
+
lines.push(` { cron: '${trigger.cron}' },`);
|
|
1016
|
+
}
|
|
1017
|
+
else {
|
|
1018
|
+
const eventName = trigger?.event ?? triggerEvent;
|
|
1019
|
+
lines.push(` { event: '${eventName}' },`);
|
|
1020
|
+
}
|
|
1021
|
+
lines.push(` async ({ event, step }) => {`);
|
|
1022
|
+
// -- Build control flow --
|
|
1023
|
+
const cfg = buildControlFlowGraph(workflow, nodeTypes);
|
|
1024
|
+
const executionOrder = performKahnsTopologicalSort(cfg);
|
|
1025
|
+
const branchingNodes = findAllBranchingNodes(workflow, nodeTypes);
|
|
1026
|
+
// For Inngest: remove trivially branching nodes that only connect success/failure to Exit.
|
|
1027
|
+
// These don't need if/else blocks — they just route status to the workflow exit.
|
|
1028
|
+
// (The unified generator keeps them for catch block error handling.)
|
|
1029
|
+
for (const nodeId of [...branchingNodes]) {
|
|
1030
|
+
const hasNonExitBranch = workflow.connections.some((conn) => conn.from.node === nodeId &&
|
|
1031
|
+
(isSuccessPort(conn.from.port) || isFailurePort(conn.from.port)) &&
|
|
1032
|
+
!isExitNode(conn.to.node));
|
|
1033
|
+
if (!hasNonExitBranch) {
|
|
1034
|
+
branchingNodes.delete(nodeId);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
const allInstanceIds = new Set(workflow.instances.map((i) => i.id));
|
|
1038
|
+
const branchRegions = new Map();
|
|
1039
|
+
branchingNodes.forEach((branchInstanceId) => {
|
|
1040
|
+
const successNodes = findNodesInBranch(branchInstanceId, RESERVED_PORT_NAMES.ON_SUCCESS, workflow, allInstanceIds, branchingNodes, nodeTypes);
|
|
1041
|
+
const failureNodes = findNodesInBranch(branchInstanceId, RESERVED_PORT_NAMES.ON_FAILURE, workflow, allInstanceIds, branchingNodes, nodeTypes);
|
|
1042
|
+
branchRegions.set(branchInstanceId, { successNodes, failureNodes });
|
|
1043
|
+
});
|
|
1044
|
+
// Handle multi-branch membership: promote nodes in multiple branches
|
|
1045
|
+
const instancesInMultipleBranches = new Set();
|
|
1046
|
+
allInstanceIds.forEach((instanceId) => {
|
|
1047
|
+
let branchCount = 0;
|
|
1048
|
+
branchRegions.forEach((region) => {
|
|
1049
|
+
if (region.successNodes.has(instanceId) || region.failureNodes.has(instanceId)) {
|
|
1050
|
+
branchCount++;
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
if (branchCount > 1) {
|
|
1054
|
+
instancesInMultipleBranches.add(instanceId);
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1057
|
+
branchRegions.forEach((region) => {
|
|
1058
|
+
instancesInMultipleBranches.forEach((instanceId) => {
|
|
1059
|
+
region.successNodes.delete(instanceId);
|
|
1060
|
+
region.failureNodes.delete(instanceId);
|
|
1061
|
+
});
|
|
1062
|
+
});
|
|
1063
|
+
// Detect branching chains for if/else if flattening
|
|
1064
|
+
const branchingChains = detectBranchingChains(branchingNodes, branchRegions);
|
|
1065
|
+
// Identify chain members (non-heads) that are emitted by their chain head
|
|
1066
|
+
const chainMembers = new Set();
|
|
1067
|
+
branchingChains.forEach((chain) => {
|
|
1068
|
+
for (let i = 1; i < chain.length; i++) {
|
|
1069
|
+
chainMembers.add(chain[i]);
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
// Compute nodes in any branch (not top-level)
|
|
1073
|
+
const nodesInAnyBranch = new Set();
|
|
1074
|
+
branchRegions.forEach((region) => {
|
|
1075
|
+
region.successNodes.forEach((n) => nodesInAnyBranch.add(n));
|
|
1076
|
+
region.failureNodes.forEach((n) => nodesInAnyBranch.add(n));
|
|
1077
|
+
});
|
|
1078
|
+
// Filter execution order to top-level nodes
|
|
1079
|
+
const topLevelNodes = executionOrder.filter((n) => !isStartNode(n) &&
|
|
1080
|
+
!isExitNode(n) &&
|
|
1081
|
+
!nodesInAnyBranch.has(n) &&
|
|
1082
|
+
!chainMembers.has(n));
|
|
1083
|
+
// -- Generate node execution code --
|
|
1084
|
+
const indent = ' ';
|
|
1085
|
+
const generatedNodes = new Set();
|
|
1086
|
+
// Pre-declare result variables so they're accessible from all scopes (branch bodies, return statement)
|
|
1087
|
+
// Skip delay nodes — step.sleep() returns void, no result variable needed
|
|
1088
|
+
const resultVarNames = [];
|
|
1089
|
+
for (const instance of workflow.instances) {
|
|
1090
|
+
if (isStartNode(instance.id) || isExitNode(instance.id))
|
|
1091
|
+
continue;
|
|
1092
|
+
if (isPerPortScopedChild(instance, workflow, nodeTypes))
|
|
1093
|
+
continue;
|
|
1094
|
+
const nt = getNodeType(instance.id, workflow, nodeTypes);
|
|
1095
|
+
if (nt && isBuiltInNode(nt) === 'delay')
|
|
1096
|
+
continue;
|
|
1097
|
+
resultVarNames.push(toValidIdentifier(instance.id) + '_result');
|
|
1098
|
+
}
|
|
1099
|
+
if (resultVarNames.length > 0) {
|
|
1100
|
+
lines.push(`${indent}let ${resultVarNames.map((v) => v + ': any').join(', ')};`);
|
|
1101
|
+
lines.push('');
|
|
1102
|
+
}
|
|
1103
|
+
generateNodeBlock(topLevelNodes, workflow, nodeTypes, branchingNodes, branchRegions, branchingChains, chainMembers, indent, lines, generatedNodes);
|
|
1104
|
+
// -- Return statement --
|
|
1105
|
+
lines.push(generateReturnStatement(workflow, indent));
|
|
1106
|
+
lines.push(' }');
|
|
1107
|
+
lines.push(');');
|
|
1108
|
+
lines.push('');
|
|
1109
|
+
// -- Serve handler (Feature 7) --
|
|
1110
|
+
if (options?.serveHandler && options?.framework) {
|
|
1111
|
+
const framework = options.framework;
|
|
1112
|
+
lines.push(`// --- Serve handler (${framework}) ---`);
|
|
1113
|
+
if (framework === 'next') {
|
|
1114
|
+
lines.push(`export const { GET, POST, PUT } = serve({`);
|
|
1115
|
+
}
|
|
1116
|
+
else {
|
|
1117
|
+
lines.push(`export const handler = serve({`);
|
|
1118
|
+
}
|
|
1119
|
+
lines.push(` client: inngest,`);
|
|
1120
|
+
lines.push(` functions: [${fnVar}],`);
|
|
1121
|
+
lines.push(`});`);
|
|
1122
|
+
lines.push('');
|
|
1123
|
+
}
|
|
1124
|
+
return lines.join('\n');
|
|
1125
|
+
}
|
|
1126
|
+
//# sourceMappingURL=inngest.js.map
|