@oomol-lab/open-flow 0.1.0-beta.73 → 0.1.0-beta.74
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 +36 -0
- package/NOTICE +7 -0
- package/README.md +40 -0
- package/dist/browser/{createResourceDialog-BWJkjiOO.js → createResourceDialog-DI9pL-Yr.js} +2 -2
- package/dist/browser/{dialog-CUy_fwx9.js → dialog-BYJGvItc.js} +54 -19
- package/dist/browser/{flowChanges-CgSnSqqP.js → flowChanges-RL-H4CjD.js} +306 -48
- package/dist/browser/{flowWorkspace-Bf7H-r0t.js → flowWorkspace-BkDsETj0.js} +20745 -20186
- package/dist/browser/preview.css +73 -3
- package/dist/browser/preview.js +21410 -20607
- package/dist/browser/{typeScriptSession-B0hC-C8y.js → typeScriptSession-CSRwWmZm.js} +1 -1
- package/dist/browser/ui.css +72 -2
- package/dist/browser/workbench.css +73 -3
- package/dist/browser/workbench.js +14 -76
- package/dist/browser/{workbenchSelect-C3e4J93X.js → workbenchSelect-BcWPWGzw.js} +1 -1
- package/dist/command/index.js +34 -34
- package/dist/common/authoring.d.ts +1 -1
- package/dist/common/authoringFields.d.ts +1 -1
- package/dist/common/authoringSchema.d.ts +28 -4
- package/dist/common/connector-proxy.d.ts +1 -1
- package/dist/common/control-api-conformance.d.ts +1 -1
- package/dist/common/control-api-conformance.js +61 -24
- package/dist/common/control-api.d.ts +4 -3
- package/dist/common/control-api.js +59 -22
- package/dist/common/control-requests.d.ts +2 -1
- package/dist/common/control-requests.js +204 -42
- package/dist/common/cron-trigger.d.ts +1 -1
- package/dist/common/decision.d.ts +1 -1
- package/dist/common/draftOperations.d.ts +1 -1
- package/dist/common/engine-contract.d.ts +3 -2
- package/dist/common/event-source-definition.d.ts +1 -1
- package/dist/common/flow-agent.d.ts +1 -1
- package/dist/{browser → common}/flow-authoring-node.d.ts +3 -3
- package/dist/{browser → common}/flow-authoring.js +75 -23
- package/dist/{browser → common}/flow-change-schema.d.ts +177 -6
- package/dist/{browser → common}/flow-change.d.ts +35 -15
- package/dist/{browser → common}/flow-change.js +77 -25
- package/dist/common/flow-connectionUsage.d.ts +1 -1
- package/dist/common/flow-encoding.d.ts +1 -1
- package/dist/common/flow-encoding.js +34 -16
- package/dist/common/flow-errorHandling.d.ts +1 -1
- package/dist/common/flow-graph.d.ts +1 -1
- package/dist/common/flow-modules.d.ts +1 -1
- package/dist/common/flow-promptTemplate.d.ts +1 -1
- package/dist/common/flow-retry.d.ts +1 -1
- package/dist/common/flow-semantics.d.ts +1 -1
- package/dist/common/flow-semantics.js +151 -32
- package/dist/common/flow-workflowFile.d.ts +1 -1
- package/dist/common/flowInspection.d.ts +3 -3
- package/dist/common/integration-trigger.d.ts +1 -1
- package/dist/common/licenses.md +118 -1
- package/dist/common/liveDetails.d.ts +1 -1
- package/dist/common/mcp.d.ts +2 -1
- package/dist/common/mcp.js +59 -22
- package/dist/common/openapi.d.ts +1 -1
- package/dist/common/poll-trigger.d.ts +1 -1
- package/dist/common/run-results.d.ts +8 -1
- package/dist/common/runtime-contract.d.ts +8 -2
- package/dist/common/runtime-contract.js +22 -5
- package/dist/common/scheduler-checkpoint.d.ts +1 -1
- package/dist/common/scheduler-dependencies.d.ts +1 -1
- package/dist/common/scheduler-node-execution.d.ts +1 -1
- package/dist/common/scheduler.d.ts +2 -2
- package/dist/common/scheduler.js +31 -12
- package/dist/common/trigger-catalog.d.ts +1 -1
- package/dist/common/trigger-config-options.d.ts +1 -1
- package/dist/common/trigger-config.d.ts +1 -1
- package/dist/common/trigger-contract.d.ts +2 -2
- package/dist/common/trigger-localization.d.ts +1 -1
- package/dist/common/webhook-response.d.ts +1 -1
- package/dist/common/webhook-trigger.d.ts +1 -1
- package/dist/common/workflow.d.ts +17 -1
- package/dist/common/workflow.js +68 -22
- package/dist/index.d.ts +6 -3
- package/package.json +7 -6
- package/src/base/common/json.ts +90 -0
- package/src/canvas/common/commands.ts +15 -0
- package/src/connector/common/actionSchema.ts +168 -0
- package/src/connector/common/proxy.ts +44 -0
- package/src/control/common/api.ts +1505 -0
- package/src/control/common/authoring.ts +912 -0
- package/src/control/common/authoringCondition.ts +110 -0
- package/src/control/common/authoringDiagnosticFields.ts +136 -0
- package/src/control/common/authoringExamples.ts +192 -0
- package/src/control/common/authoringFields.ts +53 -0
- package/src/control/common/authoringLlm.ts +70 -0
- package/src/control/common/authoringOpenApi.ts +129 -0
- package/src/control/common/authoringSchema.ts +404 -0
- package/src/control/common/authoringTools.ts +123 -0
- package/src/control/common/authoringTriggers.ts +26 -0
- package/src/control/common/checkDecoders.ts +65 -0
- package/src/control/common/conformance.ts +1989 -0
- package/src/control/common/connectorDecoders.ts +370 -0
- package/src/control/common/connectorQueries.ts +61 -0
- package/src/control/common/decoding.ts +60 -0
- package/src/control/common/draftOperations.ts +61 -0
- package/src/control/common/errors.ts +114 -0
- package/src/control/common/eventSourceSchemas.ts +13 -0
- package/src/control/common/eventSources.ts +186 -0
- package/src/control/common/flowDecoders.ts +153 -0
- package/src/control/common/flowInspection.ts +181 -0
- package/src/control/common/flowNotifications.ts +37 -0
- package/src/control/common/liveDetails.ts +124 -0
- package/src/control/common/mcp.ts +241 -0
- package/src/control/common/mcpConformance.ts +142 -0
- package/src/control/common/providerAccess.ts +28 -0
- package/src/control/common/providerIconSprite.ts +42 -0
- package/src/control/common/publicationDecoders.ts +98 -0
- package/src/control/common/random.ts +16 -0
- package/src/control/common/requests.ts +112 -0
- package/src/control/common/resultQuery.ts +8 -0
- package/src/control/common/results.ts +176 -0
- package/src/control/common/revisionDecoders.ts +52 -0
- package/src/control/common/runDecoders.ts +240 -0
- package/src/control/common/triggerCatalog.ts +89 -0
- package/src/control/common/triggerDecoders.ts +175 -0
- package/src/decision/common/decision.ts +168 -0
- package/src/event-source/common/catalog.generated.json +65 -0
- package/src/event-source/common/definition.ts +66 -0
- package/src/event-source/common/index.ts +99 -0
- package/src/execution/common/checkpoint.ts +311 -0
- package/src/execution/common/dependencies.ts +440 -0
- package/src/execution/common/engineContract.ts +80 -0
- package/src/execution/common/events.ts +328 -0
- package/src/execution/common/node-execution.ts +467 -0
- package/src/execution/common/runLifecycle.ts +250 -0
- package/src/execution/common/runtime.ts +563 -0
- package/src/execution/common/scheduler.ts +696 -0
- package/src/execution/common/wait.ts +36 -0
- package/src/flow/common/agent.ts +305 -0
- package/src/flow/common/authoring.ts +30 -0
- package/src/flow/common/change.ts +1036 -0
- package/src/flow/common/changeSchema.ts +783 -0
- package/src/flow/common/codePermissions.ts +2 -0
- package/src/flow/common/condition.ts +265 -0
- package/src/flow/common/connectionUsage.ts +131 -0
- package/src/flow/common/edgeChanges.ts +35 -0
- package/src/flow/common/encoding.ts +437 -0
- package/src/flow/common/errorHandling.ts +34 -0
- package/src/flow/common/graph.ts +892 -0
- package/src/flow/common/inputValue.ts +16 -0
- package/src/flow/common/json.ts +8 -0
- package/src/flow/common/moduleChanges.ts +31 -0
- package/src/flow/common/modules.ts +292 -0
- package/src/flow/common/nodeChanges.ts +762 -0
- package/src/flow/common/portChanges.ts +36 -0
- package/src/flow/common/promptTemplate.ts +15 -0
- package/src/flow/common/retry.ts +20 -0
- package/src/flow/common/schema.ts +162 -0
- package/src/flow/common/schemaCompare.ts +176 -0
- package/src/flow/common/schemaComparer.ts +178 -0
- package/src/flow/common/schemaKeywords.ts +53 -0
- package/src/flow/common/semantics.ts +474 -0
- package/src/flow/common/sourceField.ts +35 -0
- package/src/flow/common/triggerScheduleSchema.ts +8 -0
- package/src/flow/common/wait.ts +30 -0
- package/src/flow/common/webhookMethod.ts +7 -0
- package/src/flow/common/webhookResponse.ts +75 -0
- package/src/flow/common/workflowFile.ts +97 -0
- package/src/json-schema-subset/checker/array.ts +142 -0
- package/src/json-schema-subset/checker/cache.ts +57 -0
- package/src/json-schema-subset/checker/checker.ts +230 -0
- package/src/json-schema-subset/checker/enumAndConst.ts +113 -0
- package/src/json-schema-subset/checker/equals.ts +93 -0
- package/src/json-schema-subset/checker/numeric/checker.ts +50 -0
- package/src/json-schema-subset/checker/numeric/float.ts +121 -0
- package/src/json-schema-subset/checker/numeric/index.ts +1 -0
- package/src/json-schema-subset/checker/numeric/integer.ts +119 -0
- package/src/json-schema-subset/checker/numeric/integerNormalizer.ts +72 -0
- package/src/json-schema-subset/checker/object.ts +354 -0
- package/src/json-schema-subset/checker/range.ts +91 -0
- package/src/json-schema-subset/checker/string.ts +60 -0
- package/src/json-schema-subset/checker/tools/index.ts +3 -0
- package/src/json-schema-subset/checker/tools/mark.ts +82 -0
- package/src/json-schema-subset/checker/tools/quantum.ts +106 -0
- package/src/json-schema-subset/checker/tools/range.ts +210 -0
- package/src/json-schema-subset/checker/validator.ts +23 -0
- package/src/json-schema-subset/compiler/array.ts +163 -0
- package/src/json-schema-subset/compiler/combination.ts +109 -0
- package/src/json-schema-subset/compiler/common.ts +99 -0
- package/src/json-schema-subset/compiler/compiler.ts +188 -0
- package/src/json-schema-subset/compiler/enumAndConst.ts +75 -0
- package/src/json-schema-subset/compiler/index.ts +11 -0
- package/src/json-schema-subset/compiler/object.ts +411 -0
- package/src/json-schema-subset/compiler/primitive.ts +144 -0
- package/src/json-schema-subset/compiler/utils.ts +24 -0
- package/src/json-schema-subset/compiler/wrapper.ts +192 -0
- package/src/json-schema-subset/error.ts +55 -0
- package/src/json-schema-subset/expression/calculator.ts +442 -0
- package/src/json-schema-subset/expression/combination.ts +49 -0
- package/src/json-schema-subset/expression/expression.ts +191 -0
- package/src/json-schema-subset/expression/index.ts +25 -0
- package/src/json-schema-subset/expression/result.ts +88 -0
- package/src/json-schema-subset/expression/types.ts +36 -0
- package/src/json-schema-subset/extends/extendsContext.ts +89 -0
- package/src/json-schema-subset/extends/index.ts +2 -0
- package/src/json-schema-subset/extends/types.ts +12 -0
- package/src/json-schema-subset/global.ts +60 -0
- package/src/json-schema-subset/index.ts +8 -0
- package/src/json-schema-subset/preprocessing.ts +74 -0
- package/src/json-schema-subset/types.ts +8 -0
- package/src/json-schema-subset/utils.ts +95 -0
- package/src/localization/common/languages.ts +118 -0
- package/src/localization/common/timeZone.ts +25 -0
- package/src/openapi/common/authBindings.ts +12 -0
- package/src/openapi/common/openapi.ts +459 -0
- package/src/trigger/common/config.ts +56 -0
- package/src/trigger/common/configOptions.ts +15 -0
- package/src/trigger/common/configSchema.ts +8 -0
- package/src/trigger/common/contract.ts +132 -0
- package/src/trigger/common/cron.ts +151 -0
- package/src/trigger/common/integration.ts +498 -0
- package/src/trigger/common/poll.ts +187 -0
- package/src/trigger/common/webhook.ts +412 -0
- package/src/trigger/providers/airtable/locales/fr.json +18 -0
- package/src/trigger/providers/airtable/locales/ja.json +18 -0
- package/src/trigger/providers/airtable/locales/ko.json +18 -0
- package/src/trigger/providers/airtable/locales/ru.json +18 -0
- package/src/trigger/providers/airtable/locales/zh-CN.json +18 -0
- package/src/trigger/providers/airtable/locales/zh-TW.json +18 -0
- package/src/trigger/providers/asana/locales/fr.json +15 -0
- package/src/trigger/providers/asana/locales/ja.json +15 -0
- package/src/trigger/providers/asana/locales/ko.json +15 -0
- package/src/trigger/providers/asana/locales/ru.json +15 -0
- package/src/trigger/providers/asana/locales/zh-CN.json +15 -0
- package/src/trigger/providers/asana/locales/zh-TW.json +15 -0
- package/src/trigger/providers/calendly/locales/fr.json +16 -0
- package/src/trigger/providers/calendly/locales/ja.json +16 -0
- package/src/trigger/providers/calendly/locales/ko.json +16 -0
- package/src/trigger/providers/calendly/locales/ru.json +16 -0
- package/src/trigger/providers/calendly/locales/zh-CN.json +16 -0
- package/src/trigger/providers/calendly/locales/zh-TW.json +16 -0
- package/src/trigger/providers/catalog.generated.json +4996 -0
- package/src/trigger/providers/clickup/locales/fr.json +16 -0
- package/src/trigger/providers/clickup/locales/ja.json +16 -0
- package/src/trigger/providers/clickup/locales/ko.json +16 -0
- package/src/trigger/providers/clickup/locales/ru.json +16 -0
- package/src/trigger/providers/clickup/locales/zh-CN.json +16 -0
- package/src/trigger/providers/clickup/locales/zh-TW.json +16 -0
- package/src/trigger/providers/definitions.ts +19 -0
- package/src/trigger/providers/feishu/locales/fr.json +20 -0
- package/src/trigger/providers/feishu/locales/ja.json +20 -0
- package/src/trigger/providers/feishu/locales/ko.json +20 -0
- package/src/trigger/providers/feishu/locales/ru.json +20 -0
- package/src/trigger/providers/feishu/locales/zh-CN.json +20 -0
- package/src/trigger/providers/feishu/locales/zh-TW.json +20 -0
- package/src/trigger/providers/fieldDescriptions.ts +392 -0
- package/src/trigger/providers/fieldLabels.ts +256 -0
- package/src/trigger/providers/fireflies/locales/fr.json +17 -0
- package/src/trigger/providers/fireflies/locales/ja.json +17 -0
- package/src/trigger/providers/fireflies/locales/ko.json +17 -0
- package/src/trigger/providers/fireflies/locales/ru.json +17 -0
- package/src/trigger/providers/fireflies/locales/zh-CN.json +17 -0
- package/src/trigger/providers/fireflies/locales/zh-TW.json +17 -0
- package/src/trigger/providers/github/locales/fr.json +30 -0
- package/src/trigger/providers/github/locales/ja.json +30 -0
- package/src/trigger/providers/github/locales/ko.json +30 -0
- package/src/trigger/providers/github/locales/ru.json +30 -0
- package/src/trigger/providers/github/locales/zh-CN.json +30 -0
- package/src/trigger/providers/github/locales/zh-TW.json +30 -0
- package/src/trigger/providers/gitlab/locales/fr.json +18 -0
- package/src/trigger/providers/gitlab/locales/ja.json +18 -0
- package/src/trigger/providers/gitlab/locales/ko.json +18 -0
- package/src/trigger/providers/gitlab/locales/ru.json +18 -0
- package/src/trigger/providers/gitlab/locales/zh-CN.json +18 -0
- package/src/trigger/providers/gitlab/locales/zh-TW.json +18 -0
- package/src/trigger/providers/gmail/locales/fr.json +18 -0
- package/src/trigger/providers/gmail/locales/ja.json +18 -0
- package/src/trigger/providers/gmail/locales/ko.json +18 -0
- package/src/trigger/providers/gmail/locales/ru.json +18 -0
- package/src/trigger/providers/gmail/locales/zh-CN.json +18 -0
- package/src/trigger/providers/gmail/locales/zh-TW.json +18 -0
- package/src/trigger/providers/google-calendar/locales/fr.json +15 -0
- package/src/trigger/providers/google-calendar/locales/ja.json +15 -0
- package/src/trigger/providers/google-calendar/locales/ko.json +15 -0
- package/src/trigger/providers/google-calendar/locales/ru.json +15 -0
- package/src/trigger/providers/google-calendar/locales/zh-CN.json +15 -0
- package/src/trigger/providers/google-calendar/locales/zh-TW.json +15 -0
- package/src/trigger/providers/google-drive/locales/fr.json +48 -0
- package/src/trigger/providers/google-drive/locales/ja.json +48 -0
- package/src/trigger/providers/google-drive/locales/ko.json +48 -0
- package/src/trigger/providers/google-drive/locales/ru.json +48 -0
- package/src/trigger/providers/google-drive/locales/zh-CN.json +48 -0
- package/src/trigger/providers/google-drive/locales/zh-TW.json +48 -0
- package/src/trigger/providers/google-sheets/locales/fr.json +19 -0
- package/src/trigger/providers/google-sheets/locales/ja.json +19 -0
- package/src/trigger/providers/google-sheets/locales/ko.json +19 -0
- package/src/trigger/providers/google-sheets/locales/ru.json +19 -0
- package/src/trigger/providers/google-sheets/locales/zh-CN.json +19 -0
- package/src/trigger/providers/google-sheets/locales/zh-TW.json +19 -0
- package/src/trigger/providers/intercom/locales/fr.json +17 -0
- package/src/trigger/providers/intercom/locales/ja.json +17 -0
- package/src/trigger/providers/intercom/locales/ko.json +17 -0
- package/src/trigger/providers/intercom/locales/ru.json +17 -0
- package/src/trigger/providers/intercom/locales/zh-CN.json +17 -0
- package/src/trigger/providers/intercom/locales/zh-TW.json +17 -0
- package/src/trigger/providers/jira/locales/fr.json +17 -0
- package/src/trigger/providers/jira/locales/ja.json +17 -0
- package/src/trigger/providers/jira/locales/ko.json +17 -0
- package/src/trigger/providers/jira/locales/ru.json +17 -0
- package/src/trigger/providers/jira/locales/zh-CN.json +17 -0
- package/src/trigger/providers/jira/locales/zh-TW.json +17 -0
- package/src/trigger/providers/linear/locales/fr.json +13 -0
- package/src/trigger/providers/linear/locales/ja.json +13 -0
- package/src/trigger/providers/linear/locales/ko.json +13 -0
- package/src/trigger/providers/linear/locales/ru.json +13 -0
- package/src/trigger/providers/linear/locales/zh-CN.json +13 -0
- package/src/trigger/providers/linear/locales/zh-TW.json +13 -0
- package/src/trigger/providers/locales/fr.ts +71 -0
- package/src/trigger/providers/locales/ja.ts +71 -0
- package/src/trigger/providers/locales/ko.ts +71 -0
- package/src/trigger/providers/locales/ru.ts +71 -0
- package/src/trigger/providers/locales/zh-CN.ts +71 -0
- package/src/trigger/providers/locales/zh-TW.ts +71 -0
- package/src/trigger/providers/localization.ts +59 -0
- package/src/trigger/providers/notion/locales/fr.json +16 -0
- package/src/trigger/providers/notion/locales/ja.json +16 -0
- package/src/trigger/providers/notion/locales/ko.json +16 -0
- package/src/trigger/providers/notion/locales/ru.json +16 -0
- package/src/trigger/providers/notion/locales/zh-CN.json +16 -0
- package/src/trigger/providers/notion/locales/zh-TW.json +16 -0
- package/src/trigger/providers/one-drive/locales/fr.json +16 -0
- package/src/trigger/providers/one-drive/locales/ja.json +16 -0
- package/src/trigger/providers/one-drive/locales/ko.json +16 -0
- package/src/trigger/providers/one-drive/locales/ru.json +16 -0
- package/src/trigger/providers/one-drive/locales/zh-CN.json +16 -0
- package/src/trigger/providers/one-drive/locales/zh-TW.json +16 -0
- package/src/trigger/providers/outlook/locales/fr.json +18 -0
- package/src/trigger/providers/outlook/locales/ja.json +18 -0
- package/src/trigger/providers/outlook/locales/ko.json +18 -0
- package/src/trigger/providers/outlook/locales/ru.json +18 -0
- package/src/trigger/providers/outlook/locales/zh-CN.json +18 -0
- package/src/trigger/providers/outlook/locales/zh-TW.json +18 -0
- package/src/trigger/providers/pandadoc/locales/fr.json +12 -0
- package/src/trigger/providers/pandadoc/locales/ja.json +12 -0
- package/src/trigger/providers/pandadoc/locales/ko.json +12 -0
- package/src/trigger/providers/pandadoc/locales/ru.json +12 -0
- package/src/trigger/providers/pandadoc/locales/zh-CN.json +12 -0
- package/src/trigger/providers/pandadoc/locales/zh-TW.json +12 -0
- package/src/trigger/providers/pipedrive/locales/fr.json +15 -0
- package/src/trigger/providers/pipedrive/locales/ja.json +15 -0
- package/src/trigger/providers/pipedrive/locales/ko.json +15 -0
- package/src/trigger/providers/pipedrive/locales/ru.json +15 -0
- package/src/trigger/providers/pipedrive/locales/zh-CN.json +15 -0
- package/src/trigger/providers/pipedrive/locales/zh-TW.json +15 -0
- package/src/trigger/providers/remote.ts +163 -0
- package/src/trigger/providers/resend/locales/fr.json +16 -0
- package/src/trigger/providers/resend/locales/ja.json +16 -0
- package/src/trigger/providers/resend/locales/ko.json +16 -0
- package/src/trigger/providers/resend/locales/ru.json +16 -0
- package/src/trigger/providers/resend/locales/zh-CN.json +16 -0
- package/src/trigger/providers/resend/locales/zh-TW.json +16 -0
- package/src/trigger/providers/sentry/locales/fr.json +19 -0
- package/src/trigger/providers/sentry/locales/ja.json +19 -0
- package/src/trigger/providers/sentry/locales/ko.json +19 -0
- package/src/trigger/providers/sentry/locales/ru.json +19 -0
- package/src/trigger/providers/sentry/locales/zh-CN.json +19 -0
- package/src/trigger/providers/sentry/locales/zh-TW.json +19 -0
- package/src/trigger/providers/shopify/locales/fr.json +18 -0
- package/src/trigger/providers/shopify/locales/ja.json +18 -0
- package/src/trigger/providers/shopify/locales/ko.json +18 -0
- package/src/trigger/providers/shopify/locales/ru.json +18 -0
- package/src/trigger/providers/shopify/locales/zh-CN.json +18 -0
- package/src/trigger/providers/shopify/locales/zh-TW.json +18 -0
- package/src/trigger/providers/slack/locales/fr.json +18 -0
- package/src/trigger/providers/slack/locales/ja.json +18 -0
- package/src/trigger/providers/slack/locales/ko.json +18 -0
- package/src/trigger/providers/slack/locales/ru.json +18 -0
- package/src/trigger/providers/slack/locales/zh-CN.json +18 -0
- package/src/trigger/providers/slack/locales/zh-TW.json +18 -0
- package/src/trigger/providers/slackbot/locales/fr.json +23 -0
- package/src/trigger/providers/slackbot/locales/ja.json +23 -0
- package/src/trigger/providers/slackbot/locales/ko.json +23 -0
- package/src/trigger/providers/slackbot/locales/ru.json +23 -0
- package/src/trigger/providers/slackbot/locales/zh-CN.json +23 -0
- package/src/trigger/providers/slackbot/locales/zh-TW.json +23 -0
- package/src/trigger/providers/source-events.ts +25 -0
- package/src/trigger/providers/stripe/locales/fr.json +17 -0
- package/src/trigger/providers/stripe/locales/ja.json +17 -0
- package/src/trigger/providers/stripe/locales/ko.json +17 -0
- package/src/trigger/providers/stripe/locales/ru.json +17 -0
- package/src/trigger/providers/stripe/locales/zh-CN.json +17 -0
- package/src/trigger/providers/stripe/locales/zh-TW.json +17 -0
- package/src/trigger/providers/tally/locales/fr.json +12 -0
- package/src/trigger/providers/tally/locales/ja.json +12 -0
- package/src/trigger/providers/tally/locales/ko.json +12 -0
- package/src/trigger/providers/tally/locales/ru.json +12 -0
- package/src/trigger/providers/tally/locales/zh-CN.json +12 -0
- package/src/trigger/providers/tally/locales/zh-TW.json +12 -0
- package/src/trigger/providers/telegram/locales/fr.json +17 -0
- package/src/trigger/providers/telegram/locales/ja.json +17 -0
- package/src/trigger/providers/telegram/locales/ko.json +17 -0
- package/src/trigger/providers/telegram/locales/ru.json +17 -0
- package/src/trigger/providers/telegram/locales/zh-CN.json +17 -0
- package/src/trigger/providers/telegram/locales/zh-TW.json +17 -0
- package/src/trigger/providers/typeform/locales/fr.json +12 -0
- package/src/trigger/providers/typeform/locales/ja.json +12 -0
- package/src/trigger/providers/typeform/locales/ko.json +12 -0
- package/src/trigger/providers/typeform/locales/ru.json +12 -0
- package/src/trigger/providers/typeform/locales/zh-CN.json +12 -0
- package/src/trigger/providers/typeform/locales/zh-TW.json +12 -0
- package/src/trigger/providers/vercel/locales/fr.json +18 -0
- package/src/trigger/providers/vercel/locales/ja.json +18 -0
- package/src/trigger/providers/vercel/locales/ko.json +18 -0
- package/src/trigger/providers/vercel/locales/ru.json +18 -0
- package/src/trigger/providers/vercel/locales/zh-CN.json +18 -0
- package/src/trigger/providers/vercel/locales/zh-TW.json +18 -0
- package/src/trigger/providers/woocommerce/locales/fr.json +19 -0
- package/src/trigger/providers/woocommerce/locales/ja.json +19 -0
- package/src/trigger/providers/woocommerce/locales/ko.json +19 -0
- package/src/trigger/providers/woocommerce/locales/ru.json +19 -0
- package/src/trigger/providers/woocommerce/locales/zh-CN.json +19 -0
- package/src/trigger/providers/woocommerce/locales/zh-TW.json +19 -0
- package/src/trigger/providers/zendesk/locales/fr.json +15 -0
- package/src/trigger/providers/zendesk/locales/ja.json +15 -0
- package/src/trigger/providers/zendesk/locales/ko.json +15 -0
- package/src/trigger/providers/zendesk/locales/ru.json +15 -0
- package/src/trigger/providers/zendesk/locales/zh-CN.json +15 -0
- package/src/trigger/providers/zendesk/locales/zh-TW.json +15 -0
- package/src/trigger/providers/zoom/locales/fr.json +17 -0
- package/src/trigger/providers/zoom/locales/ja.json +17 -0
- package/src/trigger/providers/zoom/locales/ko.json +17 -0
- package/src/trigger/providers/zoom/locales/ru.json +17 -0
- package/src/trigger/providers/zoom/locales/zh-CN.json +17 -0
- package/src/trigger/providers/zoom/locales/zh-TW.json +17 -0
- package/src/types/index.ts +112 -0
- package/src/workflow/common/workflow.ts +273 -0
- package/dist/browser/lib-DrKav3HG.js +0 -11403
- /package/dist/{browser → common}/flow-authoring-edge.d.ts +0 -0
- /package/dist/{browser → common}/flow-authoring-module.d.ts +0 -0
- /package/dist/{browser → common}/flow-authoring.d.ts +0 -0
- /package/dist/{browser → common}/flow-input-value.d.ts +0 -0
- /package/dist/{browser → common}/webhook-method.d.ts +0 -0
|
@@ -0,0 +1,1036 @@
|
|
|
1
|
+
import type { JsonValue, Port, PortDefinition } from '../../types/index.ts'
|
|
2
|
+
|
|
3
|
+
import { assertOpenApiAuthBindings } from '../../openapi/common/authBindings.ts'
|
|
4
|
+
export { fixedInputValue, inputValue, inputValues } from './inputValue.ts'
|
|
5
|
+
import type { RetryConfiguration } from './retry.ts'
|
|
6
|
+
import type { WebhookMethod } from './webhookMethod.ts'
|
|
7
|
+
|
|
8
|
+
import { dequal } from 'dequal/lite'
|
|
9
|
+
import { authoringDefinitionSchemas, currentFlowModelVersion, decodeRevisionContent } from './changeSchema.ts'
|
|
10
|
+
import { nodeInputMappings, setConditionInput } from './condition.ts'
|
|
11
|
+
import { supportsNodeErrorHandling } from './errorHandling.ts'
|
|
12
|
+
import { supportsNodeRetry } from './retry.ts'
|
|
13
|
+
|
|
14
|
+
export { changeOperationsSchema, currentFlowModelVersion, decodeChangeOperations } from './changeSchema.ts'
|
|
15
|
+
export type { RetryConfiguration } from './retry.ts'
|
|
16
|
+
export { supportsNodeRetry } from './retry.ts'
|
|
17
|
+
export { nodeSystemOutputPorts, supportsNodeErrorHandling, nodeErrorSchema } from './errorHandling.ts'
|
|
18
|
+
export type { NodeErrorData } from './errorHandling.ts'
|
|
19
|
+
export type { WebhookMethod }
|
|
20
|
+
|
|
21
|
+
export type { JsonValue, Port, PortDefinition } from '../../types/index.ts'
|
|
22
|
+
|
|
23
|
+
export { isSchemaKeyword } from './schemaKeywords.ts'
|
|
24
|
+
export type { SchemaKeyword, SchemaMismatch } from './schemaKeywords.ts'
|
|
25
|
+
|
|
26
|
+
export const resourceNameMaxLength = 80
|
|
27
|
+
|
|
28
|
+
export type ResourceNameIssue = 'controlCharacter' | 'empty' | 'specialCharacter' | 'tooLong'
|
|
29
|
+
|
|
30
|
+
export function resourceNameIssue(value: string): ResourceNameIssue | undefined {
|
|
31
|
+
const name = value.trim()
|
|
32
|
+
if (name.length == 0) return 'empty'
|
|
33
|
+
if (name.length > resourceNameMaxLength) return 'tooLong'
|
|
34
|
+
for (const character of name) {
|
|
35
|
+
const code = character.charCodeAt(0)
|
|
36
|
+
if (code <= 0x1f || (code >= 0x7f && code <= 0x9f)) return 'controlCharacter'
|
|
37
|
+
}
|
|
38
|
+
if (!/^[\p{L}\p{N}](?:[\p{L}\p{N} _-]*[\p{L}\p{N}])?$/u.test(name)) return 'specialCharacter'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function validVariableName(value: string): boolean {
|
|
42
|
+
return value.length <= 256 && /^[A-Za-z_][A-Za-z0-9_]*$/.test(value) && value.slice(0, 3).toUpperCase() != 'OO_'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface InputPortDefinition extends PortDefinition {
|
|
46
|
+
readonly value?: JsonValue
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface InputPort extends InputPortDefinition {
|
|
50
|
+
readonly handle: string
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface Group {
|
|
54
|
+
readonly collapsed?: boolean
|
|
55
|
+
readonly group: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function portsByHandle<Value extends Port>(ports: readonly (Value | Group)[]): Readonly<Record<string, Value>> {
|
|
59
|
+
return Object.fromEntries(ports.flatMap((port) => ('handle' in port ? [[port.handle, port]] : [])))
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface NodeSource {
|
|
63
|
+
readonly system?: true
|
|
64
|
+
readonly field?: string
|
|
65
|
+
readonly kind: 'node'
|
|
66
|
+
readonly nodeId: string
|
|
67
|
+
readonly output: string
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface BindingSource {
|
|
71
|
+
readonly bindingId: string
|
|
72
|
+
readonly kind: 'binding'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export type FixedInputValue = { readonly kind: 'unset' } | { readonly kind: 'value'; readonly value: JsonValue }
|
|
76
|
+
export type InputValues = Readonly<Record<string, FixedInputValue>>
|
|
77
|
+
|
|
78
|
+
export type InputMapping = FixedInputValue | { readonly kind: 'sources'; readonly sources: readonly (BindingSource | NodeSource)[] }
|
|
79
|
+
|
|
80
|
+
interface GraphNodeBase {
|
|
81
|
+
readonly description?: string
|
|
82
|
+
readonly icon?: string
|
|
83
|
+
readonly inputs: Readonly<Record<string, InputMapping>>
|
|
84
|
+
readonly name?: string
|
|
85
|
+
readonly maxExecutions?: number
|
|
86
|
+
readonly timeoutMs?: number
|
|
87
|
+
readonly retry?: RetryConfiguration
|
|
88
|
+
readonly onError?: 'stop' | 'error'
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface ValueNode extends GraphNodeBase {
|
|
92
|
+
readonly kind: 'value'
|
|
93
|
+
readonly values: readonly InputPort[]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export type WaitAction = 'approve' | 'continue' | 'reject'
|
|
97
|
+
|
|
98
|
+
interface ResolutionNodeBase extends GraphNodeBase {
|
|
99
|
+
readonly inputDefinitions: readonly InputPort[]
|
|
100
|
+
readonly prompt: string
|
|
101
|
+
readonly timeoutMs?: never
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export type WaitAutoContinue =
|
|
105
|
+
| { readonly kind: 'after'; readonly durationMs: number | null }
|
|
106
|
+
| { readonly kind: 'at'; readonly at: string; readonly timezone?: string }
|
|
107
|
+
|
|
108
|
+
export interface WaitNode extends ResolutionNodeBase {
|
|
109
|
+
readonly autoContinue?: WaitAutoContinue
|
|
110
|
+
readonly kind: 'wait'
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface ApprovalNode extends ResolutionNodeBase {
|
|
114
|
+
readonly kind: 'approval'
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export type ResolutionNode = ApprovalNode | WaitNode
|
|
118
|
+
|
|
119
|
+
export type ConditionOperator =
|
|
120
|
+
| '!='
|
|
121
|
+
| '<'
|
|
122
|
+
| '<='
|
|
123
|
+
| '=='
|
|
124
|
+
| '>'
|
|
125
|
+
| '>='
|
|
126
|
+
| 'contains'
|
|
127
|
+
| 'endsWith'
|
|
128
|
+
| 'hasKey'
|
|
129
|
+
| 'hasValue'
|
|
130
|
+
| 'isEmpty'
|
|
131
|
+
| 'isFalse'
|
|
132
|
+
| 'isNotEmpty'
|
|
133
|
+
| 'isNotNull'
|
|
134
|
+
| 'isNull'
|
|
135
|
+
| 'isTrue'
|
|
136
|
+
| 'notContains'
|
|
137
|
+
| 'notHasKey'
|
|
138
|
+
| 'notHasValue'
|
|
139
|
+
| 'startsWith'
|
|
140
|
+
|
|
141
|
+
export type Source = BindingSource | NodeSource
|
|
142
|
+
|
|
143
|
+
export type ConditionOperand =
|
|
144
|
+
| { readonly kind: 'value'; readonly value?: JsonValue; readonly jsonSchema?: JsonValue }
|
|
145
|
+
| { readonly kind: 'source'; readonly source: Source }
|
|
146
|
+
|
|
147
|
+
export interface ConditionExpression {
|
|
148
|
+
readonly left: ConditionOperand
|
|
149
|
+
readonly operator: ConditionOperator
|
|
150
|
+
readonly right?: ConditionOperand
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface ConditionGroup {
|
|
154
|
+
readonly expressions: readonly ConditionExpression[]
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface ConditionCase {
|
|
158
|
+
readonly description?: string
|
|
159
|
+
readonly groups: readonly ConditionGroup[]
|
|
160
|
+
readonly output: string
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface ConditionNode extends GraphNodeBase {
|
|
164
|
+
readonly cases: readonly ConditionCase[]
|
|
165
|
+
readonly matchMode: 'first' | 'all'
|
|
166
|
+
readonly kind: 'condition'
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export type ManagedTaskExecutor =
|
|
170
|
+
| import('../../workflow/common/workflow.ts').WorkflowExecutor
|
|
171
|
+
| import('../../decision/common/decision.ts').DecisionExecutor
|
|
172
|
+
| import('../../openapi/common/openapi.ts').OpenApiExecutor
|
|
173
|
+
| { readonly kind: 'connector'; readonly action: string; readonly connectionId?: string; readonly outputMode?: 'value' }
|
|
174
|
+
| { readonly kind: 'llm'; readonly mode: 'chat' | 'json' }
|
|
175
|
+
| {
|
|
176
|
+
readonly kind: 'agent'
|
|
177
|
+
readonly code?: boolean
|
|
178
|
+
readonly model: string
|
|
179
|
+
readonly prompt: string
|
|
180
|
+
readonly maxRounds: number
|
|
181
|
+
readonly tools: readonly AgentTool[]
|
|
182
|
+
readonly notification?: {
|
|
183
|
+
readonly action: string
|
|
184
|
+
readonly connectionId?: string
|
|
185
|
+
readonly inputDefinitions: readonly InputPort[]
|
|
186
|
+
readonly messageHandle: string
|
|
187
|
+
readonly inputs: Readonly<Record<string, Exclude<AgentInput, { readonly kind: 'model' }>>>
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export type AgentInput = { readonly kind: 'value'; readonly value: JsonValue } | { readonly kind: 'input'; readonly input: string } | { readonly kind: 'model' }
|
|
192
|
+
|
|
193
|
+
interface AgentToolBase {
|
|
194
|
+
readonly id: string
|
|
195
|
+
readonly name: string
|
|
196
|
+
readonly description: string
|
|
197
|
+
readonly approval: boolean
|
|
198
|
+
readonly inputs: readonly (InputPort & { readonly source: AgentInput })[]
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export interface AgentConnectorTool extends AgentToolBase {
|
|
202
|
+
readonly kind?: 'connector'
|
|
203
|
+
readonly action: string
|
|
204
|
+
readonly connectionId?: string
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface WorkflowCapability {
|
|
208
|
+
readonly kind: 'workflow'
|
|
209
|
+
readonly name: string
|
|
210
|
+
readonly flowId: string
|
|
211
|
+
readonly revisionId: string
|
|
212
|
+
readonly inputs: readonly Port[]
|
|
213
|
+
readonly outputs: readonly Port[] | null
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface AgentWorkflowTool extends AgentToolBase, Omit<WorkflowCapability, 'inputs'> {
|
|
217
|
+
readonly action?: never
|
|
218
|
+
readonly connectionId?: never
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export type AgentTool = AgentConnectorTool | AgentWorkflowTool
|
|
222
|
+
export type TaskCapability = ConnectorCapability | WorkflowCapability
|
|
223
|
+
|
|
224
|
+
export const workflowToolNamePattern = /^[A-Za-z][A-Za-z0-9_-]{0,63}$/
|
|
225
|
+
|
|
226
|
+
export function workflowToolNameIssue(name: string, otherNames: Iterable<string> = []): 'invalid' | 'duplicate' | undefined {
|
|
227
|
+
if (!workflowToolNamePattern.test(name)) return 'invalid'
|
|
228
|
+
for (const other of otherNames) if (other == name) return 'duplicate'
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export function decodeTaskCapabilities(value: unknown): readonly TaskCapability[] {
|
|
232
|
+
if (!Array.isArray(value)) throw new TypeError('Task capabilities must be an array.')
|
|
233
|
+
const parsed = authoringDefinitionSchemas.capabilities.parse(value)
|
|
234
|
+
const connectors = decodeConnectorCapabilities(parsed.filter((item) => item.kind == 'connector'))
|
|
235
|
+
const names = new Set<string>()
|
|
236
|
+
for (const item of parsed) {
|
|
237
|
+
if (item.kind != 'workflow') continue
|
|
238
|
+
if (workflowToolNameIssue(item.name, names)) throw new TypeError('Workflow tool names must be unique provider-compatible names.')
|
|
239
|
+
names.add(item.name)
|
|
240
|
+
}
|
|
241
|
+
let connectorIndex = 0
|
|
242
|
+
return parsed.map((item) => (item.kind == 'connector' ? connectors[connectorIndex++]! : item)) as readonly TaskCapability[]
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export interface ConnectorAccessCapability {
|
|
246
|
+
readonly actionHints?: readonly string[]
|
|
247
|
+
readonly connectionHints?: readonly {
|
|
248
|
+
readonly action: string
|
|
249
|
+
readonly connectionId: string
|
|
250
|
+
readonly alias?: string
|
|
251
|
+
}[]
|
|
252
|
+
readonly kind: 'connector'
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export interface ConnectorActionCapability {
|
|
256
|
+
readonly action: string
|
|
257
|
+
readonly connections: readonly { readonly connectionId: string; readonly alias?: string }[]
|
|
258
|
+
readonly connectionId?: string
|
|
259
|
+
readonly kind: 'connector'
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export type ConnectorPermissionCapability =
|
|
263
|
+
| { readonly kind: 'connector'; readonly mode: 'shared' }
|
|
264
|
+
| { readonly kind: 'connector'; readonly mode: 'independent'; readonly actions: readonly { readonly action: string; readonly connectionId?: string }[] }
|
|
265
|
+
|
|
266
|
+
export type ConnectorCapability = ConnectorAccessCapability | ConnectorActionCapability | ConnectorPermissionCapability
|
|
267
|
+
|
|
268
|
+
export function decodeConnectorCapabilities(value: unknown): readonly ConnectorCapability[] {
|
|
269
|
+
if (!Array.isArray(value)) throw new TypeError('Connector capabilities must be an array.')
|
|
270
|
+
if (value.length == 0) return []
|
|
271
|
+
if (value.some((item) => item != null && typeof item == 'object' && !Array.isArray(item) && Object.hasOwn(item, 'mode'))) {
|
|
272
|
+
if (value.length != 1) throw new TypeError('Connector capability is declared more than once.')
|
|
273
|
+
const source = value[0] as Record<string, unknown>
|
|
274
|
+
if (source.mode == 'shared') {
|
|
275
|
+
if (source.kind != 'connector' || Object.keys(source).some((key) => !['kind', 'mode'].includes(key)))
|
|
276
|
+
throw new TypeError('Invalid shared Connector permission capability.')
|
|
277
|
+
return [{ kind: 'connector', mode: 'shared' }]
|
|
278
|
+
}
|
|
279
|
+
if (
|
|
280
|
+
Object.keys(source).some((key) => !['kind', 'mode', 'actions'].includes(key)) ||
|
|
281
|
+
source.kind != 'connector' ||
|
|
282
|
+
source.mode != 'independent' ||
|
|
283
|
+
!Array.isArray(source.actions)
|
|
284
|
+
)
|
|
285
|
+
throw new TypeError('Invalid Connector permission capability.')
|
|
286
|
+
const actions = source.actions.map((entry: unknown) => {
|
|
287
|
+
if (entry == null || typeof entry != 'object' || Array.isArray(entry)) throw new TypeError('Invalid Connector Action.')
|
|
288
|
+
const action = entry as Record<string, unknown>
|
|
289
|
+
if (
|
|
290
|
+
Object.keys(action).some((key) => !['action', 'connectionId'].includes(key)) ||
|
|
291
|
+
typeof action.action != 'string' ||
|
|
292
|
+
!/^[A-Za-z0-9_-]+\.[A-Za-z0-9_.-]+$/.test(action.action) ||
|
|
293
|
+
(Object.hasOwn(action, 'connectionId') && typeof action.connectionId != 'string')
|
|
294
|
+
)
|
|
295
|
+
throw new TypeError('Invalid Connector Action permission.')
|
|
296
|
+
return action.connectionId == null ? { action: action.action } : { action: action.action, connectionId: action.connectionId as string }
|
|
297
|
+
})
|
|
298
|
+
if (new Set(actions.map((action) => action.action)).size != actions.length) throw new TypeError('Duplicate Connector Action permission.')
|
|
299
|
+
return [{ kind: 'connector', mode: 'independent', actions }]
|
|
300
|
+
}
|
|
301
|
+
if (value.some((item) => item != null && typeof item == 'object' && !Array.isArray(item) && !Object.hasOwn(item, 'action'))) {
|
|
302
|
+
if (value.length != 1) throw new TypeError('Connector capability is declared more than once.')
|
|
303
|
+
const item = value[0]
|
|
304
|
+
if (item == null || typeof item != 'object' || Array.isArray(item)) throw new TypeError('Invalid Connector capability.')
|
|
305
|
+
const source = item as Record<string, unknown>
|
|
306
|
+
if (
|
|
307
|
+
Object.keys(source).some((key) => !['kind', 'actionHints', 'connectionHints'].includes(key)) ||
|
|
308
|
+
source.kind != 'connector' ||
|
|
309
|
+
(Object.hasOwn(source, 'actionHints') && !Array.isArray(source.actionHints)) ||
|
|
310
|
+
(Object.hasOwn(source, 'connectionHints') && !Array.isArray(source.connectionHints))
|
|
311
|
+
) {
|
|
312
|
+
throw new TypeError('Invalid Connector capability.')
|
|
313
|
+
}
|
|
314
|
+
const actionHints = ((source.actionHints as readonly unknown[] | undefined) ?? []).map((action: unknown) => {
|
|
315
|
+
if (typeof action != 'string' || !/^[A-Za-z0-9_-]+\.[A-Za-z0-9_.-]+$/.test(action)) throw new TypeError('Invalid Connector Action hint.')
|
|
316
|
+
return action
|
|
317
|
+
})
|
|
318
|
+
if (new Set(actionHints).size != actionHints.length) throw new TypeError('Duplicate Connector Action hint.')
|
|
319
|
+
const keys = new Set<string>()
|
|
320
|
+
const connectionHints = ((source.connectionHints as readonly unknown[] | undefined) ?? []).map((entry: unknown) => {
|
|
321
|
+
if (entry == null || typeof entry != 'object' || Array.isArray(entry)) throw new TypeError('Invalid Connector Connection hint.')
|
|
322
|
+
const hint = entry as Record<string, unknown>
|
|
323
|
+
if (
|
|
324
|
+
Object.keys(hint).some((key) => !['action', 'connectionId', 'alias'].includes(key)) ||
|
|
325
|
+
typeof hint.action != 'string' ||
|
|
326
|
+
!/^[A-Za-z0-9_-]+\.[A-Za-z0-9_.-]+$/.test(hint.action) ||
|
|
327
|
+
typeof hint.connectionId != 'string' ||
|
|
328
|
+
hint.connectionId.length == 0 ||
|
|
329
|
+
(Object.hasOwn(hint, 'alias') && (typeof hint.alias != 'string' || hint.alias.length == 0))
|
|
330
|
+
) {
|
|
331
|
+
throw new TypeError('Invalid Connector Connection hint.')
|
|
332
|
+
}
|
|
333
|
+
const key = `${hint.action}\0${hint.alias ?? ''}`
|
|
334
|
+
if (keys.has(key)) throw new TypeError('Duplicate Connector Connection hint.')
|
|
335
|
+
keys.add(key)
|
|
336
|
+
return hint.alias == null
|
|
337
|
+
? { action: hint.action, connectionId: hint.connectionId }
|
|
338
|
+
: { action: hint.action, connectionId: hint.connectionId, alias: hint.alias as string }
|
|
339
|
+
})
|
|
340
|
+
return [
|
|
341
|
+
{
|
|
342
|
+
kind: 'connector',
|
|
343
|
+
...(actionHints.length == 0 ? {} : { actionHints }),
|
|
344
|
+
...(connectionHints.length == 0 ? {} : { connectionHints }),
|
|
345
|
+
},
|
|
346
|
+
]
|
|
347
|
+
}
|
|
348
|
+
const actions = new Set<string>()
|
|
349
|
+
return value.map((item: unknown) => {
|
|
350
|
+
if (item == null || typeof item != 'object' || Array.isArray(item)) throw new TypeError('Invalid Connector capability.')
|
|
351
|
+
const source = item as Record<string, unknown>
|
|
352
|
+
if (
|
|
353
|
+
Object.keys(source).some((key) => !['kind', 'action', 'connections', 'connectionId'].includes(key)) ||
|
|
354
|
+
source.kind != 'connector' ||
|
|
355
|
+
typeof source.action != 'string' ||
|
|
356
|
+
!/^[A-Za-z0-9_-]+\.[A-Za-z0-9_.-]+$/.test(source.action) ||
|
|
357
|
+
!Array.isArray(source.connections)
|
|
358
|
+
) {
|
|
359
|
+
throw new TypeError('Invalid Connector capability.')
|
|
360
|
+
}
|
|
361
|
+
if (actions.has(source.action)) throw new TypeError('Connector Action is declared more than once.')
|
|
362
|
+
actions.add(source.action)
|
|
363
|
+
const ids = new Set<string>()
|
|
364
|
+
const aliases = new Set<string>()
|
|
365
|
+
const connections = source.connections.map((entry: unknown) => {
|
|
366
|
+
if (entry == null || typeof entry != 'object' || Array.isArray(entry)) throw new TypeError('Invalid Connector Connection.')
|
|
367
|
+
const connection = entry as Record<string, unknown>
|
|
368
|
+
if (
|
|
369
|
+
Object.keys(connection).some((key) => !['connectionId', 'alias'].includes(key)) ||
|
|
370
|
+
typeof connection.connectionId != 'string' ||
|
|
371
|
+
connection.connectionId.length == 0 ||
|
|
372
|
+
ids.has(connection.connectionId)
|
|
373
|
+
) {
|
|
374
|
+
throw new TypeError('Invalid or duplicate Connector Connection ID.')
|
|
375
|
+
}
|
|
376
|
+
ids.add(connection.connectionId)
|
|
377
|
+
if (Object.hasOwn(connection, 'alias')) {
|
|
378
|
+
if (typeof connection.alias != 'string' || connection.alias.length == 0 || aliases.has(connection.alias))
|
|
379
|
+
throw new TypeError('Invalid or duplicate Connector alias.')
|
|
380
|
+
aliases.add(connection.alias)
|
|
381
|
+
}
|
|
382
|
+
return { connectionId: connection.connectionId, ...(connection.alias == null ? {} : { alias: connection.alias as string }) }
|
|
383
|
+
})
|
|
384
|
+
if (Object.hasOwn(source, 'connectionId') && (typeof source.connectionId != 'string' || !ids.has(source.connectionId))) {
|
|
385
|
+
throw new TypeError('The default Connector Connection must be declared.')
|
|
386
|
+
}
|
|
387
|
+
return { kind: 'connector', action: source.action, connections, ...(source.connectionId == null ? {} : { connectionId: source.connectionId as string }) }
|
|
388
|
+
})
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
interface TaskDefinitionBase {
|
|
392
|
+
readonly inputs: readonly (InputPort | Group)[]
|
|
393
|
+
readonly name: string
|
|
394
|
+
readonly outputs: readonly (Port | Group)[]
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export interface InlineTaskDefinition extends TaskDefinitionBase {
|
|
398
|
+
readonly capabilities?: readonly TaskCapability[]
|
|
399
|
+
readonly moduleId: string
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
export interface ManagedTaskDefinition extends TaskDefinitionBase {
|
|
403
|
+
readonly executor: ManagedTaskExecutor
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export type TaskDefinition = InlineTaskDefinition | ManagedTaskDefinition
|
|
407
|
+
|
|
408
|
+
export interface TaskNode extends GraphNodeBase {
|
|
409
|
+
readonly kind: 'task'
|
|
410
|
+
readonly additionalInputs?: readonly InputPort[]
|
|
411
|
+
readonly task: TaskDefinition
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export interface Graph {
|
|
415
|
+
readonly edges: readonly GraphEdge[]
|
|
416
|
+
readonly nodes: Readonly<Record<string, GraphNode>>
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export type TriggerSchedule =
|
|
420
|
+
| { readonly expression: string; readonly timezone: string; readonly type: 'cron' }
|
|
421
|
+
| { readonly type: 'every'; readonly unit: 'day' | 'hour' | 'minute' | 'month' | 'week'; readonly value: number }
|
|
422
|
+
|
|
423
|
+
interface TriggerKeySnapshotBase {
|
|
424
|
+
readonly configInputs: readonly (InputPort | Group)[]
|
|
425
|
+
readonly definitionVersion: number
|
|
426
|
+
readonly description: string
|
|
427
|
+
readonly displayName: string
|
|
428
|
+
readonly key: string
|
|
429
|
+
readonly name: string
|
|
430
|
+
readonly outputs: readonly Port[]
|
|
431
|
+
readonly provider: string
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
export type IntegrationEndpointMethod = 'DELETE' | 'GET' | 'HEAD' | 'PATCH' | 'POST' | 'PUT'
|
|
435
|
+
|
|
436
|
+
export type IntegrationBodyFormat = 'form' | 'json' | 'multipart' | 'text'
|
|
437
|
+
|
|
438
|
+
export interface IntegrationEndpointDeclaration {
|
|
439
|
+
readonly body: {
|
|
440
|
+
readonly allowArray: boolean
|
|
441
|
+
readonly allowEmpty: boolean
|
|
442
|
+
readonly formats: readonly IntegrationBodyFormat[]
|
|
443
|
+
}
|
|
444
|
+
readonly methods: readonly IntegrationEndpointMethod[]
|
|
445
|
+
readonly successStatus: number
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
export type TriggerKeySnapshot =
|
|
449
|
+
| (TriggerKeySnapshotBase & { readonly type: 'poll' })
|
|
450
|
+
| (TriggerKeySnapshotBase & { readonly endpoint: IntegrationEndpointDeclaration; readonly type: 'integration' })
|
|
451
|
+
|
|
452
|
+
export interface WebhookBodyField extends InputPort {}
|
|
453
|
+
|
|
454
|
+
export interface WebhookOptions {
|
|
455
|
+
readonly allowedOrigins?: readonly string[]
|
|
456
|
+
readonly responseBody?:
|
|
457
|
+
| { readonly kind: 'workflow-outputs'; readonly output?: string; readonly timeoutMs?: number }
|
|
458
|
+
| { readonly kind: 'webhook-response'; readonly nodeId?: string; readonly timeoutMs?: number }
|
|
459
|
+
readonly responseData?: string
|
|
460
|
+
readonly responseHeaders?: Readonly<Record<string, string>>
|
|
461
|
+
readonly responseHeadersSource?: {
|
|
462
|
+
readonly kind: 'workflow-outputs'
|
|
463
|
+
readonly output?: string
|
|
464
|
+
}
|
|
465
|
+
readonly responseHeaderOutputs?: Readonly<Record<string, string>>
|
|
466
|
+
readonly responseStatusCode?: number
|
|
467
|
+
readonly responseStatusCodeOutput?: string
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
interface TriggerNodeBase {
|
|
471
|
+
readonly onError?: never
|
|
472
|
+
readonly description?: string
|
|
473
|
+
readonly icon?: string
|
|
474
|
+
readonly name: string
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
export type TriggerNode =
|
|
478
|
+
| (TriggerNodeBase & { readonly kind: 'manual' })
|
|
479
|
+
| (TriggerNodeBase & { readonly kind: 'start'; readonly inputDefs: readonly Port[] })
|
|
480
|
+
| (TriggerNodeBase & { readonly kind: 'error'; readonly sourceFlowIds?: readonly string[] })
|
|
481
|
+
| (TriggerNodeBase & {
|
|
482
|
+
readonly bodyFields: readonly WebhookBodyField[]
|
|
483
|
+
readonly kind: 'webhook'
|
|
484
|
+
readonly method: WebhookMethod
|
|
485
|
+
readonly options?: WebhookOptions
|
|
486
|
+
})
|
|
487
|
+
| (TriggerNodeBase & { readonly cronTimes: readonly TriggerSchedule[]; readonly kind: 'cron' })
|
|
488
|
+
| (TriggerNodeBase & {
|
|
489
|
+
readonly connectionId?: string
|
|
490
|
+
readonly config: InputValues
|
|
491
|
+
readonly definition: TriggerKeySnapshot & { readonly type: 'poll' }
|
|
492
|
+
readonly kind: 'poll'
|
|
493
|
+
readonly pollTimes: readonly TriggerSchedule[]
|
|
494
|
+
})
|
|
495
|
+
| (TriggerNodeBase & {
|
|
496
|
+
readonly connectionId?: string
|
|
497
|
+
readonly config: InputValues
|
|
498
|
+
readonly definition: TriggerKeySnapshot & { readonly type: 'integration' }
|
|
499
|
+
readonly kind: 'integration'
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
export interface OutputsNode extends Omit<GraphNodeBase, 'inputs'> {
|
|
503
|
+
readonly kind: 'outputs'
|
|
504
|
+
readonly outputDefs: readonly Port[]
|
|
505
|
+
readonly outputMappings: Readonly<Record<string, InputMapping>>
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export function isTriggerNode(node: GraphNode): node is TriggerNode {
|
|
509
|
+
return ['manual', 'start', 'error', 'webhook', 'cron', 'poll', 'integration'].includes(node.kind)
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
export interface WebhookResponseNode extends GraphNodeBase {
|
|
513
|
+
readonly kind: 'webhook-response'
|
|
514
|
+
readonly retry?: never
|
|
515
|
+
readonly onError?: never
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
export type GraphNode = WebhookResponseNode | OutputsNode | ApprovalNode | ConditionNode | TaskNode | TriggerNode | ValueNode | WaitNode
|
|
519
|
+
|
|
520
|
+
export interface FlowDocument {
|
|
521
|
+
readonly bindings: Readonly<Record<string, { readonly kind: 'variable'; readonly target: string }>>
|
|
522
|
+
readonly graph: Graph
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
export interface CodeModule {
|
|
526
|
+
readonly imports: readonly string[]
|
|
527
|
+
readonly name: string
|
|
528
|
+
readonly source: string
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
export interface RevisionContent {
|
|
532
|
+
readonly document: FlowDocument
|
|
533
|
+
readonly modelVersion: 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | typeof currentFlowModelVersion
|
|
534
|
+
readonly modules: Readonly<Record<string, CodeModule>>
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export interface GraphEdge {
|
|
538
|
+
readonly source: string
|
|
539
|
+
readonly sourceHandle?: string
|
|
540
|
+
readonly target: string
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/** Lossless upgrade of readable content. Historical content and its encoding stay unchanged. */
|
|
544
|
+
export function upgradeRevisionContent(content: RevisionContent): RevisionContent {
|
|
545
|
+
const upgraded = upgradeDecodedRevisionContent(decodeRevisionContent(content))
|
|
546
|
+
return dequal(content, upgraded) ? content : upgraded
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function upgradeDecodedRevisionContent(content: RevisionContent): RevisionContent {
|
|
550
|
+
const graph = content.document.graph
|
|
551
|
+
const hasManual = Object.values(graph.nodes).some((node) => node.kind == 'manual')
|
|
552
|
+
if (!hasManual && content.modelVersion == currentFlowModelVersion) return content
|
|
553
|
+
return {
|
|
554
|
+
...content,
|
|
555
|
+
modelVersion: currentFlowModelVersion,
|
|
556
|
+
document: {
|
|
557
|
+
...content.document,
|
|
558
|
+
graph: hasManual ? { ...graph, nodes: Object.fromEntries(Object.entries(graph.nodes).map(([id, node]) => [id, upgradeManualTrigger(node)])) } : graph,
|
|
559
|
+
},
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
export function upgradeManualTrigger(node: GraphNode): GraphNode {
|
|
564
|
+
return node.kind == 'manual' ? { ...node, kind: 'start', inputDefs: [] } : node
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
export function normalizeNodeName(value: string): string {
|
|
568
|
+
return value.trim().normalize('NFC')
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
export function nextNodeName(value: string, names: Iterable<string>): string {
|
|
572
|
+
const name = normalizeNodeName(value)
|
|
573
|
+
const used = new Set([...names].map(normalizeNodeName))
|
|
574
|
+
if (!used.has(name)) return name
|
|
575
|
+
const match = /^(.*) \((\d+)\)$/.exec(name)
|
|
576
|
+
const ordinalText = match?.[2]
|
|
577
|
+
const ordinal = ordinalText != null && Number(ordinalText) >= 2 ? Number(ordinalText) : undefined
|
|
578
|
+
const base = ordinal == null ? name : (match?.[1] ?? name)
|
|
579
|
+
let number = ordinal == null ? 2 : ordinal + 1
|
|
580
|
+
while (used.has(`${base} (${number})`)) number += 1
|
|
581
|
+
return `${base} (${number})`
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
export function nodeNameIssue(graph: Graph, nodeId: string, value: string): 'duplicate' | 'empty' | undefined {
|
|
585
|
+
const name = normalizeNodeName(value)
|
|
586
|
+
if (name.length == 0) return 'empty'
|
|
587
|
+
return Object.entries(graph.nodes).some(([candidateId, node]) => candidateId != nodeId && node.name != null && normalizeNodeName(node.name) == name)
|
|
588
|
+
? 'duplicate'
|
|
589
|
+
: undefined
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
export type ChangeOperation =
|
|
593
|
+
| { readonly kind: 'graph.node.replace'; readonly nodeId: string; readonly before: GraphNode; readonly node: GraphNode }
|
|
594
|
+
| {
|
|
595
|
+
readonly before?: readonly TaskCapability[]
|
|
596
|
+
readonly kind: 'graph.node.task.capabilities.set'
|
|
597
|
+
readonly nodeId: string
|
|
598
|
+
|
|
599
|
+
readonly value?: readonly TaskCapability[]
|
|
600
|
+
}
|
|
601
|
+
| { readonly kind: 'graph.trigger.sources.set'; readonly nodeId: string; readonly before?: readonly string[]; readonly value?: readonly string[] }
|
|
602
|
+
| { readonly binding: FlowDocument['bindings'][string]; readonly bindingId: string; readonly kind: 'binding.create' }
|
|
603
|
+
| { readonly bindingId: string; readonly kind: 'binding.delete' }
|
|
604
|
+
| { readonly before: string; readonly bindingId: string; readonly kind: 'binding.target.set'; readonly value: string }
|
|
605
|
+
| { readonly kind: 'graph.edge.connect'; readonly edge: GraphEdge }
|
|
606
|
+
| { readonly kind: 'graph.edge.disconnect'; readonly edge: GraphEdge }
|
|
607
|
+
| {
|
|
608
|
+
readonly before?: readonly InputPort[]
|
|
609
|
+
readonly kind: 'graph.node.additional-inputs.set'
|
|
610
|
+
readonly nodeId: string
|
|
611
|
+
|
|
612
|
+
readonly value?: readonly InputPort[]
|
|
613
|
+
}
|
|
614
|
+
| {
|
|
615
|
+
readonly before: Pick<ConditionNode, 'cases' | 'matchMode'>
|
|
616
|
+
readonly kind: 'graph.node.condition.set'
|
|
617
|
+
readonly nodeId: string
|
|
618
|
+
|
|
619
|
+
readonly value: Pick<ConditionNode, 'cases' | 'matchMode'>
|
|
620
|
+
}
|
|
621
|
+
| { readonly kind: 'graph.node.create'; readonly node: GraphNode; readonly nodeId: string }
|
|
622
|
+
| { readonly kind: 'graph.node.delete'; readonly nodeId: string }
|
|
623
|
+
| {
|
|
624
|
+
readonly before?: number | string
|
|
625
|
+
readonly field: 'connectionId' | 'description' | 'icon' | 'maxExecutions' | 'name' | 'timeoutMs' | 'onError'
|
|
626
|
+
readonly kind: 'graph.node.field.set'
|
|
627
|
+
readonly nodeId: string
|
|
628
|
+
|
|
629
|
+
readonly value?: number | string
|
|
630
|
+
}
|
|
631
|
+
| {
|
|
632
|
+
readonly before?: RetryConfiguration
|
|
633
|
+
readonly field: 'retry'
|
|
634
|
+
readonly kind: 'graph.node.field.set'
|
|
635
|
+
readonly nodeId: string
|
|
636
|
+
readonly value?: RetryConfiguration
|
|
637
|
+
}
|
|
638
|
+
| {
|
|
639
|
+
readonly before?: InputMapping
|
|
640
|
+
readonly handle: string
|
|
641
|
+
readonly kind: 'graph.node.input.set'
|
|
642
|
+
readonly nodeId: string
|
|
643
|
+
|
|
644
|
+
readonly value?: InputMapping
|
|
645
|
+
}
|
|
646
|
+
| {
|
|
647
|
+
readonly before: Pick<InlineTaskDefinition, 'inputs' | 'outputs'>
|
|
648
|
+
readonly kind: 'graph.node.task.ports.set'
|
|
649
|
+
readonly nodeId: string
|
|
650
|
+
|
|
651
|
+
readonly value: Pick<InlineTaskDefinition, 'inputs' | 'outputs'>
|
|
652
|
+
}
|
|
653
|
+
| {
|
|
654
|
+
readonly before: string
|
|
655
|
+
readonly kind: 'graph.node.task.name.set'
|
|
656
|
+
readonly nodeId: string
|
|
657
|
+
|
|
658
|
+
readonly value: string
|
|
659
|
+
}
|
|
660
|
+
| {
|
|
661
|
+
readonly before: readonly InputPort[]
|
|
662
|
+
readonly kind: 'graph.node.values.set'
|
|
663
|
+
readonly nodeId: string
|
|
664
|
+
|
|
665
|
+
readonly value: readonly InputPort[]
|
|
666
|
+
}
|
|
667
|
+
| {
|
|
668
|
+
readonly before: Pick<WaitNode, 'inputDefinitions' | 'prompt' | 'autoContinue'>
|
|
669
|
+
readonly kind: 'graph.node.resolution.set'
|
|
670
|
+
readonly nodeId: string
|
|
671
|
+
|
|
672
|
+
readonly value: Pick<WaitNode, 'inputDefinitions' | 'prompt' | 'autoContinue'>
|
|
673
|
+
}
|
|
674
|
+
| {
|
|
675
|
+
readonly before: Pick<Extract<TriggerNode, { readonly kind: 'webhook' }>, 'bodyFields' | 'method' | 'options'>
|
|
676
|
+
readonly kind: 'graph.node.webhook.set'
|
|
677
|
+
readonly nodeId: string
|
|
678
|
+
|
|
679
|
+
readonly value: Pick<Extract<TriggerNode, { readonly kind: 'webhook' }>, 'bodyFields' | 'method' | 'options'>
|
|
680
|
+
}
|
|
681
|
+
| {
|
|
682
|
+
readonly before?: FixedInputValue
|
|
683
|
+
readonly kind: 'graph.trigger.config.set'
|
|
684
|
+
readonly name: string
|
|
685
|
+
readonly nodeId: string
|
|
686
|
+
readonly value?: FixedInputValue
|
|
687
|
+
}
|
|
688
|
+
| {
|
|
689
|
+
readonly before: readonly TriggerSchedule[]
|
|
690
|
+
readonly kind: 'graph.trigger.schedule.set'
|
|
691
|
+
readonly nodeId: string
|
|
692
|
+
readonly value: readonly TriggerSchedule[]
|
|
693
|
+
}
|
|
694
|
+
| { readonly kind: 'module.create'; readonly module: CodeModule; readonly moduleId: string }
|
|
695
|
+
| { readonly kind: 'module.delete'; readonly moduleId: string }
|
|
696
|
+
| { readonly before: string; readonly kind: 'module.rename'; readonly moduleId: string; readonly name: string }
|
|
697
|
+
| {
|
|
698
|
+
readonly beforeImports: readonly string[]
|
|
699
|
+
readonly beforeSource: string
|
|
700
|
+
readonly imports: readonly string[]
|
|
701
|
+
readonly kind: 'module.source.replace'
|
|
702
|
+
readonly moduleId: string
|
|
703
|
+
readonly source: string
|
|
704
|
+
}
|
|
705
|
+
| {
|
|
706
|
+
readonly kind: 'graph.node.task.set'
|
|
707
|
+
readonly nodeId: string
|
|
708
|
+
|
|
709
|
+
readonly before: TaskDefinition
|
|
710
|
+
readonly value: TaskDefinition
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
export class FlowChangeError extends Error {
|
|
714
|
+
constructor(message: string) {
|
|
715
|
+
super(message)
|
|
716
|
+
this.name = 'FlowChangeError'
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
function invalid(message: string): never {
|
|
721
|
+
throw new FlowChangeError(message)
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
export function applyFlowChanges(content: RevisionContent, operations: readonly ChangeOperation[]): RevisionContent {
|
|
725
|
+
const source =
|
|
726
|
+
content.modelVersion != currentFlowModelVersion || Object.values(content.document.graph.nodes).some((node) => node.kind == 'manual')
|
|
727
|
+
? decodeRevisionContent(content)
|
|
728
|
+
: content
|
|
729
|
+
const document = { ...source.document }
|
|
730
|
+
const modules = { ...source.modules }
|
|
731
|
+
for (const operation of operations) {
|
|
732
|
+
switch (operation.kind) {
|
|
733
|
+
case 'graph.trigger.sources.set': {
|
|
734
|
+
const graph = document.graph
|
|
735
|
+
const node = graph.nodes[operation.nodeId]
|
|
736
|
+
if (node?.kind != 'error') invalid('The Flow Error node does not exist.')
|
|
737
|
+
if (!dequal(node.sourceFlowIds, operation.before)) invalid('The Flow Error node’s sources changed before this operation was applied.')
|
|
738
|
+
const { sourceFlowIds: _, ...base } = node
|
|
739
|
+
const updated = operation.value == null ? base : { ...base, sourceFlowIds: operation.value }
|
|
740
|
+
document.graph = { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: updated } }
|
|
741
|
+
break
|
|
742
|
+
}
|
|
743
|
+
case 'binding.create':
|
|
744
|
+
if (document.bindings[operation.bindingId] != null) invalid('A Binding with this ID already exists.')
|
|
745
|
+
document.bindings = { ...document.bindings, [operation.bindingId]: operation.binding }
|
|
746
|
+
break
|
|
747
|
+
case 'binding.delete': {
|
|
748
|
+
if (document.bindings[operation.bindingId] == null) invalid('The Binding does not exist.')
|
|
749
|
+
const bindings = { ...document.bindings }
|
|
750
|
+
delete bindings[operation.bindingId]
|
|
751
|
+
document.bindings = bindings
|
|
752
|
+
break
|
|
753
|
+
}
|
|
754
|
+
case 'binding.target.set': {
|
|
755
|
+
const binding = document.bindings[operation.bindingId]
|
|
756
|
+
if (binding == null) invalid('The Binding does not exist.')
|
|
757
|
+
if (binding.target != operation.before) invalid('The Binding target changed before this operation was applied.')
|
|
758
|
+
document.bindings = { ...document.bindings, [operation.bindingId]: { ...binding, target: operation.value } }
|
|
759
|
+
break
|
|
760
|
+
}
|
|
761
|
+
case 'graph.edge.connect': {
|
|
762
|
+
const graph = document.graph
|
|
763
|
+
if (graph.nodes[operation.edge.source] == null) invalid('The source Node does not exist.')
|
|
764
|
+
if (graph.nodes[operation.edge.source]?.kind == 'outputs') invalid('Outputs cannot have downstream execution edges.')
|
|
765
|
+
const node = graph.nodes[operation.edge.target]
|
|
766
|
+
if (node == null || isTriggerNode(node)) invalid('The target Node does not accept execution dependencies.')
|
|
767
|
+
if (graph.edges.some((edge) => dequal(edge, operation.edge))) invalid('The Nodes are already connected.')
|
|
768
|
+
Object.assign(document, { graph: { ...graph, edges: [...graph.edges, operation.edge] } })
|
|
769
|
+
break
|
|
770
|
+
}
|
|
771
|
+
case 'graph.edge.disconnect': {
|
|
772
|
+
const graph = document.graph
|
|
773
|
+
const edges = graph.edges.filter((edge) => !dequal(edge, operation.edge))
|
|
774
|
+
if (edges.length == graph.edges.length) invalid('The Nodes are not connected.')
|
|
775
|
+
Object.assign(document, { graph: { ...graph, edges } })
|
|
776
|
+
break
|
|
777
|
+
}
|
|
778
|
+
case 'graph.node.additional-inputs.set': {
|
|
779
|
+
const graph = document.graph
|
|
780
|
+
const node = graph.nodes[operation.nodeId]
|
|
781
|
+
if (node?.kind != 'task') invalid('The Task Node does not exist.')
|
|
782
|
+
if (!dequal(node.additionalInputs, operation.before)) invalid('The Task Node inputs changed before this operation was applied.')
|
|
783
|
+
const { additionalInputs: _, ...rest } = node
|
|
784
|
+
const updated: TaskNode = operation.value == null ? rest : { ...rest, additionalInputs: operation.value }
|
|
785
|
+
Object.assign(document, { graph: { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: updated } } })
|
|
786
|
+
break
|
|
787
|
+
}
|
|
788
|
+
case 'graph.node.condition.set': {
|
|
789
|
+
const graph = document.graph
|
|
790
|
+
const node = graph.nodes[operation.nodeId]
|
|
791
|
+
if (node?.kind != 'condition') invalid('The Condition Node does not exist.')
|
|
792
|
+
if (!dequal(node.cases, operation.before.cases) || node.matchMode != operation.before.matchMode) {
|
|
793
|
+
invalid('The Condition Node changed before this operation was applied.')
|
|
794
|
+
}
|
|
795
|
+
const updated: ConditionNode = { ...node, ...operation.value }
|
|
796
|
+
Object.assign(document, { graph: { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: updated } } })
|
|
797
|
+
break
|
|
798
|
+
}
|
|
799
|
+
case 'graph.node.replace': {
|
|
800
|
+
const graph = document.graph
|
|
801
|
+
if (!dequal(graph.nodes[operation.nodeId], operation.before)) invalid('The Node changed before this operation was applied.')
|
|
802
|
+
if (operation.node.kind != operation.before.kind) invalid('Replacing a Node cannot change its kind.')
|
|
803
|
+
if (operation.node.kind == 'task' && 'moduleId' in operation.node.task && operation.node.task.capabilities !== undefined)
|
|
804
|
+
decodeTaskCapabilities(operation.node.task.capabilities)
|
|
805
|
+
const name = normalizeNodeName(operation.node.name ?? '')
|
|
806
|
+
const issue = nodeNameIssue(graph, operation.nodeId, name)
|
|
807
|
+
if (issue != null) invalid(`Node name is ${issue}.`)
|
|
808
|
+
const node = name == operation.node.name ? operation.node : { ...operation.node, name }
|
|
809
|
+
Object.assign(document, { graph: { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: node } } })
|
|
810
|
+
break
|
|
811
|
+
}
|
|
812
|
+
case 'graph.node.create': {
|
|
813
|
+
const graph = document.graph
|
|
814
|
+
if (graph.nodes[operation.nodeId] != null) invalid('A Node with this ID already exists in the target graph.')
|
|
815
|
+
if (operation.node.kind == 'error' && Object.values(graph.nodes).some((node) => node.kind == 'error'))
|
|
816
|
+
invalid('A graph can contain only one Flow Error node.')
|
|
817
|
+
if (
|
|
818
|
+
(operation.node.kind == 'manual' || operation.node.kind == 'start') &&
|
|
819
|
+
Object.values(graph.nodes).some((node) => node.kind == 'manual' || node.kind == 'start')
|
|
820
|
+
) {
|
|
821
|
+
invalid('A graph can contain only one Start Trigger.')
|
|
822
|
+
}
|
|
823
|
+
if (operation.node.kind == 'task' && 'moduleId' in operation.node.task && operation.node.task.capabilities !== undefined)
|
|
824
|
+
decodeTaskCapabilities(operation.node.task.capabilities)
|
|
825
|
+
if (operation.node.name == null) invalid('A Node name cannot be empty.')
|
|
826
|
+
if (operation.node.kind == 'outputs' && Object.values(graph.nodes).some((node) => node.kind == 'outputs'))
|
|
827
|
+
invalid('A graph can contain only one Outputs node.')
|
|
828
|
+
const name = normalizeNodeName(operation.node.name)
|
|
829
|
+
const issue = nodeNameIssue(graph, operation.nodeId, name)
|
|
830
|
+
if (issue == 'empty') invalid('A Node name cannot be empty.')
|
|
831
|
+
if (issue == 'duplicate') invalid('A Node with this name already exists in the target graph.')
|
|
832
|
+
const node = name == operation.node.name ? operation.node : { ...operation.node, name }
|
|
833
|
+
Object.assign(document, { graph: { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: node } } })
|
|
834
|
+
break
|
|
835
|
+
}
|
|
836
|
+
case 'graph.node.delete': {
|
|
837
|
+
const graph = document.graph
|
|
838
|
+
if (graph.nodes[operation.nodeId] == null) invalid('The Node does not exist in the target graph.')
|
|
839
|
+
const removed = new Set([operation.nodeId])
|
|
840
|
+
const nodes = Object.fromEntries(Object.entries(graph.nodes).filter(([nodeId]) => !removed.has(nodeId)))
|
|
841
|
+
Object.assign(document, {
|
|
842
|
+
graph: {
|
|
843
|
+
...graph,
|
|
844
|
+
edges: graph.edges.filter((edge) => !removed.has(edge.source) && !removed.has(edge.target)),
|
|
845
|
+
nodes,
|
|
846
|
+
},
|
|
847
|
+
})
|
|
848
|
+
break
|
|
849
|
+
}
|
|
850
|
+
case 'graph.node.field.set': {
|
|
851
|
+
const graph = document.graph
|
|
852
|
+
const node = graph.nodes[operation.nodeId]
|
|
853
|
+
if (node == null) invalid('The Node does not exist in the target graph.')
|
|
854
|
+
if (
|
|
855
|
+
operation.field == 'onError' &&
|
|
856
|
+
operation.value != null &&
|
|
857
|
+
(!supportsNodeErrorHandling(node) || !['stop', 'error'].includes(String(operation.value)))
|
|
858
|
+
)
|
|
859
|
+
invalid('This node does not support this error handling setting.')
|
|
860
|
+
if (operation.field == 'retry' && operation.value != null && !supportsNodeRetry(node)) invalid('This node does not support retries.')
|
|
861
|
+
if (operation.field == 'connectionId' && node.kind != 'poll' && node.kind != 'integration') invalid('Only provider Triggers select a node Connection.')
|
|
862
|
+
if (!dequal(Reflect.get(node, operation.field), operation.before)) invalid('The Node field changed before this operation was applied.')
|
|
863
|
+
const updated = { ...node }
|
|
864
|
+
if (operation.field == 'name') {
|
|
865
|
+
if (typeof operation.value != 'string') invalid('A Node name cannot be empty.')
|
|
866
|
+
const name = normalizeNodeName(operation.value as string)
|
|
867
|
+
const issue = nodeNameIssue(graph, operation.nodeId, name)
|
|
868
|
+
if (issue == 'empty') invalid('A Node name cannot be empty.')
|
|
869
|
+
if (issue == 'duplicate') invalid('A Node with this name already exists in the target graph.')
|
|
870
|
+
Object.assign(updated, { name })
|
|
871
|
+
} else if (operation.value == null) Reflect.deleteProperty(updated, operation.field)
|
|
872
|
+
else Object.assign(updated, { [operation.field]: operation.value })
|
|
873
|
+
Object.assign(document, { graph: { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: updated } } })
|
|
874
|
+
break
|
|
875
|
+
}
|
|
876
|
+
case 'graph.node.input.set': {
|
|
877
|
+
const graph = document.graph
|
|
878
|
+
const node = graph.nodes[operation.nodeId]
|
|
879
|
+
if (node == null || isTriggerNode(node)) invalid('The Node does not accept inputs.')
|
|
880
|
+
if (!dequal(nodeInputMappings(node)[operation.handle], operation.before)) invalid('The Node input changed before this operation was applied.')
|
|
881
|
+
const inputs = { ...nodeInputMappings(node) }
|
|
882
|
+
if (operation.value == null) delete inputs[operation.handle]
|
|
883
|
+
else inputs[operation.handle] = operation.value
|
|
884
|
+
if (node.kind == 'outputs') {
|
|
885
|
+
document.graph = { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: { ...node, outputMappings: inputs } } }
|
|
886
|
+
break
|
|
887
|
+
}
|
|
888
|
+
Object.assign(document, {
|
|
889
|
+
graph: {
|
|
890
|
+
...graph,
|
|
891
|
+
nodes: {
|
|
892
|
+
...graph.nodes,
|
|
893
|
+
[operation.nodeId]: node.kind == 'condition' ? setConditionInput(node, operation.handle, operation.value) : { ...node, inputs },
|
|
894
|
+
},
|
|
895
|
+
},
|
|
896
|
+
})
|
|
897
|
+
break
|
|
898
|
+
}
|
|
899
|
+
case 'graph.node.task.capabilities.set': {
|
|
900
|
+
const graph = document.graph
|
|
901
|
+
const node = graph.nodes[operation.nodeId]
|
|
902
|
+
if (node?.kind != 'task' || !('moduleId' in node.task)) invalid('The inline Task Node does not exist.')
|
|
903
|
+
if (!dequal(node.task.capabilities, operation.before)) invalid('The inline Task capabilities changed before this operation was applied.')
|
|
904
|
+
const task = { ...node.task }
|
|
905
|
+
if (operation.value === undefined) delete task.capabilities
|
|
906
|
+
else task.capabilities = decodeTaskCapabilities(operation.value)
|
|
907
|
+
Object.assign(document, { graph: { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: { ...node, task } } } })
|
|
908
|
+
break
|
|
909
|
+
}
|
|
910
|
+
case 'graph.node.task.name.set': {
|
|
911
|
+
const graph = document.graph
|
|
912
|
+
const node = graph.nodes[operation.nodeId]
|
|
913
|
+
if (node?.kind != 'task' || !('moduleId' in node.task)) invalid('The inline Task Node does not exist.')
|
|
914
|
+
if (node.task.name != operation.before) invalid('The inline Task name changed before this operation was applied.')
|
|
915
|
+
const updated = { ...node, task: { ...node.task, name: operation.value } }
|
|
916
|
+
Object.assign(document, { graph: { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: updated } } })
|
|
917
|
+
break
|
|
918
|
+
}
|
|
919
|
+
case 'graph.node.task.ports.set': {
|
|
920
|
+
const graph = document.graph
|
|
921
|
+
const node = graph.nodes[operation.nodeId]
|
|
922
|
+
if (node?.kind != 'task' || !('moduleId' in node.task)) invalid('The inline Task Node does not exist.')
|
|
923
|
+
if (!dequal({ inputs: node.task.inputs, outputs: node.task.outputs }, operation.before)) {
|
|
924
|
+
invalid('The inline Task ports changed before this operation was applied.')
|
|
925
|
+
}
|
|
926
|
+
const updated = { ...node, task: { ...node.task, inputs: operation.value.inputs, outputs: operation.value.outputs } }
|
|
927
|
+
Object.assign(document, { graph: { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: updated } } })
|
|
928
|
+
break
|
|
929
|
+
}
|
|
930
|
+
case 'graph.node.values.set': {
|
|
931
|
+
const graph = document.graph
|
|
932
|
+
const node = graph.nodes[operation.nodeId]
|
|
933
|
+
if (node?.kind != 'value') invalid('The Value Node does not exist.')
|
|
934
|
+
if (!dequal(node.values, operation.before)) invalid('The Value Node changed before this operation was applied.')
|
|
935
|
+
Object.assign(document, { graph: { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: { ...node, values: operation.value } } } })
|
|
936
|
+
break
|
|
937
|
+
}
|
|
938
|
+
case 'graph.node.resolution.set': {
|
|
939
|
+
const graph = document.graph
|
|
940
|
+
const node = graph.nodes[operation.nodeId]
|
|
941
|
+
if (
|
|
942
|
+
(node?.kind != 'wait' && node?.kind != 'approval') ||
|
|
943
|
+
!dequal(
|
|
944
|
+
{
|
|
945
|
+
inputDefinitions: node.inputDefinitions,
|
|
946
|
+
prompt: node.prompt,
|
|
947
|
+
...(node.kind == 'wait' && node.autoContinue != null ? { autoContinue: node.autoContinue } : {}),
|
|
948
|
+
},
|
|
949
|
+
operation.before,
|
|
950
|
+
)
|
|
951
|
+
) {
|
|
952
|
+
invalid('The resolution node changed before this operation was applied.')
|
|
953
|
+
}
|
|
954
|
+
if (node.kind == 'approval' && operation.value.autoContinue != null) invalid('Approval does not support automatic continuation.')
|
|
955
|
+
const updated: ResolutionNode = { ...node, ...operation.value }
|
|
956
|
+
if (updated.kind == 'wait' && operation.value.autoContinue == null) Reflect.deleteProperty(updated, 'autoContinue')
|
|
957
|
+
document.graph = { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: updated } }
|
|
958
|
+
break
|
|
959
|
+
}
|
|
960
|
+
case 'graph.node.webhook.set': {
|
|
961
|
+
const graph = document.graph
|
|
962
|
+
const node = graph.nodes[operation.nodeId]
|
|
963
|
+
if (node?.kind != 'webhook') invalid('The Webhook Node does not exist.')
|
|
964
|
+
if (
|
|
965
|
+
node.method != operation.before.method ||
|
|
966
|
+
!dequal(node.bodyFields, operation.before.bodyFields) ||
|
|
967
|
+
!dequal(node.options, operation.before.options)
|
|
968
|
+
) {
|
|
969
|
+
invalid('The Webhook Node changed before this operation was applied.')
|
|
970
|
+
}
|
|
971
|
+
const { options: _, ...rest } = node
|
|
972
|
+
const updated: TriggerNode =
|
|
973
|
+
operation.value.options == null
|
|
974
|
+
? { ...rest, bodyFields: operation.value.bodyFields, method: operation.value.method }
|
|
975
|
+
: { ...node, ...operation.value }
|
|
976
|
+
Object.assign(document, { graph: { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: updated } } })
|
|
977
|
+
break
|
|
978
|
+
}
|
|
979
|
+
case 'graph.trigger.config.set': {
|
|
980
|
+
const graph = document.graph
|
|
981
|
+
const node = graph.nodes[operation.nodeId]
|
|
982
|
+
if (node == null || (node.kind != 'integration' && node.kind != 'poll')) invalid('The configurable Trigger Node does not exist.')
|
|
983
|
+
if (!dequal(node.config[operation.name], operation.before)) invalid('The Trigger configuration changed before this operation was applied.')
|
|
984
|
+
const config = { ...node.config }
|
|
985
|
+
if (operation.value === undefined) delete config[operation.name]
|
|
986
|
+
else config[operation.name] = operation.value
|
|
987
|
+
document.graph = { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: { ...node, config } } }
|
|
988
|
+
break
|
|
989
|
+
}
|
|
990
|
+
case 'graph.trigger.schedule.set': {
|
|
991
|
+
const graph = document.graph
|
|
992
|
+
const node = graph.nodes[operation.nodeId]
|
|
993
|
+
if (node == null || (node.kind != 'cron' && node.kind != 'poll')) invalid('The scheduled Trigger Node does not exist.')
|
|
994
|
+
const before = node.kind == 'cron' ? node.cronTimes : node.pollTimes
|
|
995
|
+
if (!dequal(before, operation.before)) invalid('The Trigger schedule changed before this operation was applied.')
|
|
996
|
+
const updated: TriggerNode = node.kind == 'cron' ? { ...node, cronTimes: operation.value } : { ...node, pollTimes: operation.value }
|
|
997
|
+
document.graph = { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: updated } }
|
|
998
|
+
break
|
|
999
|
+
}
|
|
1000
|
+
case 'module.create':
|
|
1001
|
+
if (modules[operation.moduleId] != null) invalid('A CodeModule with this ID already exists.')
|
|
1002
|
+
modules[operation.moduleId] = operation.module
|
|
1003
|
+
break
|
|
1004
|
+
case 'module.delete':
|
|
1005
|
+
if (modules[operation.moduleId] == null) invalid('The CodeModule does not exist.')
|
|
1006
|
+
delete modules[operation.moduleId]
|
|
1007
|
+
break
|
|
1008
|
+
case 'module.rename': {
|
|
1009
|
+
const module = modules[operation.moduleId]
|
|
1010
|
+
if (module == null) invalid('The CodeModule does not exist.')
|
|
1011
|
+
if (module.name != operation.before) invalid('The CodeModule name changed before this operation was applied.')
|
|
1012
|
+
modules[operation.moduleId] = { ...module, name: operation.name }
|
|
1013
|
+
break
|
|
1014
|
+
}
|
|
1015
|
+
case 'module.source.replace': {
|
|
1016
|
+
const module = modules[operation.moduleId]
|
|
1017
|
+
if (module == null) invalid('The CodeModule does not exist.')
|
|
1018
|
+
if (module.source != operation.beforeSource || !dequal(module.imports, operation.beforeImports)) {
|
|
1019
|
+
invalid('The CodeModule source changed before this operation was applied.')
|
|
1020
|
+
}
|
|
1021
|
+
modules[operation.moduleId] = { ...module, imports: operation.imports, source: operation.source }
|
|
1022
|
+
break
|
|
1023
|
+
}
|
|
1024
|
+
case 'graph.node.task.set': {
|
|
1025
|
+
const graph = document.graph
|
|
1026
|
+
const node = graph.nodes[operation.nodeId]
|
|
1027
|
+
if (node?.kind != 'task') invalid('The Task Node does not exist.')
|
|
1028
|
+
if (!dequal(node.task, operation.before)) invalid('The Task configuration changed before this operation was applied.')
|
|
1029
|
+
document.graph = { ...graph, nodes: { ...graph.nodes, [operation.nodeId]: { ...node, task: operation.value } } }
|
|
1030
|
+
break
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
assertOpenApiAuthBindings(document)
|
|
1035
|
+
return upgradeDecodedRevisionContent({ document, modelVersion: currentFlowModelVersion, modules })
|
|
1036
|
+
}
|