@solidxai/core 0.1.13-beta.2 → 0.1.13-beta.4
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/dist/commands/seed.command.d.ts +2 -0
- package/dist/commands/seed.command.d.ts.map +1 -1
- package/dist/commands/seed.command.js +21 -0
- package/dist/commands/seed.command.js.map +1 -1
- package/dist/entities/saved-filters.entity.js +3 -3
- package/dist/entities/saved-filters.entity.js.map +1 -1
- package/dist/entities/workflow-trigger-execution.entity.js +1 -1
- package/dist/entities/workflow-trigger-execution.entity.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/interfaces.d.ts +1 -0
- package/dist/interfaces.d.ts.map +1 -1
- package/dist/interfaces.js.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
- package/dist/seeders/module-metadata-seeder.service.js +44 -27
- package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
- package/dist/seeders/seed-data/solid-core-metadata.json +80 -67
- package/dist/services/workflow/nodes/execution-fail.node.d.ts +6 -0
- package/dist/services/workflow/nodes/execution-fail.node.d.ts.map +1 -0
- package/dist/services/workflow/nodes/execution-fail.node.js +81 -0
- package/dist/services/workflow/nodes/execution-fail.node.js.map +1 -0
- package/dist/services/workflow/nodes/for-each.node.d.ts +2 -0
- package/dist/services/workflow/nodes/for-each.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/for-each.node.js +114 -5
- package/dist/services/workflow/nodes/for-each.node.js.map +1 -1
- package/dist/services/workflow/nodes/if.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/if.node.js +7 -0
- package/dist/services/workflow/nodes/if.node.js.map +1 -1
- package/dist/services/workflow/nodes/log-write.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/log-write.node.js +2 -0
- package/dist/services/workflow/nodes/log-write.node.js.map +1 -1
- package/dist/services/workflow/nodes/loop-until.node.d.ts +12 -0
- package/dist/services/workflow/nodes/loop-until.node.d.ts.map +1 -0
- package/dist/services/workflow/nodes/loop-until.node.js +281 -0
- package/dist/services/workflow/nodes/loop-until.node.js.map +1 -0
- package/dist/services/workflow/nodes/parallel.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/parallel.node.js +7 -0
- package/dist/services/workflow/nodes/parallel.node.js.map +1 -1
- package/dist/services/workflow/nodes/sequential.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/sequential.node.js +7 -0
- package/dist/services/workflow/nodes/sequential.node.js.map +1 -1
- package/dist/services/workflow/nodes/switch.node.d.ts.map +1 -1
- package/dist/services/workflow/nodes/switch.node.js +7 -0
- package/dist/services/workflow/nodes/switch.node.js.map +1 -1
- package/dist/services/workflow/workflow-definition-validator.service.d.ts.map +1 -1
- package/dist/services/workflow/workflow-definition-validator.service.js +5 -2
- package/dist/services/workflow/workflow-definition-validator.service.js.map +1 -1
- package/dist/services/workflow/workflow-expression.service.d.ts.map +1 -1
- package/dist/services/workflow/workflow-expression.service.js +5 -0
- package/dist/services/workflow/workflow-expression.service.js.map +1 -1
- package/dist/services/workflow/workflow-node-registry.service.d.ts +2 -1
- package/dist/services/workflow/workflow-node-registry.service.d.ts.map +1 -1
- package/dist/services/workflow/workflow-node-registry.service.js +7 -0
- package/dist/services/workflow/workflow-node-registry.service.js.map +1 -1
- package/dist/services/workflow/workflow-runtime.service.d.ts +8 -0
- package/dist/services/workflow/workflow-runtime.service.d.ts.map +1 -1
- package/dist/services/workflow/workflow-runtime.service.js +197 -32
- package/dist/services/workflow/workflow-runtime.service.js.map +1 -1
- package/dist/solid-core.module.d.ts.map +1 -1
- package/dist/solid-core.module.js +4 -0
- package/dist/solid-core.module.js.map +1 -1
- package/dist/types/workflow-dsl.types.d.ts +14 -0
- package/dist/types/workflow-dsl.types.d.ts.map +1 -1
- package/dist/types/workflow-dsl.types.js.map +1 -1
- package/dist-tests/api/authenticate.spec.js +119 -0
- package/dist-tests/api/authenticate.spec.js.map +1 -0
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js +97 -0
- package/dist-tests/api/crud-service.findOne.cityMaster.spec.js.map +1 -0
- package/dist-tests/api/ping.spec.js +21 -0
- package/dist-tests/api/ping.spec.js.map +1 -0
- package/dist-tests/helpers/auth.js +41 -0
- package/dist-tests/helpers/auth.js.map +1 -0
- package/dist-tests/helpers/env.js +11 -0
- package/dist-tests/helpers/env.js.map +1 -0
- package/docs/agent-builder/notebook-lm-prompt-for-agent-builder.md +136 -0
- package/docs/agent-builder/team-ready-note-agent-builder.md +305 -0
- package/docs/agent-hub-grooming.md +301 -0
- package/docs/dashboards/AGENTIC_DASHBOARD_IMPLEMENTATION_PLAN.md +438 -0
- package/docs/dashboards/dashboard-curl-smoke-tests.txt +146 -0
- package/docs/dashboards/delete-legacy-dashboard-metadata.sql +172 -0
- package/docs/datasource-introspection-ddl-analysis.md +326 -0
- package/docs/datasource-introspection-implementation-plan.md +306 -0
- package/docs/grouping-enhancements.md +89 -0
- package/docs/java-spring/README.md +3 -0
- package/docs/java-spring/solid-core-module-deep-dive-report.md +1317 -0
- package/docs/module-package-import-handoff.md +691 -0
- package/docs/seed-changes.md +65 -0
- package/docs/test-data-workflow.md +200 -0
- package/docs/type-declaration-import-issue.md +24 -0
- package/docs/workflow/business-automation-example-notes.md +309 -0
- package/docs/workflow/control-flow-node-addition-sop.md +324 -0
- package/docs/workflow/data-engineering-pipeline-example-notes.md +330 -0
- package/docs/workflow/foreach-example-notes.md +187 -0
- package/docs/workflow/hello-world-example-notes.md +271 -0
- package/docs/workflow/kestra-concepts-plugins-blueprints.md +315 -0
- package/docs/workflow/loop-until-example-notes.md +198 -0
- package/docs/workflow/microservices-and-apis-example-notes.md +264 -0
- package/docs/workflow/samples.md +25 -0
- package/docs/workflow/what-is-kestra.md +79 -0
- package/docs/workflow/workflow-core-module-handoff-summary.md +191 -0
- package/docs/workflow/workflow-module-brd.md +185 -0
- package/docs/workflow/workflow-module-domain-model.md +252 -0
- package/docs/workflow/workflow-module-metadata-dsl.md +302 -0
- package/docs/workflow/workflow-module-technical-spec.md +293 -0
- package/docs/workflow/workflow-node-type-contracts.md +635 -0
- package/docs/workflow/workflow-node-ui-metadata-contract.md +1262 -0
- package/docs/workflow/workflow-solidx-model-field-spec.md +284 -0
- package/package.json +1 -1
- package/src/commands/seed.command.ts +19 -0
- package/src/entities/saved-filters.entity.ts +3 -3
- package/src/entities/workflow-trigger-execution.entity.ts +1 -1
- package/src/index.ts +2 -0
- package/src/interfaces.ts +1 -0
- package/src/seeders/module-metadata-seeder.service.ts +50 -36
- package/src/seeders/seed-data/solid-core-metadata.json +80 -67
- package/src/services/workflow/nodes/execution-fail.node.ts +82 -0
- package/src/services/workflow/nodes/for-each.node.ts +140 -6
- package/src/services/workflow/nodes/if.node.ts +7 -0
- package/src/services/workflow/nodes/log-write.node.ts +2 -0
- package/src/services/workflow/nodes/loop-until.node.ts +343 -0
- package/src/services/workflow/nodes/parallel.node.ts +7 -0
- package/src/services/workflow/nodes/sequential.node.ts +7 -0
- package/src/services/workflow/nodes/switch.node.ts +7 -0
- package/src/services/workflow/workflow-definition-validator.service.ts +5 -2
- package/src/services/workflow/workflow-expression.service.ts +5 -0
- package/src/services/workflow/workflow-node-registry.service.ts +11 -0
- package/src/services/workflow/workflow-runtime.service.ts +274 -39
- package/src/solid-core.module.ts +4 -0
- package/src/types/workflow-dsl.types.ts +43 -0
- package/.claude/settings.local.json +0 -16
- package/CLAUDE.md +0 -26
- package/src/services/1.js +0 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-write.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/log-write.node.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2GAA4F;AA4MrF,IAAM,YAAY,GAAlB,MAAM,YAAY;IACvB,KAAK,CAAC,OAAO,CACX,OAAqC;QAErC,MAAM,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,WAAW,CAClD,OAAO,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,EAChC,OAAO,CACR,CAAC;QACF,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,IAAI,MAAM,CAAC;QAC5C,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAE9E,MAAM,OAAO,CAAC,OAAO,CAAC;YACpB,KAAK;YACL,OAAO;YACP,SAAS,EAAE,UAAU;YACrB,MAAM,EAAE,WAAW;YACnB,OAAO,EAAE,aAAa,CAAC,OAAO;YAC9B,QAAQ,EAAE,aAAa,CAAC,QAAQ;SACjC,CAAC,CAAC;QAEH,OAAO;YACL,MAAM,EAAE;gBACN,KAAK;gBACL,OAAO;aACR;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AA3BY,oCAAY;uBAAZ,YAAY;IArMxB,IAAA,uDAAoB,EAAC;QACpB,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,OAAO;QAChB,QAAQ,EAAE,MAAM;QAChB,WAAW,EAAE,eAAe;QAC5B,KAAK,EAAE,WAAW;QAClB,WAAW,EAAE,iEAAiE;QAC9E,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,eAAe,CAAC;QACvC,OAAO,EAAE,CAAC,KAAK,CAAC;QAChB,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,CAAC,SAAS,CAAC;YACrB,UAAU,EAAE;gBACV,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC;oBACxC,OAAO,EAAE,MAAM;iBAChB;gBACD,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;iBACf;gBACD,OAAO,EAAE;oBACP,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,EAAE;iBACZ;gBACD,QAAQ,EAAE;oBACR,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,EAAE;iBACZ;aACF;SACF;QACD,QAAQ,EAAE;YACR,UAAU,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC;SACxD;QACD,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACzB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;aAC5B;SACF;QACD,QAAQ,EAAE;YACR;gBACE,GAAG,EAAE,gBAAgB;gBACrB,KAAK,EAAE,oBAAoB;gBAC3B,WAAW,EAAE,uCAAuC;gBACpD,QAAQ,EAAE,MAAM;gBAChB,OAAO,EACL,kDAAkD;gBACpD,iBAAiB,EAAE,IAAI;aACxB;SACF;QACD,OAAO,EAAE;YACP;gBACE,GAAG,EAAE,yBAAyB;gBAC9B,KAAK,EAAE,YAAY;gBACnB,WAAW,EAAE,8CAA8C;gBAC3D,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC;aAC1B;SACF;QACD,WAAW,EAAE;YACX;gBACE,GAAG,EAAE,YAAY;gBACjB,KAAK,EAAE,sBAAsB;gBAC7B,OAAO,EACL,uGAAuG;aAC1G;SACF;QACD,SAAS,EAAE;YACT,oBAAoB,EAAE;gBACpB,KAAK,EAAE,MAAM;gBACb,OAAO,EAAE,EAAE;gBACX,QAAQ,EAAE,EAAE;aACb;YACD,mBAAmB,EAAE;gBACnB,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE;oBACJ;wBACE,GAAG,EAAE,SAAS;wBACd,KAAK,EAAE,SAAS;wBAChB,MAAM,EAAE,CAAC,SAAS,CAAC;qBACpB;oBACD;wBACE,GAAG,EAAE,SAAS;wBACd,KAAK,EAAE,SAAS;wBAChB,MAAM,EAAE,CAAC,SAAS,CAAC;qBACpB;oBACD;wBACE,GAAG,EAAE,UAAU;wBACf,KAAK,EAAE,UAAU;wBACjB,MAAM,EAAE,CAAC,UAAU,CAAC;qBACrB;iBACF;aACF;YACD,mBAAmB,EAAE;gBACnB;oBACE,GAAG,EAAE,OAAO;oBACZ,KAAK,EAAE,OAAO;oBACd,WAAW,EAAE,uDAAuD;oBACpE,SAAS,EAAE,QAAQ;oBACnB,YAAY,EAAE,MAAM;oBACpB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC;oBAC9C,KAAK,EAAE,SAAS;iBACjB;gBACD;oBACE,GAAG,EAAE,SAAS;oBACd,KAAK,EAAE,SAAS;oBAChB,WAAW,EAAE,2CAA2C;oBACxD,SAAS,EAAE,QAAQ;oBACnB,QAAQ,EAAE,IAAI;oBACd,iBAAiB,EAAE,IAAI;oBACvB,KAAK,EAAE,SAAS;iBACjB;gBACD;oBACE,GAAG,EAAE,SAAS;oBACd,KAAK,EAAE,SAAS;oBAChB,WAAW,EAAE,wDAAwD;oBACrE,SAAS,EAAE,QAAQ;oBACnB,iBAAiB,EAAE,IAAI;oBACvB,KAAK,EAAE,UAAU;oBACjB,UAAU,EAAE,aAAa;oBACzB,QAAQ,EAAE;wBACR,MAAM,EAAE;4BACN,KAAK,EAAE,MAAM;yBACd;wBACD,MAAM,EAAE;4BACN,MAAM,EAAE,gCAAgC;yBACzC;qBACF;iBACF;gBACD;oBACE,GAAG,EAAE,UAAU;oBACf,KAAK,EAAE,UAAU;oBACjB,WAAW,EAAE,8CAA8C;oBAC3D,SAAS,EAAE,QAAQ;oBACnB,iBAAiB,EAAE,IAAI;oBACvB,KAAK,EAAE,UAAU;oBACjB,UAAU,EAAE,aAAa;oBACzB,QAAQ,EAAE;wBACR,MAAM,EAAE;4BACN,KAAK,EAAE,MAAM;yBACd;wBACD,MAAM,EAAE;4BACN,MAAM,EAAE,gCAAgC;yBACzC;qBACF;iBACF;aACF;YACD,OAAO,EAAE;gBACP;oBACE,GAAG,EAAE,OAAO;oBACZ,KAAK,EAAE,OAAO;oBACd,WAAW,EAAE,yBAAyB;oBACtC,SAAS,EAAE,QAAQ;oBACnB,IAAI,EAAE,OAAO;iBACd;gBACD;oBACE,GAAG,EAAE,SAAS;oBACd,KAAK,EAAE,SAAS;oBAChB,WAAW,EAAE,2BAA2B;oBACxC,SAAS,EAAE,QAAQ;oBACnB,IAAI,EAAE,SAAS;iBAChB;aACF;YACD,mBAAmB,EAAE,IAAI;YACzB,qBAAqB,EAAE,IAAI;YAC3B,YAAY,EAAE,IAAI;YAClB,mBAAmB,EAAE,IAAI;YACzB,cAAc,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,CAAC;SAC7D;QACD,OAAO,EAAE;YACP,SAAS,EAAE,IAAI;YACf,cAAc,EAAE,KAAK;YACrB,oBAAoB,EAAE,IAAI;YAC1B,aAAa,EAAE,MAAM;YACrB,eAAe,EAAE,CAAC,SAAS,CAAC;SAC7B;QACD,aAAa,EAAE;YACb,OAAO,EACL,6FAA6F;SAChG;QACD,EAAE,EAAE;YACF,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,SAAS;YACpB,mBAAmB,EAAE,SAAS;YAC9B,eAAe,EAAE,SAAS;YAC1B,iBAAiB,EAAE,QAAQ;YAC3B,SAAS,EAAE,IAAI;YACf,WAAW,EAAE;gBACX,cAAc,EAAE,MAAM;gBACtB,UAAU,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;gBACnC,aAAa,EAAE,IAAI;aACpB;SACF;KACF,CAAC;GACW,YAAY,CA2BxB","sourcesContent":["import { WorkflowNodeProvider } from '../../../decorators/workflow-node-provider.decorator';\nimport { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';\nimport {\n WorkflowNodeExecutionContext,\n WorkflowNodeHandlerResult,\n} from '../../../types/workflow-dsl.types';\n\n@WorkflowNodeProvider({\n type: 'log.write',\n kind: 'task',\n version: '1.0.0',\n category: 'core',\n subcategory: 'observability',\n label: 'Write Log',\n description: 'Writes an execution log entry and returns the rendered message.',\n tags: ['log', 'debug', 'observability'],\n aliases: ['log'],\n configSchema: {\n type: 'object',\n required: ['message'],\n properties: {\n level: {\n type: 'string',\n enum: ['debug', 'info', 'warn', 'error'],\n default: 'info',\n },\n message: {\n type: 'string',\n },\n context: {\n type: 'object',\n default: {},\n },\n metadata: {\n type: 'object',\n default: {},\n },\n },\n },\n uiSchema: {\n 'ui:order': ['level', 'message', 'context', 'metadata'],\n },\n outputSchema: {\n type: 'object',\n properties: {\n level: { type: 'string' },\n message: { type: 'string' },\n },\n },\n examples: [\n {\n key: 'simple-message',\n label: 'Simple log message',\n description: 'Write a simple interpolated log line.',\n language: 'yaml',\n snippet:\n 'message: \"Hello {{ input.name }}\"\\nlevel: info\\n',\n configurationOnly: true,\n },\n ],\n metrics: [\n {\n key: 'workflow.node.log.count',\n label: 'Log writes',\n description: 'Counts how many times the log node executes.',\n type: 'counter',\n tags: ['log', 'workflow'],\n },\n ],\n definitions: [\n {\n key: 'log-levels',\n label: 'Supported log levels',\n content:\n 'The node supports debug, info, warn, and error. The chosen level is stored alongside the log message.',\n },\n ],\n authoring: {\n defaultConfiguration: {\n level: 'info',\n context: {},\n metadata: {},\n },\n configurationLayout: {\n type: 'tabs',\n tabs: [\n {\n key: 'message',\n label: 'Message',\n groups: ['Message'],\n },\n {\n key: 'context',\n label: 'Context',\n fields: ['context'],\n },\n {\n key: 'metadata',\n label: 'Metadata',\n fields: ['metadata'],\n },\n ],\n },\n configurationFields: [\n {\n key: 'level',\n label: 'Level',\n description: 'The severity used for the emitted workflow log entry.',\n valueType: 'string',\n defaultValue: 'info',\n enumValues: ['debug', 'info', 'warn', 'error'],\n group: 'Message',\n },\n {\n key: 'message',\n label: 'Message',\n description: 'The text to log. Expressions are allowed.',\n valueType: 'string',\n required: true,\n expressionAllowed: true,\n group: 'Message',\n },\n {\n key: 'context',\n label: 'Context',\n description: 'Optional structured context attached to the log entry.',\n valueType: 'object',\n expressionAllowed: true,\n group: 'Advanced',\n widgetHint: 'yaml-editor',\n uiSchema: {\n layout: {\n width: 'full',\n },\n editor: {\n height: 'min(420px, calc(90vh - 330px))',\n },\n },\n },\n {\n key: 'metadata',\n label: 'Metadata',\n description: 'Optional metadata attached to the log entry.',\n valueType: 'object',\n expressionAllowed: true,\n group: 'Advanced',\n widgetHint: 'yaml-editor',\n uiSchema: {\n layout: {\n width: 'full',\n },\n editor: {\n height: 'min(420px, calc(90vh - 330px))',\n },\n },\n },\n ],\n outputs: [\n {\n key: 'level',\n label: 'Level',\n description: 'The resolved log level.',\n valueType: 'string',\n path: 'level',\n },\n {\n key: 'message',\n label: 'Message',\n description: 'The rendered log message.',\n valueType: 'string',\n path: 'message',\n },\n ],\n supportsExpressions: true,\n supportsDisableToggle: true,\n supportsName: true,\n supportsDescription: true,\n searchableText: ['log', 'message', 'debug', 'observability'],\n },\n runtime: {\n emitsLogs: true,\n emitsArtifacts: false,\n deterministicOutputs: true,\n executionMode: 'task',\n successStatuses: ['success'],\n },\n documentation: {\n summary:\n 'Use this node for debug messages, execution breadcrumbs, and quick expression verification.',\n },\n ui: {\n icon: 'si-file',\n iconColor: '#0284c7',\n iconBackgroundColor: '#e0f2fe',\n iconBorderColor: '#bae6fd',\n defaultEditorMode: 'schema',\n modalSize: 'xl',\n layoutHints: {\n preferredPanel: 'flow',\n groupOrder: ['Message', 'Advanced'],\n stickySummary: true,\n },\n },\n})\nexport class LogWriteNode implements WorkflowNodeHandler {\n async execute(\n context: WorkflowNodeExecutionContext,\n ): Promise<WorkflowNodeHandlerResult> {\n const configuration = context.expression.interpolate(\n context.node.configuration ?? {},\n context,\n );\n const level = configuration.level ?? 'info';\n const message = configuration.message ?? context.node.name ?? context.node.id;\n\n await context.emitLog({\n level,\n message,\n eventType: 'node.log',\n source: 'log.write',\n context: configuration.context,\n metadata: configuration.metadata,\n });\n\n return {\n output: {\n level,\n message,\n },\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"log-write.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/log-write.node.ts"],"names":[],"mappings":"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","sourcesContent":["import { WorkflowNodeProvider } from '../../../decorators/workflow-node-provider.decorator';\nimport { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';\nimport {\n WorkflowNodeExecutionContext,\n WorkflowNodeHandlerResult,\n} from '../../../types/workflow-dsl.types';\n\n@WorkflowNodeProvider({\n type: 'log.write',\n kind: 'task',\n version: '1.0.0',\n category: 'core',\n subcategory: 'observability',\n label: 'Write Log',\n description: 'Writes an execution log entry and returns the rendered message.',\n tags: ['log', 'debug', 'observability'],\n aliases: ['log'],\n configSchema: {\n type: 'object',\n required: ['message'],\n properties: {\n level: {\n type: 'string',\n enum: ['debug', 'info', 'warn', 'error'],\n default: 'info',\n },\n message: {\n type: 'string',\n },\n context: {\n type: 'object',\n default: {},\n },\n metadata: {\n type: 'object',\n default: {},\n },\n },\n },\n uiSchema: {\n 'ui:order': ['level', 'message', 'context', 'metadata'],\n },\n outputSchema: {\n type: 'object',\n properties: {\n level: { type: 'string' },\n message: { type: 'string' },\n },\n },\n examples: [\n {\n key: 'simple-message',\n label: 'Simple log message',\n description: 'Write a simple interpolated log line.',\n language: 'yaml',\n snippet:\n 'message: \"Hello {{ input.name }}\"\\nlevel: info\\n',\n configurationOnly: true,\n },\n ],\n metrics: [\n {\n key: 'workflow.node.log.count',\n label: 'Log writes',\n description: 'Counts how many times the log node executes.',\n type: 'counter',\n tags: ['log', 'workflow'],\n },\n ],\n definitions: [\n {\n key: 'log-levels',\n label: 'Supported log levels',\n content:\n 'The node supports debug, info, warn, and error. The chosen level is stored alongside the log message.',\n },\n ],\n authoring: {\n defaultConfiguration: {\n level: 'info',\n context: {},\n metadata: {},\n },\n configurationLayout: {\n type: 'tabs',\n tabs: [\n {\n key: 'message',\n label: 'Message',\n groups: ['Message'],\n },\n {\n key: 'context',\n label: 'Context',\n fields: ['context'],\n },\n {\n key: 'metadata',\n label: 'Metadata',\n fields: ['metadata'],\n },\n ],\n },\n configurationFields: [\n {\n key: 'level',\n label: 'Level',\n description: 'The severity used for the emitted workflow log entry.',\n valueType: 'string',\n defaultValue: 'info',\n enumValues: ['debug', 'info', 'warn', 'error'],\n group: 'Message',\n },\n {\n key: 'message',\n label: 'Message',\n description: 'The text to log. Expressions are allowed.',\n valueType: 'string',\n required: true,\n expressionAllowed: true,\n group: 'Message',\n },\n {\n key: 'context',\n label: 'Context',\n description: 'Optional structured context attached to the log entry.',\n valueType: 'object',\n expressionAllowed: true,\n group: 'Advanced',\n widgetHint: 'yaml-editor',\n uiSchema: {\n layout: {\n width: 'full',\n },\n editor: {\n height: 'min(420px, calc(90vh - 330px))',\n },\n },\n },\n {\n key: 'metadata',\n label: 'Metadata',\n description: 'Optional metadata attached to the log entry.',\n valueType: 'object',\n expressionAllowed: true,\n group: 'Advanced',\n widgetHint: 'yaml-editor',\n uiSchema: {\n layout: {\n width: 'full',\n },\n editor: {\n height: 'min(420px, calc(90vh - 330px))',\n },\n },\n },\n ],\n outputs: [\n {\n key: 'level',\n label: 'Level',\n description: 'The resolved log level.',\n valueType: 'string',\n path: 'level',\n includeInRuntimeContext: false,\n },\n {\n key: 'message',\n label: 'Message',\n description: 'The rendered log message.',\n valueType: 'string',\n path: 'message',\n includeInRuntimeContext: false,\n },\n ],\n supportsExpressions: true,\n supportsDisableToggle: true,\n supportsName: true,\n supportsDescription: true,\n searchableText: ['log', 'message', 'debug', 'observability'],\n },\n runtime: {\n emitsLogs: true,\n emitsArtifacts: false,\n deterministicOutputs: true,\n executionMode: 'task',\n successStatuses: ['success'],\n },\n documentation: {\n summary:\n 'Use this node for debug messages, execution breadcrumbs, and quick expression verification.',\n },\n ui: {\n icon: 'si-file',\n iconColor: '#0284c7',\n iconBackgroundColor: '#e0f2fe',\n iconBorderColor: '#bae6fd',\n defaultEditorMode: 'schema',\n modalSize: 'xl',\n layoutHints: {\n preferredPanel: 'flow',\n groupOrder: ['Message', 'Advanced'],\n stickySummary: true,\n },\n },\n})\nexport class LogWriteNode implements WorkflowNodeHandler {\n async execute(\n context: WorkflowNodeExecutionContext,\n ): Promise<WorkflowNodeHandlerResult> {\n const configuration = context.expression.interpolate(\n context.node.configuration ?? {},\n context,\n );\n const level = configuration.level ?? 'info';\n const message = configuration.message ?? context.node.name ?? context.node.id;\n\n await context.emitLog({\n level,\n message,\n eventType: 'node.log',\n source: 'log.write',\n context: configuration.context,\n metadata: configuration.metadata,\n });\n\n return {\n output: {\n level,\n message,\n },\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';
|
|
2
|
+
import { WorkflowNodeExecutionContext, WorkflowNodeHandlerResult } from '../../../types/workflow-dsl.types';
|
|
3
|
+
export declare class LoopUntilNode implements WorkflowNodeHandler {
|
|
4
|
+
execute(context: WorkflowNodeExecutionContext): Promise<WorkflowNodeHandlerResult>;
|
|
5
|
+
private resolveCheckFrequency;
|
|
6
|
+
private hasReachedGuardrail;
|
|
7
|
+
private optionalPositiveInteger;
|
|
8
|
+
private parseDurationMs;
|
|
9
|
+
private resolveBoolean;
|
|
10
|
+
private delay;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=loop-until.node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-until.node.d.ts","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/loop-until.node.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,mCAAmC,CAAC;AAS3C,qBAqHa,aAAc,YAAW,mBAAmB;IACjD,OAAO,CACX,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,yBAAyB,CAAC;IA4FrC,OAAO,CAAC,qBAAqB;IAyB7B,OAAO,CAAC,mBAAmB;IAgB3B,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,eAAe;IAkDvB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,KAAK;CAGd"}
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.LoopUntilNode = void 0;
|
|
10
|
+
const common_1 = require("@nestjs/common");
|
|
11
|
+
const workflow_node_provider_decorator_1 = require("../../../decorators/workflow-node-provider.decorator");
|
|
12
|
+
let LoopUntilNode = class LoopUntilNode {
|
|
13
|
+
async execute(context) {
|
|
14
|
+
const configuration = context.node.configuration ?? {};
|
|
15
|
+
const condition = configuration.condition ?? configuration.expression;
|
|
16
|
+
if (!condition) {
|
|
17
|
+
throw new common_1.BadRequestException('loopUntil requires configuration.condition.');
|
|
18
|
+
}
|
|
19
|
+
const checkFrequency = this.resolveCheckFrequency(context.expression.interpolate(configuration.checkFrequency ?? {}, context));
|
|
20
|
+
const childNodes = context.node.tasks ?? [];
|
|
21
|
+
const startedAt = Date.now();
|
|
22
|
+
let iterationCount = 0;
|
|
23
|
+
let conditionMatched = false;
|
|
24
|
+
let maxReached = false;
|
|
25
|
+
let latestChildOutputs = {};
|
|
26
|
+
while (true) {
|
|
27
|
+
iterationCount += 1;
|
|
28
|
+
context.outputs[context.node.id] = {
|
|
29
|
+
iterationCount,
|
|
30
|
+
conditionMatched: false,
|
|
31
|
+
maxReached: false,
|
|
32
|
+
};
|
|
33
|
+
const iterationOutputs = {
|
|
34
|
+
...(context.outputs ?? {}),
|
|
35
|
+
};
|
|
36
|
+
latestChildOutputs = await context.runNodes(childNodes, {
|
|
37
|
+
outputs: iterationOutputs,
|
|
38
|
+
});
|
|
39
|
+
Object.assign(context.outputs, iterationOutputs);
|
|
40
|
+
conditionMatched = context.expression.evaluateCondition(condition, {
|
|
41
|
+
...context,
|
|
42
|
+
outputs: context.outputs,
|
|
43
|
+
});
|
|
44
|
+
context.outputs[context.node.id] = {
|
|
45
|
+
iterationCount,
|
|
46
|
+
conditionMatched,
|
|
47
|
+
maxReached: false,
|
|
48
|
+
latestOutputs: latestChildOutputs,
|
|
49
|
+
};
|
|
50
|
+
await context.emitLog({
|
|
51
|
+
level: 'info',
|
|
52
|
+
eventType: 'node.loopUntil.evaluated',
|
|
53
|
+
source: 'loopUntil',
|
|
54
|
+
message: `LoopUntil node "${context.node.id}" iteration ${iterationCount} evaluated to ${conditionMatched}.`,
|
|
55
|
+
context: {
|
|
56
|
+
condition,
|
|
57
|
+
iterationCount,
|
|
58
|
+
conditionMatched,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
if (conditionMatched) {
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
maxReached = this.hasReachedGuardrail(iterationCount, startedAt, checkFrequency);
|
|
65
|
+
if (maxReached) {
|
|
66
|
+
if (checkFrequency.failOnMaxReached) {
|
|
67
|
+
throw new common_1.BadRequestException(`loopUntil "${context.node.id}" reached its maximum check frequency guardrail before the condition matched.`);
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
if (checkFrequency.intervalMs > 0) {
|
|
72
|
+
await this.delay(checkFrequency.intervalMs);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
output: {
|
|
77
|
+
iterationCount,
|
|
78
|
+
conditionMatched,
|
|
79
|
+
maxReached,
|
|
80
|
+
latestOutputs: latestChildOutputs,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
resolveCheckFrequency(value) {
|
|
85
|
+
const checkFrequency = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
86
|
+
const maxIterations = this.optionalPositiveInteger(checkFrequency.maxIterations, 'checkFrequency.maxIterations');
|
|
87
|
+
const maxDurationMs = checkFrequency.maxDuration === undefined ||
|
|
88
|
+
checkFrequency.maxDuration === null ||
|
|
89
|
+
checkFrequency.maxDuration === ''
|
|
90
|
+
? undefined
|
|
91
|
+
: this.parseDurationMs(checkFrequency.maxDuration, 'checkFrequency.maxDuration');
|
|
92
|
+
return {
|
|
93
|
+
intervalMs: this.parseDurationMs(checkFrequency.interval ?? 'PT1M', 'checkFrequency.interval'),
|
|
94
|
+
maxIterations,
|
|
95
|
+
maxDurationMs,
|
|
96
|
+
failOnMaxReached: this.resolveBoolean(checkFrequency.failOnMaxReached),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
hasReachedGuardrail(iterationCount, startedAt, checkFrequency) {
|
|
100
|
+
return ((checkFrequency.maxIterations !== undefined &&
|
|
101
|
+
iterationCount >= checkFrequency.maxIterations) ||
|
|
102
|
+
(checkFrequency.maxDurationMs !== undefined &&
|
|
103
|
+
Date.now() - startedAt >= checkFrequency.maxDurationMs));
|
|
104
|
+
}
|
|
105
|
+
optionalPositiveInteger(value, label) {
|
|
106
|
+
if (value === undefined || value === null || value === '') {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
const parsed = Number(value);
|
|
110
|
+
if (!Number.isFinite(parsed) || parsed < 1) {
|
|
111
|
+
throw new common_1.BadRequestException(`${label} must be a positive integer.`);
|
|
112
|
+
}
|
|
113
|
+
return Math.floor(parsed);
|
|
114
|
+
}
|
|
115
|
+
parseDurationMs(value, label) {
|
|
116
|
+
if (typeof value === 'number') {
|
|
117
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
118
|
+
throw new common_1.BadRequestException(`${label} must be a non-negative duration.`);
|
|
119
|
+
}
|
|
120
|
+
return value;
|
|
121
|
+
}
|
|
122
|
+
const raw = String(value ?? '').trim();
|
|
123
|
+
if (!raw) {
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
if (/^\d+$/.test(raw)) {
|
|
127
|
+
return Number(raw);
|
|
128
|
+
}
|
|
129
|
+
const isoMatch = raw.match(/^P(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/i);
|
|
130
|
+
if (isoMatch) {
|
|
131
|
+
const [, days, hours, minutes, seconds] = isoMatch;
|
|
132
|
+
return (Number(days ?? 0) * 24 * 60 * 60 * 1000 +
|
|
133
|
+
Number(hours ?? 0) * 60 * 60 * 1000 +
|
|
134
|
+
Number(minutes ?? 0) * 60 * 1000 +
|
|
135
|
+
Number(seconds ?? 0) * 1000);
|
|
136
|
+
}
|
|
137
|
+
const unitMatch = raw.match(/^(\d+(?:\.\d+)?)(ms|s|m|h|d)$/i);
|
|
138
|
+
if (unitMatch) {
|
|
139
|
+
const amount = Number(unitMatch[1]);
|
|
140
|
+
const unit = unitMatch[2].toLowerCase();
|
|
141
|
+
const multiplier = unit === 'ms'
|
|
142
|
+
? 1
|
|
143
|
+
: unit === 's'
|
|
144
|
+
? 1000
|
|
145
|
+
: unit === 'm'
|
|
146
|
+
? 60 * 1000
|
|
147
|
+
: unit === 'h'
|
|
148
|
+
? 60 * 60 * 1000
|
|
149
|
+
: 24 * 60 * 60 * 1000;
|
|
150
|
+
return amount * multiplier;
|
|
151
|
+
}
|
|
152
|
+
throw new common_1.BadRequestException(`${label} must be milliseconds, 1s/1m style, or ISO-8601 duration.`);
|
|
153
|
+
}
|
|
154
|
+
resolveBoolean(value) {
|
|
155
|
+
if (value === true || value === 'true') {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
delay(ms) {
|
|
161
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
exports.LoopUntilNode = LoopUntilNode;
|
|
165
|
+
exports.LoopUntilNode = LoopUntilNode = __decorate([
|
|
166
|
+
(0, workflow_node_provider_decorator_1.WorkflowNodeProvider)({
|
|
167
|
+
type: 'loopUntil',
|
|
168
|
+
kind: 'control',
|
|
169
|
+
category: 'control-flow',
|
|
170
|
+
label: 'Loop Until',
|
|
171
|
+
description: 'Runs child nodes repeatedly until a condition evaluates true.',
|
|
172
|
+
tags: ['loop', 'iteration', 'condition', 'polling'],
|
|
173
|
+
authoring: {
|
|
174
|
+
defaultConfiguration: {
|
|
175
|
+
condition: '{{ outputs.checkStatus.ready == true }}',
|
|
176
|
+
checkFrequency: {
|
|
177
|
+
interval: 'PT1M',
|
|
178
|
+
failOnMaxReached: false,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
configurationLayout: {
|
|
182
|
+
type: 'tabs',
|
|
183
|
+
tabs: [
|
|
184
|
+
{
|
|
185
|
+
key: 'condition',
|
|
186
|
+
label: 'Condition',
|
|
187
|
+
groups: ['Condition'],
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
key: 'guardrails',
|
|
191
|
+
label: 'Guardrails',
|
|
192
|
+
groups: ['Guardrails'],
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
configurationFields: [
|
|
197
|
+
{
|
|
198
|
+
key: 'condition',
|
|
199
|
+
label: 'Condition',
|
|
200
|
+
description: 'Boolean expression evaluated after each loop iteration. It can read outputs from the latest child-node run.',
|
|
201
|
+
valueType: 'expression',
|
|
202
|
+
required: true,
|
|
203
|
+
expressionAllowed: true,
|
|
204
|
+
widgetHint: 'textarea',
|
|
205
|
+
group: 'Condition',
|
|
206
|
+
uiSchema: {
|
|
207
|
+
layout: {
|
|
208
|
+
width: 'full',
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
key: 'checkFrequency',
|
|
214
|
+
label: 'Check Frequency',
|
|
215
|
+
description: 'Optional loop guardrails: interval, maxIterations, maxDuration, and failOnMaxReached.',
|
|
216
|
+
valueType: 'object',
|
|
217
|
+
expressionAllowed: true,
|
|
218
|
+
widgetHint: 'yaml-editor',
|
|
219
|
+
group: 'Guardrails',
|
|
220
|
+
uiSchema: {
|
|
221
|
+
layout: {
|
|
222
|
+
width: 'full',
|
|
223
|
+
},
|
|
224
|
+
editor: {
|
|
225
|
+
height: 'min(320px, calc(90vh - 360px))',
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
childSlots: [
|
|
231
|
+
{
|
|
232
|
+
key: 'tasks',
|
|
233
|
+
label: 'Loop Body',
|
|
234
|
+
description: 'Nodes that run before the condition is evaluated.',
|
|
235
|
+
kind: 'sequence',
|
|
236
|
+
layout: 'sequential',
|
|
237
|
+
required: true,
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
key: 'errors',
|
|
241
|
+
label: 'Errors',
|
|
242
|
+
description: 'Nodes that run sequentially if this loop fails.',
|
|
243
|
+
kind: 'sequence',
|
|
244
|
+
layout: 'sequential',
|
|
245
|
+
},
|
|
246
|
+
],
|
|
247
|
+
outputs: [
|
|
248
|
+
{
|
|
249
|
+
key: 'iterationCount',
|
|
250
|
+
label: 'Iteration Count',
|
|
251
|
+
description: 'Number of loop body iterations that ran.',
|
|
252
|
+
valueType: 'number',
|
|
253
|
+
path: 'iterationCount',
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
key: 'conditionMatched',
|
|
257
|
+
label: 'Condition Matched',
|
|
258
|
+
description: 'Whether the loop stopped because the condition evaluated true.',
|
|
259
|
+
valueType: 'boolean',
|
|
260
|
+
path: 'conditionMatched',
|
|
261
|
+
},
|
|
262
|
+
],
|
|
263
|
+
supportsDescription: true,
|
|
264
|
+
supportsName: true,
|
|
265
|
+
},
|
|
266
|
+
documentation: {
|
|
267
|
+
summary: 'Runs the loop body, evaluates the condition, and repeats after the configured interval until the condition is true or a guardrail is reached.',
|
|
268
|
+
},
|
|
269
|
+
ui: {
|
|
270
|
+
icon: 'si-repeat',
|
|
271
|
+
iconColor: '#0f766e',
|
|
272
|
+
iconBackgroundColor: '#ccfbf1',
|
|
273
|
+
iconBorderColor: '#99f6e4',
|
|
274
|
+
modalSize: 'lg',
|
|
275
|
+
layoutHints: {
|
|
276
|
+
groupOrder: ['Condition', 'Guardrails'],
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
})
|
|
280
|
+
], LoopUntilNode);
|
|
281
|
+
//# sourceMappingURL=loop-until.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-until.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/loop-until.node.ts"],"names":[],"mappings":"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","sourcesContent":["import { BadRequestException } from '@nestjs/common';\nimport { WorkflowNodeProvider } from '../../../decorators/workflow-node-provider.decorator';\nimport { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';\nimport {\n WorkflowNodeExecutionContext,\n WorkflowNodeHandlerResult,\n} from '../../../types/workflow-dsl.types';\n\ntype LoopUntilCheckFrequency = {\n interval?: string | number;\n maxIterations?: string | number;\n maxDuration?: string | number;\n failOnMaxReached?: boolean | string;\n};\n\n@WorkflowNodeProvider({\n type: 'loopUntil',\n kind: 'control',\n category: 'control-flow',\n label: 'Loop Until',\n description: 'Runs child nodes repeatedly until a condition evaluates true.',\n tags: ['loop', 'iteration', 'condition', 'polling'],\n authoring: {\n defaultConfiguration: {\n condition: '{{ outputs.checkStatus.ready == true }}',\n checkFrequency: {\n interval: 'PT1M',\n failOnMaxReached: false,\n },\n },\n configurationLayout: {\n type: 'tabs',\n tabs: [\n {\n key: 'condition',\n label: 'Condition',\n groups: ['Condition'],\n },\n {\n key: 'guardrails',\n label: 'Guardrails',\n groups: ['Guardrails'],\n },\n ],\n },\n configurationFields: [\n {\n key: 'condition',\n label: 'Condition',\n description:\n 'Boolean expression evaluated after each loop iteration. It can read outputs from the latest child-node run.',\n valueType: 'expression',\n required: true,\n expressionAllowed: true,\n widgetHint: 'textarea',\n group: 'Condition',\n uiSchema: {\n layout: {\n width: 'full',\n },\n },\n },\n {\n key: 'checkFrequency',\n label: 'Check Frequency',\n description:\n 'Optional loop guardrails: interval, maxIterations, maxDuration, and failOnMaxReached.',\n valueType: 'object',\n expressionAllowed: true,\n widgetHint: 'yaml-editor',\n group: 'Guardrails',\n uiSchema: {\n layout: {\n width: 'full',\n },\n editor: {\n height: 'min(320px, calc(90vh - 360px))',\n },\n },\n },\n ],\n childSlots: [\n {\n key: 'tasks',\n label: 'Loop Body',\n description: 'Nodes that run before the condition is evaluated.',\n kind: 'sequence',\n layout: 'sequential',\n required: true,\n },\n {\n key: 'errors',\n label: 'Errors',\n description: 'Nodes that run sequentially if this loop fails.',\n kind: 'sequence',\n layout: 'sequential',\n },\n ],\n outputs: [\n {\n key: 'iterationCount',\n label: 'Iteration Count',\n description: 'Number of loop body iterations that ran.',\n valueType: 'number',\n path: 'iterationCount',\n },\n {\n key: 'conditionMatched',\n label: 'Condition Matched',\n description: 'Whether the loop stopped because the condition evaluated true.',\n valueType: 'boolean',\n path: 'conditionMatched',\n },\n ],\n supportsDescription: true,\n supportsName: true,\n },\n documentation: {\n summary:\n 'Runs the loop body, evaluates the condition, and repeats after the configured interval until the condition is true or a guardrail is reached.',\n },\n ui: {\n icon: 'si-repeat',\n iconColor: '#0f766e',\n iconBackgroundColor: '#ccfbf1',\n iconBorderColor: '#99f6e4',\n modalSize: 'lg',\n layoutHints: {\n groupOrder: ['Condition', 'Guardrails'],\n },\n },\n})\nexport class LoopUntilNode implements WorkflowNodeHandler {\n async execute(\n context: WorkflowNodeExecutionContext,\n ): Promise<WorkflowNodeHandlerResult> {\n const configuration = context.node.configuration ?? {};\n const condition = configuration.condition ?? configuration.expression;\n if (!condition) {\n throw new BadRequestException('loopUntil requires configuration.condition.');\n }\n\n const checkFrequency = this.resolveCheckFrequency(\n context.expression.interpolate(configuration.checkFrequency ?? {}, context),\n );\n const childNodes = context.node.tasks ?? [];\n const startedAt = Date.now();\n let iterationCount = 0;\n let conditionMatched = false;\n let maxReached = false;\n let latestChildOutputs: Record<string, any> = {};\n\n while (true) {\n iterationCount += 1;\n context.outputs[context.node.id] = {\n iterationCount,\n conditionMatched: false,\n maxReached: false,\n };\n\n const iterationOutputs = {\n ...(context.outputs ?? {}),\n };\n\n latestChildOutputs = await context.runNodes(childNodes, {\n outputs: iterationOutputs,\n });\n\n Object.assign(context.outputs, iterationOutputs);\n\n conditionMatched = context.expression.evaluateCondition(condition, {\n ...context,\n outputs: context.outputs,\n });\n\n context.outputs[context.node.id] = {\n iterationCount,\n conditionMatched,\n maxReached: false,\n latestOutputs: latestChildOutputs,\n };\n\n await context.emitLog({\n level: 'info',\n eventType: 'node.loopUntil.evaluated',\n source: 'loopUntil',\n message: `LoopUntil node \"${context.node.id}\" iteration ${iterationCount} evaluated to ${conditionMatched}.`,\n context: {\n condition,\n iterationCount,\n conditionMatched,\n },\n });\n\n if (conditionMatched) {\n break;\n }\n\n maxReached = this.hasReachedGuardrail(\n iterationCount,\n startedAt,\n checkFrequency,\n );\n if (maxReached) {\n if (checkFrequency.failOnMaxReached) {\n throw new BadRequestException(\n `loopUntil \"${context.node.id}\" reached its maximum check frequency guardrail before the condition matched.`,\n );\n }\n break;\n }\n\n if (checkFrequency.intervalMs > 0) {\n await this.delay(checkFrequency.intervalMs);\n }\n }\n\n return {\n output: {\n iterationCount,\n conditionMatched,\n maxReached,\n latestOutputs: latestChildOutputs,\n },\n };\n }\n\n private resolveCheckFrequency(value: any) {\n const checkFrequency: LoopUntilCheckFrequency =\n value && typeof value === 'object' && !Array.isArray(value) ? value : {};\n const maxIterations = this.optionalPositiveInteger(\n checkFrequency.maxIterations,\n 'checkFrequency.maxIterations',\n );\n const maxDurationMs =\n checkFrequency.maxDuration === undefined ||\n checkFrequency.maxDuration === null ||\n checkFrequency.maxDuration === ''\n ? undefined\n : this.parseDurationMs(checkFrequency.maxDuration, 'checkFrequency.maxDuration');\n\n return {\n intervalMs: this.parseDurationMs(\n checkFrequency.interval ?? 'PT1M',\n 'checkFrequency.interval',\n ),\n maxIterations,\n maxDurationMs,\n failOnMaxReached: this.resolveBoolean(checkFrequency.failOnMaxReached),\n };\n }\n\n private hasReachedGuardrail(\n iterationCount: number,\n startedAt: number,\n checkFrequency: {\n maxIterations?: number;\n maxDurationMs?: number;\n },\n ): boolean {\n return (\n (checkFrequency.maxIterations !== undefined &&\n iterationCount >= checkFrequency.maxIterations) ||\n (checkFrequency.maxDurationMs !== undefined &&\n Date.now() - startedAt >= checkFrequency.maxDurationMs)\n );\n }\n\n private optionalPositiveInteger(value: any, label: string): number | undefined {\n if (value === undefined || value === null || value === '') {\n return undefined;\n }\n\n const parsed = Number(value);\n if (!Number.isFinite(parsed) || parsed < 1) {\n throw new BadRequestException(`${label} must be a positive integer.`);\n }\n\n return Math.floor(parsed);\n }\n\n private parseDurationMs(value: any, label: string): number {\n if (typeof value === 'number') {\n if (!Number.isFinite(value) || value < 0) {\n throw new BadRequestException(`${label} must be a non-negative duration.`);\n }\n return value;\n }\n\n const raw = String(value ?? '').trim();\n if (!raw) {\n return 0;\n }\n\n if (/^\\d+$/.test(raw)) {\n return Number(raw);\n }\n\n const isoMatch = raw.match(\n /^P(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+(?:\\.\\d+)?)S)?)?$/i,\n );\n if (isoMatch) {\n const [, days, hours, minutes, seconds] = isoMatch;\n return (\n Number(days ?? 0) * 24 * 60 * 60 * 1000 +\n Number(hours ?? 0) * 60 * 60 * 1000 +\n Number(minutes ?? 0) * 60 * 1000 +\n Number(seconds ?? 0) * 1000\n );\n }\n\n const unitMatch = raw.match(/^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d)$/i);\n if (unitMatch) {\n const amount = Number(unitMatch[1]);\n const unit = unitMatch[2].toLowerCase();\n const multiplier =\n unit === 'ms'\n ? 1\n : unit === 's'\n ? 1000\n : unit === 'm'\n ? 60 * 1000\n : unit === 'h'\n ? 60 * 60 * 1000\n : 24 * 60 * 60 * 1000;\n return amount * multiplier;\n }\n\n throw new BadRequestException(`${label} must be milliseconds, 1s/1m style, or ISO-8601 duration.`);\n }\n\n private resolveBoolean(value: any): boolean {\n if (value === true || value === 'true') {\n return true;\n }\n\n return false;\n }\n\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parallel.node.d.ts","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/parallel.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,mCAAmC,CAAC;AAE3C,
|
|
1
|
+
{"version":3,"file":"parallel.node.d.ts","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/parallel.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,mCAAmC,CAAC;AAE3C,qBAwCa,YAAa,YAAW,mBAAmB;IAChD,OAAO,CACX,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,yBAAyB,CAAC;CAqCtC"}
|
|
@@ -57,6 +57,13 @@ exports.ParallelNode = ParallelNode = __decorate([
|
|
|
57
57
|
layout: 'parallel',
|
|
58
58
|
required: true,
|
|
59
59
|
},
|
|
60
|
+
{
|
|
61
|
+
key: 'errors',
|
|
62
|
+
label: 'Errors',
|
|
63
|
+
description: 'Nodes that run sequentially if this parallel branch fails.',
|
|
64
|
+
kind: 'sequence',
|
|
65
|
+
layout: 'sequential',
|
|
66
|
+
},
|
|
60
67
|
],
|
|
61
68
|
supportsDescription: true,
|
|
62
69
|
supportsName: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parallel.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/parallel.node.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2GAA4F;
|
|
1
|
+
{"version":3,"file":"parallel.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/parallel.node.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2GAA4F;AA+CrF,IAAM,YAAY,GAAlB,MAAM,YAAY;IACvB,KAAK,CAAC,OAAO,CACX,OAAqC;QAErC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAE5C,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CACnC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YAC5B,MAAM,gBAAgB,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;YAC/C,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;YACnE,MAAM,OAAO,GAAG,EAAE,GAAG,gBAAgB,EAAE,CAAC;YAExC,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE;gBAC7B,OAAO;aACR,CAAC,CAAC;YAEH,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,CAClD,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;gBACpB,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBAClC,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;gBACnB,CAAC;gBACD,OAAO,GAAG,CAAC;YACb,CAAC,EACD,EAAyB,CAC1B,CAAC;YAEF,OAAO;gBACL,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,OAAO,EAAE,aAAa;aACvB,CAAC;QACJ,CAAC,CAAC,CACH,CAAC;QAEF,OAAO;YACL,MAAM,EAAE;gBACN,KAAK,EAAE,WAAW;aACnB;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAxCY,oCAAY;uBAAZ,YAAY;IAxCxB,IAAA,uDAAoB,EAAC;QACpB,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,cAAc;QACxB,KAAK,EAAE,UAAU;QACjB,WAAW,EAAE,yDAAyD;QACtE,IAAI,EAAE,CAAC,UAAU,EAAE,aAAa,CAAC;QACjC,SAAS,EAAE;YACT,oBAAoB,EAAE,EAAE;YACxB,UAAU,EAAE;gBACV;oBACE,GAAG,EAAE,OAAO;oBACZ,KAAK,EAAE,OAAO;oBACd,WAAW,EAAE,oCAAoC;oBACjD,IAAI,EAAE,UAAU;oBAChB,MAAM,EAAE,UAAU;oBAClB,QAAQ,EAAE,IAAI;iBACf;gBACD;oBACE,GAAG,EAAE,QAAQ;oBACb,KAAK,EAAE,QAAQ;oBACf,WAAW,EAAE,4DAA4D;oBACzE,IAAI,EAAE,UAAU;oBAChB,MAAM,EAAE,YAAY;iBACrB;aACF;YACD,mBAAmB,EAAE,IAAI;YACzB,YAAY,EAAE,IAAI;SACnB;QACD,aAAa,EAAE;YACb,OAAO,EAAE,0DAA0D;SACpE;QACD,EAAE,EAAE;YACF,IAAI,EAAE,mBAAmB;YACzB,SAAS,EAAE,SAAS;YACpB,mBAAmB,EAAE,SAAS;YAC9B,eAAe,EAAE,SAAS;YAC1B,SAAS,EAAE,IAAI;SAChB;KACF,CAAC;GACW,YAAY,CAwCxB","sourcesContent":["import { WorkflowNodeProvider } from '../../../decorators/workflow-node-provider.decorator';\nimport { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';\nimport {\n WorkflowNodeExecutionContext,\n WorkflowNodeHandlerResult,\n} from '../../../types/workflow-dsl.types';\n\n@WorkflowNodeProvider({\n type: 'parallel',\n kind: 'control',\n category: 'control-flow',\n label: 'Parallel',\n description: 'Runs child tasks concurrently and returns task outputs.',\n tags: ['parallel', 'concurrency'],\n authoring: {\n defaultConfiguration: {},\n childSlots: [\n {\n key: 'tasks',\n label: 'Tasks',\n description: 'Child tasks that run concurrently.',\n kind: 'sequence',\n layout: 'parallel',\n required: true,\n },\n {\n key: 'errors',\n label: 'Errors',\n description: 'Nodes that run sequentially if this parallel branch fails.',\n kind: 'sequence',\n layout: 'sequential',\n },\n ],\n supportsDescription: true,\n supportsName: true,\n },\n documentation: {\n summary: 'Runs child tasks concurrently and returns their outputs.',\n },\n ui: {\n icon: 'si-objects-column',\n iconColor: '#2563eb',\n iconBackgroundColor: '#dbeafe',\n iconBorderColor: '#bfdbfe',\n modalSize: 'lg',\n },\n})\nexport class ParallelNode implements WorkflowNodeHandler {\n async execute(\n context: WorkflowNodeExecutionContext,\n ): Promise<WorkflowNodeHandlerResult> {\n const childTasks = context.node.tasks ?? [];\n\n const taskResults = await Promise.all(\n childTasks.map(async (task) => {\n const inheritedOutputs = context.outputs ?? {};\n const inheritedOutputKeys = new Set(Object.keys(inheritedOutputs));\n const outputs = { ...inheritedOutputs };\n\n await context.runNodes([task], {\n outputs,\n });\n\n const branchOutputs = Object.entries(outputs).reduce(\n (acc, [key, value]) => {\n if (!inheritedOutputKeys.has(key)) {\n acc[key] = value;\n }\n return acc;\n },\n {} as Record<string, any>,\n );\n\n return {\n id: task.id,\n name: task.name,\n outputs: branchOutputs,\n };\n }),\n );\n\n return {\n output: {\n tasks: taskResults,\n },\n };\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequential.node.d.ts","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/sequential.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,mCAAmC,CAAC;AAE3C,
|
|
1
|
+
{"version":3,"file":"sequential.node.d.ts","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/sequential.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EACL,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,mCAAmC,CAAC;AAE3C,qBAwCa,cAAe,YAAW,mBAAmB;IAClD,OAAO,CACX,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,yBAAyB,CAAC;CActC"}
|
|
@@ -42,6 +42,13 @@ exports.SequentialNode = SequentialNode = __decorate([
|
|
|
42
42
|
layout: 'sequential',
|
|
43
43
|
required: true,
|
|
44
44
|
},
|
|
45
|
+
{
|
|
46
|
+
key: 'errors',
|
|
47
|
+
label: 'Errors',
|
|
48
|
+
description: 'Nodes that run sequentially if this sequence fails.',
|
|
49
|
+
kind: 'sequence',
|
|
50
|
+
layout: 'sequential',
|
|
51
|
+
},
|
|
45
52
|
],
|
|
46
53
|
supportsDescription: true,
|
|
47
54
|
supportsName: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequential.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/sequential.node.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2GAA4F;
|
|
1
|
+
{"version":3,"file":"sequential.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/sequential.node.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2GAA4F;AA+CrF,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB,KAAK,CAAC,OAAO,CACX,OAAqC;QAErC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,EAAE,CAAC;QAEnB,MAAM,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE;YACjC,OAAO;SACR,CAAC,CAAC;QAEH,OAAO;YACL,MAAM,EAAE;gBACN,KAAK,EAAE,OAAO;aACf;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAjBY,wCAAc;yBAAd,cAAc;IAxC1B,IAAA,uDAAoB,EAAC;QACpB,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,SAAS;QACf,QAAQ,EAAE,cAAc;QACxB,KAAK,EAAE,YAAY;QACnB,WAAW,EAAE,sDAAsD;QACnE,IAAI,EAAE,CAAC,YAAY,EAAE,UAAU,EAAE,SAAS,CAAC;QAC3C,SAAS,EAAE;YACT,oBAAoB,EAAE,EAAE;YACxB,UAAU,EAAE;gBACV;oBACE,GAAG,EAAE,OAAO;oBACZ,KAAK,EAAE,OAAO;oBACd,WAAW,EAAE,yCAAyC;oBACtD,IAAI,EAAE,UAAU;oBAChB,MAAM,EAAE,YAAY;oBACpB,QAAQ,EAAE,IAAI;iBACf;gBACD;oBACE,GAAG,EAAE,QAAQ;oBACb,KAAK,EAAE,QAAQ;oBACf,WAAW,EAAE,qDAAqD;oBAClE,IAAI,EAAE,UAAU;oBAChB,MAAM,EAAE,YAAY;iBACrB;aACF;YACD,mBAAmB,EAAE,IAAI;YACzB,YAAY,EAAE,IAAI;SACnB;QACD,aAAa,EAAE;YACb,OAAO,EAAE,mEAAmE;SAC7E;QACD,EAAE,EAAE;YACF,IAAI,EAAE,iBAAiB;YACvB,SAAS,EAAE,SAAS;YACpB,mBAAmB,EAAE,SAAS;YAC9B,eAAe,EAAE,SAAS;YAC1B,SAAS,EAAE,IAAI;SAChB;KACF,CAAC;GACW,cAAc,CAiB1B","sourcesContent":["import { WorkflowNodeProvider } from '../../../decorators/workflow-node-provider.decorator';\nimport { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';\nimport {\n WorkflowNodeExecutionContext,\n WorkflowNodeHandlerResult,\n} from '../../../types/workflow-dsl.types';\n\n@WorkflowNodeProvider({\n type: 'sequential',\n kind: 'control',\n category: 'control-flow',\n label: 'Sequential',\n description: 'Runs child tasks in order and returns their outputs.',\n tags: ['sequential', 'flowable', 'ordered'],\n authoring: {\n defaultConfiguration: {},\n childSlots: [\n {\n key: 'tasks',\n label: 'Tasks',\n description: 'Child tasks that run one after another.',\n kind: 'sequence',\n layout: 'sequential',\n required: true,\n },\n {\n key: 'errors',\n label: 'Errors',\n description: 'Nodes that run sequentially if this sequence fails.',\n kind: 'sequence',\n layout: 'sequential',\n },\n ],\n supportsDescription: true,\n supportsName: true,\n },\n documentation: {\n summary: 'Runs child tasks one after another in the order they are defined.',\n },\n ui: {\n icon: 'si-list-numbers',\n iconColor: '#0891b2',\n iconBackgroundColor: '#cffafe',\n iconBorderColor: '#a5f3fc',\n modalSize: 'lg',\n },\n})\nexport class SequentialNode implements WorkflowNodeHandler {\n async execute(\n context: WorkflowNodeExecutionContext,\n ): Promise<WorkflowNodeHandlerResult> {\n const childTasks = context.node.tasks ?? [];\n const outputs = {};\n\n await context.runNodes(childTasks, {\n outputs,\n });\n\n return {\n output: {\n tasks: outputs,\n },\n };\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"switch.node.d.ts","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/switch.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EAEL,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,mCAAmC,CAAC;AAE3C,
|
|
1
|
+
{"version":3,"file":"switch.node.d.ts","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/switch.node.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qDAAqD,CAAC;AAC1F,OAAO,EAEL,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,mCAAmC,CAAC;AAE3C,qBAmEa,UAAW,YAAW,mBAAmB;IAC9C,OAAO,CACX,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,yBAAyB,CAAC;IAmCrC,OAAO,CAAC,cAAc;CAkBvB"}
|
|
@@ -91,6 +91,13 @@ exports.SwitchNode = SwitchNode = __decorate([
|
|
|
91
91
|
description: 'Fallback sequence that runs when no case key matches the resolved value.',
|
|
92
92
|
kind: 'sequence',
|
|
93
93
|
},
|
|
94
|
+
{
|
|
95
|
+
key: 'errors',
|
|
96
|
+
label: 'Errors',
|
|
97
|
+
description: 'Nodes that run sequentially if the selected case fails.',
|
|
98
|
+
kind: 'sequence',
|
|
99
|
+
layout: 'sequential',
|
|
100
|
+
},
|
|
94
101
|
],
|
|
95
102
|
supportsDescription: true,
|
|
96
103
|
supportsName: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"switch.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/switch.node.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2GAA4F;
|
|
1
|
+
{"version":3,"file":"switch.node.js","sourceRoot":"","sources":["../../../../src/services/workflow/nodes/switch.node.ts"],"names":[],"mappings":"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","sourcesContent":["import { WorkflowNodeProvider } from '../../../decorators/workflow-node-provider.decorator';\nimport { WorkflowNodeHandler } from '../../../interfaces/workflow-node-handler.interface';\nimport {\n WorkflowNodeDefinition,\n WorkflowNodeExecutionContext,\n WorkflowNodeHandlerResult,\n} from '../../../types/workflow-dsl.types';\n\n@WorkflowNodeProvider({\n type: 'switch',\n kind: 'control',\n category: 'control-flow',\n label: 'Switch',\n description:\n 'Runs one case sequence based on a contextual value, with an optional default sequence.',\n tags: ['switch', 'case', 'branching', 'condition'],\n authoring: {\n defaultConfiguration: {\n value: '{{ input.value }}',\n },\n configurationFields: [\n {\n key: 'value',\n label: 'Value',\n description:\n 'Expression or literal value used to choose the matching case key.',\n valueType: 'expression',\n required: true,\n expressionAllowed: true,\n widgetHint: 'textarea',\n group: 'General',\n },\n ],\n childSlots: [\n {\n key: 'cases',\n label: 'Cases',\n description: 'Named case sequences. The matching case key is executed.',\n kind: 'case-collection',\n required: true,\n minItems: 1,\n },\n {\n key: 'defaults',\n label: 'Default',\n description:\n 'Fallback sequence that runs when no case key matches the resolved value.',\n kind: 'sequence',\n },\n {\n key: 'errors',\n label: 'Errors',\n description: 'Nodes that run sequentially if the selected case fails.',\n kind: 'sequence',\n layout: 'sequential',\n },\n ],\n supportsDescription: true,\n supportsName: true,\n },\n documentation: {\n summary:\n 'Evaluates a contextual value and runs the child node sequence under the matching case key. If no case matches, the optional default sequence runs.',\n },\n ui: {\n icon: 'si-git-branch',\n iconColor: '#db2777',\n iconBackgroundColor: '#fce7f3',\n iconBorderColor: '#f9a8d4',\n modalSize: 'lg',\n layoutHints: {\n groupOrder: ['General'],\n },\n },\n})\nexport class SwitchNode implements WorkflowNodeHandler {\n async execute(\n context: WorkflowNodeExecutionContext,\n ): Promise<WorkflowNodeHandlerResult> {\n const configuration = context.node.configuration ?? {};\n const resolvedValue = context.expression.interpolate(\n configuration.value,\n context,\n );\n const caseKey = this.resolveCaseKey(resolvedValue, context.node.cases ?? {});\n const selectedNodes = caseKey\n ? context.node.cases?.[caseKey] ?? []\n : context.node.defaults ?? [];\n\n await context.emitLog({\n level: 'info',\n eventType: 'node.switch.evaluated',\n source: 'switch',\n message: caseKey\n ? `Switch node \"${context.node.id}\" matched case \"${caseKey}\".`\n : `Switch node \"${context.node.id}\" did not match a case and will run defaults.`,\n context: {\n value: resolvedValue,\n caseKey,\n },\n });\n\n await context.runNodes(selectedNodes);\n\n return {\n output: {\n value: resolvedValue,\n case: caseKey,\n matched: Boolean(caseKey),\n },\n };\n }\n\n private resolveCaseKey(\n value: any,\n cases: Record<string, WorkflowNodeDefinition[]>,\n ): string | undefined {\n const exactKey = String(value);\n if (Object.prototype.hasOwnProperty.call(cases, exactKey)) {\n return exactKey;\n }\n\n if (typeof value === 'boolean') {\n const booleanKey = value ? 'true' : 'false';\n if (Object.prototype.hasOwnProperty.call(cases, booleanKey)) {\n return booleanKey;\n }\n }\n\n return undefined;\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-definition-validator.service.d.ts","sourceRoot":"","sources":["../../../src/services/workflow/workflow-definition-validator.service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,EAGtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAG/E,qBACa,kCAAkC;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,2BAA2B;IAElE,QAAQ,CAAC,UAAU,EAAE,qBAAqB;
|
|
1
|
+
{"version":3,"file":"workflow-definition-validator.service.d.ts","sourceRoot":"","sources":["../../../src/services/workflow/workflow-definition-validator.service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,EAGtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAG/E,qBACa,kCAAkC;IACjC,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,2BAA2B;IAElE,QAAQ,CAAC,UAAU,EAAE,qBAAqB;IAwB1C,OAAO,CAAC,gBAAgB;IAyBxB,OAAO,CAAC,eAAe;IAwDvB,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,aAAa;IAMrB,OAAO,CAAC,YAAY;CAqFrB"}
|
|
@@ -28,6 +28,8 @@ let WorkflowDefinitionValidatorService = class WorkflowDefinitionValidatorServic
|
|
|
28
28
|
}
|
|
29
29
|
const nodeIds = new Set();
|
|
30
30
|
this.validateNodes(definition.nodes, nodeIds);
|
|
31
|
+
this.validateNodes(definition.errors ?? [], nodeIds);
|
|
32
|
+
this.validateNodes(definition.finally ?? [], nodeIds);
|
|
31
33
|
this.validateTriggers(definition);
|
|
32
34
|
}
|
|
33
35
|
validateTriggers(definition) {
|
|
@@ -104,10 +106,10 @@ let WorkflowDefinitionValidatorService = class WorkflowDefinitionValidatorServic
|
|
|
104
106
|
}
|
|
105
107
|
for (const unsupportedKey of ['children', 'branches', 'nodes']) {
|
|
106
108
|
if (Object.prototype.hasOwnProperty.call(node, unsupportedKey)) {
|
|
107
|
-
throw new common_1.BadRequestException(`Workflow node "${node.id ?? 'unknown'}" uses unsupported child key "${unsupportedKey}". Use "tasks", "then", "else", "defaults", or "cases" instead.`);
|
|
109
|
+
throw new common_1.BadRequestException(`Workflow node "${node.id ?? 'unknown'}" uses unsupported child key "${unsupportedKey}". Use "tasks", "then", "else", "defaults", "errors", or "cases" instead.`);
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
|
-
for (const childKey of ['tasks', 'then', 'else', 'defaults']) {
|
|
112
|
+
for (const childKey of ['tasks', 'then', 'else', 'defaults', 'errors']) {
|
|
111
113
|
const childValue = node[childKey];
|
|
112
114
|
if (childValue !== undefined &&
|
|
113
115
|
childValue !== null &&
|
|
@@ -150,6 +152,7 @@ let WorkflowDefinitionValidatorService = class WorkflowDefinitionValidatorServic
|
|
|
150
152
|
this.validateNodes(node.then ?? [], nodeIds);
|
|
151
153
|
this.validateNodes(node.else ?? [], nodeIds);
|
|
152
154
|
this.validateNodes(node.defaults ?? [], nodeIds);
|
|
155
|
+
this.validateNodes(node.errors ?? [], nodeIds);
|
|
153
156
|
Object.values(node.cases ?? {}).forEach((caseNodes) => {
|
|
154
157
|
this.validateNodes(caseNodes, nodeIds);
|
|
155
158
|
});
|