@oomol-lab/open-flow 0.1.0-beta.73 → 0.1.0-beta.75
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 +41 -0
- package/dist/browser/{ContentIcon-CUQHjQIw.js → ContentIcon-FCpKiwjp.js} +2 -1
- package/dist/browser/{FlowCanvas-Dtf8_cQp.js → FlowCanvas-dzRBnlUT.js} +1 -1
- package/dist/browser/{createResourceDialog-BWJkjiOO.js → createResourceDialog-BeYDdUl-.js} +2 -2
- package/dist/browser/{dialog-CUy_fwx9.js → dialog-ZtpsFbl4.js} +337 -31
- package/dist/browser/{exportSvg-BOoy7-Db.js → exportSvg-DqXw1yf-.js} +2 -2
- package/dist/browser/{flowChanges-CgSnSqqP.js → flowChanges-b_5UobFj.js} +586 -87
- package/dist/browser/{flowWorkspace-Bf7H-r0t.js → flowWorkspace-ItojZbO4.js} +21162 -20242
- package/dist/browser/preview.css +254 -179
- package/dist/browser/preview.js +22201 -20625
- package/dist/browser/{typeScriptSession-B0hC-C8y.js → typeScriptSession-CSRwWmZm.js} +1 -1
- package/dist/browser/ui.css +72 -2
- package/dist/browser/workbench.css +254 -179
- package/dist/browser/workbench.js +22 -78
- package/dist/browser/{workbenchSelect-C3e4J93X.js → workbenchSelect-M441Lz0d.js} +1 -1
- package/dist/command/index.js +42 -42
- package/dist/common/authoring.d.ts +5 -5
- package/dist/common/authoringExamples.d.ts +3 -2
- package/dist/common/authoringFields.d.ts +1 -1
- package/dist/common/authoringSchema.d.ts +95 -8
- 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 +119 -31
- package/dist/common/control-api.d.ts +4 -3
- package/dist/common/control-api.js +117 -29
- package/dist/common/control-requests.d.ts +5 -4
- package/dist/common/control-requests.js +437 -103
- 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 +4 -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 +131 -30
- 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 +133 -32
- package/dist/common/flow-connectionUsage.d.ts +1 -1
- package/dist/common/flow-encoding.d.ts +1 -1
- package/dist/common/flow-encoding.js +89 -23
- package/dist/common/flow-errorHandling.d.ts +1 -1
- package/dist/common/flow-graph.d.ts +3 -2
- 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 +2 -2
- package/dist/common/flow-semantics.d.ts +1 -1
- package/dist/common/flow-semantics.js +966 -614
- package/dist/common/flow-workflowFile.d.ts +1 -1
- package/dist/common/flowInspection.d.ts +3 -3
- package/dist/common/http-request.d.ts +156 -0
- package/dist/common/http-request.js +5254 -0
- 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 +5 -4
- package/dist/common/mcp.js +117 -29
- package/dist/common/openapi.d.ts +1 -1
- package/dist/common/poll-trigger.d.ts +1 -1
- package/dist/common/run-events.js +11 -9
- package/dist/common/run-results.d.ts +8 -1
- package/dist/common/runtime-contract.d.ts +8 -2
- package/dist/common/runtime-contract.js +25 -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 +3 -3
- package/dist/common/scheduler.js +101 -33
- 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 -3
- package/dist/common/webhook-trigger.d.ts +1 -1
- package/dist/common/webhook-trigger.js +12 -11
- 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 +11 -6
- package/skills/open-flow/references/flow-authoring.md +1 -0
- package/skills/open-flow/references/flow-n8n-conversion.md +19 -15
- 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 +1506 -0
- package/src/control/common/authoring.ts +923 -0
- package/src/control/common/authoringCondition.ts +110 -0
- package/src/control/common/authoringDiagnosticFields.ts +136 -0
- package/src/control/common/authoringExamples.ts +200 -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 +410 -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 +84 -0
- package/src/execution/common/events.ts +331 -0
- package/src/execution/common/node-execution.ts +469 -0
- package/src/execution/common/runLifecycle.ts +250 -0
- package/src/execution/common/runtime.ts +563 -0
- package/src/execution/common/scheduler.ts +697 -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 +1037 -0
- package/src/flow/common/changeSchema.ts +792 -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 +898 -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 +531 -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 +71 -0
- package/src/flow/common/workflowFile.ts +97 -0
- package/src/http/common/authBindings.ts +12 -0
- package/src/http/common/headers.ts +5 -0
- package/src/http/common/httpRequest.ts +251 -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/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 +413 -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,71 @@
|
|
|
1
|
+
import type { InputPort, JsonValue, Port, PortDefinition } from './change.ts'
|
|
2
|
+
|
|
3
|
+
import { httpHeaderNameIssue } from '../../http/common/headers.ts'
|
|
4
|
+
|
|
5
|
+
export const webhookResponseTimeout = {
|
|
6
|
+
defaultMs: 30_000,
|
|
7
|
+
minMs: 1000,
|
|
8
|
+
maxMs: 60_000,
|
|
9
|
+
} as const
|
|
10
|
+
|
|
11
|
+
export const webhookStatusCodePort = { jsonSchema: { type: 'number' }, nullable: true } as const
|
|
12
|
+
|
|
13
|
+
export function webhookResponseAllowsBody(status: number): boolean {
|
|
14
|
+
return status !== 204 && status !== 205 && status !== 304
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const webhookHeaderValuePort = { jsonSchema: { type: ['string', 'number', 'boolean'] }, nullable: true } as const
|
|
18
|
+
export const webhookHeadersPort = {
|
|
19
|
+
jsonSchema: { type: 'object', additionalProperties: { type: ['string', 'number', 'boolean'] } },
|
|
20
|
+
nullable: true,
|
|
21
|
+
} as const
|
|
22
|
+
|
|
23
|
+
export function workflowOutputsPort(outputs: readonly Port[]): PortDefinition {
|
|
24
|
+
return {
|
|
25
|
+
jsonSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: Object.fromEntries(outputs.map((port) => [port.handle, port.jsonSchema])),
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
required: outputs.map((port) => port.handle),
|
|
30
|
+
},
|
|
31
|
+
nullable: false,
|
|
32
|
+
} as const
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Fixed inputs belong to the node, not author-supplied definitions. */
|
|
36
|
+
export const webhookResponseInputs: readonly InputPort[] = [
|
|
37
|
+
{ handle: 'body', jsonSchema: {}, nullable: true, value: '' },
|
|
38
|
+
{ handle: 'statusCode', jsonSchema: { type: 'number' }, nullable: false, value: 200 },
|
|
39
|
+
{ handle: 'headers', jsonSchema: webhookHeadersPort.jsonSchema, nullable: false, value: {} },
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
export interface WebhookResponseSnapshot {
|
|
43
|
+
readonly body: string
|
|
44
|
+
readonly contentType: string
|
|
45
|
+
readonly status: number
|
|
46
|
+
readonly headers: Readonly<Record<string, string>>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function validWebhookStatus(value: unknown): value is number {
|
|
50
|
+
return typeof value === 'number' && Number.isInteger(value) && value >= 200 && value <= 599 && webhookResponseAllowsBody(value)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Portable validation also runs in the isolated engine, which has no HTTP globals. */
|
|
54
|
+
export function webhookHeaderValues(source: unknown): Readonly<Record<string, string>> | undefined {
|
|
55
|
+
if (source == null || typeof source !== 'object' || Array.isArray(source)) return
|
|
56
|
+
const headers: Record<string, string> = {}
|
|
57
|
+
const names: string[] = []
|
|
58
|
+
for (const [name, value] of Object.entries(source)) {
|
|
59
|
+
if (httpHeaderNameIssue(name, names) != null) return
|
|
60
|
+
if (typeof value !== 'string' && typeof value !== 'boolean' && !(typeof value === 'number' && Number.isFinite(value))) return
|
|
61
|
+
const text = String(value)
|
|
62
|
+
if ([...text].some((character) => character.charCodeAt(0) > 255 || /[\0\r\n]/.test(character))) return
|
|
63
|
+
names.push(name)
|
|
64
|
+
Object.defineProperty(headers, name, { value: text, enumerable: true, configurable: true })
|
|
65
|
+
}
|
|
66
|
+
return headers
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function encodeWebhookBody(value: JsonValue): Pick<WebhookResponseSnapshot, 'body' | 'contentType'> {
|
|
70
|
+
return typeof value === 'string' ? { body: value, contentType: 'text/plain;charset=UTF-8' } : { body: JSON.stringify(value), contentType: 'application/json' }
|
|
71
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { GraphNode, InputMapping, JsonValue, RevisionContent } from './change.ts'
|
|
2
|
+
|
|
3
|
+
import { dequal } from 'dequal/lite'
|
|
4
|
+
import { z } from 'zod'
|
|
5
|
+
import { clearTriggerExternalConfig } from '../../trigger/common/config.ts'
|
|
6
|
+
import { decodeRevisionContent } from './changeSchema.ts'
|
|
7
|
+
import { clearConditionBindings } from './condition.ts'
|
|
8
|
+
import { clearNodeConnections } from './connectionUsage.ts'
|
|
9
|
+
import { checkJsonDepth } from './json.ts'
|
|
10
|
+
|
|
11
|
+
export interface WorkflowFile {
|
|
12
|
+
readonly kind: 'open-flow-workflow'
|
|
13
|
+
readonly version: 1
|
|
14
|
+
readonly name?: string
|
|
15
|
+
readonly content: RevisionContent
|
|
16
|
+
readonly presentation?: Readonly<Record<string, JsonValue>>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface WorkflowCleanupSummary {
|
|
20
|
+
readonly changedNodeIds: readonly string[]
|
|
21
|
+
readonly removedBindings: number
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const envelope = z.strictObject({
|
|
25
|
+
kind: z.literal('open-flow-workflow'),
|
|
26
|
+
version: z.literal(1),
|
|
27
|
+
name: z.string().optional(),
|
|
28
|
+
content: z.unknown(),
|
|
29
|
+
presentation: z.record(z.string(), z.json()).optional(),
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
/** Structural decoding only: incomplete drafts are supported, repair is never attempted. */
|
|
33
|
+
export function decodeWorkflowFile(value: unknown): WorkflowFile {
|
|
34
|
+
checkJsonDepth(value, -1)
|
|
35
|
+
const file = envelope.parse(value)
|
|
36
|
+
return { ...file, content: decodeRevisionContent(file.content) }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function parseWorkflowFile(text: string): WorkflowFile {
|
|
40
|
+
return decodeWorkflowFile(JSON.parse(text))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function cleanInput(input: InputMapping): InputMapping {
|
|
44
|
+
if (input.kind != 'sources' || !input.sources.some((source) => source.kind == 'binding')) return input
|
|
45
|
+
const sources = input.sources.filter((source) => source.kind != 'binding')
|
|
46
|
+
return sources.length == 0 ? { kind: 'unset' } : { kind: 'sources', sources }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Clear only owned structured references, never strings in code or business values. */
|
|
50
|
+
export function cleanWorkflowFile(value: unknown): { readonly file: WorkflowFile; readonly summary: WorkflowCleanupSummary } {
|
|
51
|
+
const file = decodeWorkflowFile(value)
|
|
52
|
+
const original = file.content.document.graph
|
|
53
|
+
const graph = clearNodeConnections(original)
|
|
54
|
+
const nodes = Object.fromEntries(
|
|
55
|
+
Object.entries(graph.nodes).map(([id, source]) => {
|
|
56
|
+
let node: GraphNode = source
|
|
57
|
+
if ('inputs' in node) node = { ...node, inputs: Object.fromEntries(Object.entries(node.inputs).map(([key, input]) => [key, cleanInput(input)])) }
|
|
58
|
+
if (node.kind == 'outputs')
|
|
59
|
+
node = { ...node, outputMappings: Object.fromEntries(Object.entries(node.outputMappings).map(([key, input]) => [key, cleanInput(input)])) }
|
|
60
|
+
if (node.kind == 'condition') node = clearConditionBindings(node)
|
|
61
|
+
if (node.kind == 'error' && node.sourceFlowIds != null) node = { ...node, sourceFlowIds: [] }
|
|
62
|
+
if (node.kind == 'poll' || node.kind == 'integration') node = { ...node, config: clearTriggerExternalConfig(node.definition.key, node.config) }
|
|
63
|
+
return [id, node]
|
|
64
|
+
}),
|
|
65
|
+
)
|
|
66
|
+
return {
|
|
67
|
+
file: {
|
|
68
|
+
...file,
|
|
69
|
+
content: {
|
|
70
|
+
...file.content,
|
|
71
|
+
document: {
|
|
72
|
+
...file.content.document,
|
|
73
|
+
bindings: {},
|
|
74
|
+
graph: { ...graph, nodes },
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
summary: {
|
|
79
|
+
changedNodeIds: Object.keys(nodes).filter((id) => !dequal(nodes[id], original.nodes[id])),
|
|
80
|
+
removedBindings: Object.keys(file.content.document.bindings).length,
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function encodeWorkflowFile(file: WorkflowFile): string {
|
|
86
|
+
return `${JSON.stringify(cleanWorkflowFile(file).file, null, 2)}\n`
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function workflowFileName(name: string): string {
|
|
90
|
+
// Control characters are forbidden in download filenames.
|
|
91
|
+
// oxlint-disable-next-line no-control-regex
|
|
92
|
+
return `${name.replace(/[<>:"/\\|?*\u0000-\u001f]/g, '_').replace(/[. ]+$/g, '') || 'workflow'}.openflow.json`
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function workflowNameFromFile(name: string): string {
|
|
96
|
+
return name.replace(/(?:\.openflow)?\.json$/i, '')
|
|
97
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FlowDocument } from '../../flow/common/change.ts'
|
|
2
|
+
|
|
3
|
+
/** Never allow credentials to enter a Revision as literal node inputs. */
|
|
4
|
+
export function assertHttpAuthBindings(document: FlowDocument): void {
|
|
5
|
+
for (const node of Object.values(document.graph.nodes)) {
|
|
6
|
+
if (node.kind != 'task' || !('executor' in node.task) || !['openapi', 'http-request'].includes(node.task.executor.kind)) continue
|
|
7
|
+
for (const [handle, mapping] of Object.entries(node.inputs)) {
|
|
8
|
+
if (handle.startsWith('auth.') && mapping.kind == 'value')
|
|
9
|
+
throw new TypeError('HTTP authentication accepts deployment variables and upstream outputs only.')
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Header names are case-insensitive; never silently combine duplicate business fields. */
|
|
2
|
+
export function httpHeaderNameIssue(name: string, names: readonly string[]): 'invalid' | 'duplicate' | undefined {
|
|
3
|
+
if (!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(name)) return 'invalid'
|
|
4
|
+
if (names.some((candidate) => candidate.toLowerCase() === name.toLowerCase())) return 'duplicate'
|
|
5
|
+
}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import type { InputMapping, InputPort, JsonValue, ManagedTaskDefinition, TaskNode } from '../../flow/common/change.ts'
|
|
2
|
+
|
|
3
|
+
import { dequal } from 'dequal/lite'
|
|
4
|
+
import { z } from 'zod'
|
|
5
|
+
import { remapInputMappings, renamedPort } from '../../flow/common/portChanges.ts'
|
|
6
|
+
import { httpHeaderNameIssue } from './headers.ts'
|
|
7
|
+
|
|
8
|
+
const parameterSchema = z.strictObject({ mode: z.enum(['fields', 'object']).default('fields'), names: z.array(z.string()).default([]) })
|
|
9
|
+
export const httpRequestConfigSchema = z.strictObject({
|
|
10
|
+
method: z.enum(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']).default('GET'),
|
|
11
|
+
query: parameterSchema.default({ mode: 'fields', names: [] }),
|
|
12
|
+
headers: parameterSchema.default({ mode: 'fields', names: [] }),
|
|
13
|
+
bodyFormat: z.enum(['none', 'json', 'text', 'form']).default('none'),
|
|
14
|
+
authentication: z
|
|
15
|
+
.union([
|
|
16
|
+
z.strictObject({ type: z.literal('none') }),
|
|
17
|
+
z.strictObject({ type: z.enum(['bearer', 'basic']) }),
|
|
18
|
+
z.strictObject({ type: z.literal('apiKey'), name: z.string(), in: z.enum(['header', 'query']) }),
|
|
19
|
+
])
|
|
20
|
+
.default({ type: 'none' }),
|
|
21
|
+
responseFormat: z.enum(['auto', 'json', 'text']).default('auto'),
|
|
22
|
+
statusPolicy: z.enum(['success', 'all']).default('success'),
|
|
23
|
+
})
|
|
24
|
+
export type HttpRequestConfig = z.infer<typeof httpRequestConfigSchema>
|
|
25
|
+
export interface HttpRequestExecutor extends HttpRequestConfig {
|
|
26
|
+
readonly kind: 'http-request'
|
|
27
|
+
}
|
|
28
|
+
export const httpRequestExecutorSchema = httpRequestConfigSchema.extend({ kind: z.literal('http-request') })
|
|
29
|
+
const scalarSchema = { type: ['string', 'number', 'boolean'] }
|
|
30
|
+
const queryValueSchema = { anyOf: [scalarSchema, { type: 'array', items: scalarSchema }] }
|
|
31
|
+
export const httpHeaderSchema = { type: 'object', additionalProperties: { type: 'string' } }
|
|
32
|
+
export const httpQuerySchema = { type: 'object', additionalProperties: queryValueSchema }
|
|
33
|
+
|
|
34
|
+
export function httpAuthHandles(config: HttpRequestConfig): string[] {
|
|
35
|
+
return config.authentication.type == 'none' ? [] : config.authentication.type == 'basic' ? ['auth.username', 'auth.password'] : ['auth.token']
|
|
36
|
+
}
|
|
37
|
+
// Preserve metadata on ports whose contracts did not change.
|
|
38
|
+
function retain(ports: readonly InputPort[], old: ManagedTaskDefinition['inputs']): ManagedTaskDefinition['inputs'] {
|
|
39
|
+
const remaining = new Map(ports.map((port) => [port.handle, port]))
|
|
40
|
+
return [
|
|
41
|
+
...old.flatMap((item): ManagedTaskDefinition['inputs'] => {
|
|
42
|
+
if ('group' in item) return [item]
|
|
43
|
+
const next = remaining.get(item.handle)
|
|
44
|
+
if (next == null) return []
|
|
45
|
+
remaining.delete(item.handle)
|
|
46
|
+
return [dequal(item.jsonSchema, next.jsonSchema) && item.nullable == next.nullable ? item : next]
|
|
47
|
+
}),
|
|
48
|
+
...remaining.values(),
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
export function httpRequestTask(
|
|
52
|
+
config: HttpRequestConfig = httpRequestConfigSchema.parse({}),
|
|
53
|
+
name = 'HTTP Request',
|
|
54
|
+
previous?: ManagedTaskDefinition,
|
|
55
|
+
): ManagedTaskDefinition {
|
|
56
|
+
const inputs: InputPort[] = [{ handle: 'url', jsonSchema: { type: 'string' }, nullable: false }]
|
|
57
|
+
for (const group of ['query', 'headers'] as const) {
|
|
58
|
+
if (config[group].mode == 'object') inputs.push({ handle: group, jsonSchema: group == 'query' ? httpQuerySchema : httpHeaderSchema, nullable: true })
|
|
59
|
+
else
|
|
60
|
+
for (const parameterName of config[group].names.filter((value) => value.trim()))
|
|
61
|
+
inputs.push({
|
|
62
|
+
handle: `${group == 'query' ? 'query' : 'header'}.${parameterName}`,
|
|
63
|
+
jsonSchema: group == 'query' ? queryValueSchema : { type: 'string' },
|
|
64
|
+
nullable: true,
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
if (config.bodyFormat != 'none')
|
|
68
|
+
inputs.push({
|
|
69
|
+
handle: 'body',
|
|
70
|
+
jsonSchema: config.bodyFormat == 'json' ? {} : config.bodyFormat == 'text' ? { type: 'string' } : httpQuerySchema,
|
|
71
|
+
nullable: config.bodyFormat == 'json',
|
|
72
|
+
})
|
|
73
|
+
inputs.push(...httpAuthHandles(config).map((handle) => ({ handle, jsonSchema: { type: 'string' }, nullable: false })))
|
|
74
|
+
const outputs: InputPort[] = [
|
|
75
|
+
{ handle: 'body', jsonSchema: config.responseFormat == 'text' ? { type: 'string' } : {}, nullable: true },
|
|
76
|
+
{ handle: 'statusCode', jsonSchema: { type: 'integer' }, nullable: false },
|
|
77
|
+
{ handle: 'headers', jsonSchema: httpHeaderSchema, nullable: false },
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
name,
|
|
82
|
+
executor: { ...config, kind: 'http-request' },
|
|
83
|
+
inputs: retain(inputs, previous?.inputs ?? []),
|
|
84
|
+
outputs: retain(outputs, previous?.outputs ?? []),
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export interface HttpRequestIssue {
|
|
88
|
+
field: string
|
|
89
|
+
index?: number
|
|
90
|
+
code: 'bodyUnsupported' | 'parameterNamesInvalid' | 'headerNameInvalid' | 'keyNameRequired' | 'authConflict'
|
|
91
|
+
message: string
|
|
92
|
+
}
|
|
93
|
+
export function httpRequestIssues(config: HttpRequestConfig): HttpRequestIssue[] {
|
|
94
|
+
const issues: HttpRequestIssue[] = []
|
|
95
|
+
if (['GET', 'HEAD'].includes(config.method) && config.bodyFormat != 'none')
|
|
96
|
+
issues.push({ field: 'bodyFormat', code: 'bodyUnsupported', message: 'GET and HEAD do not support a request body.' })
|
|
97
|
+
for (const group of ['query', 'headers'] as const) {
|
|
98
|
+
if (config[group].mode != 'fields') continue
|
|
99
|
+
const seen = new Set<string>()
|
|
100
|
+
for (const [index, name] of config[group].names.entries()) {
|
|
101
|
+
const key = group == 'headers' ? name.toLowerCase() : name
|
|
102
|
+
if (!name.trim() || seen.has(key))
|
|
103
|
+
issues.push({ field: group, index, code: 'parameterNamesInvalid', message: 'Parameter names must be nonempty and unique.' })
|
|
104
|
+
seen.add(key)
|
|
105
|
+
if (group == 'headers' && httpHeaderNameIssue(name, []) === 'invalid')
|
|
106
|
+
issues.push({ field: group, index, code: 'headerNameInvalid', message: 'Invalid HTTP header name.' })
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
const auth = config.authentication
|
|
110
|
+
if (auth.type != 'none') {
|
|
111
|
+
const group = auth.type == 'apiKey' && auth.in == 'query' ? 'query' : 'headers'
|
|
112
|
+
const name = auth.type == 'apiKey' ? auth.name : 'authorization'
|
|
113
|
+
if (!name.trim()) issues.push({ field: 'authentication', code: 'keyNameRequired', message: 'API Key requires a name.' })
|
|
114
|
+
if (group == 'headers' && name.trim() && httpHeaderNameIssue(name, []) === 'invalid')
|
|
115
|
+
issues.push({ field: 'authentication', code: 'headerNameInvalid', message: 'Invalid authentication header name.' })
|
|
116
|
+
if (config[group].mode == 'fields' && config[group].names.some((item) => (group == 'headers' ? item.toLowerCase() == name.toLowerCase() : item == name)))
|
|
117
|
+
issues.push({ field: 'authentication', code: 'authConflict', message: 'Authentication conflicts with a request parameter.' })
|
|
118
|
+
}
|
|
119
|
+
return issues
|
|
120
|
+
}
|
|
121
|
+
function entries(value: JsonValue | undefined): [string, JsonValue][] {
|
|
122
|
+
if (value == null) return []
|
|
123
|
+
if (typeof value != 'object' || Array.isArray(value)) throw new Error('Expected a parameter object.')
|
|
124
|
+
return Object.entries(value)
|
|
125
|
+
}
|
|
126
|
+
function scalar(value: JsonValue): string {
|
|
127
|
+
if (typeof value != 'string' && typeof value != 'number' && typeof value != 'boolean') throw new Error('Expected a scalar parameter.')
|
|
128
|
+
return String(value)
|
|
129
|
+
}
|
|
130
|
+
function append(query: URLSearchParams, name: string, value: JsonValue): void {
|
|
131
|
+
for (const item of Array.isArray(value) ? value : [value]) query.append(name, scalar(item))
|
|
132
|
+
}
|
|
133
|
+
export function httpRequestUrl(value: unknown): URL {
|
|
134
|
+
if (typeof value != 'string' || !value.trim()) throw new Error('A URL is required.')
|
|
135
|
+
const url = new URL(value)
|
|
136
|
+
if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password) throw new Error('An HTTP(S) URL without credentials is required.')
|
|
137
|
+
return url
|
|
138
|
+
}
|
|
139
|
+
export function buildHttpRequest(config: HttpRequestConfig, input: Readonly<Record<string, JsonValue>>): { url: string; init: RequestInit } {
|
|
140
|
+
if (httpRequestIssues(config).length) throw new Error('Invalid HTTP request configuration.')
|
|
141
|
+
const url = httpRequestUrl(input.url)
|
|
142
|
+
const parameters = (group: 'query' | 'headers') =>
|
|
143
|
+
config[group].mode == 'object'
|
|
144
|
+
? entries(input[group])
|
|
145
|
+
: config[group].names.flatMap((name): [string, JsonValue][] => {
|
|
146
|
+
const value = input[`${group == 'query' ? 'query' : 'header'}.${name}`]
|
|
147
|
+
return value == null ? [] : [[name, value]]
|
|
148
|
+
})
|
|
149
|
+
for (const [name, value] of parameters('query')) {
|
|
150
|
+
url.searchParams.delete(name)
|
|
151
|
+
append(url.searchParams, name, value)
|
|
152
|
+
}
|
|
153
|
+
const headers = new Headers()
|
|
154
|
+
for (const [name, value] of parameters('headers')) {
|
|
155
|
+
if (headers.has(name)) throw new Error('Duplicate HTTP header.')
|
|
156
|
+
if (typeof value != 'string') throw new Error('HTTP headers require text values.')
|
|
157
|
+
headers.set(name, value)
|
|
158
|
+
}
|
|
159
|
+
const auth = config.authentication
|
|
160
|
+
const credential = (part: string) => {
|
|
161
|
+
const value = input[`auth.${part}`]
|
|
162
|
+
if (typeof value != 'string' || !value) throw new Error('Authentication source is required.')
|
|
163
|
+
return value
|
|
164
|
+
}
|
|
165
|
+
if (auth.type != 'none') {
|
|
166
|
+
const name = auth.type == 'apiKey' ? auth.name : 'authorization'
|
|
167
|
+
if (auth.type == 'apiKey' && auth.in == 'query') {
|
|
168
|
+
if (url.searchParams.has(name)) throw new Error('Authentication conflicts with a query parameter.')
|
|
169
|
+
url.searchParams.set(name, credential('token'))
|
|
170
|
+
} else {
|
|
171
|
+
if (headers.has(name)) throw new Error('Authentication conflicts with a header.')
|
|
172
|
+
if (auth.type == 'basic') {
|
|
173
|
+
const username = credential('username')
|
|
174
|
+
if (username.includes(':')) throw new Error('Basic username cannot contain a colon.')
|
|
175
|
+
const bytes = new TextEncoder().encode(`${username}:${credential('password')}`)
|
|
176
|
+
headers.set(name, `Basic ${btoa(Array.from(bytes, (byte) => String.fromCharCode(byte)).join(''))}`)
|
|
177
|
+
} else headers.set(name, auth.type == 'bearer' ? `Bearer ${credential('token')}` : credential('token'))
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
let body: string | undefined
|
|
181
|
+
if (config.bodyFormat != 'none') {
|
|
182
|
+
if (!Object.hasOwn(input, 'body')) throw new Error('Request body is unset.')
|
|
183
|
+
let contentType: string
|
|
184
|
+
if (config.bodyFormat == 'json') {
|
|
185
|
+
body = JSON.stringify(input.body)
|
|
186
|
+
contentType = 'application/json'
|
|
187
|
+
} else if (config.bodyFormat == 'text') {
|
|
188
|
+
if (typeof input.body != 'string') throw new Error('Text body requires a string.')
|
|
189
|
+
body = input.body
|
|
190
|
+
contentType = 'text/plain'
|
|
191
|
+
} else {
|
|
192
|
+
if (input.body == null) throw new Error('Form body requires an object.')
|
|
193
|
+
const form = new URLSearchParams()
|
|
194
|
+
for (const [name, value] of entries(input.body)) append(form, name, value)
|
|
195
|
+
body = form.toString()
|
|
196
|
+
contentType = 'application/x-www-form-urlencoded'
|
|
197
|
+
}
|
|
198
|
+
const supplied = headers.get('content-type')
|
|
199
|
+
if (config.bodyFormat != 'text' && supplied != null && supplied.split(';')[0]!.trim().toLowerCase() != contentType)
|
|
200
|
+
throw new Error('Content-Type conflicts with body format.')
|
|
201
|
+
if (supplied == null) headers.set('content-type', contentType)
|
|
202
|
+
}
|
|
203
|
+
return { url: url.href, init: { method: config.method, headers, body, redirect: 'manual' } }
|
|
204
|
+
}
|
|
205
|
+
export function parseHttpResponse(config: HttpRequestConfig, status: number, headers: Headers, text: string): Record<string, JsonValue> {
|
|
206
|
+
if (config.statusPolicy == 'success' && (status < 200 || status >= 300)) throw new Error(`HTTP ${status}`)
|
|
207
|
+
let body: JsonValue = null
|
|
208
|
+
if (text && config.method != 'HEAD' && ![204, 205, 304].includes(status)) {
|
|
209
|
+
const media = (headers.get('content-type') ?? '').split(';')[0]!.trim().toLowerCase()
|
|
210
|
+
body =
|
|
211
|
+
config.responseFormat == 'json' || (config.responseFormat == 'auto' && /^application\/(json|.+\+json)$/.test(media))
|
|
212
|
+
? (JSON.parse(text) as JsonValue)
|
|
213
|
+
: text
|
|
214
|
+
}
|
|
215
|
+
return { body, statusCode: status, headers: Object.fromEntries([...headers].filter(([name]) => name != 'set-cookie')) }
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** Only a named parameter rename carries a value; changing source modes is not a rename. */
|
|
219
|
+
export function httpRequestInputs(
|
|
220
|
+
mappings: Readonly<Record<string, InputMapping>>,
|
|
221
|
+
previous: ManagedTaskDefinition,
|
|
222
|
+
next: ManagedTaskDefinition,
|
|
223
|
+
): Record<string, InputMapping> {
|
|
224
|
+
const candidate = renamedPort(previous.inputs, next.inputs)
|
|
225
|
+
const rename = candidate != null && ['query.', 'header.'].some((prefix) => candidate.every((name) => name.startsWith(prefix))) ? candidate : undefined
|
|
226
|
+
return remapInputMappings(mappings, next.inputs, rename)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** The object editor assembles named inputs without changing unrelated request settings. */
|
|
230
|
+
export function withHttpParameterFields(node: TaskNode, group: 'query' | 'headers', values: Record<string, JsonValue>): TaskNode {
|
|
231
|
+
if (!('executor' in node.task) || node.task.executor.kind !== 'http-request') return node
|
|
232
|
+
const config = node.task.executor
|
|
233
|
+
const task = httpRequestTask({ ...config, [group]: { mode: 'fields', names: Object.keys(values) } }, node.task.name, node.task)
|
|
234
|
+
const inputs = httpRequestInputs(node.inputs, node.task, task)
|
|
235
|
+
const rename = renamedPort(node.task.inputs, task.inputs)
|
|
236
|
+
for (const [name, value] of Object.entries(values)) {
|
|
237
|
+
const handle = `${group === 'query' ? 'query' : 'header'}.${name}`
|
|
238
|
+
const existing = config[group].mode === 'fields' && (config[group].names.includes(name) || rename?.[1] === handle)
|
|
239
|
+
if (inputs[handle] == null && !existing) inputs[handle] = { kind: 'value', value }
|
|
240
|
+
}
|
|
241
|
+
return { ...node, task, inputs }
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function withHttpParameterSource(node: TaskNode, group: 'query' | 'headers', mapping?: InputMapping): TaskNode {
|
|
245
|
+
if (!('executor' in node.task) || node.task.executor.kind !== 'http-request') return node
|
|
246
|
+
const task = httpRequestTask({ ...node.task.executor, [group]: { mode: 'object', names: [] } }, node.task.name, node.task)
|
|
247
|
+
const inputs = httpRequestInputs(node.inputs, node.task, task)
|
|
248
|
+
if (mapping == null) delete inputs[group]
|
|
249
|
+
else inputs[group] = mapping
|
|
250
|
+
return { ...node, task, inputs }
|
|
251
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import type { CompiledSchema } from '../compiler/index.ts'
|
|
2
|
+
import type { ExpressionResult } from '../expression/index.ts'
|
|
3
|
+
import type { Schema } from '../types.ts'
|
|
4
|
+
import type { Context } from './cache.ts'
|
|
5
|
+
|
|
6
|
+
import { ANY } from '../compiler/index.ts'
|
|
7
|
+
import {
|
|
8
|
+
ExpressionNone,
|
|
9
|
+
ExpressionContainedBy,
|
|
10
|
+
ExpressionContaining,
|
|
11
|
+
ExpressionEquals,
|
|
12
|
+
ExpressionIntersection,
|
|
13
|
+
ExpressionRejection,
|
|
14
|
+
ExpressionSingleResult,
|
|
15
|
+
} from '../expression/index.ts'
|
|
16
|
+
import { createRangeSplitter, toExpressionSingleResult } from './range.ts'
|
|
17
|
+
import { makeQuantum } from './tools/index.ts'
|
|
18
|
+
|
|
19
|
+
const splitRange = createRangeSplitter(0)
|
|
20
|
+
const quantum = makeQuantum(['hasCommon', 'hasExtra1', 'hasExtra2', 'hasRejection', 'hasCommonBroken'])
|
|
21
|
+
|
|
22
|
+
export function calculateArray<E>({ calculate }: Context<E>, schema1: CompiledSchema<E>, schema2: CompiledSchema<E>): ExpressionResult {
|
|
23
|
+
const splitResult = splitRange(schema1.minItems, schema1.maxItems, schema2.minItems, schema2.maxItems)
|
|
24
|
+
const splitExpression = toExpressionSingleResult(splitResult)
|
|
25
|
+
|
|
26
|
+
if (splitExpression === ExpressionSingleResult.Rejection) {
|
|
27
|
+
return ExpressionRejection
|
|
28
|
+
}
|
|
29
|
+
const [items1, additionalItems1] = normalizeArray(schema1)
|
|
30
|
+
const [items2, additionalItems2] = normalizeArray(schema2)
|
|
31
|
+
|
|
32
|
+
// The final slot compares additionalItems without a tuple item.
|
|
33
|
+
const itemsLength = Math.max(items1.length, items2.length) + 1
|
|
34
|
+
const length = Math.min(itemsLength, splitResult.intersection!.max)
|
|
35
|
+
const quantumVariable = quantum.variable({})
|
|
36
|
+
const minItems = Math.min(schema1.minItems ?? 0, schema2.minItems ?? 0)
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < length; i++) {
|
|
39
|
+
const subSchema1 = items1[i] ?? additionalItems1
|
|
40
|
+
const subSchema2 = items2[i] ?? additionalItems2
|
|
41
|
+
const expression = calculate(subSchema1, subSchema2)
|
|
42
|
+
|
|
43
|
+
quantumVariable.push(expression, (singleExpression, variable) => {
|
|
44
|
+
switch (singleExpression) {
|
|
45
|
+
case ExpressionSingleResult.Equals: {
|
|
46
|
+
if (!variable.hasRejection) {
|
|
47
|
+
variable.hasCommon = true
|
|
48
|
+
}
|
|
49
|
+
break
|
|
50
|
+
}
|
|
51
|
+
case ExpressionSingleResult.Containing: {
|
|
52
|
+
if (!variable.hasRejection) {
|
|
53
|
+
variable.hasCommon = true
|
|
54
|
+
}
|
|
55
|
+
variable.hasExtra1 = true
|
|
56
|
+
break
|
|
57
|
+
}
|
|
58
|
+
case ExpressionSingleResult.ContainedBy: {
|
|
59
|
+
if (!variable.hasRejection) {
|
|
60
|
+
variable.hasCommon = true
|
|
61
|
+
}
|
|
62
|
+
variable.hasExtra2 = true
|
|
63
|
+
break
|
|
64
|
+
}
|
|
65
|
+
case ExpressionSingleResult.Intersection: {
|
|
66
|
+
if (!variable.hasRejection) {
|
|
67
|
+
variable.hasCommon = true
|
|
68
|
+
}
|
|
69
|
+
variable.hasExtra1 = true
|
|
70
|
+
variable.hasExtra2 = true
|
|
71
|
+
break
|
|
72
|
+
}
|
|
73
|
+
case ExpressionSingleResult.Rejection: {
|
|
74
|
+
if (i < minItems) {
|
|
75
|
+
variable.hasCommonBroken = true
|
|
76
|
+
}
|
|
77
|
+
variable.hasRejection = true
|
|
78
|
+
variable.hasExtra1 = true
|
|
79
|
+
variable.hasExtra2 = true
|
|
80
|
+
break
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
quantumVariable.update((variable) => {
|
|
86
|
+
switch (splitExpression) {
|
|
87
|
+
case ExpressionSingleResult.Containing: {
|
|
88
|
+
variable.hasExtra1 = true
|
|
89
|
+
break
|
|
90
|
+
}
|
|
91
|
+
case ExpressionSingleResult.ContainedBy: {
|
|
92
|
+
variable.hasExtra2 = true
|
|
93
|
+
break
|
|
94
|
+
}
|
|
95
|
+
case ExpressionSingleResult.Intersection: {
|
|
96
|
+
variable.hasExtra1 = true
|
|
97
|
+
variable.hasExtra2 = true
|
|
98
|
+
break
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (schema1.uniqueItems && !schema2.uniqueItems && (schema2.maxItems ?? Number.POSITIVE_INFINITY) > 1) variable.hasExtra2 = true
|
|
102
|
+
else if (!schema1.uniqueItems && schema2.uniqueItems && (schema1.maxItems ?? Number.POSITIVE_INFINITY) > 1) variable.hasExtra1 = true
|
|
103
|
+
if (schema1.maxItems === 0 || schema2.maxItems === 0) {
|
|
104
|
+
// An unconstrained empty array can match any array schema.
|
|
105
|
+
variable.hasCommon = true
|
|
106
|
+
if (schema1.maxItems !== 0) {
|
|
107
|
+
variable.hasExtra1 = true
|
|
108
|
+
}
|
|
109
|
+
if (schema2.maxItems !== 0) {
|
|
110
|
+
variable.hasExtra2 = true
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
})
|
|
114
|
+
let expression = ExpressionNone
|
|
115
|
+
|
|
116
|
+
for (const { hasExtra1, hasExtra2, hasCommon, hasCommonBroken } of quantumVariable) {
|
|
117
|
+
let finalHasCommon = hasCommon
|
|
118
|
+
if (hasCommonBroken) {
|
|
119
|
+
finalHasCommon = false
|
|
120
|
+
}
|
|
121
|
+
if (!finalHasCommon) {
|
|
122
|
+
expression |= ExpressionRejection
|
|
123
|
+
} else if (hasExtra1 && hasExtra2) {
|
|
124
|
+
expression |= ExpressionIntersection
|
|
125
|
+
} else if (hasExtra1) {
|
|
126
|
+
expression |= ExpressionContaining
|
|
127
|
+
} else if (hasExtra2) {
|
|
128
|
+
expression |= ExpressionContainedBy
|
|
129
|
+
} else {
|
|
130
|
+
expression |= ExpressionEquals
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return expression
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function normalizeArray<E>({ items, additionalItems }: CompiledSchema<E>): [readonly Schema<E>[], Schema<E>] {
|
|
137
|
+
if (Array.isArray(items)) {
|
|
138
|
+
return [items as readonly Schema<E>[], (additionalItems ?? ANY) as Schema<E>]
|
|
139
|
+
} else {
|
|
140
|
+
return [[], (items ?? ANY) as Schema<E>]
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { CompiledObject, CompiledSchema, CompiledValue } from '../compiler/index.ts'
|
|
2
|
+
import type { ExpressionResult } from '../expression/index.ts'
|
|
3
|
+
import type { ExtendsSchema } from '../extends/index.ts'
|
|
4
|
+
import type { Schema } from '../types.ts'
|
|
5
|
+
import type { DeepReadonly } from '../utils.ts'
|
|
6
|
+
|
|
7
|
+
import { getId, isCompiledObject } from '../compiler/index.ts'
|
|
8
|
+
|
|
9
|
+
export type Context<E> = {
|
|
10
|
+
readonly isEquals: EqualsChecker
|
|
11
|
+
readonly calculate: SchemaCalculator<E>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type EqualsChecker = (value1: CompiledValue, value2: CompiledValue) => boolean
|
|
15
|
+
export type SchemaCalculator<E> = (superSchema: Schema<E>, subSchema: Schema<E>) => ExpressionResult
|
|
16
|
+
|
|
17
|
+
export function wrapEqualsCheckerWithCache(check: (object1: CompiledObject, object2: CompiledObject) => boolean): EqualsChecker {
|
|
18
|
+
const map = new Map<string, boolean>()
|
|
19
|
+
|
|
20
|
+
return (value1, value2) => {
|
|
21
|
+
const isObject1 = isCompiledObject(value1)
|
|
22
|
+
const isObject2 = isCompiledObject(value2)
|
|
23
|
+
|
|
24
|
+
if (isObject1 !== isObject2) {
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
if (!isObject1) {
|
|
28
|
+
return value1 === value2
|
|
29
|
+
}
|
|
30
|
+
const object1 = value1 as CompiledObject
|
|
31
|
+
const object2 = value2 as CompiledObject
|
|
32
|
+
|
|
33
|
+
return getWithCache(map, object1, object2, check)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function wrapSchemaCalculatorWithCache<E>(check: SchemaCalculator<E>): SchemaCalculator<E> {
|
|
38
|
+
const map = new Map<string, ExpressionResult>()
|
|
39
|
+
return (schema1, schema2) => getWithCache(map, schema1, schema2, check)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getWithCache<R, E, N extends ExtendsSchema | DeepReadonly<CompiledSchema<E>> | DeepReadonly<CompiledObject>>(
|
|
43
|
+
map: Map<string, R>,
|
|
44
|
+
node1: N,
|
|
45
|
+
node2: N,
|
|
46
|
+
check: (n1: N, n2: N) => R,
|
|
47
|
+
): R {
|
|
48
|
+
const id1 = getId(node1)
|
|
49
|
+
const id2 = getId(node2)
|
|
50
|
+
const key = `${id1}/${id2}`
|
|
51
|
+
|
|
52
|
+
let result = map.get(key)
|
|
53
|
+
if (result === undefined) {
|
|
54
|
+
map.set(key, (result = check(node1, node2)))
|
|
55
|
+
}
|
|
56
|
+
return result
|
|
57
|
+
}
|