@oomol-lab/open-flow 0.1.0-beta.72 → 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 +90 -42
- 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,370 @@
|
|
|
1
|
+
import type { InputPortDefinition } from '../../flow/common/change.ts'
|
|
2
|
+
import type {
|
|
3
|
+
ConnectorAccess,
|
|
4
|
+
ConnectorAccessSnapshot,
|
|
5
|
+
ConnectorAccessGrant,
|
|
6
|
+
ConnectorAccessCandidates,
|
|
7
|
+
ConnectorAccessCandidatesBatch,
|
|
8
|
+
ConnectorAction,
|
|
9
|
+
ConnectorActionMetadata,
|
|
10
|
+
ConnectorConnection,
|
|
11
|
+
ConnectorProvider,
|
|
12
|
+
LeinaBot,
|
|
13
|
+
ProviderAccessBinding,
|
|
14
|
+
ProviderAccessBindingCandidate,
|
|
15
|
+
} from './api.ts'
|
|
16
|
+
|
|
17
|
+
import { exact, requiredFields, integer, invalidResponse, jsonValue, record, string } from './decoding.ts'
|
|
18
|
+
import { ApiError } from './errors.ts'
|
|
19
|
+
import { parseProviderAccessSource } from './providerAccess.ts'
|
|
20
|
+
import { providerIconAppearance } from './providerIconSprite.ts'
|
|
21
|
+
|
|
22
|
+
export function leinaBots(value: unknown): readonly LeinaBot[] {
|
|
23
|
+
const source = record(value)
|
|
24
|
+
if (!Array.isArray(source.bots)) return invalidResponse('Leina bots: expected an array.')
|
|
25
|
+
const bots = source.bots.map((entry) => {
|
|
26
|
+
const bot = record(entry)
|
|
27
|
+
if (!Array.isArray(bot.platforms)) return invalidResponse('Leina platforms: expected an array.')
|
|
28
|
+
return { leinaId: string(bot.leinaId), name: string(bot.name), status: string(bot.status), platforms: bot.platforms.map(string) }
|
|
29
|
+
})
|
|
30
|
+
if (new Set(bots.map((bot) => bot.leinaId)).size != bots.length) return invalidResponse('Leina bots: duplicate identifiers.')
|
|
31
|
+
return bots
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function accessPermissions(value: unknown): NonNullable<ProviderAccessBindingCandidate['permissions']> {
|
|
35
|
+
const source = record(value)
|
|
36
|
+
exact(source, ['actionIds', 'allActions', 'triggerIds', 'allTriggers', 'configured', 'proxy'])
|
|
37
|
+
if (!Array.isArray(source.actionIds)) return invalidResponse('permissions.actionIds: expected an array.')
|
|
38
|
+
if (!Array.isArray(source.triggerIds)) return invalidResponse('permissions.triggerIds: expected an array.')
|
|
39
|
+
if (typeof source.allActions != 'boolean') return invalidResponse('permissions.allActions: expected a boolean.')
|
|
40
|
+
if (typeof source.allTriggers != 'boolean') return invalidResponse('permissions.allTriggers: expected a boolean.')
|
|
41
|
+
if (typeof source.configured != 'boolean') return invalidResponse('permissions.configured: expected a boolean.')
|
|
42
|
+
if (typeof source.proxy != 'boolean') return invalidResponse('permissions.proxy: expected a boolean.')
|
|
43
|
+
const actionIds = source.actionIds.map(string)
|
|
44
|
+
const triggerIds = source.triggerIds.map(string)
|
|
45
|
+
if (new Set(actionIds).size != actionIds.length) return invalidResponse('permissions.actionIds: duplicate IDs.')
|
|
46
|
+
if (source.allActions && actionIds.length != 0) return invalidResponse('permissions.actionIds: must be empty when allActions is true.')
|
|
47
|
+
if (new Set(triggerIds).size != triggerIds.length) return invalidResponse('permissions.triggerIds: duplicate IDs.')
|
|
48
|
+
if (source.allTriggers && triggerIds.length != 0) return invalidResponse('permissions.triggerIds: must be empty when allTriggers is true.')
|
|
49
|
+
if (source.proxy && (!source.allActions || !source.allTriggers || source.configured)) {
|
|
50
|
+
return invalidResponse('permissions.proxy: requires allActions=true, allTriggers=true and configured=false.')
|
|
51
|
+
}
|
|
52
|
+
return { actionIds, triggerIds, allTriggers: source.allTriggers, allActions: source.allActions, configured: source.configured, proxy: source.proxy }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function accessBinding(value: unknown, candidate: true): ProviderAccessBindingCandidate
|
|
56
|
+
function accessBinding(value: unknown, candidate: false): ProviderAccessBinding
|
|
57
|
+
function accessBinding(value: unknown, candidate: boolean): ProviderAccessBinding | ProviderAccessBindingCandidate {
|
|
58
|
+
const source = record(value)
|
|
59
|
+
const policyRevision = source.policyRevision
|
|
60
|
+
const status = source.status
|
|
61
|
+
const isDefault = source.isDefault
|
|
62
|
+
const legacy = Object.hasOwn(source, 'displayName') && !Object.hasOwn(source, 'connectionDisplayName')
|
|
63
|
+
const permissions = candidate && Object.hasOwn(source, 'permissions') ? accessPermissions(source.permissions) : undefined
|
|
64
|
+
const permissionGroupName = source.permissionGroupName
|
|
65
|
+
exact(source, [
|
|
66
|
+
'accessBindingId',
|
|
67
|
+
'connectionId',
|
|
68
|
+
'source',
|
|
69
|
+
legacy ? 'displayName' : 'connectionDisplayName',
|
|
70
|
+
...(candidate && Object.hasOwn(source, 'isDefault') ? ['isDefault'] : []),
|
|
71
|
+
...(candidate && permissions != null ? ['permissions'] : []),
|
|
72
|
+
...(Object.hasOwn(source, 'permissionGroupName') ? ['permissionGroupName'] : []),
|
|
73
|
+
...(policyRevision == null ? [] : ['policyRevision']),
|
|
74
|
+
'providerId',
|
|
75
|
+
...(candidate ? [] : ['status']),
|
|
76
|
+
])
|
|
77
|
+
if (policyRevision != null && typeof policyRevision != 'string') return invalidResponse('policyRevision: expected a string.')
|
|
78
|
+
if (candidate && isDefault !== undefined && typeof isDefault != 'boolean') return invalidResponse('isDefault: expected a boolean.')
|
|
79
|
+
if (permissionGroupName !== undefined && permissionGroupName !== null && typeof permissionGroupName != 'string')
|
|
80
|
+
return invalidResponse('permissionGroupName: expected a string or null.')
|
|
81
|
+
if (!candidate && status != 'active' && status != 'forbidden' && status != 'invalid' && status != 'missing') return invalidResponse()
|
|
82
|
+
let bindingSource
|
|
83
|
+
try {
|
|
84
|
+
bindingSource = parseProviderAccessSource(source.source)
|
|
85
|
+
} catch {
|
|
86
|
+
return invalidResponse("source: expected { kind: 'admin-delegation' } or { kind: 'policy', ruleId: string | null }.")
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
accessBindingId: string(source.accessBindingId),
|
|
90
|
+
connectionId: string(source.connectionId),
|
|
91
|
+
source: bindingSource,
|
|
92
|
+
connectionDisplayName: string(legacy ? source.displayName : source.connectionDisplayName),
|
|
93
|
+
...(candidate && typeof isDefault == 'boolean' ? { isDefault } : {}),
|
|
94
|
+
...(permissions == null ? {} : { permissions }),
|
|
95
|
+
...(permissionGroupName === undefined ? {} : { permissionGroupName }),
|
|
96
|
+
...(policyRevision == null ? {} : { policyRevision }),
|
|
97
|
+
providerId: string(source.providerId),
|
|
98
|
+
...(candidate ? {} : { status: status as ProviderAccessBinding['status'] }),
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function accessMode(value: unknown): ConnectorAccess['mode'] {
|
|
103
|
+
if (value != 'implicit' && value != 'selectable') return invalidResponse('mode: expected implicit or selectable.')
|
|
104
|
+
return value as ConnectorAccess['mode']
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function connectorAccess(value: unknown): ConnectorAccess {
|
|
108
|
+
const source = record(value)
|
|
109
|
+
exact(source, [
|
|
110
|
+
'accessRevision',
|
|
111
|
+
'bindings',
|
|
112
|
+
'mode',
|
|
113
|
+
'sharedAccessDigest',
|
|
114
|
+
...('providerIds' in source ? ['providerIds'] : []),
|
|
115
|
+
...('discardedBindingCount' in source ? ['discardedBindingCount'] : []),
|
|
116
|
+
'version',
|
|
117
|
+
])
|
|
118
|
+
const accessRevision = integer(source.accessRevision)
|
|
119
|
+
if (source.version != 1 || accessRevision < 0 || !Array.isArray(source.bindings)) return invalidResponse()
|
|
120
|
+
if ('providerIds' in source && !Array.isArray(source.providerIds)) return invalidResponse()
|
|
121
|
+
const providerIds = source.providerIds == null ? undefined : (source.providerIds as unknown[]).map((id) => string(id))
|
|
122
|
+
if (providerIds != null && new Set(providerIds).size != providerIds.length) return invalidResponse()
|
|
123
|
+
let discardedBindingCount = source.discardedBindingCount == null ? 0 : integer(source.discardedBindingCount)
|
|
124
|
+
if (discardedBindingCount < 0) return invalidResponse()
|
|
125
|
+
const bindings: ProviderAccessBinding[] = []
|
|
126
|
+
for (const entry of source.bindings) {
|
|
127
|
+
try {
|
|
128
|
+
bindings.push(accessBinding(entry, false))
|
|
129
|
+
} catch (error) {
|
|
130
|
+
if (!(error instanceof ApiError) || error.code != 'response.invalid') throw error
|
|
131
|
+
if (
|
|
132
|
+
entry != null &&
|
|
133
|
+
typeof entry == 'object' &&
|
|
134
|
+
!Array.isArray(entry) &&
|
|
135
|
+
typeof entry.accessBindingId == 'string' &&
|
|
136
|
+
entry.accessBindingId.length > 0 &&
|
|
137
|
+
typeof entry.providerId == 'string' &&
|
|
138
|
+
entry.providerId.length > 0
|
|
139
|
+
) {
|
|
140
|
+
bindings.push({
|
|
141
|
+
accessBindingId: entry.accessBindingId,
|
|
142
|
+
providerId: entry.providerId,
|
|
143
|
+
connectionId: null,
|
|
144
|
+
source: null,
|
|
145
|
+
status: 'invalid',
|
|
146
|
+
connectionDisplayName:
|
|
147
|
+
typeof entry.connectionDisplayName == 'string' && entry.connectionDisplayName.length > 0
|
|
148
|
+
? entry.connectionDisplayName
|
|
149
|
+
: typeof entry.displayName == 'string' && entry.displayName.length > 0
|
|
150
|
+
? entry.displayName
|
|
151
|
+
: entry.providerId,
|
|
152
|
+
permissionGroupName: typeof entry.permissionGroupName == 'string' ? entry.permissionGroupName : null,
|
|
153
|
+
})
|
|
154
|
+
} else discardedBindingCount++
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (new Set(bindings.map((binding) => binding.accessBindingId)).size != bindings.length) return invalidResponse()
|
|
158
|
+
return {
|
|
159
|
+
accessRevision,
|
|
160
|
+
...(discardedBindingCount == 0 ? {} : { discardedBindingCount }),
|
|
161
|
+
...(providerIds == null ? {} : { providerIds }),
|
|
162
|
+
bindings,
|
|
163
|
+
mode: accessMode(source.mode),
|
|
164
|
+
sharedAccessDigest: string(source.sharedAccessDigest),
|
|
165
|
+
version: 1,
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function accessGrants(value: unknown): readonly ConnectorAccessGrant[] {
|
|
170
|
+
if (!Array.isArray(value)) return invalidResponse()
|
|
171
|
+
const bindings = value.map((candidate) => {
|
|
172
|
+
const entry = record(candidate)
|
|
173
|
+
exact(entry, [
|
|
174
|
+
'accessBindingId',
|
|
175
|
+
'connectionId',
|
|
176
|
+
'providerId',
|
|
177
|
+
'source',
|
|
178
|
+
'connectionDisplayName',
|
|
179
|
+
...('permissionGroupName' in entry ? ['permissionGroupName'] : []),
|
|
180
|
+
])
|
|
181
|
+
let identity
|
|
182
|
+
try {
|
|
183
|
+
identity = parseProviderAccessSource(entry.source)
|
|
184
|
+
} catch {
|
|
185
|
+
return invalidResponse()
|
|
186
|
+
}
|
|
187
|
+
if (entry.permissionGroupName != null && typeof entry.permissionGroupName != 'string') return invalidResponse()
|
|
188
|
+
return {
|
|
189
|
+
accessBindingId: string(entry.accessBindingId),
|
|
190
|
+
connectionId: string(entry.connectionId),
|
|
191
|
+
providerId: string(entry.providerId),
|
|
192
|
+
source: identity,
|
|
193
|
+
connectionDisplayName: string(entry.connectionDisplayName),
|
|
194
|
+
...('permissionGroupName' in entry ? { permissionGroupName: entry.permissionGroupName as string | null } : {}),
|
|
195
|
+
}
|
|
196
|
+
})
|
|
197
|
+
if (new Set(bindings.map((binding) => binding.accessBindingId)).size != bindings.length) return invalidResponse()
|
|
198
|
+
return bindings
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export function connectorAccessSnapshot(value: unknown): ConnectorAccessSnapshot {
|
|
202
|
+
const source = record(value)
|
|
203
|
+
exact(source, ['mode', 'sharedAccessDigest', 'sharedBindings', 'selectedBindings', 'version'])
|
|
204
|
+
if (source.version != 2) return invalidResponse()
|
|
205
|
+
const mode = accessMode(source.mode)
|
|
206
|
+
const sharedBindings = accessGrants(source.sharedBindings)
|
|
207
|
+
const selectedBindings = accessGrants(source.selectedBindings)
|
|
208
|
+
if (mode == 'implicit' && (sharedBindings.length > 0 || selectedBindings.length > 0)) return invalidResponse()
|
|
209
|
+
return { mode, sharedAccessDigest: string(source.sharedAccessDigest), sharedBindings, selectedBindings, version: 2 }
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function connectorAccessCandidates(value: unknown, providerId: string): ConnectorAccessCandidates {
|
|
213
|
+
const source = record(value)
|
|
214
|
+
exact(source, ['candidates', 'mode', 'providerId', 'version'])
|
|
215
|
+
if (source.version != 1) return invalidResponse('version: expected 1.')
|
|
216
|
+
if (string(source.providerId) != providerId) return invalidResponse('providerId: does not match the requested provider.')
|
|
217
|
+
if (!Array.isArray(source.candidates)) return invalidResponse('candidates: expected an array.')
|
|
218
|
+
const candidates = source.candidates.map((candidate) => accessBinding(candidate, true))
|
|
219
|
+
if (candidates.some((candidate) => candidate.providerId != providerId))
|
|
220
|
+
return invalidResponse('candidates[].providerId: does not match the requested provider.')
|
|
221
|
+
if (new Set(candidates.map((candidate) => candidate.accessBindingId)).size != candidates.length)
|
|
222
|
+
return invalidResponse('candidates[].accessBindingId: duplicate IDs.')
|
|
223
|
+
return { candidates, mode: accessMode(source.mode), providerId, version: 1 }
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export function connectorAccessCandidatesBatch(value: unknown, providerIds: readonly string[]): ConnectorAccessCandidatesBatch {
|
|
227
|
+
const source = record(value)
|
|
228
|
+
exact(source, ['results', 'version'])
|
|
229
|
+
if (source.version != 1) return invalidResponse('version: expected 1.')
|
|
230
|
+
if (!Array.isArray(source.results)) return invalidResponse('results: expected an array.')
|
|
231
|
+
const remaining = new Set(providerIds)
|
|
232
|
+
const results = source.results.map((entry) => {
|
|
233
|
+
const item = record(entry)
|
|
234
|
+
const providerId = string(item.providerId)
|
|
235
|
+
if (!remaining.delete(providerId)) return invalidResponse('results[].providerId: duplicate or unrequested provider.')
|
|
236
|
+
if (!Object.hasOwn(item, 'error')) return connectorAccessCandidates(item, providerId)
|
|
237
|
+
exact(item, ['providerId', 'error'])
|
|
238
|
+
const error = record(item.error)
|
|
239
|
+
exact(error, ['code', 'message'])
|
|
240
|
+
return { providerId, error: { code: string(error.code), message: string(error.message) } }
|
|
241
|
+
})
|
|
242
|
+
if (remaining.size != 0) return invalidResponse('results: missing requested providers.')
|
|
243
|
+
return { results, version: 1 }
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function connection(value: unknown): ConnectorConnection {
|
|
247
|
+
const source = record(value)
|
|
248
|
+
requiredFields(source, [
|
|
249
|
+
...(Object.hasOwn(source, 'providerAccountId') ? ['providerAccountId'] : []),
|
|
250
|
+
...(Object.hasOwn(source, 'alias') ? ['alias'] : []),
|
|
251
|
+
...(Object.hasOwn(source, 'builtInAccount') ? ['builtInAccount'] : []),
|
|
252
|
+
'connectionId',
|
|
253
|
+
'displayName',
|
|
254
|
+
'isDefault',
|
|
255
|
+
'serviceId',
|
|
256
|
+
'status',
|
|
257
|
+
])
|
|
258
|
+
if (source.builtInAccount !== undefined && typeof source.builtInAccount != 'boolean') return invalidResponse()
|
|
259
|
+
const status = source.status
|
|
260
|
+
if (status != 'active' && status != 'disconnected' && status != 'error' && status != 'reauth_required') return invalidResponse()
|
|
261
|
+
if (typeof source.isDefault != 'boolean') return invalidResponse()
|
|
262
|
+
return {
|
|
263
|
+
...(source.providerAccountId === undefined ? {} : { providerAccountId: string(source.providerAccountId) }),
|
|
264
|
+
...(source.alias === undefined ? {} : { alias: string(source.alias) }),
|
|
265
|
+
...(source.builtInAccount === undefined ? {} : { builtInAccount: source.builtInAccount }),
|
|
266
|
+
connectionId: string(source.connectionId),
|
|
267
|
+
displayName: string(source.displayName),
|
|
268
|
+
isDefault: source.isDefault,
|
|
269
|
+
serviceId: string(source.serviceId),
|
|
270
|
+
status: status as ConnectorConnection['status'],
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function port(value: unknown, input = false): InputPortDefinition {
|
|
275
|
+
const source = record(value)
|
|
276
|
+
const description = source.description
|
|
277
|
+
const hasValue = input && Object.hasOwn(source, 'value')
|
|
278
|
+
requiredFields(source, ['jsonSchema', 'nullable', ...(description == null ? [] : ['description']), ...(hasValue ? ['value'] : [])])
|
|
279
|
+
if (description != null && typeof description != 'string') return invalidResponse()
|
|
280
|
+
if (typeof source.nullable != 'boolean') return invalidResponse()
|
|
281
|
+
return {
|
|
282
|
+
...(description == null ? {} : { description }),
|
|
283
|
+
jsonSchema: jsonValue(source.jsonSchema),
|
|
284
|
+
nullable: source.nullable,
|
|
285
|
+
...(hasValue ? { value: jsonValue(source.value) } : {}),
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function inputPort(value: unknown): InputPortDefinition {
|
|
290
|
+
return port(value, true)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function ports<Value>(value: unknown, decode: (value: unknown) => Value): Readonly<Record<string, Value>> {
|
|
294
|
+
return Object.fromEntries(Object.entries(record(value)).map(([handle, candidate]) => [handle, decode(candidate)]))
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export function connectorActionMetadata(value: unknown): ConnectorActionMetadata {
|
|
298
|
+
const source = record(value)
|
|
299
|
+
const homepageUrl = source.homepageUrl
|
|
300
|
+
const icon = source.icon
|
|
301
|
+
requiredFields(source, [
|
|
302
|
+
'actionId',
|
|
303
|
+
...(Object.hasOwn(source, 'operationType') ? ['operationType'] : []),
|
|
304
|
+
...(Object.hasOwn(source, 'inputSchema') ? ['inputSchema'] : []),
|
|
305
|
+
...(Object.hasOwn(source, 'outputSchema') ? ['outputSchema'] : []),
|
|
306
|
+
'authenticated',
|
|
307
|
+
'description',
|
|
308
|
+
...(homepageUrl == null ? [] : ['homepageUrl']),
|
|
309
|
+
...(icon == null ? [] : ['icon']),
|
|
310
|
+
...('iconSprite' in source ? ['iconSprite'] : []),
|
|
311
|
+
...('iconSpritePosition' in source ? ['iconSpritePosition'] : []),
|
|
312
|
+
'inputs',
|
|
313
|
+
'name',
|
|
314
|
+
'outputs',
|
|
315
|
+
'serviceId',
|
|
316
|
+
'serviceName',
|
|
317
|
+
])
|
|
318
|
+
if ((homepageUrl != null && typeof homepageUrl != 'string') || (icon != null && typeof icon != 'string')) return invalidResponse()
|
|
319
|
+
const result: ConnectorActionMetadata = {
|
|
320
|
+
...(source.inputSchema === undefined ? {} : { inputSchema: jsonValue(source.inputSchema) }),
|
|
321
|
+
...(source.outputSchema === undefined ? {} : { outputSchema: jsonValue(source.outputSchema) }),
|
|
322
|
+
actionId: string(source.actionId),
|
|
323
|
+
...(source.operationType == null ? {} : { operationType: string(source.operationType) }),
|
|
324
|
+
authenticated: typeof source.authenticated == 'boolean' ? source.authenticated : invalidResponse(),
|
|
325
|
+
description: typeof source.description == 'string' ? source.description : invalidResponse(),
|
|
326
|
+
...(homepageUrl == null ? {} : { homepageUrl }),
|
|
327
|
+
...(icon == null ? {} : { icon }),
|
|
328
|
+
...providerIconAppearance(source.iconSprite, source.iconSpritePosition),
|
|
329
|
+
inputs: ports(source.inputs, inputPort),
|
|
330
|
+
name: string(source.name),
|
|
331
|
+
outputs: ports(source.outputs, port),
|
|
332
|
+
serviceId: string(source.serviceId),
|
|
333
|
+
serviceName: string(source.serviceName),
|
|
334
|
+
}
|
|
335
|
+
return result
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export function connectorAction(value: unknown): ConnectorAction {
|
|
339
|
+
const { defaultConnection, ...metadata } = record(value)
|
|
340
|
+
const action = connectorActionMetadata(metadata)
|
|
341
|
+
if (defaultConnection == null) return action
|
|
342
|
+
const preferred = connection(defaultConnection)
|
|
343
|
+
if (preferred.serviceId != action.serviceId || preferred.status != 'active') return invalidResponse()
|
|
344
|
+
return { ...action, defaultConnection: preferred }
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export function connectorProvider(value: unknown): ConnectorProvider {
|
|
348
|
+
const source = record(value)
|
|
349
|
+
const homepageUrl = source.homepageUrl
|
|
350
|
+
const icon = source.icon
|
|
351
|
+
if (source.noSetup !== undefined && typeof source.noSetup != 'boolean') return invalidResponse()
|
|
352
|
+
requiredFields(source, [
|
|
353
|
+
...(Object.hasOwn(source, 'noSetup') ? ['noSetup'] : []),
|
|
354
|
+
'serviceId',
|
|
355
|
+
'serviceName',
|
|
356
|
+
...(homepageUrl == null ? [] : ['homepageUrl']),
|
|
357
|
+
...(icon == null ? [] : ['icon']),
|
|
358
|
+
...('iconSprite' in source ? ['iconSprite'] : []),
|
|
359
|
+
...('iconSpritePosition' in source ? ['iconSpritePosition'] : []),
|
|
360
|
+
])
|
|
361
|
+
if ((homepageUrl != null && typeof homepageUrl != 'string') || (icon != null && typeof icon != 'string')) return invalidResponse()
|
|
362
|
+
return {
|
|
363
|
+
...(homepageUrl == null ? {} : { homepageUrl }),
|
|
364
|
+
...(icon == null ? {} : { icon }),
|
|
365
|
+
...providerIconAppearance(source.iconSprite, source.iconSpritePosition),
|
|
366
|
+
serviceId: string(source.serviceId),
|
|
367
|
+
serviceName: string(source.serviceName),
|
|
368
|
+
...(source.noSetup === undefined ? {} : { noSetup: source.noSetup }),
|
|
369
|
+
}
|
|
370
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ConnectorAction, ConnectorConnection, ConnectorProvider } from './api.ts'
|
|
2
|
+
|
|
3
|
+
import { connection, connectorAction, connectorProvider } from './connectorDecoders.ts'
|
|
4
|
+
import { requiredFields, invalidResponse, record, string } from './decoding.ts'
|
|
5
|
+
|
|
6
|
+
export interface RequestQuery<Value> {
|
|
7
|
+
readonly path: string
|
|
8
|
+
readonly decode: (data: unknown) => Value
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const scope = (flowId?: string) => (flowId == null ? '' : `?flowId=${encodeURIComponent(flowId)}`)
|
|
12
|
+
|
|
13
|
+
export function connectorProvidersQuery(flowId?: string, locale?: string): RequestQuery<readonly ConnectorProvider[]> {
|
|
14
|
+
const parameters = new URLSearchParams({ ...(flowId == null ? {} : { flowId }), ...(locale == null ? {} : { locale }) }).toString()
|
|
15
|
+
return {
|
|
16
|
+
path: `/v1/connector/providers${parameters ? `?${parameters}` : ''}`,
|
|
17
|
+
decode: (value) => {
|
|
18
|
+
const source = record(value)
|
|
19
|
+
requiredFields(source, ['providers', 'version'])
|
|
20
|
+
if (source.version != 1 || !Array.isArray(source.providers)) return invalidResponse()
|
|
21
|
+
return source.providers.map(connectorProvider)
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function connectorActionQuery(actionId: string, flowId?: string, locale?: string): RequestQuery<ConnectorAction> {
|
|
27
|
+
const parameters = new URLSearchParams({ ...(flowId == null ? {} : { flowId }), ...(locale == null ? {} : { locale }) }).toString()
|
|
28
|
+
return {
|
|
29
|
+
path: `/v1/connector/actions/${encodeURIComponent(actionId)}${parameters ? `?${parameters}` : ''}`,
|
|
30
|
+
decode: (value) => {
|
|
31
|
+
const source = record(value)
|
|
32
|
+
requiredFields(source, ['action', 'version'])
|
|
33
|
+
if (source.version != 1) return invalidResponse()
|
|
34
|
+
return connectorAction(source.action)
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function allConnectorConnectionsQuery(flowId?: string): RequestQuery<readonly ConnectorConnection[]> {
|
|
40
|
+
return {
|
|
41
|
+
path: `/v1/connector/connections${scope(flowId)}`,
|
|
42
|
+
decode: (value) => {
|
|
43
|
+
const source = record(value)
|
|
44
|
+
requiredFields(source, ['connections', 'version'])
|
|
45
|
+
if (source.version != 1 || !Array.isArray(source.connections)) return invalidResponse()
|
|
46
|
+
return source.connections.map(connection)
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function connectorConnectionsQuery(serviceId: string, flowId?: string): RequestQuery<readonly ConnectorConnection[]> {
|
|
52
|
+
return {
|
|
53
|
+
path: `/v1/connector/connections/${encodeURIComponent(serviceId)}${scope(flowId)}`,
|
|
54
|
+
decode: (value) => {
|
|
55
|
+
const source = record(value)
|
|
56
|
+
requiredFields(source, ['connections', 'serviceId', 'version'])
|
|
57
|
+
if (source.version != 1 || string(source.serviceId) != serviceId || !Array.isArray(source.connections)) return invalidResponse()
|
|
58
|
+
return source.connections.map(connection)
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { JsonValue } from '../../flow/common/change.ts'
|
|
2
|
+
|
|
3
|
+
import { ApiError } from './errors.ts'
|
|
4
|
+
|
|
5
|
+
export class InvalidResponseError extends ApiError {
|
|
6
|
+
readonly detail?: string
|
|
7
|
+
|
|
8
|
+
constructor(detail?: string) {
|
|
9
|
+
super(502, 'response.invalid', `The Control API returned an invalid response.${detail == null ? '' : ` ${detail}`}`)
|
|
10
|
+
this.detail = detail
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function invalidResponse(detail?: string): never {
|
|
15
|
+
throw new InvalidResponseError(detail)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function record(value: unknown): Readonly<Record<string, unknown>> {
|
|
19
|
+
if (value == null || typeof value != 'object' || Array.isArray(value)) return invalidResponse('Expected an object.')
|
|
20
|
+
return value as Readonly<Record<string, unknown>>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function string(value: unknown): string {
|
|
24
|
+
return typeof value == 'string' && value.length > 0 ? value : invalidResponse('Expected a non-empty string.')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function requiredFields(value: Readonly<Record<string, unknown>>, keys: readonly string[]): void {
|
|
28
|
+
const missing = keys.filter((key) => !Object.hasOwn(value, key))
|
|
29
|
+
if (missing.length > 0) invalidResponse(`Missing fields: ${missing.join(', ')}.`)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function exact(value: Readonly<Record<string, unknown>>, keys: readonly string[]): void {
|
|
33
|
+
const actual = Object.keys(value)
|
|
34
|
+
if (actual.length != keys.length || actual.some((key) => !keys.includes(key))) {
|
|
35
|
+
const missing = keys.filter((key) => !Object.hasOwn(value, key))
|
|
36
|
+
const unexpected = actual.filter((key) => !keys.includes(key))
|
|
37
|
+
invalidResponse(
|
|
38
|
+
[missing.length > 0 ? `Missing fields: ${missing.join(', ')}.` : '', unexpected.length > 0 ? `Unexpected fields: ${unexpected.join(', ')}.` : '']
|
|
39
|
+
.filter(Boolean)
|
|
40
|
+
.join(' '),
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function integer(value: unknown): number {
|
|
46
|
+
return Number.isSafeInteger(value) ? (value as number) : invalidResponse('Expected a safe integer.')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function jsonValue(value: unknown): JsonValue {
|
|
50
|
+
if (value === null || typeof value == 'boolean' || typeof value == 'string') return value
|
|
51
|
+
if (typeof value == 'number' && Number.isFinite(value)) return value
|
|
52
|
+
if (Array.isArray(value)) return value.map(jsonValue)
|
|
53
|
+
const source = record(value)
|
|
54
|
+
return Object.fromEntries(Object.entries(source).map(([key, item]) => [key, jsonValue(item)]))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function optionalString(value: unknown): string | undefined {
|
|
58
|
+
if (value == null) return
|
|
59
|
+
return string(value)
|
|
60
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ChangeOperation, JsonValue, TriggerKeySnapshot, TriggerSchedule } from '../../flow/common/change.ts'
|
|
2
|
+
|
|
3
|
+
import { z } from 'zod'
|
|
4
|
+
import { changeOperationsSchema } from '../../flow/common/change.ts'
|
|
5
|
+
import { decodeChangeOperation, parseOperation } from '../../flow/common/changeSchema.ts'
|
|
6
|
+
import { checkJsonDepth } from '../../flow/common/json.ts'
|
|
7
|
+
import { createProviderTrigger } from '../../flow/common/nodeChanges.ts'
|
|
8
|
+
import { triggerScheduleSchema } from '../../flow/common/triggerScheduleSchema.ts'
|
|
9
|
+
|
|
10
|
+
const text = z.string().min(1)
|
|
11
|
+
const json: z.ZodType<JsonValue> = z.json()
|
|
12
|
+
const triggerCreate: z.ZodType<Extract<DraftOperation, { kind: 'graph.trigger.create' }>> = z.strictObject({
|
|
13
|
+
kind: z.literal('graph.trigger.create'),
|
|
14
|
+
nodeId: text,
|
|
15
|
+
key: text,
|
|
16
|
+
connectionId: text.optional(),
|
|
17
|
+
name: text.optional(),
|
|
18
|
+
config: z.record(text, json),
|
|
19
|
+
schedule: triggerScheduleSchema.readonly().optional(),
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
export type DraftOperation =
|
|
23
|
+
| ChangeOperation
|
|
24
|
+
| {
|
|
25
|
+
readonly kind: 'graph.trigger.create'
|
|
26
|
+
readonly nodeId: string
|
|
27
|
+
readonly key: string
|
|
28
|
+
readonly connectionId?: string
|
|
29
|
+
readonly name?: string
|
|
30
|
+
readonly config: Readonly<Record<string, JsonValue>>
|
|
31
|
+
readonly schedule?: readonly TriggerSchedule[]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function decodeDraftOperations(value: unknown): readonly DraftOperation[] {
|
|
35
|
+
checkJsonDepth(value)
|
|
36
|
+
return z
|
|
37
|
+
.array(z.unknown())
|
|
38
|
+
.min(1)
|
|
39
|
+
.parse(value)
|
|
40
|
+
.map((candidate, index) => {
|
|
41
|
+
const { kind } = parseOperation(candidate, index, z.object({ kind: text }).parse)
|
|
42
|
+
return kind == 'graph.trigger.create' ? parseOperation(candidate, index, triggerCreate.parse) : decodeChangeOperation(candidate, index)
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function draftOperationsSchema(kind?: string): JsonValue {
|
|
47
|
+
if (kind != null && kind != 'graph.trigger.create') return changeOperationsSchema(kind)
|
|
48
|
+
const trigger = z.toJSONSchema(triggerCreate)
|
|
49
|
+
if (kind == 'graph.trigger.create') return trigger as JsonValue
|
|
50
|
+
const schema = changeOperationsSchema() as Record<string, JsonValue>
|
|
51
|
+
return { ...schema, items: { anyOf: [schema.items!, trigger as JsonValue] } }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function resolveDraftOperations(operations: readonly DraftOperation[], definition: (key: string) => TriggerKeySnapshot): readonly ChangeOperation[] {
|
|
55
|
+
return operations.flatMap((operation) => {
|
|
56
|
+
if (operation.kind != 'graph.trigger.create') return [operation]
|
|
57
|
+
const snapshot = definition(operation.key)
|
|
58
|
+
if (snapshot.type != 'poll' && operation.schedule != null) throw new Error('Only Poll triggers accept a schedule.')
|
|
59
|
+
return createProviderTrigger(operation.nodeId, snapshot, operation)
|
|
60
|
+
})
|
|
61
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
export const controlErrorCode = {
|
|
2
|
+
authenticationRequired: 'authentication.required',
|
|
3
|
+
authorizationDenied: 'authorization.denied',
|
|
4
|
+
bindingUnresolved: 'binding.unresolved',
|
|
5
|
+
connectorActionNotFound: 'connector.action-not-found',
|
|
6
|
+
connectorAccessConflict: 'connector.access-conflict',
|
|
7
|
+
connectorAccessInvalid: 'connector.access-invalid',
|
|
8
|
+
connectorAccessRequired: 'connector.access-required',
|
|
9
|
+
connectorAccessUnsupported: 'connector.access-unsupported',
|
|
10
|
+
connectorUnconfigured: 'connector.unconfigured',
|
|
11
|
+
connectorUnavailable: 'connector.unavailable',
|
|
12
|
+
connectorConsoleUnconfigured: 'connector.console-unconfigured',
|
|
13
|
+
engineUnavailable: 'engine.unavailable',
|
|
14
|
+
engineUnsupported: 'engine.unsupported',
|
|
15
|
+
eventSourceInvalid: 'event-source.invalid',
|
|
16
|
+
eventSourceIdentityUnavailable: 'event-source.identity-unavailable',
|
|
17
|
+
eventSourceNotFound: 'event-source.not-found',
|
|
18
|
+
eventSourceConflict: 'event-source.conflict',
|
|
19
|
+
flowInvalid: 'flow.invalid',
|
|
20
|
+
flowRepairRequired: 'flow.repair-required',
|
|
21
|
+
flowUpgradeRequired: 'flow.upgrade-required',
|
|
22
|
+
flowNotFound: 'flow.not-found',
|
|
23
|
+
flowBusy: 'flow.busy',
|
|
24
|
+
flowConflict: 'flow.conflict',
|
|
25
|
+
flowPresentationConflict: 'flow.presentation-conflict',
|
|
26
|
+
flowRevisionConflict: 'flow.revision-conflict',
|
|
27
|
+
liveConflict: 'live.conflict',
|
|
28
|
+
liveNotFound: 'live.not-found',
|
|
29
|
+
pageInvalidCursor: 'page.invalid-cursor',
|
|
30
|
+
publicationConflict: 'publication.conflict',
|
|
31
|
+
publicationNotFound: 'publication.not-found',
|
|
32
|
+
publicationUnsupported: 'publication.unsupported',
|
|
33
|
+
publishOperationNotFound: 'publication.operation-not-found',
|
|
34
|
+
routeNotFound: 'route.not-found',
|
|
35
|
+
runConflict: 'run.conflict',
|
|
36
|
+
runEventsExpired: 'run.events-expired',
|
|
37
|
+
runInvalid: 'run.invalid',
|
|
38
|
+
runNotFound: 'run.not-found',
|
|
39
|
+
runNotTerminal: 'run.not-terminal',
|
|
40
|
+
runOverloaded: 'run.overloaded',
|
|
41
|
+
runWaitNotFound: 'run.wait-not-found',
|
|
42
|
+
triggerKeyInvalid: 'trigger-key.invalid',
|
|
43
|
+
triggerKeyNotFound: 'trigger-key.not-found',
|
|
44
|
+
triggerNotFound: 'trigger.not-found',
|
|
45
|
+
variableInvalid: 'variable.invalid',
|
|
46
|
+
variableLimitReached: 'variable.limit-reached',
|
|
47
|
+
variableNotFound: 'variable.not-found',
|
|
48
|
+
} as const
|
|
49
|
+
|
|
50
|
+
export type ControlErrorCode = (typeof controlErrorCode)[keyof typeof controlErrorCode]
|
|
51
|
+
|
|
52
|
+
export const controlErrorMetadata = {
|
|
53
|
+
[controlErrorCode.eventSourceInvalid]: { status: 400 },
|
|
54
|
+
[controlErrorCode.eventSourceIdentityUnavailable]: { status: 409 },
|
|
55
|
+
[controlErrorCode.eventSourceNotFound]: { status: 404 },
|
|
56
|
+
[controlErrorCode.eventSourceConflict]: { status: 409 },
|
|
57
|
+
[controlErrorCode.authenticationRequired]: { status: 401 },
|
|
58
|
+
[controlErrorCode.authorizationDenied]: { status: 403 },
|
|
59
|
+
[controlErrorCode.bindingUnresolved]: { status: 409 },
|
|
60
|
+
[controlErrorCode.connectorActionNotFound]: { status: 404 },
|
|
61
|
+
[controlErrorCode.connectorAccessConflict]: { status: 412 },
|
|
62
|
+
[controlErrorCode.connectorAccessInvalid]: { status: 409 },
|
|
63
|
+
[controlErrorCode.connectorAccessRequired]: { status: 409 },
|
|
64
|
+
[controlErrorCode.connectorAccessUnsupported]: { status: 409 },
|
|
65
|
+
[controlErrorCode.connectorUnconfigured]: { status: 503 },
|
|
66
|
+
[controlErrorCode.connectorUnavailable]: { status: 503 },
|
|
67
|
+
[controlErrorCode.connectorConsoleUnconfigured]: { status: 503 },
|
|
68
|
+
[controlErrorCode.engineUnavailable]: { status: 503 },
|
|
69
|
+
[controlErrorCode.engineUnsupported]: { status: 409 },
|
|
70
|
+
[controlErrorCode.flowInvalid]: { status: 400 },
|
|
71
|
+
[controlErrorCode.flowRepairRequired]: { status: 409 },
|
|
72
|
+
[controlErrorCode.flowUpgradeRequired]: { status: 409 },
|
|
73
|
+
[controlErrorCode.flowNotFound]: { status: 404 },
|
|
74
|
+
[controlErrorCode.flowBusy]: { status: 409 },
|
|
75
|
+
[controlErrorCode.flowConflict]: { status: 409 },
|
|
76
|
+
[controlErrorCode.flowPresentationConflict]: { status: 412 },
|
|
77
|
+
[controlErrorCode.flowRevisionConflict]: { status: 412 },
|
|
78
|
+
[controlErrorCode.liveConflict]: { status: 412 },
|
|
79
|
+
[controlErrorCode.liveNotFound]: { status: 404 },
|
|
80
|
+
[controlErrorCode.pageInvalidCursor]: { status: 400 },
|
|
81
|
+
[controlErrorCode.publicationConflict]: { status: 409 },
|
|
82
|
+
[controlErrorCode.publicationNotFound]: { status: 404 },
|
|
83
|
+
[controlErrorCode.publicationUnsupported]: { status: 409 },
|
|
84
|
+
[controlErrorCode.publishOperationNotFound]: { status: 404 },
|
|
85
|
+
[controlErrorCode.routeNotFound]: { status: 404 },
|
|
86
|
+
[controlErrorCode.runConflict]: { status: 409 },
|
|
87
|
+
[controlErrorCode.runEventsExpired]: { status: 410 },
|
|
88
|
+
[controlErrorCode.runInvalid]: { status: 400 },
|
|
89
|
+
[controlErrorCode.runNotFound]: { status: 404 },
|
|
90
|
+
[controlErrorCode.runNotTerminal]: { status: 409 },
|
|
91
|
+
[controlErrorCode.runOverloaded]: { status: 429 },
|
|
92
|
+
[controlErrorCode.runWaitNotFound]: { status: 404 },
|
|
93
|
+
[controlErrorCode.triggerKeyInvalid]: { status: 409 },
|
|
94
|
+
[controlErrorCode.triggerKeyNotFound]: { status: 404 },
|
|
95
|
+
[controlErrorCode.triggerNotFound]: { status: 404 },
|
|
96
|
+
[controlErrorCode.variableInvalid]: { status: 400 },
|
|
97
|
+
[controlErrorCode.variableLimitReached]: { status: 409 },
|
|
98
|
+
[controlErrorCode.variableNotFound]: { status: 404 },
|
|
99
|
+
} as const satisfies Record<ControlErrorCode, { readonly status: number }>
|
|
100
|
+
|
|
101
|
+
export class ApiError extends Error {
|
|
102
|
+
readonly code: string
|
|
103
|
+
readonly status: number
|
|
104
|
+
|
|
105
|
+
readonly details?: Readonly<Record<string, unknown>>
|
|
106
|
+
|
|
107
|
+
constructor(status: number, code: string, message: string, details?: Readonly<Record<string, unknown>>) {
|
|
108
|
+
super(message)
|
|
109
|
+
this.code = code
|
|
110
|
+
this.details = details
|
|
111
|
+
this.name = 'ApiError'
|
|
112
|
+
this.status = status
|
|
113
|
+
}
|
|
114
|
+
}
|